github.com/goravel/framework@v1.13.9/database/gorm/cursor.go (about) 1 package gorm 2 3 import ( 4 "reflect" 5 "strings" 6 "time" 7 8 "github.com/mitchellh/mapstructure" 9 "gorm.io/gorm" 10 11 "github.com/goravel/framework/support/carbon" 12 "github.com/goravel/framework/support/str" 13 ) 14 15 type CursorImpl struct { 16 query *QueryImpl 17 row map[string]any 18 } 19 20 func (c *CursorImpl) Scan(value any) error { 21 msConfig := &mapstructure.DecoderConfig{ 22 DecodeHook: mapstructure.ComposeDecodeHookFunc( 23 ToTimeHookFunc(), ToCarbonHookFunc(), ToDeletedAtHookFunc(), 24 ), 25 Squash: true, 26 Result: value, 27 MatchName: func(mapKey, fieldName string) bool { 28 return str.Case2Camel(mapKey) == fieldName || strings.EqualFold(mapKey, fieldName) 29 }, 30 } 31 32 decoder, err := mapstructure.NewDecoder(msConfig) 33 if err != nil { 34 return err 35 } 36 37 if err := decoder.Decode(c.row); err != nil { 38 return err 39 } 40 41 for _, item := range c.query.conditions.with { 42 // Need to new a query, avoid to clear the conditions 43 query := c.query.new(c.query.instance) 44 // The new query must be cleared 45 query.clearConditions() 46 if err := query.Load(value, item.query, item.args...); err != nil { 47 return err 48 } 49 } 50 51 return nil 52 } 53 54 func ToTimeHookFunc() mapstructure.DecodeHookFunc { 55 return func(f reflect.Type, t reflect.Type, data any) (any, error) { 56 if t != reflect.TypeOf(time.Time{}) { 57 return data, nil 58 } 59 60 switch f.Kind() { 61 case reflect.String: 62 return time.Parse(time.RFC3339, data.(string)) 63 case reflect.Float64: 64 return time.Unix(0, int64(data.(float64))*int64(time.Millisecond)), nil 65 case reflect.Int64: 66 return time.Unix(0, data.(int64)*int64(time.Millisecond)), nil 67 default: 68 return data, nil 69 } 70 } 71 } 72 73 func ToCarbonHookFunc() mapstructure.DecodeHookFunc { 74 return func(f reflect.Type, t reflect.Type, data any) (any, error) { 75 if f == reflect.TypeOf(time.Time{}) { 76 switch t { 77 case reflect.TypeOf(carbon.DateTime{}): 78 return carbon.NewDateTime(carbon.FromStdTime(data.(time.Time))), nil 79 case reflect.TypeOf(carbon.DateTimeMilli{}): 80 return carbon.NewDateTimeMilli(carbon.FromStdTime(data.(time.Time))), nil 81 case reflect.TypeOf(carbon.DateTimeMicro{}): 82 return carbon.NewDateTimeMicro(carbon.FromStdTime(data.(time.Time))), nil 83 case reflect.TypeOf(carbon.DateTimeNano{}): 84 return carbon.NewDateTimeNano(carbon.FromStdTime(data.(time.Time))), nil 85 case reflect.TypeOf(carbon.Date{}): 86 return carbon.NewDate(carbon.FromStdTime(data.(time.Time))), nil 87 case reflect.TypeOf(carbon.DateMilli{}): 88 return carbon.NewDateMilli(carbon.FromStdTime(data.(time.Time))), nil 89 case reflect.TypeOf(carbon.DateMicro{}): 90 return carbon.NewDateMicro(carbon.FromStdTime(data.(time.Time))), nil 91 case reflect.TypeOf(carbon.DateNano{}): 92 return carbon.NewDateNano(carbon.FromStdTime(data.(time.Time))), nil 93 case reflect.TypeOf(carbon.Timestamp{}): 94 return carbon.NewTimestamp(carbon.FromStdTime(data.(time.Time))), nil 95 case reflect.TypeOf(carbon.TimestampMilli{}): 96 return carbon.NewTimestampMilli(carbon.FromStdTime(data.(time.Time))), nil 97 case reflect.TypeOf(carbon.TimestampMicro{}): 98 return carbon.NewTimestampMicro(carbon.FromStdTime(data.(time.Time))), nil 99 case reflect.TypeOf(carbon.TimestampNano{}): 100 return carbon.NewTimestampNano(carbon.FromStdTime(data.(time.Time))), nil 101 } 102 } 103 if f.Kind() == reflect.String { 104 switch t { 105 case reflect.TypeOf(carbon.DateTime{}): 106 return carbon.NewDateTime(carbon.Parse(data.(string))), nil 107 case reflect.TypeOf(carbon.DateTimeMilli{}): 108 return carbon.NewDateTimeMilli(carbon.Parse(data.(string))), nil 109 case reflect.TypeOf(carbon.DateTimeMicro{}): 110 return carbon.NewDateTimeMicro(carbon.Parse(data.(string))), nil 111 case reflect.TypeOf(carbon.DateTimeNano{}): 112 return carbon.NewDateTimeNano(carbon.Parse(data.(string))), nil 113 case reflect.TypeOf(carbon.Date{}): 114 return carbon.NewDate(carbon.Parse(data.(string))), nil 115 case reflect.TypeOf(carbon.DateMilli{}): 116 return carbon.NewDateMilli(carbon.Parse(data.(string))), nil 117 case reflect.TypeOf(carbon.DateMicro{}): 118 return carbon.NewDateMicro(carbon.Parse(data.(string))), nil 119 case reflect.TypeOf(carbon.DateNano{}): 120 return carbon.NewDateNano(carbon.Parse(data.(string))), nil 121 case reflect.TypeOf(carbon.Timestamp{}): 122 return carbon.NewTimestamp(carbon.Parse(data.(string))), nil 123 case reflect.TypeOf(carbon.TimestampMilli{}): 124 return carbon.NewTimestampMilli(carbon.Parse(data.(string))), nil 125 case reflect.TypeOf(carbon.TimestampMicro{}): 126 return carbon.NewTimestampMicro(carbon.Parse(data.(string))), nil 127 case reflect.TypeOf(carbon.TimestampNano{}): 128 return carbon.NewTimestampNano(carbon.Parse(data.(string))), nil 129 } 130 } 131 132 return data, nil 133 } 134 } 135 136 func ToDeletedAtHookFunc() mapstructure.DecodeHookFunc { 137 return func(f reflect.Type, t reflect.Type, data any) (any, error) { 138 if t != reflect.TypeOf(gorm.DeletedAt{}) { 139 return data, nil 140 } 141 142 if f == reflect.TypeOf(time.Time{}) { 143 return gorm.DeletedAt{Time: data.(time.Time), Valid: true}, nil 144 } 145 146 if f.Kind() == reflect.String { 147 return gorm.DeletedAt{Time: carbon.Parse(data.(string)).ToStdTime(), Valid: true}, nil 148 } 149 150 return data, nil 151 } 152 }