go-vise

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

commit 05f006f0444e9925baf7d6fa4d03472d37f30bc9
parent 9d4e1346d9a91161e0f52694436b2efecf121f9c
Author: lash <dev@holbrook.no>
Date:   Sun,  1 Sep 2024 20:32:01 +0100

Move all db implementations to separate packages

Diffstat:
Mdb/db.go | 46++++++++++++++++++++++++++++++----------------
Ddb/fs.go | 144-------------------------------------------------------------------------------
Adb/fs/fs.go | 146+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adb/fs/fs_test.go | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adb/fs/log.go | 9+++++++++
Ddb/fs_test.go | 99-------------------------------------------------------------------------------
Ddb/gdbm.go | 94-------------------------------------------------------------------------------
Adb/gdbm/gdbm.go | 96+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adb/gdbm/gdbm_test.go | 66++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adb/gdbm/log.go | 9+++++++++
Ddb/gdbm_test.go | 64----------------------------------------------------------------
Ddb/mem.go | 97-------------------------------------------------------------------------------
Adb/mem/log.go | 9+++++++++
Adb/mem/mem.go | 98+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Adb/mem/mem_test.go | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Ddb/mem_test.go | 54------------------------------------------------------
Adb/postgres/log.go | 9+++++++++
Mdb/postgres/pg.go | 6+++---
Mdb/postgres/pg_test.go | 2+-
19 files changed, 633 insertions(+), 572 deletions(-)

diff --git a/db/db.go b/db/db.go @@ -62,9 +62,11 @@ type Db interface { // * DATATYPE_TEMPLATE // * DATATYPE_STATICLOAD SetLanguage(*lang.Language) + // Prefix returns the current active datatype prefix + Prefix() uint8 } -type lookupKey struct { +type LookupKey struct { Default []byte Translation []byte } @@ -83,8 +85,8 @@ 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 { +// baseDb is a base class for all Db implementations. +type baseDb struct { pfx uint8 sid []byte lock uint8 @@ -92,37 +94,49 @@ type BaseDb struct { seal bool } -func NewBaseDb() *BaseDb { - db := &BaseDb{} - db.defaultLock() +func NewDbBase() *DbBase { + db := &DbBase{ + baseDb: &baseDb{}, + } + db.baseDb.defaultLock() return db } +type DbBase struct { + *baseDb +} + +type BaseDb baseDb + // ensures default locking of read-only entries -func(db *BaseDb) defaultLock() { +func(db *baseDb) defaultLock() { db.lock |= safeLock } -func(db *BaseDb) Safe() bool { +func(db *baseDb) Safe() bool { return db.lock & safeLock == safeLock } +func(db *baseDb) Prefix() uint8 { + return db.pfx +} + // SetPrefix implements the Db interface. -func(db *BaseDb) SetPrefix(pfx uint8) { +func(db *baseDb) SetPrefix(pfx uint8) { db.pfx = pfx } // SetLanguage implements the Db interface. -func(db *BaseDb) SetLanguage(ln *lang.Language) { +func(db *baseDb) SetLanguage(ln *lang.Language) { db.lang = ln } // SetSession implements the Db interface. -func(db *BaseDb) SetSession(sessionId string) { +func(db *baseDb) SetSession(sessionId string) { db.sid = append([]byte(sessionId), 0x2E) } // SetLock implements the Db interface. -func(db *BaseDb) SetLock(pfx uint8, lock bool) error { +func(db *baseDb) SetLock(pfx uint8, lock bool) error { if db.seal { return errors.New("SetLock on sealed db") } @@ -139,12 +153,12 @@ func(db *BaseDb) SetLock(pfx uint8, lock bool) error { return nil } -func(db *BaseDb) checkPut() bool { +func(db *baseDb) checkPut() bool { return db.pfx & db.lock == 0 } // CheckPut returns true if the current selected data type can be written to. -func(db *BaseDb) CheckPut() bool { +func(db *baseDb) CheckPut() bool { return db.checkPut() } @@ -152,9 +166,9 @@ func(db *BaseDb) CheckPut() bool { // ToKey creates a DbKey within the current session context. // // TODO: hard to read, clean up -func(db *BaseDb) ToKey(ctx context.Context, key []byte) (lookupKey, error) { +func(db *baseDb) ToKey(ctx context.Context, key []byte) (LookupKey, error) { var ln *lang.Language - var lk lookupKey + var lk LookupKey var b []byte if db.pfx == DATATYPE_UNKNOWN { return lk, errors.New("datatype prefix cannot be UNKNOWN") diff --git a/db/fs.go b/db/fs.go @@ -1,144 +0,0 @@ -package db - -import ( - "context" - "errors" - "io/fs" - "io/ioutil" - "os" - "path" -) - -// holds string (filepath) versions of lookupKey -type fsLookupKey struct { - Default string - Translation string -} - -// pure filesystem backend implementation if the Db interface. -type fsDb struct { - *BaseDb - dir string -} - -// NewFsDb creates a filesystem backed Db implementation. -func NewFsDb() *fsDb { - db := &fsDb{ - BaseDb: NewBaseDb(), - } - return db -} - -// Connect implements the Db interface. -func(fdb *fsDb) Connect(ctx context.Context, connStr string) error { - if fdb.dir != "" { - panic("already connected") - } - err := os.MkdirAll(connStr, 0700) - if err != nil { - return err - } - fdb.dir = connStr - return nil -} - -// Get implements the Db interface. -func(fdb *fsDb) Get(ctx context.Context, key []byte) ([]byte, error) { - var f *os.File - lk, err := fdb.ToKey(ctx, key) - if err != nil { - return nil, err - } - flk, err := fdb.pathFor(ctx, &lk) - if err != nil { - return nil, err - } - flka, err := fdb.altPathFor(ctx, &lk) - if err != nil { - return nil, err - } - for i, fp := range([]string{flk.Translation, flka.Translation, flk.Default, flka.Default}) { - if fp == "" { - logg.TraceCtxf(ctx, "fs get skip missing", "i", i) - continue - } - logg.TraceCtxf(ctx, "trying fs get", "i", i, "key", key, "path", fp) - f, err = os.Open(fp) - if err == nil { - break - } - if !errors.Is(err, fs.ErrNotExist) { - return nil, err - } - } - if f == nil { - return nil, NewErrNotFound(key) - } - defer f.Close() - b, err := ioutil.ReadAll(f) - if err != nil { - return nil, err - } - return b, nil -} - -// Put implements the Db interface. -func(fdb *fsDb) Put(ctx context.Context, key []byte, val []byte) error { - if !fdb.checkPut() { - return errors.New("unsafe put and safety set") - } - lk, err := fdb.ToKey(ctx, key) - if err != nil { - return err - } - flk, err := fdb.pathFor(ctx, &lk) - if err != nil { - return err - } - logg.TraceCtxf(ctx, "fs put", "key", key, "lk", lk, "flk", flk, "val", val) - if flk.Translation != "" { - err = ioutil.WriteFile(flk.Translation, val, 0600) - if err != nil { - return err - } - return nil - } - return ioutil.WriteFile(flk.Default, val, 0600) -} - -// Close implements the Db interface. -func(fdb *fsDb) Close() error { - return nil -} - -// create a key safe for the filesystem. -func(fdb *fsDb) pathFor(ctx context.Context, lk *lookupKey) (fsLookupKey, error) { - var flk fsLookupKey - lk.Default[0] += 0x30 - flk.Default = path.Join(fdb.dir, string(lk.Default)) - if lk.Translation != nil { - lk.Translation[0] += 0x30 - flk.Translation = path.Join(fdb.dir, string(lk.Translation)) - } - return flk, nil -} - -// create a key safe for the filesystem, matching legacy resource.FsResource name. -func(fdb *fsDb) altPathFor(ctx context.Context, lk *lookupKey) (fsLookupKey, error) { - var flk fsLookupKey - fb := string(lk.Default[1:]) - if fdb.pfx == DATATYPE_BIN { - fb += ".bin" - } - flk.Default = path.Join(fdb.dir, fb) - - if lk.Translation != nil { - fb = string(lk.Translation[1:]) - if fdb.pfx == DATATYPE_BIN { - fb += ".bin" - } - flk.Translation = path.Join(fdb.dir, fb) - } - - return flk, nil -} diff --git a/db/fs/fs.go b/db/fs/fs.go @@ -0,0 +1,146 @@ +package fs + +import ( + "context" + "errors" + "io/fs" + "io/ioutil" + "os" + "path" + + "git.defalsify.org/vise.git/db" +) + +// holds string (filepath) versions of LookupKey +type fsLookupKey struct { + Default string + Translation string +} + +// pure filesystem backend implementation if the Db interface. +type fsDb struct { + *db.DbBase + dir string +} + +// NewFsDb creates a filesystem backed Db implementation. +func NewFsDb() *fsDb { + db := &fsDb{ + DbBase: db.NewDbBase(), + } + return db +} + +// Connect implements the Db interface. +func(fdb *fsDb) Connect(ctx context.Context, connStr string) error { + if fdb.dir != "" { + panic("already connected") + } + err := os.MkdirAll(connStr, 0700) + if err != nil { + return err + } + fdb.dir = connStr + return nil +} + +// Get implements the Db interface. +func(fdb *fsDb) Get(ctx context.Context, key []byte) ([]byte, error) { + var f *os.File + lk, err := fdb.ToKey(ctx, key) + if err != nil { + return nil, err + } + flk, err := fdb.pathFor(ctx, &lk) + if err != nil { + return nil, err + } + flka, err := fdb.altPathFor(ctx, &lk) + if err != nil { + return nil, err + } + for i, fp := range([]string{flk.Translation, flka.Translation, flk.Default, flka.Default}) { + if fp == "" { + logg.TraceCtxf(ctx, "fs get skip missing", "i", i) + continue + } + logg.TraceCtxf(ctx, "trying fs get", "i", i, "key", key, "path", fp) + f, err = os.Open(fp) + if err == nil { + break + } + if !errors.Is(err, fs.ErrNotExist) { + return nil, err + } + } + if f == nil { + return nil, db.NewErrNotFound(key) + } + defer f.Close() + b, err := ioutil.ReadAll(f) + if err != nil { + return nil, err + } + return b, nil +} + +// Put implements the Db interface. +func(fdb *fsDb) Put(ctx context.Context, key []byte, val []byte) error { + if !fdb.CheckPut() { + return errors.New("unsafe put and safety set") + } + lk, err := fdb.ToKey(ctx, key) + if err != nil { + return err + } + flk, err := fdb.pathFor(ctx, &lk) + if err != nil { + return err + } + logg.TraceCtxf(ctx, "fs put", "key", key, "lk", lk, "flk", flk, "val", val) + if flk.Translation != "" { + err = ioutil.WriteFile(flk.Translation, val, 0600) + if err != nil { + return err + } + return nil + } + return ioutil.WriteFile(flk.Default, val, 0600) +} + +// Close implements the Db interface. +func(fdb *fsDb) Close() error { + return nil +} + +// create a key safe for the filesystem. +func(fdb *fsDb) pathFor(ctx context.Context, lk *db.LookupKey) (fsLookupKey, error) { + var flk fsLookupKey + lk.Default[0] += 0x30 + flk.Default = path.Join(fdb.dir, string(lk.Default)) + if lk.Translation != nil { + lk.Translation[0] += 0x30 + flk.Translation = path.Join(fdb.dir, string(lk.Translation)) + } + return flk, nil +} + +// create a key safe for the filesystem, matching legacy resource.FsResource name. +func(fdb *fsDb) altPathFor(ctx context.Context, lk *db.LookupKey) (fsLookupKey, error) { + var flk fsLookupKey + fb := string(lk.Default[1:]) + if fdb.Prefix() == db.DATATYPE_BIN { + fb += ".bin" + } + flk.Default = path.Join(fdb.dir, fb) + + if lk.Translation != nil { + fb = string(lk.Translation[1:]) + if fdb.Prefix() == db.DATATYPE_BIN { + fb += ".bin" + } + flk.Translation = path.Join(fdb.dir, fb) + } + + return flk, nil +} diff --git a/db/fs/fs_test.go b/db/fs/fs_test.go @@ -0,0 +1,101 @@ +package fs + +import ( + "bytes" + "context" + "io/ioutil" + "os" + "path" + "testing" + + "git.defalsify.org/vise.git/db" +) + +func TestCasesFs(t *testing.T) { + ctx := context.Background() + + store := NewFsDb() + d, err := ioutil.TempDir("", "vise-db-fs-*") + if err != nil { + t.Fatal(err) + } + err = store.Connect(ctx, d) + if err != nil { + t.Fatal(err) + } + + err = db.RunTests(t, ctx, store) + if err != nil { + t.Fatal(err) + } +} + +func TestPutGetFs(t *testing.T) { + var dbi db.Db + ctx := context.Background() + sid := "ses" + d, err := ioutil.TempDir("", "vise-db-*") + if err != nil { + t.Fatal(err) + } + store := NewFsDb() + store.SetPrefix(db.DATATYPE_USERDATA) + store.SetSession(sid) + + dbi = store + _ = dbi + + err = store.Connect(ctx, d) + if err != nil { + t.Fatal(err) + } + err = store.Put(ctx, []byte("foo"), []byte("bar")) + if err != nil { + t.Fatal(err) + } + v, err := store.Get(ctx, []byte("foo")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(v, []byte("bar")) { + t.Fatalf("expected value 'bar', found '%s'", v) + } + _, err = store.Get(ctx, []byte("bar")) + if err == nil { + t.Fatal("expected get error for key 'bar'") + } +} + +func TestPutGetFsAlt(t *testing.T) { + ctx := context.Background() + sid := "zezion" + d, err := ioutil.TempDir("", "vise-db-*") + if err != nil { + t.Fatal(err) + } + store := NewFsDb() + store.SetPrefix(db.DATATYPE_TEMPLATE) + store.SetSession(sid) + + fp := path.Join(d, sid) + err = os.MkdirAll(fp, 0700) + if err != nil { + t.Fatal(err) + } + store.Connect(ctx, fp) + fp = path.Join(fp, "inky") + + b := []byte("pinky blinky clyde") + err = ioutil.WriteFile(fp, b, 0700) + if err != nil { + t.Fatal(err) + } + + v, err := store.Get(ctx, []byte("inky")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(v, b) { + t.Fatalf("expected %x, got %x", b, v) + } +} diff --git a/db/fs/log.go b/db/fs/log.go @@ -0,0 +1,9 @@ +package fs + +import ( + "git.defalsify.org/vise.git/logging" +) + +var ( + logg logging.Logger = logging.NewVanilla().WithDomain("fsdb") +) diff --git a/db/fs_test.go b/db/fs_test.go @@ -1,99 +0,0 @@ -package db - -import ( - "bytes" - "context" - "io/ioutil" - "os" - "path" - "testing" -) - -func TestCasesFs(t *testing.T) { - ctx := context.Background() - - db := NewFsDb() - d, err := ioutil.TempDir("", "vise-db-fs-*") - if err != nil { - t.Fatal(err) - } - err = db.Connect(ctx, d) - if err != nil { - t.Fatal(err) - } - - err = runTests(t, ctx, db) - if err != nil { - t.Fatal(err) - } -} - -func TestPutGetFs(t *testing.T) { - var dbi Db - ctx := context.Background() - sid := "ses" - d, err := ioutil.TempDir("", "vise-db-*") - if err != nil { - t.Fatal(err) - } - db := NewFsDb() - db.SetPrefix(DATATYPE_USERDATA) - db.SetSession(sid) - - dbi = db - _ = dbi - - err = db.Connect(ctx, d) - if err != nil { - t.Fatal(err) - } - err = db.Put(ctx, []byte("foo"), []byte("bar")) - if err != nil { - t.Fatal(err) - } - v, err := db.Get(ctx, []byte("foo")) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(v, []byte("bar")) { - t.Fatalf("expected value 'bar', found '%s'", v) - } - _, err = db.Get(ctx, []byte("bar")) - if err == nil { - t.Fatal("expected get error for key 'bar'") - } -} - -func TestPutGetFsAlt(t *testing.T) { - ctx := context.Background() - sid := "zezion" - d, err := ioutil.TempDir("", "vise-db-*") - if err != nil { - t.Fatal(err) - } - db := NewFsDb() - db.SetPrefix(DATATYPE_TEMPLATE) - db.SetSession(sid) - - fp := path.Join(d, sid) - err = os.MkdirAll(fp, 0700) - if err != nil { - t.Fatal(err) - } - db.Connect(ctx, fp) - fp = path.Join(fp, "inky") - - b := []byte("pinky blinky clyde") - err = ioutil.WriteFile(fp, b, 0700) - if err != nil { - t.Fatal(err) - } - - v, err := db.Get(ctx, []byte("inky")) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(v, b) { - t.Fatalf("expected %x, got %x", b, v) - } -} diff --git a/db/gdbm.go b/db/gdbm.go @@ -1,94 +0,0 @@ -package db - -import ( - "context" - "errors" - "os" - - 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 -} - -// Creates a new gdbm backed Db implementation. -func NewGdbmDb() *gdbmDb { - db := &gdbmDb{ - BaseDb: NewBaseDb(), - } - return db -} - -// Connect implements Db -func(gdb *gdbmDb) Connect(ctx context.Context, connStr string) error { - if gdb.conn != nil { - panic("already connected") - } - var db *gdbm.Database - _, err := os.Stat(connStr) - if err != nil { - if !errors.Is(os.ErrNotExist, err) { - return err - } - db, err = gdbm.Open(connStr, gdbm.ModeWrcreat) - } else { - db, err = gdbm.Open(connStr, gdbm.ModeWriter | gdbm.ModeReader) - } - - if err != nil { - return err - } - gdb.conn = db - return nil -} - -// Put implements Db -func(gdb *gdbmDb) Put(ctx context.Context, key []byte, val []byte) error { - if !gdb.checkPut() { - return errors.New("unsafe put and safety set") - } - lk, err := gdb.ToKey(ctx, key) - if err != nil { - return err - } - logg.TraceCtxf(ctx, "gdbm put", "key", key, "lk", lk, "val", val) - if lk.Translation != nil { - return gdb.conn.Store(lk.Translation, val, true) - } - return gdb.conn.Store(lk.Default, val, true) -} - -// Get implements Db -func(gdb *gdbmDb) Get(ctx context.Context, key []byte) ([]byte, error) { - var v []byte - lk, err := gdb.ToKey(ctx, key) - if err != nil { - return nil, err - } - if lk.Translation != nil { - v, err = gdb.conn.Fetch(lk.Translation) - if err != nil { - if !errors.Is(gdbm.ErrItemNotFound, err) { - return nil, err - } - } - return v, nil - } - v, err = gdb.conn.Fetch(lk.Default) - if err != nil { - if errors.Is(gdbm.ErrItemNotFound, err) { - return nil, NewErrNotFound(key) - } - return nil, err - } - return v, nil -} - -// Close implements Db -func(gdb *gdbmDb) Close() error { - return gdb.Close() -} diff --git a/db/gdbm/gdbm.go b/db/gdbm/gdbm.go @@ -0,0 +1,96 @@ +package gdbm + +import ( + "context" + "errors" + "os" + + gdbm "github.com/graygnuorg/go-gdbm" + + "git.defalsify.org/vise.git/db" +) + +// gdbmDb is a gdbm backend implementation of the Db interface. +type gdbmDb struct { + *db.DbBase + conn *gdbm.Database + prefix uint8 +} + +// Creates a new gdbm backed Db implementation. +func NewGdbmDb() *gdbmDb { + db := &gdbmDb{ + DbBase: db.NewDbBase(), + } + return db +} + +// Connect implements Db +func(gdb *gdbmDb) Connect(ctx context.Context, connStr string) error { + if gdb.conn != nil { + panic("already connected") + } + var db *gdbm.Database + _, err := os.Stat(connStr) + if err != nil { + if !errors.Is(os.ErrNotExist, err) { + return err + } + db, err = gdbm.Open(connStr, gdbm.ModeWrcreat) + } else { + db, err = gdbm.Open(connStr, gdbm.ModeWriter | gdbm.ModeReader) + } + + if err != nil { + return err + } + gdb.conn = db + return nil +} + +// Put implements Db +func(gdb *gdbmDb) Put(ctx context.Context, key []byte, val []byte) error { + if !gdb.CheckPut() { + return errors.New("unsafe put and safety set") + } + lk, err := gdb.ToKey(ctx, key) + if err != nil { + return err + } + logg.TraceCtxf(ctx, "gdbm put", "key", key, "lk", lk, "val", val) + if lk.Translation != nil { + return gdb.conn.Store(lk.Translation, val, true) + } + return gdb.conn.Store(lk.Default, val, true) +} + +// Get implements Db +func(gdb *gdbmDb) Get(ctx context.Context, key []byte) ([]byte, error) { + var v []byte + lk, err := gdb.ToKey(ctx, key) + if err != nil { + return nil, err + } + if lk.Translation != nil { + v, err = gdb.conn.Fetch(lk.Translation) + if err != nil { + if !errors.Is(gdbm.ErrItemNotFound, err) { + return nil, err + } + } + return v, nil + } + v, err = gdb.conn.Fetch(lk.Default) + if err != nil { + if errors.Is(gdbm.ErrItemNotFound, err) { + return nil, db.NewErrNotFound(key) + } + return nil, err + } + return v, nil +} + +// Close implements Db +func(gdb *gdbmDb) Close() error { + return gdb.Close() +} diff --git a/db/gdbm/gdbm_test.go b/db/gdbm/gdbm_test.go @@ -0,0 +1,66 @@ +package gdbm + +import ( + "bytes" + "context" + "io/ioutil" + "testing" + + "git.defalsify.org/vise.git/db" +) + +func TestCasesGdbm(t *testing.T) { + ctx := context.Background() + + store := NewGdbmDb() + f, err := ioutil.TempFile("", "vise-db-gdbm-*") + if err != nil { + t.Fatal(err) + } + err = store.Connect(ctx, f.Name()) + if err != nil { + t.Fatal(err) + } + + err = db.RunTests(t, ctx, store) + if err != nil { + t.Fatal(err) + } +} + +func TestPutGetGdbm(t *testing.T) { + var dbi db.Db + ctx := context.Background() + sid := "ses" + f, err := ioutil.TempFile("", "vise-db-*") + if err != nil { + t.Fatal(err) + } + store := NewGdbmDb() + store.SetPrefix(db.DATATYPE_USERDATA) + store.SetSession(sid) + + dbi = store + _ = dbi + + err = store.Connect(ctx, f.Name()) + if err != nil { + t.Fatal(err) + } + err = store.Put(ctx, []byte("foo"), []byte("bar")) + if err != nil { + t.Fatal(err) + } + v, err := store.Get(ctx, []byte("foo")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(v, []byte("bar")) { + t.Fatalf("expected value 'bar', found '%s'", v) + } + _, err = store.Get(ctx, []byte("bar")) + if err == nil { + t.Fatal("expected get error for key 'bar'") + } + +} diff --git a/db/gdbm/log.go b/db/gdbm/log.go @@ -0,0 +1,9 @@ +package gdbm + +import ( + "git.defalsify.org/vise.git/logging" +) + +var ( + logg logging.Logger = logging.NewVanilla().WithDomain("gdbmdb") +) diff --git a/db/gdbm_test.go b/db/gdbm_test.go @@ -1,64 +0,0 @@ -package db - -import ( - "bytes" - "context" - "io/ioutil" - "testing" -) - -func TestCasesGdbm(t *testing.T) { - ctx := context.Background() - - db := NewGdbmDb() - f, err := ioutil.TempFile("", "vise-db-gdbm-*") - if err != nil { - t.Fatal(err) - } - err = db.Connect(ctx, f.Name()) - if err != nil { - t.Fatal(err) - } - - err = runTests(t, ctx, db) - if err != nil { - t.Fatal(err) - } -} - -func TestPutGetGdbm(t *testing.T) { - var dbi Db - ctx := context.Background() - sid := "ses" - f, err := ioutil.TempFile("", "vise-db-*") - if err != nil { - t.Fatal(err) - } - db := NewGdbmDb() - db.SetPrefix(DATATYPE_USERDATA) - db.SetSession(sid) - - dbi = db - _ = dbi - - err = db.Connect(ctx, f.Name()) - if err != nil { - t.Fatal(err) - } - err = db.Put(ctx, []byte("foo"), []byte("bar")) - if err != nil { - t.Fatal(err) - } - v, err := db.Get(ctx, []byte("foo")) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(v, []byte("bar")) { - t.Fatalf("expected value 'bar', found '%s'", v) - } - _, err = db.Get(ctx, []byte("bar")) - if err == nil { - t.Fatal("expected get error for key 'bar'") - } - -} diff --git a/db/mem.go b/db/mem.go @@ -1,97 +0,0 @@ -package db - -import ( - "context" - "encoding/hex" - "errors" -) - -// holds string (hex) versions of lookupKey -type memLookupKey struct { - Default string - Translation string -} - -// memDb is a memory backend implementation of the Db interface. -type memDb struct { - *BaseDb - store map[string][]byte -} - -// NewmemDb returns an in-process volatile Db implementation. -func NewMemDb() *memDb { - db := &memDb{ - BaseDb: NewBaseDb(), - } - db.BaseDb.defaultLock() - return db -} - -// Connect implements Db -func(mdb *memDb) Connect(ctx context.Context, connStr string) error { - if mdb.store != nil { - panic("already connected") - } - mdb.store = make(map[string][]byte) - return nil -} - -// convert to a supported map key type -func(mdb *memDb) toHexKey(ctx context.Context, key []byte) (memLookupKey, error) { - var mk memLookupKey - lk, err := mdb.ToKey(ctx, key) - mk.Default = hex.EncodeToString(lk.Default) - if lk.Translation != nil { - mk.Translation = hex.EncodeToString(lk.Translation) - } - logg.TraceCtxf(ctx, "converted key", "orig", key, "b", lk, "s", mk) - return mk, err -} - -// Get implements Db -func(mdb *memDb) Get(ctx context.Context, key []byte) ([]byte, error) { - var v []byte - var ok bool - mk, err := mdb.toHexKey(ctx, key) - if err != nil { - return nil, err - } - logg.TraceCtxf(ctx, "mem get", "k", mk) - if mk.Translation != "" { - v, ok = mdb.store[mk.Translation] - if ok { - return v, nil - } - } - v, ok = mdb.store[mk.Default] - if !ok { - //b, _ := hex.DecodeString(k) - return nil, NewErrNotFound(key) - } - return v, nil -} - -// Put implements Db -func(mdb *memDb) Put(ctx context.Context, key []byte, val []byte) error { - var k string - if !mdb.checkPut() { - return errors.New("unsafe put and safety set") - } - mk, err := mdb.toHexKey(ctx, key) - if err != nil { - return err - } - if mk.Translation != "" { - k = mk.Translation - } else { - k = mk.Default - } - mdb.store[k] = val - logg.TraceCtxf(ctx, "mem put", "k", k, "mk", mk, "v", val) - return nil -} - -// Close implements Db -func(mdb *memDb) Close() error { - return nil -} diff --git a/db/mem/log.go b/db/mem/log.go @@ -0,0 +1,9 @@ +package mem + +import ( + "git.defalsify.org/vise.git/logging" +) + +var ( + logg logging.Logger = logging.NewVanilla().WithDomain("memdb") +) diff --git a/db/mem/mem.go b/db/mem/mem.go @@ -0,0 +1,98 @@ +package mem + +import ( + "context" + "encoding/hex" + "errors" + + "git.defalsify.org/vise.git/db" +) + +// holds string (hex) versions of lookupKey +type memLookupKey struct { + Default string + Translation string +} + +// memDb is a memory backend implementation of the Db interface. +type memDb struct { + *db.DbBase + store map[string][]byte +} + +// NewmemDb returns an in-process volatile Db implementation. +func NewMemDb() *memDb { + db := &memDb{ + DbBase: db.NewDbBase(), + } + return db +} + +// Connect implements Db +func(mdb *memDb) Connect(ctx context.Context, connStr string) error { + if mdb.store != nil { + panic("already connected") + } + mdb.store = make(map[string][]byte) + return nil +} + +// convert to a supported map key type +func(mdb *memDb) toHexKey(ctx context.Context, key []byte) (memLookupKey, error) { + var mk memLookupKey + lk, err := mdb.ToKey(ctx, key) + mk.Default = hex.EncodeToString(lk.Default) + if lk.Translation != nil { + mk.Translation = hex.EncodeToString(lk.Translation) + } + logg.TraceCtxf(ctx, "converted key", "orig", key, "b", lk, "s", mk) + return mk, err +} + +// Get implements Db +func(mdb *memDb) Get(ctx context.Context, key []byte) ([]byte, error) { + var v []byte + var ok bool + mk, err := mdb.toHexKey(ctx, key) + if err != nil { + return nil, err + } + logg.TraceCtxf(ctx, "mem get", "k", mk) + if mk.Translation != "" { + v, ok = mdb.store[mk.Translation] + if ok { + return v, nil + } + } + v, ok = mdb.store[mk.Default] + if !ok { + //b, _ := hex.DecodeString(k) + return nil, db.NewErrNotFound(key) + } + return v, nil +} + +// Put implements Db +func(mdb *memDb) Put(ctx context.Context, key []byte, val []byte) error { + var k string + if !mdb.CheckPut() { + return errors.New("unsafe put and safety set") + } + mk, err := mdb.toHexKey(ctx, key) + if err != nil { + return err + } + if mk.Translation != "" { + k = mk.Translation + } else { + k = mk.Default + } + mdb.store[k] = val + logg.TraceCtxf(ctx, "mem put", "k", k, "mk", mk, "v", val) + return nil +} + +// Close implements Db +func(mdb *memDb) Close() error { + return nil +} diff --git a/db/mem/mem_test.go b/db/mem/mem_test.go @@ -0,0 +1,56 @@ +package mem + +import ( + "bytes" + "context" + "testing" + + "git.defalsify.org/vise.git/db" +) + +func TestCasesMem(t *testing.T) { + ctx := context.Background() + + store := NewMemDb() + err := store.Connect(ctx, "") + if err != nil { + t.Fatal(err) + } + + err = db.RunTests(t, ctx, store) + if err != nil { + t.Fatal(err) + } +} + +func TestPutGetMem(t *testing.T) { + var dbi db.Db + ctx := context.Background() + sid := "ses" + store := NewMemDb() + store.SetPrefix(db.DATATYPE_USERDATA) + store.SetSession(sid) + + dbi = store + _ = dbi + + err := store.Connect(ctx, "") + if err != nil { + t.Fatal(err) + } + err = store.Put(ctx, []byte("foo"), []byte("bar")) + if err != nil { + t.Fatal(err) + } + v, err := store.Get(ctx, []byte("foo")) + if err != nil { + t.Fatal(err) + } + if !bytes.Equal(v, []byte("bar")) { + t.Fatalf("expected value 'bar', found '%s'", v) + } + _, err = store.Get(ctx, []byte("bar")) + if err == nil { + t.Fatal("expected get error for key 'bar'") + } +} diff --git a/db/mem_test.go b/db/mem_test.go @@ -1,54 +0,0 @@ -package db - -import ( - "bytes" - "context" - "testing" -) - -func TestCasesMem(t *testing.T) { - ctx := context.Background() - - db := NewMemDb() - err := db.Connect(ctx, "") - if err != nil { - t.Fatal(err) - } - - err = runTests(t, ctx, db) - if err != nil { - t.Fatal(err) - } -} - -func TestPutGetMem(t *testing.T) { - var dbi Db - ctx := context.Background() - sid := "ses" - db := NewMemDb() - db.SetPrefix(DATATYPE_USERDATA) - db.SetSession(sid) - - dbi = db - _ = dbi - - err := db.Connect(ctx, "") - if err != nil { - t.Fatal(err) - } - err = db.Put(ctx, []byte("foo"), []byte("bar")) - if err != nil { - t.Fatal(err) - } - v, err := db.Get(ctx, []byte("foo")) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(v, []byte("bar")) { - t.Fatalf("expected value 'bar', found '%s'", v) - } - _, err = db.Get(ctx, []byte("bar")) - if err == nil { - t.Fatal("expected get error for key 'bar'") - } -} diff --git a/db/postgres/log.go b/db/postgres/log.go @@ -0,0 +1,9 @@ +package postgres + +import ( + "git.defalsify.org/vise.git/logging" +) + +var ( + logg logging.Logger = logging.NewVanilla().WithDomain("postgresdb") +) diff --git a/db/postgres/pg.go b/db/postgres/pg.go @@ -1,4 +1,4 @@ -package db +package postgres import ( "context" @@ -12,7 +12,7 @@ import ( // pgDb is a Postgres backend implementation of the Db interface. type pgDb struct { - *db.BaseDb + *db.DbBase conn *pgxpool.Pool schema string prefix uint8 @@ -21,7 +21,7 @@ type pgDb struct { // NewpgDb creates a new Postgres backed Db implementation. func NewPgDb() *pgDb { db := &pgDb{ - BaseDb: db.NewBaseDb(), + DbBase: db.NewDbBase(), schema: "public", } return db diff --git a/db/postgres/pg_test.go b/db/postgres/pg_test.go @@ -1,4 +1,4 @@ -package db +package postgres import ( "bytes"