Skip to content

Commit

Permalink
DB: Make use of the QueryBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
yhabteab committed Jan 24, 2024
1 parent c24343b commit b5df5ca
Showing 1 changed file with 8 additions and 102 deletions.
110 changes: 8 additions & 102 deletions database/db.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package database

import (
"context"
"fmt"
"github.com/go-sql-driver/mysql"
"github.com/icinga/icinga-go-library/backoff"
"github.com/icinga/icinga-go-library/com"
Expand All @@ -19,7 +18,6 @@ import (
"golang.org/x/sync/semaphore"
"net/url"
"strconv"
"strings"
"sync"
"time"
)
Expand Down Expand Up @@ -202,129 +200,37 @@ func (db *DB) BuildColumns(subject interface{}) []string {

// BuildDeleteStmt returns a DELETE statement for the given struct.
func (db *DB) BuildDeleteStmt(from interface{}) string {
return fmt.Sprintf(
`DELETE FROM "%s" WHERE id IN (?)`,
TableName(from),
)
return NewQB(from).Delete()
}

// BuildInsertStmt returns an INSERT INTO statement for the given struct.
func (db *DB) BuildInsertStmt(into interface{}) (string, int) {
columns := db.BuildColumns(into)

return fmt.Sprintf(
`INSERT INTO "%s" ("%s") VALUES (%s)`,
TableName(into),
strings.Join(columns, `", "`),
fmt.Sprintf(":%s", strings.Join(columns, ", :")),
), len(columns)
return NewQB(into).Insert(db)
}

// BuildInsertIgnoreStmt returns an INSERT statement for the specified struct for
// which the database ignores rows that have already been inserted.
func (db *DB) BuildInsertIgnoreStmt(into interface{}) (string, int) {
table := TableName(into)
columns := db.BuildColumns(into)
var clause string

switch db.DriverName() {
case driver.MySQL:
// MySQL treats UPDATE id = id as a no-op.
clause = fmt.Sprintf(`ON DUPLICATE KEY UPDATE "%s" = "%s"`, columns[0], columns[0])
case driver.PostgreSQL:
clause = fmt.Sprintf("ON CONFLICT ON CONSTRAINT pk_%s DO NOTHING", table)
}

return fmt.Sprintf(
`INSERT INTO "%s" ("%s") VALUES (%s) %s`,
table,
strings.Join(columns, `", "`),
fmt.Sprintf(":%s", strings.Join(columns, ", :")),
clause,
), len(columns)
return NewQB(into).InsertIgnore(db)
}

// BuildSelectStmt returns a SELECT query that creates the FROM part from the given table struct
// and the column list from the specified columns struct.
func (db *DB) BuildSelectStmt(table interface{}, columns interface{}) string {
q := fmt.Sprintf(
`SELECT "%s" FROM "%s"`,
strings.Join(db.BuildColumns(columns), `", "`),
TableName(table),
)

if scoper, ok := table.(Scoper); ok {
where, _ := db.BuildWhere(scoper.Scope())
q += ` WHERE ` + where
}
qb := NewQB(table)
qb.SetColumns(db.BuildColumns(columns)...)

return q
return qb.Select(db)
}

// BuildUpdateStmt returns an UPDATE statement for the given struct.
func (db *DB) BuildUpdateStmt(update interface{}) (string, int) {
columns := db.BuildColumns(update)
set := make([]string, 0, len(columns))

for _, col := range columns {
set = append(set, fmt.Sprintf(`"%s" = :%s`, col, col))
}

return fmt.Sprintf(
`UPDATE "%s" SET %s WHERE id = :id`,
TableName(update),
strings.Join(set, ", "),
), len(columns) + 1 // +1 because of WHERE id = :id
return NewQB(update).Update(db)
}

// BuildUpsertStmt returns an upsert statement for the given struct.
func (db *DB) BuildUpsertStmt(subject interface{}) (stmt string, placeholders int) {
insertColumns := db.BuildColumns(subject)
table := TableName(subject)
var updateColumns []string

if upserter, ok := subject.(Upserter); ok {
updateColumns = db.BuildColumns(upserter.Upsert())
} else {
updateColumns = insertColumns
}

var clause, setFormat string
switch db.DriverName() {
case driver.MySQL:
clause = "ON DUPLICATE KEY UPDATE"
setFormat = `"%[1]s" = VALUES("%[1]s")`
case driver.PostgreSQL:
clause = fmt.Sprintf("ON CONFLICT ON CONSTRAINT pk_%s DO UPDATE SET", table)
setFormat = `"%[1]s" = EXCLUDED."%[1]s"`
}

set := make([]string, 0, len(updateColumns))

for _, col := range updateColumns {
set = append(set, fmt.Sprintf(setFormat, col))
}

return fmt.Sprintf(
`INSERT INTO "%s" ("%s") VALUES (%s) %s %s`,
table,
strings.Join(insertColumns, `", "`),
fmt.Sprintf(":%s", strings.Join(insertColumns, ",:")),
clause,
strings.Join(set, ","),
), len(insertColumns)
}

// BuildWhere returns a WHERE clause with named placeholder conditions built from the specified struct
// combined with the AND operator.
func (db *DB) BuildWhere(subject interface{}) (string, int) {
columns := db.BuildColumns(subject)
where := make([]string, 0, len(columns))
for _, col := range columns {
where = append(where, fmt.Sprintf(`"%s" = :%s`, col, col))
}

return strings.Join(where, ` AND `), len(columns)
return NewQB(subject).Upsert(db)
}

// OnSuccess is a callback for successful (bulk) DML operations.
Expand Down

0 comments on commit b5df5ca

Please sign in to comment.