mirror of
https://github.com/astaxie/beego.git
synced 2024-12-23 00:00:50 +00:00
Merge pull request #1856 from b055/develop
added functionality for column type time
This commit is contained in:
commit
6362dc397a
@ -55,6 +55,8 @@ checkColumn:
|
||||
col = fmt.Sprintf(T["string"], fieldSize)
|
||||
case TypeTextField:
|
||||
col = T["string-text"]
|
||||
case TypeTimeField:
|
||||
col = T["time.Time-clock"]
|
||||
case TypeDateField:
|
||||
col = T["time.Time-date"]
|
||||
case TypeDateTimeField:
|
||||
@ -264,7 +266,7 @@ func getColumnDefault(fi *fieldInfo) string {
|
||||
|
||||
// These defaults will be useful if there no config value orm:"default" and NOT NULL is on
|
||||
switch fi.fieldType {
|
||||
case TypeDateField, TypeDateTimeField, TypeTextField:
|
||||
case TypeTimeField, TypeDateField, TypeDateTimeField, TypeTextField:
|
||||
return v
|
||||
|
||||
case TypeBitField, TypeSmallIntegerField, TypeIntegerField,
|
||||
|
18
orm/db.go
18
orm/db.go
@ -24,6 +24,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
formatTime = "15:04:05"
|
||||
formatDate = "2006-01-02"
|
||||
formatDateTime = "2006-01-02 15:04:05"
|
||||
)
|
||||
@ -175,7 +176,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
||||
value = field.Float()
|
||||
}
|
||||
}
|
||||
case TypeDateField, TypeDateTimeField:
|
||||
case TypeTimeField, TypeDateField, TypeDateTimeField:
|
||||
value = field.Interface()
|
||||
if t, ok := value.(time.Time); ok {
|
||||
d.ins.TimeToDB(&t, tz)
|
||||
@ -229,7 +230,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
|
||||
}
|
||||
}
|
||||
switch fi.fieldType {
|
||||
case TypeDateField, TypeDateTimeField:
|
||||
case TypeTimeField, TypeDateField, TypeDateTimeField:
|
||||
if fi.autoNow || fi.autoNowAdd && insert {
|
||||
if insert {
|
||||
if t, ok := value.(time.Time); ok && !t.IsZero() {
|
||||
@ -1098,7 +1099,7 @@ setValue:
|
||||
} else {
|
||||
value = str.String()
|
||||
}
|
||||
case fieldType == TypeDateField || fieldType == TypeDateTimeField:
|
||||
case fieldType == TypeTimeField || fieldType == TypeDateField || fieldType == TypeDateTimeField:
|
||||
if str == nil {
|
||||
switch t := val.(type) {
|
||||
case time.Time:
|
||||
@ -1118,15 +1119,20 @@ setValue:
|
||||
if len(s) >= 19 {
|
||||
s = s[:19]
|
||||
t, err = time.ParseInLocation(formatDateTime, s, tz)
|
||||
} else {
|
||||
} else if len(s) >= 10 {
|
||||
if len(s) > 10 {
|
||||
s = s[:10]
|
||||
}
|
||||
t, err = time.ParseInLocation(formatDate, s, tz)
|
||||
} else if len(s) >= 8 {
|
||||
if len(s) > 8 {
|
||||
s = s[:8]
|
||||
}
|
||||
t, err = time.ParseInLocation(formatTime, s, tz)
|
||||
}
|
||||
t = t.In(DefaultTimeLoc)
|
||||
|
||||
if err != nil && s != "0000-00-00" && s != "0000-00-00 00:00:00" {
|
||||
if err != nil && s != "00:00:00" && s != "0000-00-00" && s != "0000-00-00 00:00:00" {
|
||||
tErr = err
|
||||
goto end
|
||||
}
|
||||
@ -1255,7 +1261,7 @@ setValue:
|
||||
field.SetString(value.(string))
|
||||
}
|
||||
}
|
||||
case fieldType == TypeDateField || fieldType == TypeDateTimeField:
|
||||
case fieldType == TypeTimeField || fieldType == TypeDateField || fieldType == TypeDateTimeField:
|
||||
if isNative {
|
||||
if value == nil {
|
||||
value = time.Time{}
|
||||
|
@ -74,24 +74,32 @@ outFor:
|
||||
case reflect.String:
|
||||
v := val.String()
|
||||
if fi != nil {
|
||||
if fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField {
|
||||
if fi.fieldType == TypeTimeField || fi.fieldType == TypeDateField || fi.fieldType == TypeDateTimeField {
|
||||
var t time.Time
|
||||
var err error
|
||||
if len(v) >= 19 {
|
||||
s := v[:19]
|
||||
t, err = time.ParseInLocation(formatDateTime, s, DefaultTimeLoc)
|
||||
} else {
|
||||
} else if len(v) >= 10 {
|
||||
s := v
|
||||
if len(v) > 10 {
|
||||
s = v[:10]
|
||||
}
|
||||
t, err = time.ParseInLocation(formatDate, s, tz)
|
||||
} else {
|
||||
s := v
|
||||
if len(s) > 8 {
|
||||
s = v[:8]
|
||||
}
|
||||
t, err = time.ParseInLocation(formatTime, s, tz)
|
||||
}
|
||||
if err == nil {
|
||||
if fi.fieldType == TypeDateField {
|
||||
v = t.In(tz).Format(formatDate)
|
||||
} else {
|
||||
} else if fi.fieldType == TypeDateTimeField {
|
||||
v = t.In(tz).Format(formatDateTime)
|
||||
} else {
|
||||
v = t.In(tz).Format(formatTime)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -137,8 +145,10 @@ outFor:
|
||||
if v, ok := arg.(time.Time); ok {
|
||||
if fi != nil && fi.fieldType == TypeDateField {
|
||||
arg = v.In(tz).Format(formatDate)
|
||||
} else {
|
||||
} else if fi.fieldType == TypeDateTimeField {
|
||||
arg = v.In(tz).Format(formatDateTime)
|
||||
} else {
|
||||
arg = v.In(tz).Format(formatTime)
|
||||
}
|
||||
} else {
|
||||
typ := val.Type()
|
||||
|
@ -25,6 +25,7 @@ const (
|
||||
TypeBooleanField = 1 << iota
|
||||
TypeCharField
|
||||
TypeTextField
|
||||
TypeTimeField
|
||||
TypeDateField
|
||||
TypeDateTimeField
|
||||
TypeBitField
|
||||
@ -46,9 +47,9 @@ const (
|
||||
|
||||
// Define some logic enum
|
||||
const (
|
||||
IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5
|
||||
IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9
|
||||
IsRelField = ^-RelReverseMany >> 14 << 15
|
||||
IsIntegerField = ^-TypePositiveBigIntegerField >> 5 << 6
|
||||
IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 9 << 10
|
||||
IsRelField = ^-RelReverseMany >> 15 << 16
|
||||
IsFieldType = ^-RelReverseMany<<1 + 1
|
||||
)
|
||||
|
||||
@ -145,6 +146,59 @@ func (e *CharField) RawValue() interface{} {
|
||||
// verify CharField implement Fielder
|
||||
var _ Fielder = new(CharField)
|
||||
|
||||
// A time, represented in go by a time.Time instance.
|
||||
// only time values like 10:00:00
|
||||
// Has a few extra, optional attr tag:
|
||||
//
|
||||
// auto_now:
|
||||
// Automatically set the field to now every time the object is saved. Useful for “last-modified” timestamps.
|
||||
// Note that the current date is always used; it’s not just a default value that you can override.
|
||||
//
|
||||
// auto_now_add:
|
||||
// Automatically set the field to now when the object is first created. Useful for creation of timestamps.
|
||||
// Note that the current date is always used; it’s not just a default value that you can override.
|
||||
//
|
||||
// eg: `orm:"auto_now"` or `orm:"auto_now_add"`
|
||||
type TimeField time.Time
|
||||
|
||||
func (e TimeField) Value() time.Time {
|
||||
return time.Time(e)
|
||||
}
|
||||
|
||||
func (e *TimeField) Set(d time.Time) {
|
||||
*e = TimeField(d)
|
||||
}
|
||||
|
||||
func (e *TimeField) String() string {
|
||||
return e.Value().String()
|
||||
}
|
||||
|
||||
func (e *TimeField) FieldType() int {
|
||||
return TypeDateField
|
||||
}
|
||||
|
||||
func (e *TimeField) SetRaw(value interface{}) error {
|
||||
switch d := value.(type) {
|
||||
case time.Time:
|
||||
e.Set(d)
|
||||
case string:
|
||||
v, err := timeParse(d, formatTime)
|
||||
if err != nil {
|
||||
e.Set(v)
|
||||
}
|
||||
return err
|
||||
default:
|
||||
return fmt.Errorf("<TimeField.SetRaw> unknown value `%s`", value)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (e *TimeField) RawValue() interface{} {
|
||||
return e.Value()
|
||||
}
|
||||
|
||||
var _ Fielder = new(TimeField)
|
||||
|
||||
// DateField A date, represented in go by a time.Time instance.
|
||||
// only date values like 2006-01-02
|
||||
// Has a few extra, optional attr tag:
|
||||
|
@ -248,6 +248,9 @@ checkType:
|
||||
if fieldType == TypeDateTimeField && tags["type"] == "date" {
|
||||
fieldType = TypeDateField
|
||||
}
|
||||
if fieldType == TypeTimeField && tags["type"] == "time" {
|
||||
fieldType = TypeTimeField
|
||||
}
|
||||
}
|
||||
|
||||
switch fieldType {
|
||||
@ -353,7 +356,7 @@ checkType:
|
||||
case TypeTextField:
|
||||
fi.index = false
|
||||
fi.unique = false
|
||||
case TypeDateField, TypeDateTimeField:
|
||||
case TypeTimeField, TypeDateField, TypeDateTimeField:
|
||||
if attrs["auto_now"] {
|
||||
fi.autoNow = true
|
||||
} else if attrs["auto_now_add"] {
|
||||
@ -406,7 +409,7 @@ checkType:
|
||||
fi.index = false
|
||||
}
|
||||
|
||||
if fi.auto || fi.pk || fi.unique || fieldType == TypeDateField || fieldType == TypeDateTimeField {
|
||||
if fi.auto || fi.pk || fi.unique || fieldType == TypeTimeField || fieldType == TypeDateField || fieldType == TypeDateTimeField {
|
||||
// can not set default
|
||||
initial.Clear()
|
||||
}
|
||||
|
@ -112,6 +112,7 @@ type Data struct {
|
||||
Boolean bool
|
||||
Char string `orm:"size(50)"`
|
||||
Text string `orm:"type(text)"`
|
||||
Time time.Time `orm:"type(time)"`
|
||||
Date time.Time `orm:"type(date)"`
|
||||
DateTime time.Time `orm:"column(datetime)"`
|
||||
Byte byte
|
||||
@ -136,6 +137,7 @@ type DataNull struct {
|
||||
Boolean bool `orm:"null"`
|
||||
Char string `orm:"null;size(50)"`
|
||||
Text string `orm:"null;type(text)"`
|
||||
Time time.Time `orm:"null;type(time)"`
|
||||
Date time.Time `orm:"null;type(date)"`
|
||||
DateTime time.Time `orm:"null;column(datetime)"`
|
||||
Byte byte `orm:"null"`
|
||||
|
@ -34,6 +34,7 @@ var _ = os.PathSeparator
|
||||
var (
|
||||
testDate = formatDate + " -0700"
|
||||
testDateTime = formatDateTime + " -0700"
|
||||
testTime = formatTime + " -0700"
|
||||
)
|
||||
|
||||
type argAny []interface{}
|
||||
@ -240,6 +241,7 @@ var DataValues = map[string]interface{}{
|
||||
"Boolean": true,
|
||||
"Char": "char",
|
||||
"Text": "text",
|
||||
"Time": time.Now(),
|
||||
"Date": time.Now(),
|
||||
"DateTime": time.Now(),
|
||||
"Byte": byte(1<<8 - 1),
|
||||
@ -267,7 +269,6 @@ func TestDataTypes(t *testing.T) {
|
||||
e := ind.FieldByName(name)
|
||||
e.Set(reflect.ValueOf(value))
|
||||
}
|
||||
|
||||
id, err := dORM.Insert(&d)
|
||||
throwFail(t, err)
|
||||
throwFail(t, AssertIs(id, 1))
|
||||
@ -288,6 +289,9 @@ func TestDataTypes(t *testing.T) {
|
||||
case "DateTime":
|
||||
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDateTime)
|
||||
value = value.(time.Time).In(DefaultTimeLoc).Format(testDateTime)
|
||||
case "Time":
|
||||
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testTime)
|
||||
value = value.(time.Time).In(DefaultTimeLoc).Format(testTime)
|
||||
}
|
||||
throwFail(t, AssertIs(vu == value, true), value, vu)
|
||||
}
|
||||
@ -1521,6 +1525,7 @@ func TestRawQueryRow(t *testing.T) {
|
||||
Boolean bool
|
||||
Char string
|
||||
Text string
|
||||
Time time.Time
|
||||
Date time.Time
|
||||
DateTime time.Time
|
||||
Byte byte
|
||||
@ -1549,14 +1554,14 @@ func TestRawQueryRow(t *testing.T) {
|
||||
Q := dDbBaser.TableQuote()
|
||||
|
||||
cols := []string{
|
||||
"id", "boolean", "char", "text", "date", "datetime", "byte", "rune", "int", "int8", "int16", "int32",
|
||||
"id", "boolean", "char", "text", "time", "date", "datetime", "byte", "rune", "int", "int8", "int16", "int32",
|
||||
"int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "decimal",
|
||||
}
|
||||
sep := fmt.Sprintf("%s, %s", Q, Q)
|
||||
query := fmt.Sprintf("SELECT %s%s%s FROM data WHERE id = ?", Q, strings.Join(cols, sep), Q)
|
||||
var id int
|
||||
values := []interface{}{
|
||||
&id, &Boolean, &Char, &Text, &Date, &DateTime, &Byte, &Rune, &Int, &Int8, &Int16, &Int32,
|
||||
&id, &Boolean, &Char, &Text, &Time, &Date, &DateTime, &Byte, &Rune, &Int, &Int8, &Int16, &Int32,
|
||||
&Int64, &Uint, &Uint8, &Uint16, &Uint32, &Uint64, &Float32, &Float64, &Decimal,
|
||||
}
|
||||
err := dORM.Raw(query, 1).QueryRow(values...)
|
||||
@ -1567,6 +1572,10 @@ func TestRawQueryRow(t *testing.T) {
|
||||
switch col {
|
||||
case "id":
|
||||
throwFail(t, AssertIs(id, 1))
|
||||
case "time":
|
||||
v = v.(time.Time).In(DefaultTimeLoc)
|
||||
value := dataValues[col].(time.Time).In(DefaultTimeLoc)
|
||||
throwFail(t, AssertIs(v, value, testTime))
|
||||
case "date":
|
||||
v = v.(time.Time).In(DefaultTimeLoc)
|
||||
value := dataValues[col].(time.Time).In(DefaultTimeLoc)
|
||||
@ -1614,6 +1623,9 @@ func TestQueryRows(t *testing.T) {
|
||||
e := ind.FieldByName(name)
|
||||
vu := e.Interface()
|
||||
switch name {
|
||||
case "Time":
|
||||
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testTime)
|
||||
value = value.(time.Time).In(DefaultTimeLoc).Format(testTime)
|
||||
case "Date":
|
||||
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDate)
|
||||
value = value.(time.Time).In(DefaultTimeLoc).Format(testDate)
|
||||
@ -1638,6 +1650,9 @@ func TestQueryRows(t *testing.T) {
|
||||
e := ind.FieldByName(name)
|
||||
vu := e.Interface()
|
||||
switch name {
|
||||
case "Time":
|
||||
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testTime)
|
||||
value = value.(time.Time).In(DefaultTimeLoc).Format(testTime)
|
||||
case "Date":
|
||||
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDate)
|
||||
value = value.(time.Time).In(DefaultTimeLoc).Format(testDate)
|
||||
|
Loading…
Reference in New Issue
Block a user