@@ -258,150 +258,46 @@ func (db *DB) MarshalLogObject(encoder zapcore.ObjectEncoder) error {
258258 return nil
259259}
260260
261+ // QueryBuilder returns a fully initialised and ready to use *[QueryBuilder] instance for the given subject/struct.
262+ func (db * DB ) QueryBuilder (subject any ) * QueryBuilder {
263+ return & QueryBuilder {subject : subject }
264+ }
265+
261266// BuildColumns returns all columns of the given struct.
262267func (db * DB ) BuildColumns (subject interface {}) []string {
263268 return slices .Clone (db .columnMap .Columns (subject ))
264269}
265270
266271// BuildDeleteStmt returns a DELETE statement for the given struct.
267272func (db * DB ) BuildDeleteStmt (from interface {}) string {
268- return fmt .Sprintf (
269- `DELETE FROM "%s" WHERE id IN (?)` ,
270- TableName (from ),
271- )
273+ return db .QueryBuilder (from ).Delete ()
272274}
273275
274276// BuildInsertStmt returns an INSERT INTO statement for the given struct.
275277func (db * DB ) BuildInsertStmt (into interface {}) (string , int ) {
276- columns := db .columnMap .Columns (into )
277-
278- return fmt .Sprintf (
279- `INSERT INTO "%s" ("%s") VALUES (%s)` ,
280- TableName (into ),
281- strings .Join (columns , `", "` ),
282- fmt .Sprintf (":%s" , strings .Join (columns , ", :" )),
283- ), len (columns )
278+ return db .QueryBuilder (into ).Insert (db )
284279}
285280
286281// BuildInsertIgnoreStmt returns an INSERT statement for the specified struct for
287282// which the database ignores rows that have already been inserted.
288283func (db * DB ) BuildInsertIgnoreStmt (into interface {}) (string , int ) {
289- table := TableName (into )
290- columns := db .columnMap .Columns (into )
291- var clause string
292-
293- switch db .DriverName () {
294- case MySQL :
295- // MySQL treats UPDATE id = id as a no-op.
296- clause = fmt .Sprintf (`ON DUPLICATE KEY UPDATE "%s" = "%s"` , columns [0 ], columns [0 ])
297- case PostgreSQL :
298- var constraint string
299- if constrainter , ok := into .(PgsqlOnConflictConstrainter ); ok {
300- constraint = constrainter .PgsqlOnConflictConstraint ()
301- } else {
302- constraint = "pk_" + table
303- }
304-
305- clause = fmt .Sprintf ("ON CONFLICT ON CONSTRAINT %s DO NOTHING" , constraint )
306- }
307-
308- return fmt .Sprintf (
309- `INSERT INTO "%s" ("%s") VALUES (%s) %s` ,
310- table ,
311- strings .Join (columns , `", "` ),
312- fmt .Sprintf (":%s" , strings .Join (columns , ", :" )),
313- clause ,
314- ), len (columns )
284+ return db .QueryBuilder (into ).InsertIgnore (db )
315285}
316286
317287// BuildSelectStmt returns a SELECT query that creates the FROM part from the given table struct
318288// and the column list from the specified columns struct.
319289func (db * DB ) BuildSelectStmt (table interface {}, columns interface {}) string {
320- q := fmt .Sprintf (
321- `SELECT "%s" FROM "%s"` ,
322- strings .Join (db .columnMap .Columns (columns ), `", "` ),
323- TableName (table ),
324- )
325-
326- if scoper , ok := table .(Scoper ); ok {
327- where , _ := db .BuildWhere (scoper .Scope ())
328- q += ` WHERE ` + where
329- }
330-
331- return q
290+ return db .QueryBuilder (table ).SetColumns (db .columnMap .Columns (columns )... ).Select (db )
332291}
333292
334293// BuildUpdateStmt returns an UPDATE statement for the given struct.
335294func (db * DB ) BuildUpdateStmt (update interface {}) (string , int ) {
336- columns := db .columnMap .Columns (update )
337- set := make ([]string , 0 , len (columns ))
338-
339- for _ , col := range columns {
340- set = append (set , fmt .Sprintf (`"%s" = :%s` , col , col ))
341- }
342-
343- return fmt .Sprintf (
344- `UPDATE "%s" SET %s WHERE id = :id` ,
345- TableName (update ),
346- strings .Join (set , ", " ),
347- ), len (columns ) + 1 // +1 because of WHERE id = :id
295+ return db .QueryBuilder (update ).Update (db )
348296}
349297
350298// BuildUpsertStmt returns an upsert statement for the given struct.
351299func (db * DB ) BuildUpsertStmt (subject interface {}) (stmt string , placeholders int ) {
352- insertColumns := db .columnMap .Columns (subject )
353- table := TableName (subject )
354- var updateColumns []string
355-
356- if upserter , ok := subject .(Upserter ); ok {
357- updateColumns = db .columnMap .Columns (upserter .Upsert ())
358- } else {
359- updateColumns = insertColumns
360- }
361-
362- var clause , setFormat string
363- switch db .DriverName () {
364- case MySQL :
365- clause = "ON DUPLICATE KEY UPDATE"
366- setFormat = `"%[1]s" = VALUES("%[1]s")`
367- case PostgreSQL :
368- var constraint string
369- if constrainter , ok := subject .(PgsqlOnConflictConstrainter ); ok {
370- constraint = constrainter .PgsqlOnConflictConstraint ()
371- } else {
372- constraint = "pk_" + table
373- }
374-
375- clause = fmt .Sprintf ("ON CONFLICT ON CONSTRAINT %s DO UPDATE SET" , constraint )
376- setFormat = `"%[1]s" = EXCLUDED."%[1]s"`
377- }
378-
379- set := make ([]string , 0 , len (updateColumns ))
380-
381- for _ , col := range updateColumns {
382- set = append (set , fmt .Sprintf (setFormat , col ))
383- }
384-
385- return fmt .Sprintf (
386- `INSERT INTO "%s" ("%s") VALUES (%s) %s %s` ,
387- table ,
388- strings .Join (insertColumns , `", "` ),
389- fmt .Sprintf (":%s" , strings .Join (insertColumns , ",:" )),
390- clause ,
391- strings .Join (set , "," ),
392- ), len (insertColumns )
393- }
394-
395- // BuildWhere returns a WHERE clause with named placeholder conditions built from the specified struct
396- // combined with the AND operator.
397- func (db * DB ) BuildWhere (subject interface {}) (string , int ) {
398- columns := db .columnMap .Columns (subject )
399- where := make ([]string , 0 , len (columns ))
400- for _ , col := range columns {
401- where = append (where , fmt .Sprintf (`"%s" = :%s` , col , col ))
402- }
403-
404- return strings .Join (where , ` AND ` ), len (columns )
300+ return db .QueryBuilder (subject ).Upsert (db )
405301}
406302
407303// OnSuccess is a callback for successful (bulk) DML operations.
0 commit comments