27
27
// ErrConvertingToTime is thrown when a value cannot be converted to a Time
28
28
ErrConvertingToTime = errors .NewKind ("value %q can't be converted to time.Time" )
29
29
30
- // ErrVarCharTruncation is thrown when a value is textually longer than the destination capacity
30
+ // ErrCharTruncation is thrown when a Char value is textually longer than the destination capacity
31
+ ErrCharTruncation = errors .NewKind ("string value of %q is longer than destination capacity %d" )
32
+
33
+ // ErrVarCharTruncation is thrown when a VarChar value is textually longer than the destination capacity
31
34
ErrVarCharTruncation = errors .NewKind ("string value of %q is longer than destination capacity %d" )
32
35
33
36
// ErrValueNotNil is thrown when a value that was expected to be nil, is not
@@ -198,6 +201,8 @@ var (
198
201
Timestamp timestampT
199
202
// Date is a date with day, month and year.
200
203
Date dateT
204
+ // Datetime is a date and a time
205
+ Datetime datetimeT
201
206
// Text is a string type.
202
207
Text textT
203
208
// Boolean is a boolean type.
@@ -218,6 +223,11 @@ func Array(underlying Type) Type {
218
223
return arrayT {underlying }
219
224
}
220
225
226
+ // Char returns a new Char type of the given length.
227
+ func Char (length int ) Type {
228
+ return charT {length : length }
229
+ }
230
+
221
231
// VarChar returns a new VarChar type of the given length.
222
232
func VarChar (length int ) Type {
223
233
return varCharT {length : length }
@@ -254,10 +264,16 @@ func MysqlTypeToType(sql query.Type) (Type, error) {
254
264
return Date , nil
255
265
case sqltypes .Text :
256
266
return Text , nil
267
+ case sqltypes .Char :
268
+ // Since we can't get the size of the sqltypes.Char to instantiate a
269
+ // specific Char(length) type we return a Text here
270
+ return Text , nil
257
271
case sqltypes .VarChar :
258
272
// Since we can't get the size of the sqltypes.VarChar to instantiate a
259
273
// specific VarChar(length) type we return a Text here
260
274
return Text , nil
275
+ case sqltypes .Datetime :
276
+ return Datetime , nil
261
277
case sqltypes .Bit :
262
278
return Boolean , nil
263
279
case sqltypes .TypeJSON :
@@ -597,6 +613,109 @@ func (t dateT) Compare(a, b interface{}) (int, error) {
597
613
return 0 , nil
598
614
}
599
615
616
+ type datetimeT struct {}
617
+
618
+ // DatetimeLayout is the layout of the MySQL date format in the representation
619
+ // Go understands.
620
+ const DatetimeLayout = "2006-01-02 15:04:05"
621
+
622
+ func (t datetimeT ) String () string { return "DATETIME" }
623
+
624
+ func (t datetimeT ) Type () query.Type {
625
+ return sqltypes .Datetime
626
+ }
627
+
628
+ func (t datetimeT ) SQL (v interface {}) (sqltypes.Value , error ) {
629
+ if v == nil {
630
+ return sqltypes .NULL , nil
631
+ }
632
+
633
+ v , err := t .Convert (v )
634
+ if err != nil {
635
+ return sqltypes.Value {}, err
636
+ }
637
+
638
+ return sqltypes .MakeTrusted (
639
+ sqltypes .Datetime ,
640
+ []byte (v .(time.Time ).Format (DatetimeLayout )),
641
+ ), nil
642
+ }
643
+
644
+ func (t datetimeT ) Convert (v interface {}) (interface {}, error ) {
645
+ switch value := v .(type ) {
646
+ case time.Time :
647
+ return value .UTC (), nil
648
+ case string :
649
+ t , err := time .Parse (DatetimeLayout , value )
650
+ if err != nil {
651
+ return nil , ErrConvertingToTime .Wrap (err , v )
652
+ }
653
+ return t .UTC (), nil
654
+ default :
655
+ ts , err := Int64 .Convert (v )
656
+ if err != nil {
657
+ return nil , ErrInvalidType .New (reflect .TypeOf (v ))
658
+ }
659
+
660
+ return time .Unix (ts .(int64 ), 0 ).UTC (), nil
661
+ }
662
+ }
663
+
664
+ func (t datetimeT ) Compare (a , b interface {}) (int , error ) {
665
+ av := a .(time.Time )
666
+ bv := b .(time.Time )
667
+ if av .Before (bv ) {
668
+ return - 1 , nil
669
+ } else if av .After (bv ) {
670
+ return 1 , nil
671
+ }
672
+ return 0 , nil
673
+ }
674
+
675
+ type charT struct {
676
+ length int
677
+ }
678
+
679
+ func (t charT ) Capacity () int { return t .length }
680
+
681
+ func (t charT ) String () string { return fmt .Sprintf ("CHAR(%d)" , t .length ) }
682
+
683
+ func (t charT ) Type () query.Type {
684
+ return sqltypes .Char
685
+ }
686
+
687
+ func (t charT ) SQL (v interface {}) (sqltypes.Value , error ) {
688
+ if v == nil {
689
+ return sqltypes .MakeTrusted (sqltypes .Char , nil ), nil
690
+ }
691
+
692
+ v , err := t .Convert (v )
693
+ if err != nil {
694
+ return sqltypes.Value {}, err
695
+ }
696
+
697
+ return sqltypes .MakeTrusted (sqltypes .Char , []byte (v .(string ))), nil
698
+ }
699
+
700
+ // Converts any value that can be casted to a string
701
+ func (t charT ) Convert (v interface {}) (interface {}, error ) {
702
+ val , err := cast .ToStringE (v )
703
+ if err != nil {
704
+ return nil , ErrConvertToSQL .New (t )
705
+ }
706
+
707
+ if len (val ) > t .length {
708
+ return nil , ErrCharTruncation .New (val , t .length )
709
+ }
710
+ return val , nil
711
+ }
712
+
713
+ // Compares two strings lexicographically
714
+ func (t charT ) Compare (a interface {}, b interface {}) (int , error ) {
715
+ return strings .Compare (a .(string ), b .(string )), nil
716
+ }
717
+
718
+
600
719
type varCharT struct {
601
720
length int
602
721
}
@@ -1013,9 +1132,9 @@ func IsInteger(t Type) bool {
1013
1132
return IsSigned (t ) || IsUnsigned (t )
1014
1133
}
1015
1134
1016
- // IsTime checks if t is a timestamp or date.
1135
+ // IsTime checks if t is a timestamp, date or datetime
1017
1136
func IsTime (t Type ) bool {
1018
- return t == Timestamp || t == Date
1137
+ return t == Timestamp || t == Date || t == Datetime
1019
1138
}
1020
1139
1021
1140
// IsDecimal checks if t is decimal type.
@@ -1025,7 +1144,13 @@ func IsDecimal(t Type) bool {
1025
1144
1026
1145
// IsText checks if t is a text type.
1027
1146
func IsText (t Type ) bool {
1028
- return t == Text || t == Blob || t == JSON || IsVarChar (t )
1147
+ return t == Text || t == Blob || t == JSON || IsVarChar (t ) || IsChar (t )
1148
+ }
1149
+
1150
+ // IsChar checks if t is a Char type.
1151
+ func IsChar (t Type ) bool {
1152
+ _ , ok := t .(charT )
1153
+ return ok
1029
1154
}
1030
1155
1031
1156
// IsVarChar checks if t is a varchar type.
@@ -1082,9 +1207,13 @@ func MySQLTypeName(t Type) string {
1082
1207
case sqltypes .Float64 :
1083
1208
return "DOUBLE"
1084
1209
case sqltypes .Timestamp :
1210
+ return "TIMESTAMP"
1211
+ case sqltypes .Datetime :
1085
1212
return "DATETIME"
1086
1213
case sqltypes .Date :
1087
1214
return "DATE"
1215
+ case sqltypes .Char :
1216
+ return "CHAR"
1088
1217
case sqltypes .VarChar :
1089
1218
return "VARCHAR"
1090
1219
case sqltypes .Text :
0 commit comments