go-vise

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

commit 1757ba50d6a03e1cd0b294925bf94d8bf7f3c568
parent 5348e19880454920c387b3c1191716898cc5e79a
Author: lash <dev@holbrook.no>
Date:   Sat,  9 Nov 2024 00:16:02 +0000

Implement postgres dumper

Diffstat:
Mdb/postgres/dump.go | 36++++++++++++++++++++++++++++++++++--
Adb/postgres/dump_test.go | 91+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mdb/postgres/pg.go | 2++
Mdb/postgres/pg_test.go | 2+-
4 files changed, 128 insertions(+), 3 deletions(-)

diff --git a/db/postgres/dump.go b/db/postgres/dump.go @@ -1,12 +1,44 @@ package postgres import ( + "fmt" "context" - "errors" "git.defalsify.org/vise.git/db" ) func(pdb *pgDb) Dump(ctx context.Context, key []byte) (*db.Dumper, error) { - return nil, errors.New("unimplemented") + tx, err := pdb.conn.BeginTx(ctx, defaultTxOptions) + if err != nil { + return nil, err + } + + query := fmt.Sprintf("SELECT key, value FROM %s.kv_vise WHERE key >= $1 AND key < $2", pdb.schema) + rs, err := tx.Query(ctx, query, key, key[0]) + if err != nil { + tx.Rollback(ctx) + return nil, err + } + defer rs.Close() + + if rs.Next() { + r := rs.RawValues() + tx.Commit(ctx) + //tx.Rollback(ctx) + pdb.it = rs + pdb.itBase = key + return db.NewDumper(pdb.dumpFunc).WithFirst(r[0], r[1]), nil + } + + return nil, db.NewErrNotFound(key) +} + +func(pdb *pgDb) dumpFunc(ctx context.Context) ([]byte, []byte) { + if !pdb.it.Next() { + pdb.it = nil + pdb.itBase = nil + return nil, nil + } + r := pdb.it.RawValues() + return r[0], r[1] } diff --git a/db/postgres/dump_test.go b/db/postgres/dump_test.go @@ -0,0 +1,91 @@ +package postgres + +import ( + "bytes" + "context" + "encoding/base64" + "strings" + "testing" + + pgxmock "github.com/pashagolub/pgxmock/v4" + "github.com/jackc/pgx/v5/pgtype" + "github.com/jackc/pgx/v5/pgconn" + + "git.defalsify.org/vise.git/db" +) + +func TestDumpPg(t *testing.T) { + ses := "xyzzy" + + mock, err := pgxmock.NewPool() + if err != nil { + t.Fatal(err) + } + defer mock.Close() + + store := NewPgDb().WithConnection(mock).WithSchema("vvise") + store.SetPrefix(db.DATATYPE_USERDATA) + store.SetSession(ses) + ctx := context.Background() + +// store.SetPrefix(db.DATATYPE_USERDATA) +// err = store.Put(ctx, []byte("bar"), []byte("inky")) +// if err != nil { +// t.Fatal(err) +// } +// err = store.Put(ctx, []byte("foobar"), []byte("pinky")) +// if err != nil { +// t.Fatal(err) +// } +// err = store.Put(ctx, []byte("foobarbaz"), []byte("blinky")) +// if err != nil { +// t.Fatal(err) +// } +// err = store.Put(ctx, []byte("xyzzy"), []byte("clyde")) +// if err != nil { +// t.Fatal(err) +// } + + typMap := pgtype.NewMap() + k := []byte("foo") + mockVfd := pgconn.FieldDescription{ + Name: "value", + DataTypeOID: pgtype.ByteaOID, + Format: typMap.FormatCodeForOID(pgtype.ByteaOID), + } + mockKfd := pgconn.FieldDescription{ + Name: "key", + DataTypeOID: pgtype.ByteaOID, + Format: typMap.FormatCodeForOID(pgtype.ByteaOID), + } + rows := pgxmock.NewRowsWithColumnDefinition(mockKfd, mockVfd) + //rows = rows.AddRow([]byte("bar"), []byte("inky")) + rows = rows.AddRow([]byte("foobar"), []byte("pinky")) + rows = rows.AddRow([]byte("foobarbaz"), []byte("blinky")) + //rows = rows.AddRow([]byte("xyzzy"), []byte("clyde")) + + mock.ExpectBegin() + mock.ExpectQuery("SELECT key, value FROM vvise.kv_vise").WithArgs(k, k[0]).WillReturnRows(rows) + mock.ExpectCommit() + + o, err := store.Dump(ctx, []byte("foo")) + if err != nil { + t.Fatal(err) + } + k, _ = o.Next(ctx) + br, err := base64.StdEncoding.DecodeString(strings.Trim(string(k), "\"")) + if !bytes.Equal(br, []byte("foobar")) { + t.Fatalf("expected key 'foobar', got %s", br) + } + + k, _ = o.Next(ctx) + br, err = base64.StdEncoding.DecodeString(strings.Trim(string(k), "\"")) + if !bytes.Equal(br, []byte("foobarbaz")) { + t.Fatalf("expected key 'foobarbaz', got %s", br) + } + + k, _ = o.Next(ctx) + if k != nil { + t.Fatalf("expected nil") + } +} diff --git a/db/postgres/pg.go b/db/postgres/pg.go @@ -26,6 +26,8 @@ type pgDb struct { schema string prefix uint8 prepd bool + it pgx.Rows + itBase []byte } // NewpgDb creates a new Postgres backed Db implementation. diff --git a/db/postgres/pg_test.go b/db/postgres/pg_test.go @@ -55,7 +55,7 @@ func TestPutGetPg(t *testing.T) { typMap := pgtype.NewMap() k := []byte("foo") - ks := append([]byte{db.DATATYPE_USERDATA}, []byte("xyzzy.foo")...) + ks := append([]byte{db.DATATYPE_USERDATA}, []byte("foo")...) v := []byte("bar") resInsert := pgxmock.NewResult("UPDATE", 1) mock.ExpectBegin()