model_map_slice.go (2664B)
1 package bun 2 3 import ( 4 "context" 5 "database/sql" 6 "errors" 7 "sort" 8 9 "github.com/uptrace/bun/dialect/feature" 10 "github.com/uptrace/bun/schema" 11 ) 12 13 type mapSliceModel struct { 14 mapModel 15 dest *[]map[string]interface{} 16 17 keys []string 18 } 19 20 var _ Model = (*mapSliceModel)(nil) 21 22 func newMapSliceModel(db *DB, dest *[]map[string]interface{}) *mapSliceModel { 23 return &mapSliceModel{ 24 mapModel: mapModel{ 25 db: db, 26 }, 27 dest: dest, 28 } 29 } 30 31 func (m *mapSliceModel) Value() interface{} { 32 return m.dest 33 } 34 35 func (m *mapSliceModel) SetCap(cap int) { 36 if cap > 100 { 37 cap = 100 38 } 39 if slice := *m.dest; len(slice) < cap { 40 *m.dest = make([]map[string]interface{}, 0, cap) 41 } 42 } 43 44 func (m *mapSliceModel) ScanRows(ctx context.Context, rows *sql.Rows) (int, error) { 45 columns, err := rows.Columns() 46 if err != nil { 47 return 0, err 48 } 49 50 m.rows = rows 51 m.columns = columns 52 dest := makeDest(m, len(columns)) 53 54 slice := *m.dest 55 if len(slice) > 0 { 56 slice = slice[:0] 57 } 58 59 var n int 60 61 for rows.Next() { 62 m.m = make(map[string]interface{}, len(m.columns)) 63 64 m.scanIndex = 0 65 if err := rows.Scan(dest...); err != nil { 66 return 0, err 67 } 68 69 slice = append(slice, m.m) 70 n++ 71 } 72 if err := rows.Err(); err != nil { 73 return 0, err 74 } 75 76 *m.dest = slice 77 return n, nil 78 } 79 80 func (m *mapSliceModel) appendColumns(fmter schema.Formatter, b []byte) (_ []byte, err error) { 81 if err := m.initKeys(); err != nil { 82 return nil, err 83 } 84 85 for i, k := range m.keys { 86 if i > 0 { 87 b = append(b, ", "...) 88 } 89 b = fmter.AppendIdent(b, k) 90 } 91 92 return b, nil 93 } 94 95 func (m *mapSliceModel) appendValues(fmter schema.Formatter, b []byte) (_ []byte, err error) { 96 if err := m.initKeys(); err != nil { 97 return nil, err 98 } 99 slice := *m.dest 100 101 b = append(b, "VALUES "...) 102 if m.db.features.Has(feature.ValuesRow) { 103 b = append(b, "ROW("...) 104 } else { 105 b = append(b, '(') 106 } 107 108 if fmter.IsNop() { 109 for i := range m.keys { 110 if i > 0 { 111 b = append(b, ", "...) 112 } 113 b = append(b, '?') 114 } 115 return b, nil 116 } 117 118 for i, el := range slice { 119 if i > 0 { 120 b = append(b, "), "...) 121 if m.db.features.Has(feature.ValuesRow) { 122 b = append(b, "ROW("...) 123 } else { 124 b = append(b, '(') 125 } 126 } 127 128 for j, key := range m.keys { 129 if j > 0 { 130 b = append(b, ", "...) 131 } 132 b = schema.Append(fmter, b, el[key]) 133 } 134 } 135 136 b = append(b, ')') 137 138 return b, nil 139 } 140 141 func (m *mapSliceModel) initKeys() error { 142 if m.keys != nil { 143 return nil 144 } 145 146 slice := *m.dest 147 if len(slice) == 0 { 148 return errors.New("bun: map slice is empty") 149 } 150 151 first := slice[0] 152 keys := make([]string, 0, len(first)) 153 154 for k := range first { 155 keys = append(keys, k) 156 } 157 158 sort.Strings(keys) 159 m.keys = keys 160 161 return nil 162 }