2022-12-07 23:21:36 +01:00
|
|
|
package sq
|
|
|
|
|
|
|
|
import (
|
|
|
|
"context"
|
|
|
|
"database/sql"
|
|
|
|
"github.com/jmoiron/sqlx"
|
|
|
|
"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)
|
2022-12-21 15:34:59 +01:00
|
|
|
AddListener(listener Listener)
|
2022-12-22 10:06:25 +01:00
|
|
|
Exit() error
|
2022-12-07 23:21:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
type database struct {
|
|
|
|
db *sqlx.DB
|
|
|
|
txctr uint16
|
|
|
|
lock sync.Mutex
|
2022-12-21 15:34:59 +01:00
|
|
|
lstr []Listener
|
2022-12-07 23:21:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func NewDB(db *sqlx.DB) DB {
|
|
|
|
return &database{
|
|
|
|
db: db,
|
|
|
|
txctr: 0,
|
|
|
|
lock: sync.Mutex{},
|
2022-12-21 15:34:59 +01:00
|
|
|
lstr: make([]Listener, 0),
|
2022-12-07 23:21:36 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-12-21 15:34:59 +01:00
|
|
|
func (db *database) AddListener(listener Listener) {
|
|
|
|
db.lstr = append(db.lstr, listener)
|
2022-12-07 23:21:36 +01:00
|
|
|
}
|
|
|
|
|
2022-12-21 15:34:59 +01:00
|
|
|
func (db *database) Exec(ctx context.Context, sqlstr string, prep PP) (sql.Result, error) {
|
|
|
|
origsql := sqlstr
|
|
|
|
for _, v := range db.lstr {
|
2022-12-21 15:41:41 +01:00
|
|
|
err := v.PreExec(ctx, nil, &sqlstr, &prep)
|
2022-12-21 15:34:59 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
res, err := db.db.NamedExecContext(ctx, sqlstr, prep)
|
|
|
|
|
|
|
|
for _, v := range db.lstr {
|
|
|
|
v.PostExec(nil, origsql, sqlstr, prep)
|
2022-12-07 23:21:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return res, nil
|
|
|
|
}
|
|
|
|
|
2022-12-21 15:34:59 +01:00
|
|
|
func (db *database) Query(ctx context.Context, sqlstr string, prep PP) (*sqlx.Rows, error) {
|
|
|
|
origsql := sqlstr
|
|
|
|
for _, v := range db.lstr {
|
2022-12-21 15:41:41 +01:00
|
|
|
err := v.PreQuery(ctx, nil, &sqlstr, &prep)
|
2022-12-21 15:34:59 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
rows, err := sqlx.NamedQueryContext(ctx, db.db, sqlstr, prep)
|
|
|
|
|
|
|
|
for _, v := range db.lstr {
|
|
|
|
v.PostQuery(nil, origsql, sqlstr, prep)
|
2022-12-07 23:21:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
return rows, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func (db *database) Ping(ctx context.Context) error {
|
2022-12-21 15:34:59 +01:00
|
|
|
for _, v := range db.lstr {
|
2022-12-21 15:41:41 +01:00
|
|
|
err := v.PrePing(ctx)
|
2022-12-21 15:34:59 +01:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2022-12-07 23:21:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
err := db.db.PingContext(ctx)
|
2022-12-21 15:34:59 +01:00
|
|
|
|
|
|
|
for _, v := range db.lstr {
|
|
|
|
v.PostPing(err)
|
|
|
|
}
|
|
|
|
|
2022-12-07 23:21:36 +01:00
|
|
|
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()
|
|
|
|
|
2022-12-21 15:34:59 +01:00
|
|
|
for _, v := range db.lstr {
|
2022-12-21 15:41:41 +01:00
|
|
|
err := v.PreTxBegin(ctx, txid)
|
2022-12-21 15:34:59 +01:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2022-12-07 23:21:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
xtx, err := db.db.BeginTxx(ctx, &sql.TxOptions{Isolation: iso})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2022-12-21 15:34:59 +01:00
|
|
|
for _, v := range db.lstr {
|
|
|
|
v.PostTxBegin(txid, err)
|
|
|
|
}
|
|
|
|
|
2022-12-07 23:21:36 +01:00
|
|
|
return NewTransaction(xtx, txid, db.lstr), nil
|
|
|
|
}
|
2022-12-22 10:06:25 +01:00
|
|
|
|
|
|
|
func (db *database) Exit() error {
|
|
|
|
return db.db.Close()
|
|
|
|
}
|