From e90144cf0a84c2a309981ed1c8d160fc24dfb2d2 Mon Sep 17 00:00:00 2001 From: Wondertan Date: Wed, 30 Jul 2025 22:00:45 +0200 Subject: [PATCH 1/3] feat(keytransform): support transction feature --- keytransform/keytransform.go | 60 ++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/keytransform/keytransform.go b/keytransform/keytransform.go index c1c74149..2f7413b0 100644 --- a/keytransform/keytransform.go +++ b/keytransform/keytransform.go @@ -2,6 +2,7 @@ package keytransform import ( "context" + "fmt" ds "github.com/ipfs/go-datastore" dsq "github.com/ipfs/go-datastore/query" @@ -31,6 +32,7 @@ type Datastore struct { var _ ds.Datastore = (*Datastore)(nil) var _ ds.Batching = (*Datastore)(nil) +var _ ds.TxnDatastore = (*Datastore)(nil) var _ ds.Shim = (*Datastore)(nil) var _ ds.PersistentDatastore = (*Datastore)(nil) var _ ds.CheckedDatastore = (*Datastore)(nil) @@ -224,6 +226,23 @@ func (d *Datastore) Batch(ctx context.Context) (ds.Batch, error) { }, nil } +func (d *Datastore) NewTransaction(ctx context.Context, readOnly bool) (ds.Txn, error) { + tds, ok := d.child.(ds.TxnDatastore) + if !ok { + return nil, fmt.Errorf("txn not supported") + } + + childTxn, err := tds.NewTransaction(ctx, readOnly) + if err != nil { + return nil, err + } + + return &transformTxn{ + dst: childTxn, + f: d.ConvertKey, + }, nil +} + type transformBatch struct { dst ds.Batch @@ -244,6 +263,47 @@ func (t *transformBatch) Commit(ctx context.Context) error { return t.dst.Commit(ctx) } +type transformTxn struct { + ds *Datastore + dst ds.Txn + + f KeyMapping +} + +var _ ds.Txn = (*transformTxn)(nil) + +func (t *transformTxn) Put(ctx context.Context, key ds.Key, val []byte) error { + return t.dst.Put(ctx, t.f(key), val) +} + +func (t *transformTxn) Delete(ctx context.Context, key ds.Key) error { + return t.dst.Delete(ctx, t.f(key)) +} + +func (t *transformTxn) Commit(ctx context.Context) error { + return t.dst.Commit(ctx) +} + +func (t *transformTxn) Get(ctx context.Context, key ds.Key) (value []byte, err error) { + return t.dst.Get(ctx, t.f(key)) +} + +func (t *transformTxn) Has(ctx context.Context, key ds.Key) (exists bool, err error) { + return t.dst.Has(ctx, t.f(key)) +} + +func (t *transformTxn) GetSize(ctx context.Context, key ds.Key) (size int, err error) { + return t.dst.GetSize(ctx, t.f(key)) +} + +func (t *transformTxn) Query(ctx context.Context, q dsq.Query) (dsq.Results, error) { + return t.ds.Query(ctx, q) +} + +func (t *transformTxn) Discard(ctx context.Context) { + t.dst.Discard(ctx) +} + func (d *Datastore) Check(ctx context.Context) error { if c, ok := d.child.(ds.CheckedDatastore); ok { return c.Check(ctx) From de4fd817859c5860766a64e7c17f853494bf683d Mon Sep 17 00:00:00 2001 From: Wondertan Date: Wed, 30 Jul 2025 23:38:00 +0200 Subject: [PATCH 2/3] nit --- keytransform/keytransform.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keytransform/keytransform.go b/keytransform/keytransform.go index 2f7413b0..1ce1418e 100644 --- a/keytransform/keytransform.go +++ b/keytransform/keytransform.go @@ -2,7 +2,7 @@ package keytransform import ( "context" - "fmt" + "errors" ds "github.com/ipfs/go-datastore" dsq "github.com/ipfs/go-datastore/query" @@ -229,7 +229,7 @@ func (d *Datastore) Batch(ctx context.Context) (ds.Batch, error) { func (d *Datastore) NewTransaction(ctx context.Context, readOnly bool) (ds.Txn, error) { tds, ok := d.child.(ds.TxnDatastore) if !ok { - return nil, fmt.Errorf("txn not supported") + return nil, errors.New("keytransform: transaction feature not supported") } childTxn, err := tds.NewTransaction(ctx, readOnly) From 4d3eeae52ad27434e487122c9e65742bbb3e653a Mon Sep 17 00:00:00 2001 From: Wondertan Date: Fri, 1 Aug 2025 03:26:54 +0200 Subject: [PATCH 3/3] avoid conversion if already converted --- keytransform/transforms.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/keytransform/transforms.go b/keytransform/transforms.go index cc39897e..143a622e 100644 --- a/keytransform/transforms.go +++ b/keytransform/transforms.go @@ -29,6 +29,10 @@ type PrefixTransform struct { // ConvertKey adds the prefix. func (p PrefixTransform) ConvertKey(k ds.Key) ds.Key { + if p.Prefix.IsAncestorOf(k) { + return k + } + return p.Prefix.Child(k) }