Move to own sql abstraction on top of jmoiron/sqlx
This commit is contained in:
77
server/sq/database.go
Normal file
77
server/sq/database.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package sq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/rs/zerolog/log"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type DB interface {
|
||||
Exec(ctx context.Context, sql string, prep PP) (sql.Result, error)
|
||||
Query(ctx context.Context, sql string, prep PP) (*sqlx.Rows, error)
|
||||
Ping(ctx context.Context) error
|
||||
BeginTransaction(ctx context.Context, iso sql.IsolationLevel) (Tx, error)
|
||||
}
|
||||
|
||||
type database struct {
|
||||
db *sqlx.DB
|
||||
txctr uint16
|
||||
lock sync.Mutex
|
||||
}
|
||||
|
||||
func NewDB(db *sqlx.DB) DB {
|
||||
return &database{
|
||||
db: db,
|
||||
txctr: 0,
|
||||
lock: sync.Mutex{},
|
||||
}
|
||||
}
|
||||
|
||||
func (db *database) Exec(ctx context.Context, sql string, prep PP) (sql.Result, error) {
|
||||
log.Debug().Msg(fmt.Sprintf("[SQL-EXEC] %s", fmtSQLPrint(sql)))
|
||||
|
||||
res, err := db.db.NamedExecContext(ctx, sql, prep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (db *database) Query(ctx context.Context, sql string, prep PP) (*sqlx.Rows, error) {
|
||||
log.Debug().Msg(fmt.Sprintf("[SQL-QUERY] %s", fmtSQLPrint(sql)))
|
||||
|
||||
rows, err := db.db.NamedQueryContext(ctx, sql, prep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
|
||||
func (db *database) Ping(ctx context.Context) error {
|
||||
log.Debug().Msg("[SQL-PING]")
|
||||
|
||||
err := db.db.PingContext(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *database) BeginTransaction(ctx context.Context, iso sql.IsolationLevel) (Tx, error) {
|
||||
db.lock.Lock()
|
||||
txid := db.txctr
|
||||
db.txctr += 1 // with overflow !
|
||||
db.lock.Unlock()
|
||||
|
||||
log.Debug().Msg(fmt.Sprintf("[SQL-TX<%d>-START]", txid))
|
||||
|
||||
xtx, err := db.db.BeginTxx(ctx, &sql.TxOptions{Isolation: iso})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return NewTransaction(xtx, txid), nil
|
||||
}
|
||||
3
server/sq/params.go
Normal file
3
server/sq/params.go
Normal file
@@ -0,0 +1,3 @@
|
||||
package sq
|
||||
|
||||
type PP map[string]any
|
||||
12
server/sq/queryable.go
Normal file
12
server/sq/queryable.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package sq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
type Queryable interface {
|
||||
Exec(ctx context.Context, sql string, prep PP) (sql.Result, error)
|
||||
Query(ctx context.Context, sql string, prep PP) (*sqlx.Rows, error)
|
||||
}
|
||||
60
server/sq/transaction.go
Normal file
60
server/sq/transaction.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package sq
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"github.com/rs/zerolog/log"
|
||||
)
|
||||
|
||||
type Tx interface {
|
||||
Rollback() error
|
||||
Commit() error
|
||||
Exec(ctx context.Context, sql string, prep PP) (sql.Result, error)
|
||||
Query(ctx context.Context, sql string, prep PP) (*sqlx.Rows, error)
|
||||
}
|
||||
|
||||
type transaction struct {
|
||||
tx *sqlx.Tx
|
||||
id uint16
|
||||
}
|
||||
|
||||
func NewTransaction(xtx *sqlx.Tx, txid uint16) Tx {
|
||||
return &transaction{
|
||||
tx: xtx,
|
||||
id: txid,
|
||||
}
|
||||
}
|
||||
|
||||
func (tx *transaction) Rollback() error {
|
||||
log.Debug().Msg(fmt.Sprintf("[SQL-TX<%d>-ROLLBACK]", tx.id))
|
||||
|
||||
return tx.tx.Rollback()
|
||||
}
|
||||
|
||||
func (tx *transaction) Commit() error {
|
||||
log.Debug().Msg(fmt.Sprintf("[SQL-TX<%d>-COMMIT]", tx.id))
|
||||
|
||||
return tx.tx.Commit()
|
||||
}
|
||||
|
||||
func (tx *transaction) Exec(ctx context.Context, sql string, prep PP) (sql.Result, error) {
|
||||
log.Debug().Msg(fmt.Sprintf("[SQL-TX<%d>-EXEC] %s", tx.id, fmtSQLPrint(sql)))
|
||||
|
||||
res, err := tx.tx.NamedExecContext(ctx, sql, prep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
||||
func (tx *transaction) Query(ctx context.Context, sql string, prep PP) (*sqlx.Rows, error) {
|
||||
log.Debug().Msg(fmt.Sprintf("[SQL-TX<%d>-QUERY] %s", tx.id, fmtSQLPrint(sql)))
|
||||
|
||||
rows, err := sqlx.NamedQueryContext(ctx, tx.tx, sql, prep)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return rows, nil
|
||||
}
|
||||
16
server/sq/util.go
Normal file
16
server/sq/util.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package sq
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
func fmtSQLPrint(sql string) string {
|
||||
if strings.Contains(sql, ";") {
|
||||
return "(...multi...)"
|
||||
}
|
||||
|
||||
sql = strings.ReplaceAll(sql, "\r", "")
|
||||
sql = strings.ReplaceAll(sql, "\n", " ")
|
||||
|
||||
return sql
|
||||
}
|
||||
Reference in New Issue
Block a user