Fix settings handler build
This commit is contained in:
1 parent
ce7c417884
commit
b272aed8fd
13 files changed
+458
-60
No files matched your search
@@ -0,0 +1,93 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// dbx is the database the server talks to: SQLite, or PostgreSQL. The
|
||||
// queries are written once, for SQLite; on PostgreSQL each is rewritten
|
||||
// (pgSQL) on its way.
|
||||
type dbx struct {
|
||||
*sql.DB
|
||||
pg bool
|
||||
}
|
||||
|
||||
func (d *dbx) q(query string) string {
|
||||
if d.pg {
|
||||
return pgSQL(query)
|
||||
}
|
||||
return query
|
||||
}
|
||||
|
||||
func (d *dbx) Exec(query string, args ...any) (sql.Result, error) {
|
||||
return d.DB.Exec(d.q(query), args...)
|
||||
}
|
||||
func (d *dbx) Query(query string, args ...any) (*sql.Rows, error) {
|
||||
return d.DB.Query(d.q(query), args...)
|
||||
}
|
||||
func (d *dbx) QueryRow(query string, args ...any) *sql.Row {
|
||||
return d.DB.QueryRow(d.q(query), args...)
|
||||
}
|
||||
func (d *dbx) Begin() (*txx, error) {
|
||||
tx, err := d.DB.Begin()
|
||||
return &txx{Tx: tx, pg: d.pg}, err
|
||||
}
|
||||
|
||||
// insert runs an INSERT and gives the new row's id (LastInsertId on SQLite,
|
||||
// RETURNING id on PostgreSQL, which has no LastInsertId).
|
||||
func (d *dbx) insert(query string, args ...any) (int64, error) {
|
||||
if d.pg {
|
||||
var id int64
|
||||
err := d.DB.QueryRow(pgSQL(query)+" RETURNING id", args...).Scan(&id)
|
||||
return id, err
|
||||
}
|
||||
res, err := d.DB.Exec(query, args...)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return res.LastInsertId()
|
||||
}
|
||||
|
||||
type txx struct {
|
||||
*sql.Tx
|
||||
pg bool
|
||||
}
|
||||
|
||||
func (t *txx) Exec(query string, args ...any) (sql.Result, error) {
|
||||
if t.pg {
|
||||
query = pgSQL(query)
|
||||
}
|
||||
return t.Tx.Exec(query, args...)
|
||||
}
|
||||
|
||||
// pgSQL rewrites a query for SQLite into PostgreSQL's: $n placeholders,
|
||||
// INSERT OR IGNORE as ON CONFLICT DO NOTHING, and in table definitions
|
||||
// BIGSERIAL keys, BIGINT numbers (times are Unix seconds), BYTEA blobs and
|
||||
// ADD COLUMN IF NOT EXISTS.
|
||||
func pgSQL(q string) string {
|
||||
if strings.HasPrefix(q, "INSERT OR IGNORE ") {
|
||||
q = "INSERT " + strings.TrimPrefix(q, "INSERT OR IGNORE ") + " ON CONFLICT DO NOTHING"
|
||||
}
|
||||
if strings.Contains(q, "CREATE TABLE") || strings.Contains(q, "ALTER TABLE") {
|
||||
q = strings.ReplaceAll(q, "INTEGER PRIMARY KEY AUTOINCREMENT", "BIGSERIAL PRIMARY KEY")
|
||||
q = strings.ReplaceAll(q, "INTEGER", "BIGINT")
|
||||
q = strings.ReplaceAll(q, "BLOB", "BYTEA")
|
||||
q = strings.ReplaceAll(q, "ADD COLUMN ", "ADD COLUMN IF NOT EXISTS ")
|
||||
}
|
||||
var b strings.Builder
|
||||
n, quoted := 0, false
|
||||
for _, r := range q {
|
||||
switch {
|
||||
case r == '\'':
|
||||
quoted = !quoted
|
||||
case r == '?' && !quoted:
|
||||
n++
|
||||
b.WriteString("$" + strconv.Itoa(n))
|
||||
continue
|
||||
}
|
||||
b.WriteRune(r)
|
||||
}
|
||||
return b.String()
|
||||
}
|
||||
Reference in new issue
Block a user