query_values.go (4364B)
1 package bun 2 3 import ( 4 "fmt" 5 "reflect" 6 "strconv" 7 8 "github.com/uptrace/bun/dialect/feature" 9 "github.com/uptrace/bun/schema" 10 ) 11 12 type ValuesQuery struct { 13 baseQuery 14 customValueQuery 15 16 withOrder bool 17 } 18 19 var ( 20 _ Query = (*ValuesQuery)(nil) 21 _ schema.NamedArgAppender = (*ValuesQuery)(nil) 22 ) 23 24 func NewValuesQuery(db *DB, model interface{}) *ValuesQuery { 25 q := &ValuesQuery{ 26 baseQuery: baseQuery{ 27 db: db, 28 conn: db.DB, 29 }, 30 } 31 q.setModel(model) 32 return q 33 } 34 35 func (q *ValuesQuery) Conn(db IConn) *ValuesQuery { 36 q.setConn(db) 37 return q 38 } 39 40 func (q *ValuesQuery) Err(err error) *ValuesQuery { 41 q.setErr(err) 42 return q 43 } 44 45 func (q *ValuesQuery) Column(columns ...string) *ValuesQuery { 46 for _, column := range columns { 47 q.addColumn(schema.UnsafeIdent(column)) 48 } 49 return q 50 } 51 52 // Value overwrites model value for the column. 53 func (q *ValuesQuery) Value(column string, expr string, args ...interface{}) *ValuesQuery { 54 if q.table == nil { 55 q.err = errNilModel 56 return q 57 } 58 q.addValue(q.table, column, expr, args) 59 return q 60 } 61 62 func (q *ValuesQuery) WithOrder() *ValuesQuery { 63 q.withOrder = true 64 return q 65 } 66 67 func (q *ValuesQuery) AppendNamedArg(fmter schema.Formatter, b []byte, name string) ([]byte, bool) { 68 switch name { 69 case "Columns": 70 bb, err := q.AppendColumns(fmter, b) 71 if err != nil { 72 q.setErr(err) 73 return b, true 74 } 75 return bb, true 76 } 77 return b, false 78 } 79 80 // AppendColumns appends the table columns. It is used by CTE. 81 func (q *ValuesQuery) AppendColumns(fmter schema.Formatter, b []byte) (_ []byte, err error) { 82 if q.err != nil { 83 return nil, q.err 84 } 85 if q.model == nil { 86 return nil, errNilModel 87 } 88 89 if q.tableModel != nil { 90 fields, err := q.getFields() 91 if err != nil { 92 return nil, err 93 } 94 95 b = appendColumns(b, "", fields) 96 97 if q.withOrder { 98 b = append(b, ", _order"...) 99 } 100 101 return b, nil 102 } 103 104 switch model := q.model.(type) { 105 case *mapSliceModel: 106 return model.appendColumns(fmter, b) 107 } 108 109 return nil, fmt.Errorf("bun: Values does not support %T", q.model) 110 } 111 112 func (q *ValuesQuery) Operation() string { 113 return "VALUES" 114 } 115 116 func (q *ValuesQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, err error) { 117 if q.err != nil { 118 return nil, q.err 119 } 120 if q.model == nil { 121 return nil, errNilModel 122 } 123 124 fmter = formatterWithModel(fmter, q) 125 126 if q.tableModel != nil { 127 fields, err := q.getFields() 128 if err != nil { 129 return nil, err 130 } 131 return q.appendQuery(fmter, b, fields) 132 } 133 134 switch model := q.model.(type) { 135 case *mapSliceModel: 136 return model.appendValues(fmter, b) 137 } 138 139 return nil, fmt.Errorf("bun: Values does not support %T", q.model) 140 } 141 142 func (q *ValuesQuery) appendQuery( 143 fmter schema.Formatter, 144 b []byte, 145 fields []*schema.Field, 146 ) (_ []byte, err error) { 147 b = append(b, "VALUES "...) 148 if q.db.features.Has(feature.ValuesRow) { 149 b = append(b, "ROW("...) 150 } else { 151 b = append(b, '(') 152 } 153 154 switch model := q.tableModel.(type) { 155 case *structTableModel: 156 b, err = q.appendValues(fmter, b, fields, model.strct) 157 if err != nil { 158 return nil, err 159 } 160 161 if q.withOrder { 162 b = append(b, ", "...) 163 b = strconv.AppendInt(b, 0, 10) 164 } 165 case *sliceTableModel: 166 slice := model.slice 167 sliceLen := slice.Len() 168 for i := 0; i < sliceLen; i++ { 169 if i > 0 { 170 b = append(b, "), "...) 171 if q.db.features.Has(feature.ValuesRow) { 172 b = append(b, "ROW("...) 173 } else { 174 b = append(b, '(') 175 } 176 } 177 178 b, err = q.appendValues(fmter, b, fields, slice.Index(i)) 179 if err != nil { 180 return nil, err 181 } 182 183 if q.withOrder { 184 b = append(b, ", "...) 185 b = strconv.AppendInt(b, int64(i), 10) 186 } 187 } 188 default: 189 return nil, fmt.Errorf("bun: Values does not support %T", q.model) 190 } 191 192 b = append(b, ')') 193 194 return b, nil 195 } 196 197 func (q *ValuesQuery) appendValues( 198 fmter schema.Formatter, b []byte, fields []*schema.Field, strct reflect.Value, 199 ) (_ []byte, err error) { 200 isTemplate := fmter.IsNop() 201 for i, f := range fields { 202 if i > 0 { 203 b = append(b, ", "...) 204 } 205 206 app, ok := q.modelValues[f.Name] 207 if ok { 208 b, err = app.AppendQuery(fmter, b) 209 if err != nil { 210 return nil, err 211 } 212 continue 213 } 214 215 if isTemplate { 216 b = append(b, '?') 217 } else { 218 b = f.AppendValue(fmter, b, indirect(strct)) 219 } 220 221 if fmter.HasFeature(feature.DoubleColonCast) { 222 b = append(b, "::"...) 223 b = append(b, f.UserSQLType...) 224 } 225 } 226 return b, nil 227 }