package bun import ( "context" "database/sql" "errors" "sort" "github.com/uptrace/bun/dialect/feature" "github.com/uptrace/bun/schema" ) type mapSliceModel struct { mapModel dest *[]map[string]interface{} keys []string } var _ model = (*mapSliceModel)(nil) func newMapSliceModel(db *DB, dest *[]map[string]interface{}) *mapSliceModel { return &mapSliceModel{ mapModel: mapModel{ db: db, }, dest: dest, } } func (m *mapSliceModel) Value() interface{} { return m.dest } func (m *mapSliceModel) SetCap(cap int) { if cap > 100 { cap = 100 } if slice := *m.dest; len(slice) < cap { *m.dest = make([]map[string]interface{}, 0, cap) } } func (m *mapSliceModel) ScanRows(ctx context.Context, rows *sql.Rows) (int, error) { columns, err := rows.Columns() if err != nil { return 0, err } m.rows = rows m.columns = columns dest := makeDest(m, len(columns)) slice := *m.dest if len(slice) > 0 { slice = slice[:0] } var n int for rows.Next() { m.m = make(map[string]interface{}, len(m.columns)) m.scanIndex = 0 if err := rows.Scan(dest...); err != nil { return 0, err } slice = append(slice, m.m) n++ } if err := rows.Err(); err != nil { return 0, err } *m.dest = slice return n, nil } func (m *mapSliceModel) appendColumns(fmter schema.Formatter, b []byte) (_ []byte, err error) { if err := m.initKeys(); err != nil { return nil, err } for i, k := range m.keys { if i > 0 { b = append(b, ", "...) } b = fmter.AppendIdent(b, k) } return b, nil } func (m *mapSliceModel) appendValues(fmter schema.Formatter, b []byte) (_ []byte, err error) { if err := m.initKeys(); err != nil { return nil, err } slice := *m.dest b = append(b, "VALUES "...) if m.db.features.Has(feature.ValuesRow) { b = append(b, "ROW("...) } else { b = append(b, '(') } if fmter.IsNop() { for i := range m.keys { if i > 0 { b = append(b, ", "...) } b = append(b, '?') } return b, nil } for i, el := range slice { if i > 0 { b = append(b, "), "...) if m.db.features.Has(feature.ValuesRow) { b = append(b, "ROW("...) } else { b = append(b, '(') } } for j, key := range m.keys { if j > 0 { b = append(b, ", "...) } b = fmter.Dialect().Append(fmter, b, el[key]) } } b = append(b, ')') return b, nil } func (m *mapSliceModel) initKeys() error { if m.keys != nil { return nil } slice := *m.dest if len(slice) == 0 { return errors.New("bun: map slice is empty") } first := slice[0] keys := make([]string, 0, len(first)) for k := range first { keys = append(keys, k) } sort.Strings(keys) m.keys = keys return nil }