query_delete.go (8343B)
1 package bun 2 3 import ( 4 "context" 5 "database/sql" 6 "time" 7 8 "github.com/uptrace/bun/dialect/feature" 9 "github.com/uptrace/bun/internal" 10 "github.com/uptrace/bun/schema" 11 ) 12 13 type DeleteQuery struct { 14 whereBaseQuery 15 returningQuery 16 } 17 18 var _ Query = (*DeleteQuery)(nil) 19 20 func NewDeleteQuery(db *DB) *DeleteQuery { 21 q := &DeleteQuery{ 22 whereBaseQuery: whereBaseQuery{ 23 baseQuery: baseQuery{ 24 db: db, 25 conn: db.DB, 26 }, 27 }, 28 } 29 return q 30 } 31 32 func (q *DeleteQuery) Conn(db IConn) *DeleteQuery { 33 q.setConn(db) 34 return q 35 } 36 37 func (q *DeleteQuery) Model(model interface{}) *DeleteQuery { 38 q.setModel(model) 39 return q 40 } 41 42 func (q *DeleteQuery) Err(err error) *DeleteQuery { 43 q.setErr(err) 44 return q 45 } 46 47 // Apply calls the fn passing the DeleteQuery as an argument. 48 func (q *DeleteQuery) Apply(fn func(*DeleteQuery) *DeleteQuery) *DeleteQuery { 49 if fn != nil { 50 return fn(q) 51 } 52 return q 53 } 54 55 func (q *DeleteQuery) With(name string, query schema.QueryAppender) *DeleteQuery { 56 q.addWith(name, query, false) 57 return q 58 } 59 60 func (q *DeleteQuery) WithRecursive(name string, query schema.QueryAppender) *DeleteQuery { 61 q.addWith(name, query, true) 62 return q 63 } 64 65 func (q *DeleteQuery) Table(tables ...string) *DeleteQuery { 66 for _, table := range tables { 67 q.addTable(schema.UnsafeIdent(table)) 68 } 69 return q 70 } 71 72 func (q *DeleteQuery) TableExpr(query string, args ...interface{}) *DeleteQuery { 73 q.addTable(schema.SafeQuery(query, args)) 74 return q 75 } 76 77 func (q *DeleteQuery) ModelTableExpr(query string, args ...interface{}) *DeleteQuery { 78 q.modelTableName = schema.SafeQuery(query, args) 79 return q 80 } 81 82 //------------------------------------------------------------------------------ 83 84 func (q *DeleteQuery) WherePK(cols ...string) *DeleteQuery { 85 q.addWhereCols(cols) 86 return q 87 } 88 89 func (q *DeleteQuery) Where(query string, args ...interface{}) *DeleteQuery { 90 q.addWhere(schema.SafeQueryWithSep(query, args, " AND ")) 91 return q 92 } 93 94 func (q *DeleteQuery) WhereOr(query string, args ...interface{}) *DeleteQuery { 95 q.addWhere(schema.SafeQueryWithSep(query, args, " OR ")) 96 return q 97 } 98 99 func (q *DeleteQuery) WhereGroup(sep string, fn func(*DeleteQuery) *DeleteQuery) *DeleteQuery { 100 saved := q.where 101 q.where = nil 102 103 q = fn(q) 104 105 where := q.where 106 q.where = saved 107 108 q.addWhereGroup(sep, where) 109 110 return q 111 } 112 113 func (q *DeleteQuery) WhereDeleted() *DeleteQuery { 114 q.whereDeleted() 115 return q 116 } 117 118 func (q *DeleteQuery) WhereAllWithDeleted() *DeleteQuery { 119 q.whereAllWithDeleted() 120 return q 121 } 122 123 func (q *DeleteQuery) ForceDelete() *DeleteQuery { 124 q.flags = q.flags.Set(forceDeleteFlag) 125 return q 126 } 127 128 //------------------------------------------------------------------------------ 129 130 // Returning adds a RETURNING clause to the query. 131 // 132 // To suppress the auto-generated RETURNING clause, use `Returning("NULL")`. 133 func (q *DeleteQuery) Returning(query string, args ...interface{}) *DeleteQuery { 134 q.addReturning(schema.SafeQuery(query, args)) 135 return q 136 } 137 138 //------------------------------------------------------------------------------ 139 140 func (q *DeleteQuery) Operation() string { 141 return "DELETE" 142 } 143 144 func (q *DeleteQuery) AppendQuery(fmter schema.Formatter, b []byte) (_ []byte, err error) { 145 if q.err != nil { 146 return nil, q.err 147 } 148 149 fmter = formatterWithModel(fmter, q) 150 151 if q.isSoftDelete() { 152 now := time.Now() 153 154 if err := q.tableModel.updateSoftDeleteField(now); err != nil { 155 return nil, err 156 } 157 158 upd := &UpdateQuery{ 159 whereBaseQuery: q.whereBaseQuery, 160 returningQuery: q.returningQuery, 161 } 162 upd.Set(q.softDeleteSet(fmter, now)) 163 164 return upd.AppendQuery(fmter, b) 165 } 166 167 withAlias := q.db.features.Has(feature.DeleteTableAlias) 168 169 b, err = q.appendWith(fmter, b) 170 if err != nil { 171 return nil, err 172 } 173 174 b = append(b, "DELETE FROM "...) 175 176 if withAlias { 177 b, err = q.appendFirstTableWithAlias(fmter, b) 178 } else { 179 b, err = q.appendFirstTable(fmter, b) 180 } 181 if err != nil { 182 return nil, err 183 } 184 185 if q.hasMultiTables() { 186 b = append(b, " USING "...) 187 b, err = q.appendOtherTables(fmter, b) 188 if err != nil { 189 return nil, err 190 } 191 } 192 193 if q.hasFeature(feature.Output) && q.hasReturning() { 194 b = append(b, " OUTPUT "...) 195 b, err = q.appendOutput(fmter, b) 196 if err != nil { 197 return nil, err 198 } 199 } 200 201 b, err = q.mustAppendWhere(fmter, b, withAlias) 202 if err != nil { 203 return nil, err 204 } 205 206 if q.hasFeature(feature.Returning) && q.hasReturning() { 207 b = append(b, " RETURNING "...) 208 b, err = q.appendReturning(fmter, b) 209 if err != nil { 210 return nil, err 211 } 212 } 213 214 return b, nil 215 } 216 217 func (q *DeleteQuery) isSoftDelete() bool { 218 return q.tableModel != nil && q.table.SoftDeleteField != nil && !q.flags.Has(forceDeleteFlag) 219 } 220 221 func (q *DeleteQuery) softDeleteSet(fmter schema.Formatter, tm time.Time) string { 222 b := make([]byte, 0, 32) 223 if fmter.HasFeature(feature.UpdateMultiTable) { 224 b = append(b, q.table.SQLAlias...) 225 b = append(b, '.') 226 } 227 b = append(b, q.table.SoftDeleteField.SQLName...) 228 b = append(b, " = "...) 229 b = schema.Append(fmter, b, tm) 230 return internal.String(b) 231 } 232 233 //------------------------------------------------------------------------------ 234 235 func (q *DeleteQuery) Scan(ctx context.Context, dest ...interface{}) error { 236 _, err := q.scanOrExec(ctx, dest, true) 237 return err 238 } 239 240 func (q *DeleteQuery) Exec(ctx context.Context, dest ...interface{}) (sql.Result, error) { 241 return q.scanOrExec(ctx, dest, len(dest) > 0) 242 } 243 244 func (q *DeleteQuery) scanOrExec( 245 ctx context.Context, dest []interface{}, hasDest bool, 246 ) (sql.Result, error) { 247 if q.err != nil { 248 return nil, q.err 249 } 250 251 if q.table != nil { 252 if err := q.beforeDeleteHook(ctx); err != nil { 253 return nil, err 254 } 255 } 256 257 // Run append model hooks before generating the query. 258 if err := q.beforeAppendModel(ctx, q); err != nil { 259 return nil, err 260 } 261 262 // Generate the query before checking hasReturning. 263 queryBytes, err := q.AppendQuery(q.db.fmter, q.db.makeQueryBytes()) 264 if err != nil { 265 return nil, err 266 } 267 268 useScan := hasDest || (q.hasReturning() && q.hasFeature(feature.Returning|feature.Output)) 269 var model Model 270 271 if useScan { 272 var err error 273 model, err = q.getModel(dest) 274 if err != nil { 275 return nil, err 276 } 277 } 278 279 query := internal.String(queryBytes) 280 281 var res sql.Result 282 283 if useScan { 284 res, err = q.scan(ctx, q, query, model, hasDest) 285 if err != nil { 286 return nil, err 287 } 288 } else { 289 res, err = q.exec(ctx, q, query) 290 if err != nil { 291 return nil, err 292 } 293 } 294 295 if q.table != nil { 296 if err := q.afterDeleteHook(ctx); err != nil { 297 return nil, err 298 } 299 } 300 301 return res, nil 302 } 303 304 func (q *DeleteQuery) beforeDeleteHook(ctx context.Context) error { 305 if hook, ok := q.table.ZeroIface.(BeforeDeleteHook); ok { 306 if err := hook.BeforeDelete(ctx, q); err != nil { 307 return err 308 } 309 } 310 return nil 311 } 312 313 func (q *DeleteQuery) afterDeleteHook(ctx context.Context) error { 314 if hook, ok := q.table.ZeroIface.(AfterDeleteHook); ok { 315 if err := hook.AfterDelete(ctx, q); err != nil { 316 return err 317 } 318 } 319 return nil 320 } 321 322 func (q *DeleteQuery) String() string { 323 buf, err := q.AppendQuery(q.db.Formatter(), nil) 324 if err != nil { 325 panic(err) 326 } 327 328 return string(buf) 329 } 330 331 //------------------------------------------------------------------------------ 332 333 func (q *DeleteQuery) QueryBuilder() QueryBuilder { 334 return &deleteQueryBuilder{q} 335 } 336 337 func (q *DeleteQuery) ApplyQueryBuilder(fn func(QueryBuilder) QueryBuilder) *DeleteQuery { 338 return fn(q.QueryBuilder()).Unwrap().(*DeleteQuery) 339 } 340 341 type deleteQueryBuilder struct { 342 *DeleteQuery 343 } 344 345 func (q *deleteQueryBuilder) WhereGroup( 346 sep string, fn func(QueryBuilder) QueryBuilder, 347 ) QueryBuilder { 348 q.DeleteQuery = q.DeleteQuery.WhereGroup(sep, func(qs *DeleteQuery) *DeleteQuery { 349 return fn(q).(*deleteQueryBuilder).DeleteQuery 350 }) 351 return q 352 } 353 354 func (q *deleteQueryBuilder) Where(query string, args ...interface{}) QueryBuilder { 355 q.DeleteQuery.Where(query, args...) 356 return q 357 } 358 359 func (q *deleteQueryBuilder) WhereOr(query string, args ...interface{}) QueryBuilder { 360 q.DeleteQuery.WhereOr(query, args...) 361 return q 362 } 363 364 func (q *deleteQueryBuilder) WhereDeleted() QueryBuilder { 365 q.DeleteQuery.WhereDeleted() 366 return q 367 } 368 369 func (q *deleteQueryBuilder) WhereAllWithDeleted() QueryBuilder { 370 q.DeleteQuery.WhereAllWithDeleted() 371 return q 372 } 373 374 func (q *deleteQueryBuilder) WherePK(cols ...string) QueryBuilder { 375 q.DeleteQuery.WherePK(cols...) 376 return q 377 } 378 379 func (q *deleteQueryBuilder) Unwrap() interface{} { 380 return q.DeleteQuery 381 }