Commit 6362dc39 authored by astaxie's avatar astaxie

Merge pull request #1856 from b055/develop

added functionality for column type time
parents 813f47fd d49c7f96
...@@ -55,6 +55,8 @@ checkColumn: ...@@ -55,6 +55,8 @@ checkColumn:
col = fmt.Sprintf(T["string"], fieldSize) col = fmt.Sprintf(T["string"], fieldSize)
case TypeTextField: case TypeTextField:
col = T["string-text"] col = T["string-text"]
case TypeTimeField:
col = T["time.Time-clock"]
case TypeDateField: case TypeDateField:
col = T["time.Time-date"] col = T["time.Time-date"]
case TypeDateTimeField: case TypeDateTimeField:
...@@ -264,7 +266,7 @@ func getColumnDefault(fi *fieldInfo) string { ...@@ -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 // These defaults will be useful if there no config value orm:"default" and NOT NULL is on
switch fi.fieldType { switch fi.fieldType {
case TypeDateField, TypeDateTimeField, TypeTextField: case TypeTimeField, TypeDateField, TypeDateTimeField, TypeTextField:
return v return v
case TypeBitField, TypeSmallIntegerField, TypeIntegerField, case TypeBitField, TypeSmallIntegerField, TypeIntegerField,
......
...@@ -24,6 +24,7 @@ import ( ...@@ -24,6 +24,7 @@ import (
) )
const ( const (
formatTime = "15:04:05"
formatDate = "2006-01-02" formatDate = "2006-01-02"
formatDateTime = "2006-01-02 15:04:05" formatDateTime = "2006-01-02 15:04:05"
) )
...@@ -175,7 +176,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val ...@@ -175,7 +176,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
value = field.Float() value = field.Float()
} }
} }
case TypeDateField, TypeDateTimeField: case TypeTimeField, TypeDateField, TypeDateTimeField:
value = field.Interface() value = field.Interface()
if t, ok := value.(time.Time); ok { if t, ok := value.(time.Time); ok {
d.ins.TimeToDB(&t, tz) d.ins.TimeToDB(&t, tz)
...@@ -229,7 +230,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val ...@@ -229,7 +230,7 @@ func (d *dbBase) collectFieldValue(mi *modelInfo, fi *fieldInfo, ind reflect.Val
} }
} }
switch fi.fieldType { switch fi.fieldType {
case TypeDateField, TypeDateTimeField: case TypeTimeField, TypeDateField, TypeDateTimeField:
if fi.autoNow || fi.autoNowAdd && insert { if fi.autoNow || fi.autoNowAdd && insert {
if insert { if insert {
if t, ok := value.(time.Time); ok && !t.IsZero() { if t, ok := value.(time.Time); ok && !t.IsZero() {
...@@ -1098,7 +1099,7 @@ setValue: ...@@ -1098,7 +1099,7 @@ setValue:
} else { } else {
value = str.String() value = str.String()
} }
case fieldType == TypeDateField || fieldType == TypeDateTimeField: case fieldType == TypeTimeField || fieldType == TypeDateField || fieldType == TypeDateTimeField:
if str == nil { if str == nil {
switch t := val.(type) { switch t := val.(type) {
case time.Time: case time.Time:
...@@ -1118,15 +1119,20 @@ setValue: ...@@ -1118,15 +1119,20 @@ setValue:
if len(s) >= 19 { if len(s) >= 19 {
s = s[:19] s = s[:19]
t, err = time.ParseInLocation(formatDateTime, s, tz) t, err = time.ParseInLocation(formatDateTime, s, tz)
} else { } else if len(s) >= 10 {
if len(s) > 10 { if len(s) > 10 {
s = s[:10] s = s[:10]
} }
t, err = time.ParseInLocation(formatDate, s, tz) 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) 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 tErr = err
goto end goto end
} }
...@@ -1255,7 +1261,7 @@ setValue: ...@@ -1255,7 +1261,7 @@ setValue:
field.SetString(value.(string)) field.SetString(value.(string))
} }
} }
case fieldType == TypeDateField || fieldType == TypeDateTimeField: case fieldType == TypeTimeField || fieldType == TypeDateField || fieldType == TypeDateTimeField:
if isNative { if isNative {
if value == nil { if value == nil {
value = time.Time{} value = time.Time{}
......
...@@ -74,24 +74,32 @@ outFor: ...@@ -74,24 +74,32 @@ outFor:
case reflect.String: case reflect.String:
v := val.String() v := val.String()
if fi != nil { 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 t time.Time
var err error var err error
if len(v) >= 19 { if len(v) >= 19 {
s := v[:19] s := v[:19]
t, err = time.ParseInLocation(formatDateTime, s, DefaultTimeLoc) t, err = time.ParseInLocation(formatDateTime, s, DefaultTimeLoc)
} else { } else if len(v) >= 10 {
s := v s := v
if len(v) > 10 { if len(v) > 10 {
s = v[:10] s = v[:10]
} }
t, err = time.ParseInLocation(formatDate, s, tz) 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 err == nil {
if fi.fieldType == TypeDateField { if fi.fieldType == TypeDateField {
v = t.In(tz).Format(formatDate) v = t.In(tz).Format(formatDate)
} else { } else if fi.fieldType == TypeDateTimeField {
v = t.In(tz).Format(formatDateTime) v = t.In(tz).Format(formatDateTime)
} else {
v = t.In(tz).Format(formatTime)
} }
} }
} }
...@@ -137,8 +145,10 @@ outFor: ...@@ -137,8 +145,10 @@ outFor:
if v, ok := arg.(time.Time); ok { if v, ok := arg.(time.Time); ok {
if fi != nil && fi.fieldType == TypeDateField { if fi != nil && fi.fieldType == TypeDateField {
arg = v.In(tz).Format(formatDate) arg = v.In(tz).Format(formatDate)
} else { } else if fi.fieldType == TypeDateTimeField {
arg = v.In(tz).Format(formatDateTime) arg = v.In(tz).Format(formatDateTime)
} else {
arg = v.In(tz).Format(formatTime)
} }
} else { } else {
typ := val.Type() typ := val.Type()
......
...@@ -25,6 +25,7 @@ const ( ...@@ -25,6 +25,7 @@ const (
TypeBooleanField = 1 << iota TypeBooleanField = 1 << iota
TypeCharField TypeCharField
TypeTextField TypeTextField
TypeTimeField
TypeDateField TypeDateField
TypeDateTimeField TypeDateTimeField
TypeBitField TypeBitField
...@@ -46,9 +47,9 @@ const ( ...@@ -46,9 +47,9 @@ const (
// Define some logic enum // Define some logic enum
const ( const (
IsIntegerField = ^-TypePositiveBigIntegerField >> 4 << 5 IsIntegerField = ^-TypePositiveBigIntegerField >> 5 << 6
IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 8 << 9 IsPositiveIntegerField = ^-TypePositiveBigIntegerField >> 9 << 10
IsRelField = ^-RelReverseMany >> 14 << 15 IsRelField = ^-RelReverseMany >> 15 << 16
IsFieldType = ^-RelReverseMany<<1 + 1 IsFieldType = ^-RelReverseMany<<1 + 1
) )
...@@ -145,6 +146,59 @@ func (e *CharField) RawValue() interface{} { ...@@ -145,6 +146,59 @@ func (e *CharField) RawValue() interface{} {
// verify CharField implement Fielder // verify CharField implement Fielder
var _ Fielder = new(CharField) 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. // DateField A date, represented in go by a time.Time instance.
// only date values like 2006-01-02 // only date values like 2006-01-02
// Has a few extra, optional attr tag: // Has a few extra, optional attr tag:
......
...@@ -248,6 +248,9 @@ checkType: ...@@ -248,6 +248,9 @@ checkType:
if fieldType == TypeDateTimeField && tags["type"] == "date" { if fieldType == TypeDateTimeField && tags["type"] == "date" {
fieldType = TypeDateField fieldType = TypeDateField
} }
if fieldType == TypeTimeField && tags["type"] == "time" {
fieldType = TypeTimeField
}
} }
switch fieldType { switch fieldType {
...@@ -353,7 +356,7 @@ checkType: ...@@ -353,7 +356,7 @@ checkType:
case TypeTextField: case TypeTextField:
fi.index = false fi.index = false
fi.unique = false fi.unique = false
case TypeDateField, TypeDateTimeField: case TypeTimeField, TypeDateField, TypeDateTimeField:
if attrs["auto_now"] { if attrs["auto_now"] {
fi.autoNow = true fi.autoNow = true
} else if attrs["auto_now_add"] { } else if attrs["auto_now_add"] {
...@@ -406,7 +409,7 @@ checkType: ...@@ -406,7 +409,7 @@ checkType:
fi.index = false 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 // can not set default
initial.Clear() initial.Clear()
} }
......
...@@ -112,6 +112,7 @@ type Data struct { ...@@ -112,6 +112,7 @@ type Data struct {
Boolean bool Boolean bool
Char string `orm:"size(50)"` Char string `orm:"size(50)"`
Text string `orm:"type(text)"` Text string `orm:"type(text)"`
Time time.Time `orm:"type(time)"`
Date time.Time `orm:"type(date)"` Date time.Time `orm:"type(date)"`
DateTime time.Time `orm:"column(datetime)"` DateTime time.Time `orm:"column(datetime)"`
Byte byte Byte byte
...@@ -136,6 +137,7 @@ type DataNull struct { ...@@ -136,6 +137,7 @@ type DataNull struct {
Boolean bool `orm:"null"` Boolean bool `orm:"null"`
Char string `orm:"null;size(50)"` Char string `orm:"null;size(50)"`
Text string `orm:"null;type(text)"` Text string `orm:"null;type(text)"`
Time time.Time `orm:"null;type(time)"`
Date time.Time `orm:"null;type(date)"` Date time.Time `orm:"null;type(date)"`
DateTime time.Time `orm:"null;column(datetime)"` DateTime time.Time `orm:"null;column(datetime)"`
Byte byte `orm:"null"` Byte byte `orm:"null"`
......
...@@ -34,6 +34,7 @@ var _ = os.PathSeparator ...@@ -34,6 +34,7 @@ var _ = os.PathSeparator
var ( var (
testDate = formatDate + " -0700" testDate = formatDate + " -0700"
testDateTime = formatDateTime + " -0700" testDateTime = formatDateTime + " -0700"
testTime = formatTime + " -0700"
) )
type argAny []interface{} type argAny []interface{}
...@@ -240,6 +241,7 @@ var DataValues = map[string]interface{}{ ...@@ -240,6 +241,7 @@ var DataValues = map[string]interface{}{
"Boolean": true, "Boolean": true,
"Char": "char", "Char": "char",
"Text": "text", "Text": "text",
"Time": time.Now(),
"Date": time.Now(), "Date": time.Now(),
"DateTime": time.Now(), "DateTime": time.Now(),
"Byte": byte(1<<8 - 1), "Byte": byte(1<<8 - 1),
...@@ -267,7 +269,6 @@ func TestDataTypes(t *testing.T) { ...@@ -267,7 +269,6 @@ func TestDataTypes(t *testing.T) {
e := ind.FieldByName(name) e := ind.FieldByName(name)
e.Set(reflect.ValueOf(value)) e.Set(reflect.ValueOf(value))
} }
id, err := dORM.Insert(&d) id, err := dORM.Insert(&d)
throwFail(t, err) throwFail(t, err)
throwFail(t, AssertIs(id, 1)) throwFail(t, AssertIs(id, 1))
...@@ -288,6 +289,9 @@ func TestDataTypes(t *testing.T) { ...@@ -288,6 +289,9 @@ func TestDataTypes(t *testing.T) {
case "DateTime": case "DateTime":
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDateTime) vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDateTime)
value = value.(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) throwFail(t, AssertIs(vu == value, true), value, vu)
} }
...@@ -1521,6 +1525,7 @@ func TestRawQueryRow(t *testing.T) { ...@@ -1521,6 +1525,7 @@ func TestRawQueryRow(t *testing.T) {
Boolean bool Boolean bool
Char string Char string
Text string Text string
Time time.Time
Date time.Time Date time.Time
DateTime time.Time DateTime time.Time
Byte byte Byte byte
...@@ -1549,14 +1554,14 @@ func TestRawQueryRow(t *testing.T) { ...@@ -1549,14 +1554,14 @@ func TestRawQueryRow(t *testing.T) {
Q := dDbBaser.TableQuote() Q := dDbBaser.TableQuote()
cols := []string{ 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", "int64", "uint", "uint8", "uint16", "uint32", "uint64", "float32", "float64", "decimal",
} }
sep := fmt.Sprintf("%s, %s", Q, Q) sep := fmt.Sprintf("%s, %s", Q, Q)
query := fmt.Sprintf("SELECT %s%s%s FROM data WHERE id = ?", Q, strings.Join(cols, sep), Q) query := fmt.Sprintf("SELECT %s%s%s FROM data WHERE id = ?", Q, strings.Join(cols, sep), Q)
var id int var id int
values := []interface{}{ 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, &Int64, &Uint, &Uint8, &Uint16, &Uint32, &Uint64, &Float32, &Float64, &Decimal,
} }
err := dORM.Raw(query, 1).QueryRow(values...) err := dORM.Raw(query, 1).QueryRow(values...)
...@@ -1567,6 +1572,10 @@ func TestRawQueryRow(t *testing.T) { ...@@ -1567,6 +1572,10 @@ func TestRawQueryRow(t *testing.T) {
switch col { switch col {
case "id": case "id":
throwFail(t, AssertIs(id, 1)) 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": case "date":
v = v.(time.Time).In(DefaultTimeLoc) v = v.(time.Time).In(DefaultTimeLoc)
value := dataValues[col].(time.Time).In(DefaultTimeLoc) value := dataValues[col].(time.Time).In(DefaultTimeLoc)
...@@ -1614,6 +1623,9 @@ func TestQueryRows(t *testing.T) { ...@@ -1614,6 +1623,9 @@ func TestQueryRows(t *testing.T) {
e := ind.FieldByName(name) e := ind.FieldByName(name)
vu := e.Interface() vu := e.Interface()
switch name { switch name {
case "Time":
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testTime)
value = value.(time.Time).In(DefaultTimeLoc).Format(testTime)
case "Date": case "Date":
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDate) vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDate)
value = value.(time.Time).In(DefaultTimeLoc).Format(testDate) value = value.(time.Time).In(DefaultTimeLoc).Format(testDate)
...@@ -1638,6 +1650,9 @@ func TestQueryRows(t *testing.T) { ...@@ -1638,6 +1650,9 @@ func TestQueryRows(t *testing.T) {
e := ind.FieldByName(name) e := ind.FieldByName(name)
vu := e.Interface() vu := e.Interface()
switch name { switch name {
case "Time":
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testTime)
value = value.(time.Time).In(DefaultTimeLoc).Format(testTime)
case "Date": case "Date":
vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDate) vu = vu.(time.Time).In(DefaultTimeLoc).Format(testDate)
value = value.(time.Time).In(DefaultTimeLoc).Format(testDate) value = value.(time.Time).In(DefaultTimeLoc).Format(testDate)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment