go-vise

Constrained Size Output Virtual Machine
Info | Log | Files | Refs | README | LICENSE

commit 326bdb5018ae81ee493371b56bd4564a8b35da59
parent 654cd518130db0a8ff3dd8f18504257bb4a37dd6
Author: lash <dev@holbrook.no>
Date:   Fri, 30 Aug 2024 17:58:10 +0100

Add documentation for db

Diffstat:
Mdb/db.go | 14++++++++++++++
Mdb/fs.go | 8+++++++-
Mdb/fs_test.go | 5+++++
Mdb/gdbm.go | 5+++++
Mdb/gdbm_test.go | 5+++++
Mdb/mem.go | 6++++++
Mdb/mem_test.go | 5+++++
Mdb/pg.go | 89++++++++++++++++++++++++++++++-------------------------------------------------
Mdb/pg_test.go | 7++++++-
9 files changed, 87 insertions(+), 57 deletions(-)

diff --git a/db/db.go b/db/db.go @@ -15,13 +15,23 @@ const ( DATATYPE_USERSTART ) +// Db abstracts all data storage and retrieval as a key-value store type Db interface { + // Connect prepares the storage backend for use Connect(ctx context.Context, connStr string) error + // Close implements io.Closer Close() error + // Get retrieves the value belonging to a key. Errors if the key does not exist, or if the retrieval otherwise fails. Get(ctx context.Context, key []byte) ([]byte, error) + // Put stores a value under a key. Any existing value will be replaced. Errors if the value could not be stored. Put(ctx context.Context, key []byte, val []byte) error } +// ToDbKey generates a key to use Db to store a value for a particular context. +// +// If language is nil, then default language storage context will be used. +// +// If language is not nil, and the context does not support language, the language value will silently will be ignored. func ToDbKey(typ uint8, b []byte, l *lang.Language) []byte { k := []byte{typ} if l != nil && l.Code != "" { @@ -31,19 +41,23 @@ func ToDbKey(typ uint8, b []byte, l *lang.Language) []byte { return append(k, b...) } +// BaseDb is a base class for all Db implementations. type BaseDb struct { pfx uint8 sid []byte } +// SetPrefix sets the storage context prefix to use for consecutive Get and Put operations. func(db *BaseDb) SetPrefix(pfx uint8) { db.pfx = pfx } +// SetSession sets the session context to use for consecutive Get and Put operations. func(db *BaseDb) SetSession(sessionId string) { db.sid = append([]byte(sessionId), 0x2E) } +// ToKey creates a DbKey within the current session context. func(db *BaseDb) ToKey(key []byte) ([]byte, error) { if db.pfx == DATATYPE_UNKNOWN { return nil, errors.New("datatype prefix cannot be UNKNOWN") diff --git a/db/fs.go b/db/fs.go @@ -8,11 +8,13 @@ import ( "path" ) +// FsDb is a pure filesystem backend implementation if the Db interface. type FsDb struct { BaseDb dir string } +// Connect implements Db func(fdb *FsDb) Connect(ctx context.Context, connStr string) error { fi, err := os.Stat(connStr) if err != nil { @@ -25,6 +27,7 @@ func(fdb *FsDb) Connect(ctx context.Context, connStr string) error { return nil } +// Get implements Db func(fdb *FsDb) Get(ctx context.Context, key []byte) ([]byte, error) { fp, err := fdb.pathFor(key) if err != nil { @@ -42,6 +45,7 @@ func(fdb *FsDb) Get(ctx context.Context, key []byte) ([]byte, error) { return b, nil } +// Put implements Db func(fdb *FsDb) Put(ctx context.Context, key []byte, val []byte) error { fp, err := fdb.pathFor(key) if err != nil { @@ -50,10 +54,12 @@ func(fdb *FsDb) Put(ctx context.Context, key []byte, val []byte) error { return ioutil.WriteFile(fp, val, 0600) } +// Close implements Db func(fdb *FsDb) Close() error { return nil } - + +// create a key safe for the filesystem func(fdb *FsDb) pathFor(key []byte) (string, error) { kb, err := fdb.ToKey(key) if err != nil { diff --git a/db/fs_test.go b/db/fs_test.go @@ -8,6 +8,7 @@ import ( ) func TestPutGetFs(t *testing.T) { + var dbi Db ctx := context.Background() sid := "ses" d, err := ioutil.TempDir("", "vise-db-*") @@ -17,6 +18,10 @@ func TestPutGetFs(t *testing.T) { db := &FsDb{} db.SetPrefix(DATATYPE_USERSTART) db.SetSession(sid) + + dbi = db + _ = dbi + err = db.Connect(ctx, d) if err != nil { t.Fatal(err) diff --git a/db/gdbm.go b/db/gdbm.go @@ -7,12 +7,14 @@ import ( gdbm "github.com/graygnuorg/go-gdbm" ) +// GdbmDb is a gdbm backend implementation of the Db interface. type GdbmDb struct { BaseDb conn *gdbm.Database prefix uint8 } +// Connect implements Db func(gdb *GdbmDb) Connect(ctx context.Context, connStr string) error { db, err := gdbm.Open(connStr, gdbm.ModeWrcreat) if err != nil { @@ -22,6 +24,7 @@ func(gdb *GdbmDb) Connect(ctx context.Context, connStr string) error { return nil } +// Put implements Db func(gdb *GdbmDb) Put(ctx context.Context, key []byte, val []byte) error { k, err := gdb.ToKey(key) if err != nil { @@ -30,6 +33,7 @@ func(gdb *GdbmDb) Put(ctx context.Context, key []byte, val []byte) error { return gdb.conn.Store(k, val, true) } +// Get implements Db func(gdb *GdbmDb) Get(ctx context.Context, key []byte) ([]byte, error) { k, err := gdb.ToKey(key) if err != nil { @@ -45,6 +49,7 @@ func(gdb *GdbmDb) Get(ctx context.Context, key []byte) ([]byte, error) { return v, nil } +// Close implements Db func(gdb *GdbmDb) Close() error { return gdb.Close() } diff --git a/db/gdbm_test.go b/db/gdbm_test.go @@ -8,6 +8,7 @@ import ( ) func TestPutGetGdbm(t *testing.T) { + var dbi Db ctx := context.Background() sid := "ses" f, err := ioutil.TempFile("", "vise-db-*") @@ -17,6 +18,10 @@ func TestPutGetGdbm(t *testing.T) { db := &GdbmDb{} db.SetPrefix(DATATYPE_USERSTART) db.SetSession(sid) + + dbi = db + _ = dbi + err = db.Connect(ctx, f.Name()) if err != nil { t.Fatal(err) diff --git a/db/mem.go b/db/mem.go @@ -5,21 +5,25 @@ import ( "fmt" ) +// MemDb is a memory backend implementation of the Db interface. type MemDb struct { BaseDb store map[string][]byte } +// Connect implements Db func(mdb *MemDb) Connect(ctx context.Context, connStr string) error { mdb.store = make(map[string][]byte) return nil } +// convert to a supported map key type func(mdb *MemDb) toHexKey(key []byte) (string, error) { k, err := mdb.ToKey(key) return fmt.Sprintf("%x", k), err } +// Get implements Db func(mdb *MemDb) Get(ctx context.Context, key []byte) ([]byte, error) { k, err := mdb.toHexKey(key) if err != nil { @@ -32,6 +36,7 @@ func(mdb *MemDb) Get(ctx context.Context, key []byte) ([]byte, error) { return v, nil } +// Put implements Db func(mdb *MemDb) Put(ctx context.Context, key []byte, val []byte) error { k, err := mdb.toHexKey(key) if err != nil { @@ -41,6 +46,7 @@ func(mdb *MemDb) Put(ctx context.Context, key []byte, val []byte) error { return nil } +// Close implements Db func(mdb *MemDb) Close() error { return nil } diff --git a/db/mem_test.go b/db/mem_test.go @@ -7,11 +7,16 @@ import ( ) func TestPutGetMem(t *testing.T) { + var dbi Db ctx := context.Background() sid := "ses" db := &MemDb{} db.SetPrefix(DATATYPE_USERSTART) db.SetSession(sid) + + dbi = db + _ = dbi + err := db.Connect(ctx, "") if err != nil { t.Fatal(err) diff --git a/db/pg.go b/db/pg.go @@ -7,6 +7,7 @@ import ( "github.com/jackc/pgx/v5/pgxpool" ) +// PgDb is a Postgresql backend implementation of the Db interface. type PgDb struct { BaseDb conn *pgxpool.Pool @@ -14,17 +15,20 @@ type PgDb struct { prefix uint8 } +// NewPgDb creates a new PgDb reference. func NewPgDb() *PgDb { return &PgDb{ schema: "public", } } +// WithSchema sets the Postgres schema to use for the storage table. func(pdb *PgDb) WithSchema(schema string) *PgDb { pdb.schema = schema return pdb } +// Connect implements Db. func(pdb *PgDb) Connect(ctx context.Context, connStr string) error { var err error conn, err := pgxpool.New(ctx, connStr) @@ -35,61 +39,7 @@ func(pdb *PgDb) Connect(ctx context.Context, connStr string) error { return pdb.prepare(ctx) } -func(pdb *PgDb) prepare(ctx context.Context) error { - tx, err := pdb.conn.Begin(ctx) - if err != nil { - tx.Rollback(ctx) - return err - } -// query := fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.kv_vise_domain ( -// id SERIAL PRIMARY KEY, -// name VARCHAR(256) NOT NULL -// ); -//`, pdb.schema) -// _, err = tx.Exec(ctx, query) -// if err != nil { -// tx.Rollback(ctx) -// return err -// } -// -// query = fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.kv_vise ( -// id SERIAL NOT NULL, -// domain_id INT NOT NULL, -// key VARCHAR(256) NOT NULL, -// value BYTEA NOT NULL, -// constraint fk_domain -// FOREIGN KEY (domain_id) -// REFERENCES %s.kv_vise_domain(id) -// ); -//`, pdb.schema, pdb.schema) -// _, err = tx.Exec(ctx, query) -// if err != nil { -// tx.Rollback(ctx) -// return err -// } - - query := fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.kv_vise ( - id SERIAL NOT NULL, - key BYTEA NOT NULL UNIQUE, - value BYTEA NOT NULL - ); -`, pdb.schema) - _, err = tx.Exec(ctx, query) - if err != nil { - tx.Rollback(ctx) - return err - } - - err = tx.Commit(ctx) - if err != nil { - //if !errors.Is(pgx.ErrTxCommitRollback) { - tx.Rollback(ctx) - return err - //} - } - return nil -} - +// Put implements Db. func(pdb *PgDb) Put(ctx context.Context, key []byte, val []byte) error { k, err := pdb.ToKey(key) if err != nil { @@ -109,6 +59,7 @@ func(pdb *PgDb) Put(ctx context.Context, key []byte, val []byte) error { return nil } +// Get implements Db. func(pdb *PgDb) Get(ctx context.Context, key []byte) ([]byte, error) { k, err := pdb.ToKey(key) if err != nil { @@ -133,7 +84,35 @@ func(pdb *PgDb) Get(ctx context.Context, key []byte) ([]byte, error) { return b, nil } +// Close implements Db. func(pdb *PgDb) Close() error { pdb.Close() return nil } + +// set up table +func(pdb *PgDb) prepare(ctx context.Context) error { + tx, err := pdb.conn.Begin(ctx) + if err != nil { + tx.Rollback(ctx) + return err + } + query := fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.kv_vise ( + id SERIAL NOT NULL, + key BYTEA NOT NULL UNIQUE, + value BYTEA NOT NULL + ); +`, pdb.schema) + _, err = tx.Exec(ctx, query) + if err != nil { + tx.Rollback(ctx) + return err + } + + err = tx.Commit(ctx) + if err != nil { + tx.Rollback(ctx) + return err + } + return nil +} diff --git a/db/pg_test.go b/db/pg_test.go @@ -7,12 +7,17 @@ import ( ) func TestPutGetPg(t *testing.T) { - t.Skip("need postgresql mock") + var dbi Db ses := "xyzzy" db := NewPgDb().WithSchema("vvise") db.SetPrefix(DATATYPE_USERSTART) db.SetSession(ses) ctx := context.Background() + + dbi = db + _ = dbi + + t.Skip("need postgresql mock") err := db.Connect(ctx, "postgres://vise:esiv@localhost:5432/visedb") if err != nil { t.Fatal(err)