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:
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)
+ }
+
}