model.go (4389B)
1 package bun 2 3 import ( 4 "context" 5 "database/sql" 6 "errors" 7 "fmt" 8 "reflect" 9 "time" 10 11 "github.com/uptrace/bun/schema" 12 ) 13 14 var errNilModel = errors.New("bun: Model(nil)") 15 16 var ( 17 timeType = reflect.TypeOf((*time.Time)(nil)).Elem() 18 bytesType = reflect.TypeOf((*[]byte)(nil)).Elem() 19 ) 20 21 type Model = schema.Model 22 23 type rowScanner interface { 24 ScanRow(ctx context.Context, rows *sql.Rows) error 25 } 26 27 type TableModel interface { 28 Model 29 30 schema.BeforeAppendModelHook 31 schema.BeforeScanRowHook 32 schema.AfterScanRowHook 33 ScanColumn(column string, src interface{}) error 34 35 Table() *schema.Table 36 Relation() *schema.Relation 37 38 join(string) *relationJoin 39 getJoin(string) *relationJoin 40 getJoins() []relationJoin 41 addJoin(relationJoin) *relationJoin 42 43 rootValue() reflect.Value 44 parentIndex() []int 45 mount(reflect.Value) 46 47 updateSoftDeleteField(time.Time) error 48 } 49 50 func newModel(db *DB, dest []interface{}) (Model, error) { 51 if len(dest) == 1 { 52 return _newModel(db, dest[0], true) 53 } 54 55 values := make([]reflect.Value, len(dest)) 56 57 for i, el := range dest { 58 v := reflect.ValueOf(el) 59 if v.Kind() != reflect.Ptr { 60 return nil, fmt.Errorf("bun: Scan(non-pointer %T)", dest) 61 } 62 63 v = v.Elem() 64 if v.Kind() != reflect.Slice { 65 return newScanModel(db, dest), nil 66 } 67 68 values[i] = v 69 } 70 71 return newSliceModel(db, dest, values), nil 72 } 73 74 func newSingleModel(db *DB, dest interface{}) (Model, error) { 75 return _newModel(db, dest, false) 76 } 77 78 func _newModel(db *DB, dest interface{}, scan bool) (Model, error) { 79 switch dest := dest.(type) { 80 case nil: 81 return nil, errNilModel 82 case Model: 83 return dest, nil 84 case sql.Scanner: 85 if !scan { 86 return nil, fmt.Errorf("bun: Model(unsupported %T)", dest) 87 } 88 return newScanModel(db, []interface{}{dest}), nil 89 } 90 91 v := reflect.ValueOf(dest) 92 if !v.IsValid() { 93 return nil, errNilModel 94 } 95 if v.Kind() != reflect.Ptr { 96 return nil, fmt.Errorf("bun: Model(non-pointer %T)", dest) 97 } 98 99 if v.IsNil() { 100 typ := v.Type().Elem() 101 if typ.Kind() == reflect.Struct { 102 return newStructTableModel(db, dest, db.Table(typ)), nil 103 } 104 return nil, fmt.Errorf("bun: Model(nil %s %T)", typ.Kind(), dest) 105 } 106 107 v = v.Elem() 108 typ := v.Type() 109 110 switch typ { 111 case timeType, bytesType: 112 return newScanModel(db, []interface{}{dest}), nil 113 } 114 115 switch v.Kind() { 116 case reflect.Map: 117 if err := validMap(typ); err != nil { 118 return nil, err 119 } 120 mapPtr := v.Addr().Interface().(*map[string]interface{}) 121 return newMapModel(db, mapPtr), nil 122 case reflect.Struct: 123 return newStructTableModelValue(db, dest, v), nil 124 case reflect.Slice: 125 switch elemType := sliceElemType(v); elemType.Kind() { 126 case reflect.Struct: 127 if elemType != timeType { 128 return newSliceTableModel(db, dest, v, elemType), nil 129 } 130 case reflect.Map: 131 if err := validMap(elemType); err != nil { 132 return nil, err 133 } 134 slicePtr := v.Addr().Interface().(*[]map[string]interface{}) 135 return newMapSliceModel(db, slicePtr), nil 136 } 137 return newSliceModel(db, []interface{}{dest}, []reflect.Value{v}), nil 138 } 139 140 if scan { 141 return newScanModel(db, []interface{}{dest}), nil 142 } 143 144 return nil, fmt.Errorf("bun: Model(unsupported %T)", dest) 145 } 146 147 func newTableModelIndex( 148 db *DB, 149 table *schema.Table, 150 root reflect.Value, 151 index []int, 152 rel *schema.Relation, 153 ) (TableModel, error) { 154 typ := typeByIndex(table.Type, index) 155 156 if typ.Kind() == reflect.Struct { 157 return &structTableModel{ 158 db: db, 159 table: table.Dialect().Tables().Get(typ), 160 rel: rel, 161 162 root: root, 163 index: index, 164 }, nil 165 } 166 167 if typ.Kind() == reflect.Slice { 168 structType := indirectType(typ.Elem()) 169 if structType.Kind() == reflect.Struct { 170 m := sliceTableModel{ 171 structTableModel: structTableModel{ 172 db: db, 173 table: table.Dialect().Tables().Get(structType), 174 rel: rel, 175 176 root: root, 177 index: index, 178 }, 179 } 180 m.init(typ) 181 return &m, nil 182 } 183 } 184 185 return nil, fmt.Errorf("bun: NewModel(%s)", typ) 186 } 187 188 func validMap(typ reflect.Type) error { 189 if typ.Key().Kind() != reflect.String || typ.Elem().Kind() != reflect.Interface { 190 return fmt.Errorf("bun: Model(unsupported %s) (expected *map[string]interface{})", 191 typ) 192 } 193 return nil 194 } 195 196 //------------------------------------------------------------------------------ 197 198 func isSingleRowModel(m Model) bool { 199 switch m.(type) { 200 case *mapModel, 201 *structTableModel, 202 *scanModel: 203 return true 204 default: 205 return false 206 } 207 }