aboutsummaryrefslogtreecommitdiff
path: root/dbstore/tx.go
diff options
context:
space:
mode:
authorPaul Duncan <pabs@pablotron.org>2022-02-18 20:57:40 -0500
committerPaul Duncan <pabs@pablotron.org>2022-02-18 20:57:40 -0500
commitd1483e75727afccc251f70f5a58e756efaff8b9e (patch)
tree4ade0479bf39ca470b24e9e482f118ff24845a21 /dbstore/tx.go
parent262479663d607966fadc06ee44c6191d0dce88ed (diff)
downloadcvez-d1483e75727afccc251f70f5a58e756efaff8b9e.tar.bz2
cvez-d1483e75727afccc251f70f5a58e756efaff8b9e.zip
dbstore: refactor sqlfs and tx, add tx tests
Diffstat (limited to 'dbstore/tx.go')
-rw-r--r--dbstore/tx.go105
1 files changed, 105 insertions, 0 deletions
diff --git a/dbstore/tx.go b/dbstore/tx.go
new file mode 100644
index 0000000..460bbe1
--- /dev/null
+++ b/dbstore/tx.go
@@ -0,0 +1,105 @@
+// database storage
+package dbstore
+
+import (
+ "context"
+ db_sql "database/sql"
+ "fmt"
+ _ "github.com/mattn/go-sqlite3"
+)
+
+type Tx struct {
+ tx *db_sql.Tx // underlying transaction
+ sts map[string]*db_sql.Stmt // prepared statements
+ closed bool // are the statements closed?
+ done bool // is the transaction done?
+ err error // last error
+}
+
+func newTx(ctx context.Context, db *db_sql.DB, queryIds []string) (Tx, error) {
+ var r Tx
+
+ // begin context
+ if tx, err := db.BeginTx(ctx, nil); err != nil {
+ return r, err
+ } else {
+ r.tx = tx
+ }
+
+ // build query map
+ queries, err := getQueries(queryIds)
+ if err != nil {
+ return r, err
+ }
+
+ // build statements
+ sts := make(map[string]*db_sql.Stmt)
+ for id, sql := range(queries) {
+ if st, err := r.tx.PrepareContext(ctx, sql); err != nil {
+ return r, err
+ } else {
+ sts[id] = st
+ }
+ }
+ r.sts = sts
+
+ // return success
+ return r, nil
+}
+
+// Finalize statements.
+func (tx Tx) Close() {
+ if !tx.closed {
+ for id, st := range(tx.sts) {
+ // close statement
+ st.Close()
+
+ // delete key
+ delete(tx.sts, id)
+ }
+
+ // mark transaction as closed
+ tx.closed = true
+ }
+}
+
+// Finalize statements, commit transaction.
+func (tx Tx) Commit() error {
+ // close statements
+ // FIXME: this isn't really necessary, rollback and commit will take
+ // care of it according to the database/sql docs
+ tx.Close()
+
+ if !tx.done {
+ tx.err = tx.tx.Commit()
+ tx.done = true
+ }
+
+ // return last error
+ return tx.err
+}
+
+// Finalize statements, rollback transaction.
+func (tx Tx) Rollback() error {
+ // close statements
+ // FIXME: this isn't really necessary, rollback and commit will take
+ // care of it according to the database/sql docs
+ tx.Close()
+
+ if !tx.done {
+ tx.err = tx.tx.Rollback()
+ tx.done = true
+ }
+
+ // return last error
+ return tx.err
+}
+
+// execute given prepared statement
+func (tx Tx) Exec(ctx context.Context, id string, args... interface{}) (db_sql.Result, error) {
+ if st, ok := tx.sts[id]; !ok {
+ return nil, fmt.Errorf("unknown statement: %s", id)
+ } else {
+ return st.ExecContext(ctx, args...)
+ }
+}