model_map.go (3119B)
1 package bun 2 3 import ( 4 "context" 5 "database/sql" 6 "reflect" 7 "sort" 8 9 "github.com/uptrace/bun/schema" 10 ) 11 12 type mapModel struct { 13 db *DB 14 15 dest *map[string]interface{} 16 m map[string]interface{} 17 18 rows *sql.Rows 19 columns []string 20 _columnTypes []*sql.ColumnType 21 scanIndex int 22 } 23 24 var _ Model = (*mapModel)(nil) 25 26 func newMapModel(db *DB, dest *map[string]interface{}) *mapModel { 27 m := &mapModel{ 28 db: db, 29 dest: dest, 30 } 31 if dest != nil { 32 m.m = *dest 33 } 34 return m 35 } 36 37 func (m *mapModel) Value() interface{} { 38 return m.dest 39 } 40 41 func (m *mapModel) ScanRows(ctx context.Context, rows *sql.Rows) (int, error) { 42 if !rows.Next() { 43 return 0, rows.Err() 44 } 45 46 columns, err := rows.Columns() 47 if err != nil { 48 return 0, err 49 } 50 51 m.rows = rows 52 m.columns = columns 53 dest := makeDest(m, len(columns)) 54 55 if m.m == nil { 56 m.m = make(map[string]interface{}, len(m.columns)) 57 } 58 59 m.scanIndex = 0 60 if err := rows.Scan(dest...); err != nil { 61 return 0, err 62 } 63 64 *m.dest = m.m 65 66 return 1, nil 67 } 68 69 func (m *mapModel) Scan(src interface{}) error { 70 if _, ok := src.([]byte); !ok { 71 return m.scanRaw(src) 72 } 73 74 columnTypes, err := m.columnTypes() 75 if err != nil { 76 return err 77 } 78 79 scanType := columnTypes[m.scanIndex].ScanType() 80 switch scanType.Kind() { 81 case reflect.Interface: 82 return m.scanRaw(src) 83 case reflect.Slice: 84 if scanType.Elem().Kind() == reflect.Uint8 { 85 return m.scanRaw(src) 86 } 87 } 88 89 dest := reflect.New(scanType).Elem() 90 if err := schema.Scanner(scanType)(dest, src); err != nil { 91 return err 92 } 93 94 return m.scanRaw(dest.Interface()) 95 } 96 97 func (m *mapModel) columnTypes() ([]*sql.ColumnType, error) { 98 if m._columnTypes == nil { 99 columnTypes, err := m.rows.ColumnTypes() 100 if err != nil { 101 return nil, err 102 } 103 m._columnTypes = columnTypes 104 } 105 return m._columnTypes, nil 106 } 107 108 func (m *mapModel) scanRaw(src interface{}) error { 109 columnName := m.columns[m.scanIndex] 110 m.scanIndex++ 111 m.m[columnName] = src 112 return nil 113 } 114 115 func (m *mapModel) appendColumnsValues(fmter schema.Formatter, b []byte) []byte { 116 keys := make([]string, 0, len(m.m)) 117 118 for k := range m.m { 119 keys = append(keys, k) 120 } 121 sort.Strings(keys) 122 123 b = append(b, " ("...) 124 125 for i, k := range keys { 126 if i > 0 { 127 b = append(b, ", "...) 128 } 129 b = fmter.AppendIdent(b, k) 130 } 131 132 b = append(b, ") VALUES ("...) 133 134 isTemplate := fmter.IsNop() 135 for i, k := range keys { 136 if i > 0 { 137 b = append(b, ", "...) 138 } 139 if isTemplate { 140 b = append(b, '?') 141 } else { 142 b = schema.Append(fmter, b, m.m[k]) 143 } 144 } 145 146 b = append(b, ")"...) 147 148 return b 149 } 150 151 func (m *mapModel) appendSet(fmter schema.Formatter, b []byte) []byte { 152 keys := make([]string, 0, len(m.m)) 153 154 for k := range m.m { 155 keys = append(keys, k) 156 } 157 sort.Strings(keys) 158 159 isTemplate := fmter.IsNop() 160 for i, k := range keys { 161 if i > 0 { 162 b = append(b, ", "...) 163 } 164 165 b = fmter.AppendIdent(b, k) 166 b = append(b, " = "...) 167 if isTemplate { 168 b = append(b, '?') 169 } else { 170 b = schema.Append(fmter, b, m.m[k]) 171 } 172 } 173 174 return b 175 } 176 177 func makeDest(v interface{}, n int) []interface{} { 178 dest := make([]interface{}, n) 179 for i := range dest { 180 dest[i] = v 181 } 182 return dest 183 }