go-vise

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

commit 8343b4bd57be0991946478ae28500d9cd6857222
parent 9828fc359d69a95eff6d7488d2820e68cfac61cf
Author: lash <dev@holbrook.no>
Date:   Fri, 30 Aug 2024 15:26:33 +0100

Add put and get for postgresql

Diffstat:
Mdb/db.go | 8+++++---
Adb/error.go | 17+++++++++++++++++
Mdb/fs.go | 8+++++++-
Mdb/pg.go | 100++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------
Mdb/pg_test.go | 28++++++++++++++++++++++++++--
5 files changed, 134 insertions(+), 27 deletions(-)

diff --git a/db/db.go b/db/db.go @@ -16,14 +16,16 @@ const ( type Db interface { Connect(ctx context.Context, connStr string) error + Close() error Get(ctx context.Context, sessionId string, key []byte) ([]byte, error) Put(ctx context.Context, sessionId string, key []byte, val []byte) error } -func ToDbKey(typ uint8, s string, l *lang.Language) []byte { +func ToDbKey(typ uint8, b []byte, l *lang.Language) []byte { k := []byte{typ} if l != nil && l.Code != "" { - s += "_" + l.Code + k = append(k, []byte("_" + l.Code)...) + //s += "_" + l.Code } - return append(k, []byte(s)...) + return append(k, b...) } diff --git a/db/error.go b/db/error.go @@ -0,0 +1,17 @@ +package db + +import ( + "fmt" +) + +type ErrNotFound struct { + k []byte +} + +func NewErrNotFound(k []byte) error { + return ErrNotFound{k} +} + +func(e ErrNotFound) Error() string { + return fmt.Sprintf("key not found: %x", e.k) +} diff --git a/db/fs.go b/db/fs.go @@ -44,9 +44,15 @@ func(fdb *FsDb) Put(ctx context.Context, sessionId string, key []byte, val []byt return ioutil.WriteFile(fp, val, 0600) } +func(fdb *FsDb) Close() error { + return nil +} + func(fdb *FsDb) pathFor(sessionId string, key []byte) string{ - k := sessionId + "." + string(key) + k := append([]byte(sessionId), 0x2E) + k = append(k, key...) kb := ToDbKey(DATATYPE_USERSTART, k, nil) kb[0] += 30 return path.Join(fdb.dir, string(kb)) } + diff --git a/db/pg.go b/db/pg.go @@ -12,11 +12,13 @@ import ( type PgDb struct { conn *pgxpool.Pool schema string + prefix uint8 } func NewPgDb() *PgDb { return &PgDb{ schema: "public", + prefix: DATATYPE_USERSTART, } } @@ -25,6 +27,14 @@ func(pdb *PgDb) WithSchema(schema string) *PgDb { return pdb } +func(pdb *PgDb) SetPrefix(pfx uint8) error { + if pfx < DATATYPE_USERSTART { + return fmt.Errorf("prefix cannot be < %d", DATATYPE_USERSTART) + } + pdb.prefix = pfx + return nil +} + func(pdb *PgDb) Connect(ctx context.Context, connStr string) error { var err error conn, err := pgxpool.New(ctx, connStr) @@ -41,27 +51,39 @@ func(pdb *PgDb) prepare(ctx context.Context) error { 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_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 ( + 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) + key BYTEA NOT NULL UNIQUE, + value BYTEA NOT NULL ); -`, pdb.schema, pdb.schema) +`, pdb.schema) _, err = tx.Exec(ctx, query) if err != nil { tx.Rollback(ctx) @@ -78,14 +100,50 @@ func(pdb *PgDb) prepare(ctx context.Context) error { return nil } -func(pdb *PgDb) domainId(ctx context.Context, domain string) { - +func(pdb *PgDb) dbKey(sessionId string, key []byte) []byte { + b := append([]byte(sessionId), 0x2E) + b = append(b, key...) + return ToDbKey(pdb.prefix, b, nil) } func(pdb *PgDb) Put(ctx context.Context, sessionId string, key []byte, val []byte) error { + k := pdb.dbKey(sessionId, key) + tx, err := pdb.conn.Begin(ctx) + if err != nil { + return err + } + query := fmt.Sprintf("INSERT INTO %s.kv_vise (key, value) VALUES ($1, $2) ON CONFLICT(key) DO UPDATE SET value = $2;", pdb.schema) + _, err = tx.Exec(ctx, query, k, val) + if err != nil { + tx.Rollback(ctx) + return err + } + tx.Commit(ctx) return nil } func(pdb *PgDb) Get(ctx context.Context, sessionId string, key []byte) ([]byte, error) { - return nil, nil + k := pdb.dbKey(sessionId, key) + tx, err := pdb.conn.Begin(ctx) + if err != nil { + return nil, err + } + query := fmt.Sprintf("SELECT value FROM %s.kv_vise WHERE key = $1", pdb.schema) + rs, err := tx.Query(ctx, query, k) + if err != nil { + return nil, err + } + defer rs.Close() + if !rs.Next() { + return nil, NewErrNotFound(k) + + } + r := rs.RawValues() + b := r[0] + return b, nil +} + +func(pdb *PgDb) Close() error { + pdb.Close() + return nil } diff --git a/db/pg_test.go b/db/pg_test.go @@ -1,16 +1,40 @@ package db import ( + "bytes" "context" "testing" ) func TestCreate(t *testing.T) { - t.Skip("need postgresql mock") - db := NewPgDb().WithSchema("govise") +// t.Skip("need postgresql mock") + db := NewPgDb().WithSchema("vvise") ctx := context.Background() err := db.Connect(ctx, "postgres://vise:esiv@localhost:5432/visedb") if err != nil { t.Fatal(err) } + err = db.Put(ctx, "xyzzy", []byte("foo"), []byte("bar")) + if err != nil { + t.Fatal(err) + } + b, err := db.Get(ctx, "xyzzy", []byte("foo")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(b, []byte("bar")) { + t.Fatalf("expected 'bar', got %x", b) + } + err = db.Put(ctx, "xyzzy", []byte("foo"), []byte("plugh")) + if err != nil { + t.Fatal(err) + } + b, err = db.Get(ctx, "xyzzy", []byte("foo")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(b, []byte("plugh")) { + t.Fatalf("expected 'plugh', got %x", b) + } + }