diff --git a/filter/filters.go b/filter/filters.go index 4165dfb..71726fc 100644 --- a/filter/filters.go +++ b/filter/filters.go @@ -35,7 +35,7 @@ func (Any) ValuesRange() *Range { } // EQ is a shorthand for Equal. -func EQ(v values.Value) SortableFilter { +func EQ(v values.Value) Equal { return Equal{Value: v} } diff --git a/kv/bbolt/bolt.go b/kv/bbolt/bolt.go index 4487341..815f472 100644 --- a/kv/bbolt/bolt.go +++ b/kv/bbolt/bolt.go @@ -17,6 +17,7 @@ package bbolt import ( "bytes" "context" + "errors" "time" bolt "go.etcd.io/bbolt" @@ -165,7 +166,7 @@ func (tx *Tx) Put(k kv.Key, v kv.Value) error { return nil // bucket creation, no need to put value } err = b.Put(k[0], v) - if err == bolt.ErrTxNotWritable { + if errors.Is(err, bolt.ErrTxNotWritable) { err = kv.ErrReadOnly } return err @@ -177,8 +178,8 @@ func (tx *Tx) Del(k kv.Key) error { return nil } err := b.Delete(k[0]) - if err == bolt.ErrTxNotWritable { - err = kv.ErrReadOnly + if errors.Is(err, bolt.ErrTxNotWritable) { + return kv.ErrReadOnly } return err } diff --git a/kv/bbolt/bolt_test.go b/kv/bbolt/bolt_test.go index ecc2f7b..a4ec8a2 100644 --- a/kv/bbolt/bolt_test.go +++ b/kv/bbolt/bolt_test.go @@ -1,16 +1,17 @@ -package bbolt +package bbolt_test import ( "path/filepath" "testing" "github.com/hidal-go/hidalgo/kv" + "github.com/hidal-go/hidalgo/kv/bbolt" "github.com/hidal-go/hidalgo/kv/kvtest" ) func TestBBolt(t *testing.T) { kvtest.RunTestLocal(t, func(path string) (kv.KV, error) { path = filepath.Join(path, "bbolt.db") - return OpenPath(path) + return bbolt.OpenPath(path) }, nil) } diff --git a/kv/bolt/bolt.go b/kv/bolt/bolt.go index 1d29462..e544b00 100644 --- a/kv/bolt/bolt.go +++ b/kv/bolt/bolt.go @@ -17,6 +17,7 @@ package bolt import ( "bytes" "context" + "errors" "time" "github.com/boltdb/bolt" @@ -165,7 +166,7 @@ func (tx *Tx) Put(k kv.Key, v kv.Value) error { return nil // bucket creation, no need to put value } err = b.Put(k[0], v) - if err == bolt.ErrTxNotWritable { + if errors.Is(err, bolt.ErrTxNotWritable) { err = kv.ErrReadOnly } return err @@ -177,7 +178,7 @@ func (tx *Tx) Del(k kv.Key) error { return nil } err := b.Delete(k[0]) - if err == bolt.ErrTxNotWritable { + if errors.Is(err, bolt.ErrTxNotWritable) { err = kv.ErrReadOnly } return err diff --git a/kv/bolt/bolt_test.go b/kv/bolt/bolt_test.go index 1178479..1b33919 100644 --- a/kv/bolt/bolt_test.go +++ b/kv/bolt/bolt_test.go @@ -1,16 +1,17 @@ -package bolt +package bolt_test import ( "path/filepath" "testing" "github.com/hidal-go/hidalgo/kv" + "github.com/hidal-go/hidalgo/kv/bolt" "github.com/hidal-go/hidalgo/kv/kvtest" ) func TestBolt(t *testing.T) { kvtest.RunTestLocal(t, func(path string) (kv.KV, error) { path = filepath.Join(path, "bolt.db") - return OpenPath(path) + return bolt.OpenPath(path) }, nil) } diff --git a/kv/flat/badger/badger.go b/kv/flat/badger/badger.go index 7ca9b25..18d6f2d 100644 --- a/kv/flat/badger/badger.go +++ b/kv/flat/badger/badger.go @@ -2,6 +2,7 @@ package badger import ( "context" + "errors" "github.com/dgraph-io/badger/v2" @@ -85,7 +86,7 @@ type Tx struct { func (tx *Tx) Commit(ctx context.Context) error { err := tx.tx.Commit() - if err == badger.ErrConflict { + if errors.Is(err, badger.ErrConflict) { err = flat.ErrConflict } return err @@ -101,7 +102,7 @@ func (tx *Tx) Get(ctx context.Context, key flat.Key) (flat.Value, error) { return nil, flat.ErrNotFound } item, err := tx.tx.Get(key) - if err == badger.ErrKeyNotFound { + if errors.Is(err, badger.ErrKeyNotFound) { return nil, flat.ErrNotFound } else if err != nil { return nil, err @@ -115,7 +116,7 @@ func (tx *Tx) GetBatch(ctx context.Context, keys []flat.Key) ([]flat.Value, erro func (tx *Tx) Put(k flat.Key, v flat.Value) error { err := tx.tx.Set(k, v) - if err == badger.ErrConflict { + if errors.Is(err, badger.ErrConflict) { err = flat.ErrConflict } return err @@ -123,7 +124,7 @@ func (tx *Tx) Put(k flat.Key, v flat.Value) error { func (tx *Tx) Del(k flat.Key) error { err := tx.tx.Delete(k) - if err == badger.ErrConflict { + if errors.Is(err, badger.ErrConflict) { err = flat.ErrConflict } return err @@ -142,11 +143,11 @@ var ( ) type Iterator struct { + err error it *badger.Iterator pref flat.Key first bool valid bool - err error } func (it *Iterator) Reset() { diff --git a/kv/flat/badger/badger_test.go b/kv/flat/badger/badger_test.go index e32b1f9..41124f2 100644 --- a/kv/flat/badger/badger_test.go +++ b/kv/flat/badger/badger_test.go @@ -1,12 +1,13 @@ -package badger +package badger_test import ( "testing" "github.com/hidal-go/hidalgo/kv/flat" + "github.com/hidal-go/hidalgo/kv/flat/badger" "github.com/hidal-go/hidalgo/kv/kvtest" ) func TestBadger(t *testing.T) { - kvtest.RunTestLocal(t, flat.UpgradeOpenPath(OpenPath), nil) + kvtest.RunTestLocal(t, flat.UpgradeOpenPath(badger.OpenPath), nil) } diff --git a/kv/flat/btree/btree.go b/kv/flat/btree/btree.go index 311bb0e..3cc5e76 100644 --- a/kv/flat/btree/btree.go +++ b/kv/flat/btree/btree.go @@ -17,6 +17,7 @@ package btree import ( "bytes" "context" + "errors" "io" "github.com/hidal-go/hidalgo/base" @@ -152,7 +153,7 @@ func (it *Iterator) WithPrefix(pref flat.Key) flat.Iterator { func (it *Iterator) next() bool { k, v, err := it.e.Next() - if err == io.EOF { + if errors.Is(err, io.EOF) { return false } else if !bytes.HasPrefix(k, it.pref) { return false diff --git a/kv/flat/btree/btree_test.go b/kv/flat/btree/btree_test.go index 6de5d55..da0a39a 100644 --- a/kv/flat/btree/btree_test.go +++ b/kv/flat/btree/btree_test.go @@ -1,15 +1,16 @@ -package btree +package btree_test import ( "testing" "github.com/hidal-go/hidalgo/kv" "github.com/hidal-go/hidalgo/kv/flat" + "github.com/hidal-go/hidalgo/kv/flat/btree" "github.com/hidal-go/hidalgo/kv/kvtest" ) func TestBtree(t *testing.T) { - kvtest.RunTest(t, func(t testing.TB) kv.KV { - return flat.Upgrade(New()) + kvtest.RunTest(t, func(tb testing.TB) kv.KV { + return flat.Upgrade(btree.New()) }, nil) } diff --git a/kv/flat/btree/keys.go b/kv/flat/btree/keys.go index d5c4f75..6e65292 100644 --- a/kv/flat/btree/keys.go +++ b/kv/flat/btree/keys.go @@ -79,22 +79,22 @@ func init() { var ( btDPool = sync.Pool{New: func() interface{} { return &d{} }} - btEPool = btEpool{sync.Pool{New: func() interface{} { return &Enumerator{} }}} - btTPool = btTpool{sync.Pool{New: func() interface{} { return &Tree{} }}} + btEPool = enumPool{sync.Pool{New: func() interface{} { return &Enumerator{} }}} + btTPool = treePool{sync.Pool{New: func() interface{} { return &Tree{} }}} btXPool = sync.Pool{New: func() interface{} { return &x{} }} ) -type btTpool struct{ sync.Pool } +type treePool struct{ sync.Pool } -func (p *btTpool) get(cmp Cmp) *Tree { +func (p *treePool) get(cmp Cmp) *Tree { x := p.Get().(*Tree) x.cmp = cmp return x } -type btEpool struct{ sync.Pool } +type enumPool struct{ sync.Pool } -func (p *btEpool) get(err error, hit bool, i int, k []byte, q *d, t *Tree, ver int64) *Enumerator { +func (p *enumPool) get(err error, hit bool, i int, k []byte, q *d, t *Tree, ver int64) *Enumerator { x := p.Get().(*Enumerator) x.err, x.hit, x.i, x.k, x.q, x.t, x.ver = err, hit, i, k, q, t, ver return x @@ -110,10 +110,10 @@ type ( Cmp func(a, b []byte) int d struct { // data page - c int - d [2*kd + 1]de n *d p *d + d [2*kd + 1]de + c int } de struct { // d element @@ -131,21 +131,21 @@ type ( // other words, io.EOF from an Enumaretor is "sticky" (idempotent). Enumerator struct { err error - hit bool - i int - k []byte q *d t *Tree + k []byte + i int ver int64 + hit bool } // Tree is a B+tree. Tree struct { - c int + r interface{} cmp Cmp first *d last *d - r interface{} + c int ver int64 } @@ -155,8 +155,8 @@ type ( } x struct { // index page - c int x [2*kx + 2]xe + c int } ) @@ -332,7 +332,7 @@ func (t *Tree) catX(p, q, r *x, pi int) { // Delete removes the k's KV pair, if it exists, in which case Delete returns // true. -func (t *Tree) Delete(k []byte) (ok bool) { +func (t *Tree) Delete(k []byte) bool { pi := -1 var p *x q := t.r @@ -341,8 +341,7 @@ func (t *Tree) Delete(k []byte) (ok bool) { } for { - var i int - i, ok = t.find(q, k) + i, ok := t.find(q, k) if ok { switch x := q.(type) { case *x: @@ -352,7 +351,6 @@ func (t *Tree) Delete(k []byte) (ok bool) { pi = i + 1 p = x q = x.x[pi].ch - ok = false continue case *d: t.extract(x, i) @@ -864,37 +862,37 @@ func (e *Enumerator) Close() { // next item in the key collation order. If there is no item to return, err == // io.EOF is returned. func (e *Enumerator) Next() (k, v []byte, err error) { - if err = e.err; err != nil { - return + if e.err != nil { + return nil, nil, e.err } if e.ver != e.t.ver { f, hit := e.t.Seek(e.k) if !e.hit && hit { if err = f.next(); err != nil { - return + return nil, nil, err } } *e = *f f.Close() } + if e.q == nil { - e.err, err = io.EOF, io.EOF - return + e.err = io.EOF + return nil, nil, io.EOF } if e.i >= e.q.c { if err = e.next(); err != nil { - return + return nil, nil, err } } i := e.q.d[e.i] - k, v = i.k, i.v - e.k, e.hit = k, false - e.next() - return + e.k, e.hit = i.k, false + _ = e.next() + return i.k, i.v, err } func (e *Enumerator) next() error { @@ -911,6 +909,7 @@ func (e *Enumerator) next() error { e.err = io.EOF } } + return e.err } @@ -918,37 +917,37 @@ func (e *Enumerator) next() error { // previous item in the key collation order. If there is no item to return, err // == io.EOF is returned. func (e *Enumerator) Prev() (k, v []byte, err error) { - if err = e.err; err != nil { - return + if e.err != nil { + return nil, nil, e.err } if e.ver != e.t.ver { f, hit := e.t.Seek(e.k) if !e.hit && hit { if err = f.prev(); err != nil { - return + return nil, nil, err } } *e = *f f.Close() } + if e.q == nil { - e.err, err = io.EOF, io.EOF - return + e.err = io.EOF + return nil, nil, io.EOF } if e.i >= e.q.c { if err = e.next(); err != nil { - return + return nil, nil, err } } i := e.q.d[e.i] - k, v = i.k, i.v - e.k, e.hit = k, false - e.prev() - return + e.k, e.hit = i.k, false + _ = e.prev() + return i.k, i.v, err } func (e *Enumerator) prev() error { @@ -968,5 +967,6 @@ func (e *Enumerator) prev() error { e.i = e.q.c - 1 } + return e.err } diff --git a/kv/flat/helpers.go b/kv/flat/helpers.go index 0fdce20..7a01249 100644 --- a/kv/flat/helpers.go +++ b/kv/flat/helpers.go @@ -1,6 +1,9 @@ package flat -import "context" +import ( + "context" + "errors" +) // Update is a helper to open a read-write transaction and update the database. // The update function may be called multiple times in case of conflicts with other writes. @@ -18,7 +21,7 @@ func Update(ctx context.Context, kv KV, update func(tx Tx) error) error { } return tx.Commit(ctx) }() - if err == ErrConflict { + if errors.Is(err, ErrConflict) { continue } else if err != nil { return err @@ -28,7 +31,7 @@ func Update(ctx context.Context, kv KV, update func(tx Tx) error) error { } // View is a helper to open a read-only transaction to read the database. -func View(ctx context.Context, kv KV, view func(tx Tx) error) error { +func View(_ context.Context, kv KV, view func(tx Tx) error) error { tx, err := kv.Tx(false) if err != nil { return err diff --git a/kv/flat/kv.go b/kv/flat/kv.go index b8500bb..19cf38e 100644 --- a/kv/flat/kv.go +++ b/kv/flat/kv.go @@ -3,6 +3,7 @@ package flat import ( "context" + "errors" "fmt" "github.com/hidal-go/hidalgo/base" @@ -82,7 +83,7 @@ func GetBatch(ctx context.Context, tx Getter, keys []Key) ([]Value, error) { var err error for i, k := range keys { vals[i], err = tx.Get(ctx, k) - if err == ErrNotFound { + if errors.Is(err, ErrNotFound) { vals[i] = nil } else if err != nil { return nil, err diff --git a/kv/flat/leveldb/leveldb.go b/kv/flat/leveldb/leveldb.go index 97a85d2..7fd4852 100644 --- a/kv/flat/leveldb/leveldb.go +++ b/kv/flat/leveldb/leveldb.go @@ -16,6 +16,7 @@ package leveldb import ( "context" + "errors" "github.com/syndtr/goleveldb/leveldb" "github.com/syndtr/goleveldb/leveldb/iterator" @@ -140,7 +141,7 @@ func (tx *Tx) Get(ctx context.Context, key flat.Key) (flat.Value, error) { } else { val, err = tx.sn.Get(key, tx.db.ro) } - if err == leveldb.ErrNotFound { + if errors.Is(err, leveldb.ErrNotFound) { return nil, flat.ErrNotFound } else if err != nil { return nil, err diff --git a/kv/flat/leveldb/leveldb_test.go b/kv/flat/leveldb/leveldb_test.go index a48976f..47af8e9 100644 --- a/kv/flat/leveldb/leveldb_test.go +++ b/kv/flat/leveldb/leveldb_test.go @@ -1,12 +1,13 @@ -package leveldb +package leveldb_test import ( "testing" "github.com/hidal-go/hidalgo/kv/flat" + "github.com/hidal-go/hidalgo/kv/flat/leveldb" "github.com/hidal-go/hidalgo/kv/kvtest" ) func TestLeveldb(t *testing.T) { - kvtest.RunTestLocal(t, flat.UpgradeOpenPath(OpenPath), nil) + kvtest.RunTestLocal(t, flat.UpgradeOpenPath(leveldb.OpenPath), nil) } diff --git a/kv/flat/pebble/pebble.go b/kv/flat/pebble/pebble.go index 4e08e0a..44c52bf 100644 --- a/kv/flat/pebble/pebble.go +++ b/kv/flat/pebble/pebble.go @@ -3,6 +3,7 @@ package pebble import ( "bytes" "context" + "errors" "github.com/cockroachdb/pebble" @@ -93,7 +94,7 @@ func (tx *Tx) Get(ctx context.Context, key flat.Key) (flat.Value, error) { return nil, flat.ErrNotFound } val, closer, err := tx.tx.Get(key) - if err == pebble.ErrNotFound { + if errors.Is(err, pebble.ErrNotFound) { return nil, flat.ErrNotFound } else if err != nil { return nil, err @@ -136,10 +137,10 @@ var ( ) type Iterator struct { + err error it *pebble.Iterator pref flat.Key first bool - err error } func (it *Iterator) Reset() { diff --git a/kv/flat/pebble/pebble_test.go b/kv/flat/pebble/pebble_test.go index bcfab69..d317729 100644 --- a/kv/flat/pebble/pebble_test.go +++ b/kv/flat/pebble/pebble_test.go @@ -1,14 +1,15 @@ -package pebble +package pebble_test import ( "testing" "github.com/hidal-go/hidalgo/kv/flat" + "github.com/hidal-go/hidalgo/kv/flat/pebble" "github.com/hidal-go/hidalgo/kv/kvtest" ) func TestPebble(t *testing.T) { - kvtest.RunTestLocal(t, flat.UpgradeOpenPath(OpenPath), &kvtest.Options{ + kvtest.RunTestLocal(t, flat.UpgradeOpenPath(pebble.OpenPath), &kvtest.Options{ NoTx: true, }) } diff --git a/kv/flat/registry.go b/kv/flat/registry.go index da04d93..ef84c01 100644 --- a/kv/flat/registry.go +++ b/kv/flat/registry.go @@ -12,8 +12,8 @@ type OpenPathFunc func(path string) (KV, error) // Registration is an information about the database driver. type Registration struct { - base.Registration OpenPath OpenPathFunc + base.Registration } var registry = make(map[string]Registration) diff --git a/kv/flat/upgrade_test.go b/kv/flat/upgrade_test.go index 4d661ad..e847eee 100644 --- a/kv/flat/upgrade_test.go +++ b/kv/flat/upgrade_test.go @@ -1,4 +1,4 @@ -package flat +package flat_test import ( "testing" @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/hidal-go/hidalgo/kv" + "github.com/hidal-go/hidalgo/kv/flat" ) func TestSepEscape(t *testing.T) { @@ -13,6 +14,6 @@ func TestSepEscape(t *testing.T) { []byte(`\/aa/b\b/c/d/\`), []byte(`/aa/b\b/c/d/`), } - k2 := KeyUnescape(KeyEscape(k)) + k2 := flat.KeyUnescape(flat.KeyEscape(k)) require.Equal(t, k, k2) } diff --git a/kv/helpers.go b/kv/helpers.go index 071d0d0..5d99edd 100644 --- a/kv/helpers.go +++ b/kv/helpers.go @@ -1,6 +1,9 @@ package kv -import "context" +import ( + "context" + "errors" +) // Update is a helper to open a read-write transaction and update the database. // The update function may be called multiple times in case of conflicts with other writes. @@ -18,7 +21,7 @@ func Update(ctx context.Context, kv KV, update func(tx Tx) error) error { } return tx.Commit(ctx) }() - if err == ErrConflict { + if errors.Is(err, ErrConflict) { continue } else if err != nil { return err diff --git a/kv/kv.go b/kv/kv.go index e68d4e8..0bddebe 100644 --- a/kv/kv.go +++ b/kv/kv.go @@ -170,7 +170,7 @@ func GetBatch(ctx context.Context, tx Getter, keys []Key) ([]Value, error) { var err error for i, k := range keys { vals[i], err = tx.Get(ctx, k) - if err == ErrNotFound { + if errors.Is(err, ErrNotFound) { vals[i] = nil } else if err != nil { return nil, err diff --git a/kv/kv_test.go b/kv/kv_test.go index 1ef4c67..d283965 100644 --- a/kv/kv_test.go +++ b/kv/kv_test.go @@ -1,43 +1,44 @@ -package kv +package kv_test import ( "testing" + "github.com/hidal-go/hidalgo/kv" "github.com/stretchr/testify/require" ) var keyCompareCases = []struct { - k1, k2 Key + k1, k2 kv.Key exp int }{ { - k1: SKey("a"), - k2: SKey("a"), + k1: kv.SKey("a"), + k2: kv.SKey("a"), exp: 0, }, { - k1: SKey("a"), - k2: SKey("b"), + k1: kv.SKey("a"), + k2: kv.SKey("b"), exp: -1, }, { - k1: SKey("a"), - k2: SKey("a", "b"), + k1: kv.SKey("a"), + k2: kv.SKey("a", "b"), exp: -1, }, { - k1: SKey("a", "b"), - k2: SKey("a", "a"), + k1: kv.SKey("a", "b"), + k2: kv.SKey("a", "a"), exp: +1, }, { k1: nil, - k2: SKey("a", "b"), + k2: kv.SKey("a", "b"), exp: -1, }, { - k1: SKey("ab"), - k2: SKey("a", "b"), + k1: kv.SKey("ab"), + k2: kv.SKey("a", "b"), exp: +1, }, } @@ -55,52 +56,52 @@ func TestKeyCompare(t *testing.T) { } var keyHasPrefixCases = []struct { - key, pref Key + key, pref kv.Key exp bool }{ { - key: SKey("a"), - pref: SKey("a"), + key: kv.SKey("a"), + pref: kv.SKey("a"), exp: true, }, { - key: SKey("a"), - pref: SKey("b"), + key: kv.SKey("a"), + pref: kv.SKey("b"), exp: false, }, { - key: SKey("a"), - pref: SKey("a", "b"), + key: kv.SKey("a"), + pref: kv.SKey("a", "b"), exp: false, }, { - key: SKey("a", "b"), - pref: SKey("a"), + key: kv.SKey("a", "b"), + pref: kv.SKey("a"), exp: true, }, { - key: SKey("a", "b"), - pref: SKey("a", "a"), + key: kv.SKey("a", "b"), + pref: kv.SKey("a", "a"), exp: false, }, { key: nil, - pref: SKey("a", "b"), + pref: kv.SKey("a", "b"), exp: false, }, { - key: SKey("a", "b"), + key: kv.SKey("a", "b"), pref: nil, exp: true, }, { - key: SKey("ab"), - pref: SKey("a", "b"), + key: kv.SKey("ab"), + pref: kv.SKey("a", "b"), exp: false, }, { - key: SKey("a", "b"), - pref: SKey("ab"), + key: kv.SKey("a", "b"), + pref: kv.SKey("ab"), exp: false, }, } @@ -115,10 +116,10 @@ func TestKeyHasPrefix(t *testing.T) { } func TestKeyAppend(t *testing.T) { - k := SKey("a", "b", "c") - k = k.Append(SKey("d")) - require.Equal(t, SKey("a", "b", "c", "d"), k) - k = SKey("a", "b", "c") + k := kv.SKey("a", "b", "c") + k = k.Append(kv.SKey("d")) + require.Equal(t, kv.SKey("a", "b", "c", "d"), k) + k = kv.SKey("a", "b", "c") k = k.AppendBytes([]byte("d")) - require.Equal(t, SKey("a", "b", "c", "d"), k) + require.Equal(t, kv.SKey("a", "b", "c", "d"), k) } diff --git a/kv/kvdebug/kvdebug.go b/kv/kvdebug/kvdebug.go index 3bbc870..21359e8 100644 --- a/kv/kvdebug/kvdebug.go +++ b/kv/kvdebug/kvdebug.go @@ -2,6 +2,7 @@ package kvdebug import ( "context" + "errors" "fmt" "log" "sync/atomic" @@ -40,6 +41,8 @@ type Stats struct { } type KV struct { + KV kv.KV + stats Stats running struct { txRO int64 @@ -47,8 +50,6 @@ type KV struct { iter int64 } log bool - - KV kv.KV } func (d *KV) logging() bool { @@ -148,7 +149,7 @@ func (tx *kvTX) Get(ctx context.Context, k kv.Key) (kv.Value, error) { v, err := tx.tx.Get(ctx, k) d := tx.kv atomic.AddInt64(&d.stats.Get.N, 1) - if err == kv.ErrNotFound { + if errors.Is(err, kv.ErrNotFound) { atomic.AddInt64(&d.stats.Get.Miss, 1) } else if err != nil { atomic.AddInt64(&d.stats.Errs, 1) diff --git a/kv/kvtest/helpers.go b/kv/kvtest/helpers.go index af38ef3..15bfaae 100644 --- a/kv/kvtest/helpers.go +++ b/kv/kvtest/helpers.go @@ -9,64 +9,64 @@ import ( "github.com/hidal-go/hidalgo/kv" ) -func NewTest(t testing.TB, db kv.KV) *Test { - return &Test{t: t, db: db} +func NewTest(tb testing.TB, db kv.KV) *Test { + return &Test{tb: tb, db: db} } type Test struct { - t testing.TB + tb testing.TB db kv.KV } func (t Test) Get(key kv.Key) (kv.Value, error) { tx, err := t.db.Tx(false) - require.NoError(t.t, err) + require.NoError(t.tb, err) defer tx.Close() return tx.Get(context.TODO(), key) } func (t Test) NotExists(k kv.Key) { v, err := t.Get(k) - require.Equal(t.t, kv.ErrNotFound, err) - require.Equal(t.t, kv.Value(nil), v) + require.Equal(t.tb, kv.ErrNotFound, err) + require.Equal(t.tb, kv.Value(nil), v) } func (t Test) Expect(k kv.Key, exp kv.Value) { v, err := t.Get(k) - require.NoError(t.t, err) - require.Equal(t.t, exp, v) + require.NoError(t.tb, err) + require.Equal(t.tb, exp, v) } func (t Test) Put(key kv.Key, val kv.Value) { tx, err := t.db.Tx(true) - require.NoError(t.t, err) + require.NoError(t.tb, err) defer tx.Close() err = tx.Put(key, val) - require.NoError(t.t, err) + require.NoError(t.tb, err) ctx := context.TODO() got, err := tx.Get(ctx, key) - require.NoError(t.t, err) - require.Equal(t.t, val, got) + require.NoError(t.tb, err) + require.Equal(t.tb, val, got) err = tx.Commit(ctx) - require.NoError(t.t, err) + require.NoError(t.tb, err) } func (t Test) Del(key kv.Key) { tx, err := t.db.Tx(true) - require.NoError(t.t, err) + require.NoError(t.tb, err) defer tx.Close() err = tx.Del(key) - require.NoError(t.t, err) + require.NoError(t.tb, err) ctx := context.TODO() got, err := tx.Get(ctx, key) - require.Equal(t.t, kv.ErrNotFound, err) - require.Equal(t.t, kv.Value(nil), got) + require.Equal(t.tb, kv.ErrNotFound, err) + require.Equal(t.tb, kv.Value(nil), got) err = tx.Commit(ctx) - require.NoError(t.t, err) + require.NoError(t.tb, err) } func (t Test) ExpectIt(it kv.Iterator, exp []kv.Pair) { @@ -81,30 +81,30 @@ func (t Test) ExpectIt(it kv.Iterator, exp []kv.Pair) { Val: it.Val().Clone(), }) } - require.NoError(t.t, it.Err()) - require.Equal(t.t, exp, got) + require.NoError(t.tb, it.Err()) + require.Equal(t.tb, exp, got) } func (t Test) Scan(exp []kv.Pair, opts ...kv.IteratorOption) { tx, err := t.db.Tx(false) - require.NoError(t.t, err) + require.NoError(t.tb, err) defer tx.Close() it := tx.Scan(opts...) defer it.Close() - require.NoError(t.t, it.Err()) + require.NoError(t.tb, it.Err()) t.ExpectIt(it, exp) } func (t Test) ScanReset(exp []kv.Pair, opts ...kv.IteratorOption) { tx, err := t.db.Tx(false) - require.NoError(t.t, err) + require.NoError(t.tb, err) defer tx.Close() it := tx.Scan(opts...) defer it.Close() - require.NoError(t.t, it.Err()) + require.NoError(t.tb, it.Err()) t.ExpectIt(it, exp) it.Reset() diff --git a/kv/kvtest/kvtest.go b/kv/kvtest/kvtest.go index f57bbc8..55d9606 100644 --- a/kv/kvtest/kvtest.go +++ b/kv/kvtest/kvtest.go @@ -16,7 +16,7 @@ import ( // Func is a constructor for database implementations. // It returns an empty database and a function to destroy it. -type Func func(t testing.TB) kv.KV +type Func func(tb testing.TB) kv.KV type Options struct { NoLocks bool // not safe for concurrent writes @@ -47,18 +47,18 @@ func RunTestLocal(t *testing.T, open kv.OpenPathFunc, opts *Options) { if opts == nil { opts = &Options{} } - RunTest(t, func(t testing.TB) kv.KV { + RunTest(t, func(tb testing.TB) kv.KV { dir, err := ioutil.TempDir("", "dal-kv-") - require.NoError(t, err) - t.Cleanup(func() { + require.NoError(tb, err) + tb.Cleanup(func() { _ = os.RemoveAll(dir) }) db, err := open(dir) if err != nil { - require.NoError(t, err) + require.NoError(tb, err) } - t.Cleanup(func() { + tb.Cleanup(func() { db.Close() db.Close() // test double close }) @@ -67,8 +67,8 @@ func RunTestLocal(t *testing.T, open kv.OpenPathFunc, opts *Options) { } var testList = []struct { + test func(tb testing.TB, db kv.KV) name string - test func(t testing.TB, db kv.KV) concurrent bool // requires concurrent safety txOnly bool // requires transactions }{ @@ -78,8 +78,8 @@ var testList = []struct { {name: "increment", test: increment, txOnly: true, concurrent: true}, } -func basic(t testing.TB, db kv.KV) { - td := NewTest(t, db) +func basic(tb testing.TB, db kv.KV) { + td := NewTest(tb, db) keys := []kv.Key{ {[]byte("a")}, @@ -95,12 +95,12 @@ func basic(t testing.TB, db kv.KV) { td.NotExists(k) } - var all []kv.Pair + all := make([]kv.Pair, len(keys)) for i, k := range keys { v := kv.Value(strconv.Itoa(i)) td.Put(k, v) td.Expect(k, v) - all = append(all, kv.Pair{Key: k, Val: v}) + all[i] = kv.Pair{Key: k, Val: v} } td.ScanReset(all) @@ -117,8 +117,8 @@ func basic(t testing.TB, db kv.KV) { } } -func readonly(t testing.TB, db kv.KV) { - td := NewTest(t, db) +func readonly(tb testing.TB, db kv.KV) { + td := NewTest(tb, db) key := kv.Key{[]byte("a")} val := []byte("v") @@ -127,26 +127,26 @@ func readonly(t testing.TB, db kv.KV) { nokey := kv.Key{[]byte("b")} tx, err := db.Tx(false) - require.NoError(t, err) + require.NoError(tb, err) defer tx.Close() // writing anything on read-only tx must fail err = tx.Put(key, val) - require.Equal(t, kv.ErrReadOnly, err) + require.Equal(tb, kv.ErrReadOnly, err) err = tx.Put(nokey, val) - require.Equal(t, kv.ErrReadOnly, err) + require.Equal(tb, kv.ErrReadOnly, err) // deleting records on read-only tx must fail err = tx.Del(key) - require.Equal(t, kv.ErrReadOnly, err) + require.Equal(tb, kv.ErrReadOnly, err) // deleting non-existed record on read-only tx must still fail err = tx.Del(nokey) - require.Equal(t, kv.ErrReadOnly, err) + require.Equal(tb, kv.ErrReadOnly, err) } -func seek(t testing.TB, db kv.KV) { - td := NewTest(t, db) +func seek(tb testing.TB, db kv.KV) { + td := NewTest(tb, db) keys := []kv.Key{ {[]byte("a")}, @@ -157,15 +157,15 @@ func seek(t testing.TB, db kv.KV) { {[]byte("c")}, } - var all []kv.Pair + all := make([]kv.Pair, len(keys)) for i, k := range keys { v := kv.Value(strconv.Itoa(i)) td.Put(k, v) - all = append(all, kv.Pair{Key: k, Val: v}) + all[i] = kv.Pair{Key: k, Val: v} } tx, err := db.Tx(false) - require.NoError(t, err) + require.NoError(tb, err) defer tx.Close() ctx := context.TODO() @@ -181,9 +181,9 @@ func seek(t testing.TB, db kv.KV) { // seek to each key, current value must match corresponding element, and iterating further must return everything else for i, p := range all { ok := kv.Seek(ctx, it, p.Key) - require.True(t, ok) - require.Equal(t, p.Key, it.Key()) - require.Equal(t, p.Val, it.Val()) + require.True(tb, ok) + require.Equal(tb, p.Key, it.Key()) + require.Equal(tb, p.Val, it.Val()) td.ExpectIt(it, all[i+1:]) } @@ -191,14 +191,14 @@ func seek(t testing.TB, db kv.KV) { for _, off := range []int{1, 2} { for i := range all[:len(all)-off] { ok := kv.Seek(ctx, it, all[i].Key) - require.True(t, ok) - require.Equal(t, all[i].Key, it.Key()) - require.Equal(t, all[i].Val, it.Val()) + require.True(tb, ok) + require.Equal(tb, all[i].Key, it.Key()) + require.Equal(tb, all[i].Val, it.Val()) ok = kv.Seek(ctx, it, all[i+off].Key) - require.True(t, ok) - require.Equal(t, all[i+off].Key, it.Key()) - require.Equal(t, all[i+off].Val, it.Val()) + require.True(tb, ok) + require.Equal(tb, all[i+off].Key, it.Key()) + require.Equal(tb, all[i+off].Val, it.Val()) td.ExpectIt(it, all[i+off+1:]) } @@ -211,14 +211,14 @@ func seek(t testing.TB, db kv.KV) { continue } ok := kv.Seek(ctx, it, all[i].Key) - require.True(t, ok) - require.Equal(t, all[i].Key, it.Key()) - require.Equal(t, all[i].Val, it.Val()) + require.True(tb, ok) + require.Equal(tb, all[i].Key, it.Key()) + require.Equal(tb, all[i].Val, it.Val()) ok = kv.Seek(ctx, it, all[i-off].Key) - require.True(t, ok) - require.Equal(t, all[i-off].Key, it.Key()) - require.Equal(t, all[i-off].Val, it.Val()) + require.True(tb, ok) + require.Equal(tb, all[i-off].Key, it.Key()) + require.Equal(tb, all[i-off].Val, it.Val()) td.ExpectIt(it, all[i-off+1:]) } @@ -228,8 +228,8 @@ func seek(t testing.TB, db kv.KV) { td.ExpectIt(it, all) } -func increment(t testing.TB, db kv.KV) { - td := NewTest(t, db) +func increment(tb testing.TB, db kv.KV) { + td := NewTest(tb, db) key := kv.Key{[]byte("a")} td.Put(key, []byte("0")) @@ -266,7 +266,7 @@ func increment(t testing.TB, db kv.KV) { wg.Wait() select { case err := <-errc: - require.NoError(t, err) + require.NoError(tb, err) default: } td.Expect(key, []byte("10")) diff --git a/kv/options/prefix_flat.go b/kv/options/prefix_flat.go index 71dd31b..2ff4f00 100644 --- a/kv/options/prefix_flat.go +++ b/kv/options/prefix_flat.go @@ -10,7 +10,7 @@ import ( // WithPrefixFlat returns IteratorOption that limits scanned key to a given binary prefix. // Store implementations can optimize this by implementing flat.PrefixIterator. -func WithPrefixFlat(pref flat.Key) IteratorOption { +func WithPrefixFlat(pref flat.Key) PrefixFlat { return PrefixFlat{Pref: pref} } @@ -73,14 +73,11 @@ func (it *prefixIteratorFlat) Next(ctx context.Context) bool { it.done = true return false } - } else { - if !it.base.Next(ctx) { - it.done = true - return false - } + } else if !it.base.Next(ctx) { + it.done = true + return false } - key := it.base.Key() - if bytes.HasPrefix(key, it.pref) { + if key := it.base.Key(); bytes.HasPrefix(key, it.pref) { return true } // keys are sorted, and we reached the end of the prefix diff --git a/kv/options/prefix_kv.go b/kv/options/prefix_kv.go index 4334690..ceddb94 100644 --- a/kv/options/prefix_kv.go +++ b/kv/options/prefix_kv.go @@ -9,7 +9,7 @@ import ( // WithPrefixKV returns IteratorOption that limits scanned key to a given binary prefix. // Store implementations can optimize this by implementing kv.PrefixIterator. -func WithPrefixKV(pref kv.Key) IteratorOption { +func WithPrefixKV(pref kv.Key) PrefixKV { return PrefixKV{Pref: pref} } @@ -72,11 +72,9 @@ func (it *prefixIteratorKV) Next(ctx context.Context) bool { it.done = true return false } - } else { - if !it.base.Next(ctx) { - it.done = true - return false - } + } else if !it.base.Next(ctx) { + it.done = true + return false } key := it.base.Key() if key.HasPrefix(it.pref) { diff --git a/kv/registry.go b/kv/registry.go index 1eb62ea..cd8c45e 100644 --- a/kv/registry.go +++ b/kv/registry.go @@ -11,8 +11,8 @@ type OpenPathFunc func(path string) (KV, error) // Registration is an information about the database driver. type Registration struct { - base.Registration OpenPath OpenPathFunc + base.Registration } var registry = make(map[string]Registration) diff --git a/legacy/nosql/couch/ouch.go b/legacy/nosql/couch/ouch.go index bda9add..9a56c1e 100644 --- a/legacy/nosql/couch/ouch.go +++ b/legacy/nosql/couch/ouch.go @@ -22,7 +22,7 @@ func Traits() nosql.Traits { } } -func DialDriver(ctx context.Context, driver, addr, dbName string) (*kivik.Client, string, error) { +func DialDriver(_ context.Context, driver, addr, dbName string) (*kivik.Client, string, error) { addrParsed, err := url.Parse(addr) if err != nil { return nil, "", err @@ -40,12 +40,12 @@ func DialDriver(ctx context.Context, driver, addr, dbName string) (*kivik.Client return cli, dbName, err } -func Dial(create bool, driver, addr, ns string, opt nosql.Options) (*DB, error) { +func Dial(create bool, driver, addr, ns string, _ nosql.Options) (*DB, error) { ctx := context.TODO() // TODO - replace with parameter value client, dbName, err := DialDriver(ctx, driver, addr, ns) if err != nil { - return nil, fmt.Errorf("cannot open driver: %v", err) + return nil, fmt.Errorf("cannot open driver: %w", err) } var db *kivik.DB @@ -63,8 +63,8 @@ func Dial(create bool, driver, addr, ns string, opt nosql.Options) (*DB, error) } type collection struct { - primary nosql.Index secondary []nosql.Index + primary nosql.Index } type DB struct { @@ -259,9 +259,9 @@ func (q ouchQuery) putSelector(field string, v interface{}) { type Query struct { db *DB - col string qu ouchQuery pathFilters map[string][]nosql.FieldFilter + col string } func (q *Query) WithFields(filters ...nosql.FieldFilter) nosql.Query { @@ -277,7 +277,7 @@ func (q *Query) buildFilters() { term := map[string]interface{}{} for _, filter := range filterList { testValue := toOuchValue(filter.Value) - test := "" + var test string switch filter.Filter { case nosql.Equal: test = "$eq" @@ -383,13 +383,13 @@ func (q *Query) Iterate() nosql.DocIterator { } type Iterator struct { - db *DB - col string - qu ouchQuery + prevID interface{} err error + qu ouchQuery rows *kivik.Rows doc map[string]interface{} - prevID interface{} + db *DB + col string closed bool } @@ -555,11 +555,11 @@ func (d *Delete) Do(ctx context.Context) error { type Update struct { db *DB + update nosql.Document + inc map[string]int // increment the named numeric field by the int col string key nosql.Key - update nosql.Document upsert bool - inc map[string]int // increment the named numeric field by the int } func (u *Update) Inc(field string, dn int) nosql.Update { @@ -580,7 +580,7 @@ func (u *Update) Upsert(d nosql.Document) nosql.Update { func (u *Update) Do(ctx context.Context) error { orig, id, rev, err := u.db.findByKey(ctx, u.col, u.key) - if err == nosql.ErrNotFound { + if errors.Is(err, nosql.ErrNotFound) { if !u.upsert { return err } diff --git a/legacy/nosql/couch/test/couchtest.go b/legacy/nosql/couch/test/couchtest.go index d07d942..cbe8435 100644 --- a/legacy/nosql/couch/test/couchtest.go +++ b/legacy/nosql/couch/test/couchtest.go @@ -24,10 +24,10 @@ func init() { func CouchVersion(vers string) nosqltest.Database { return nosqltest.Database{ Traits: couch.Traits(), - Run: func(t testing.TB) nosql.Database { + Run: func(tb testing.TB) nosql.Database { pool, err := dockertest.NewPool("") if err != nil { - t.Fatal(err) + tb.Fatal(err) } cont, err := pool.Run("couchdb", vers, []string{ @@ -35,9 +35,9 @@ func CouchVersion(vers string) nosqltest.Database { "COUCHDB_PASSWORD=test", }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = cont.Close() }) @@ -54,14 +54,14 @@ func CouchVersion(vers string) nosqltest.Database { return err }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } qs, err := couch.Dial(true, couch.DriverCouch, addr, "test", nil) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = qs.Close() }) return qs diff --git a/legacy/nosql/couch/test/pouchtest.go b/legacy/nosql/couch/test/pouchtest.go index 78615fe..468c0a4 100644 --- a/legacy/nosql/couch/test/pouchtest.go +++ b/legacy/nosql/couch/test/pouchtest.go @@ -24,14 +24,14 @@ func init() { func Pouch() nosqltest.Database { return nosqltest.Database{ Traits: couch.Traits(), - Run: func(t testing.TB) nosql.Database { + Run: func(tb testing.TB) nosql.Database { dir, err := ioutil.TempDir("", "pouch-") if err != nil { - t.Fatal("failed to make temp dir:", err) + tb.Fatal("failed to make temp dir:", err) } t.Cleanup(func() { if err := os.RemoveAll(dir); err != nil { // remove the test data - t.Fatal(err) + tb.Fatal(err) } }) @@ -40,9 +40,9 @@ func Pouch() nosqltest.Database { qs, err := couch.Dial(false, couch.DriverPouch, dir+"/"+name, name, nil) if err != nil { os.RemoveAll(dir) - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { qs.Close() ctx := context.TODO() if c, err := kivik.New(ctx, couch.DriverPouch, dir); err == nil { diff --git a/legacy/nosql/elastic/elastic.go b/legacy/nosql/elastic/elastic.go index 8023d80..433f3ca 100644 --- a/legacy/nosql/elastic/elastic.go +++ b/legacy/nosql/elastic/elastic.go @@ -4,6 +4,7 @@ import ( "bytes" "context" "encoding/json" + "errors" "fmt" "io" "strconv" @@ -62,12 +63,10 @@ func Dial(addr, index string, opt nosql.Options) (*DB, error) { } major, err := strconv.Atoi(strings.SplitN(vers, ".", 2)[0]) if err != nil { - return nil, fmt.Errorf("cannot parse version: %v", err) + return nil, fmt.Errorf("cannot parse version: %w", err) } ind := opt.GetString("index", index) - if err != nil { - return nil, err - } + // TODO FIXME: Check returned value from opt.GetString(). settings := `{ "number_of_shards":1, "number_of_replicas":0 @@ -88,19 +87,19 @@ func Dial(addr, index string, opt nosql.Options) (*DB, error) { type collection struct { typ string - compPK bool // compose PK from existing keys; if false, use id instead of target field - primary nosql.Index secondary []nosql.Index + primary nosql.Index + compPK bool // compose PK from existing keys; if false, use id instead of target field } type DB struct { - cli *elastic.Client - ind struct { - one bool // use one index for all types (<= v5) + cli *elastic.Client + colls map[string]collection + ind struct { pref string settings json.RawMessage + one bool // use one index for all types (<= v5) } - colls map[string]collection } func (db *DB) Close() error { @@ -164,13 +163,8 @@ func (db *DB) EnsureIndex(ctx context.Context, typ string, primary nosql.Index, if _, ok := props[f]; ok { continue } - var typ indType - switch ind.Type { - case nosql.StringExact: - typ = indKeyword - } - if typ != "" { - props[f] = property{Type: typ} + if ind.Type == nosql.StringExact { + props[f] = property{Type: indKeyword} } } } @@ -408,7 +402,7 @@ func convRegexp(o interface{}) interface{} { if strings.HasSuffix(s, "$") { s = s[:len(s)-1] } else { - s = s + ".*" + s += ".*" } return s } @@ -508,14 +502,14 @@ func (q elasticQuery) Source() (interface{}, error) { type indexRef struct { cli *elastic.Client - ind string c *collection + ind string } type Query struct { indexRef - limit int64 qu elasticQuery + limit int64 } func (q *Query) WithFields(filters ...nosql.FieldFilter) nosql.Query { @@ -569,13 +563,12 @@ func (q *Query) Iterate() nosql.DocIterator { } type Iterator struct { + err error + qu *elastic.ScrollService + buf *elastic.SearchResult indexRef - qu *elastic.ScrollService - - buf *elastic.SearchResult - done bool i int - err error + done bool } func (it *Iterator) Next(ctx context.Context) bool { @@ -590,7 +583,7 @@ func (it *Iterator) Next(ctx context.Context) bool { } else { it.i++ } - if it.err == io.EOF { + if errors.Is(it.err, io.EOF) { it.err = nil it.done = true } @@ -660,18 +653,18 @@ func (d *Delete) Do(ctx context.Context) error { } type Update struct { - indexRef - key nosql.Key - upsert map[string]interface{} inc map[string]int + + indexRef + key nosql.Key } func (u *Update) Inc(field string, dn int) nosql.Update { if u.inc == nil { u.inc = make(map[string]int) } - u.inc[field] = u.inc[field] + dn + u.inc[field] += dn return u } @@ -720,11 +713,11 @@ func (db *DB) BatchInsert(col string) nosql.DocWriter { const batchSize = 100 type inserter struct { + err error indexRef buf []elastic.BulkableRequest ikeys []nosql.Key keys []nosql.Key - err error } func (w *inserter) WriteDoc(ctx context.Context, key nosql.Key, d nosql.Document) error { diff --git a/legacy/nosql/elastic/test/elastictest.go b/legacy/nosql/elastic/test/elastictest.go index 232af06..bf26fcb 100644 --- a/legacy/nosql/elastic/test/elastictest.go +++ b/legacy/nosql/elastic/test/elastictest.go @@ -17,7 +17,7 @@ var versions = []string{ } func init() { - var vers []nosqltest.Version + vers := make([]nosqltest.Version, 0, len(versions)) for _, v := range versions { vers = append(vers, nosqltest.Version{ Name: v, Factory: ElasticVersion(v), @@ -29,19 +29,19 @@ func init() { func ElasticVersion(vers string) nosqltest.Database { return nosqltest.Database{ Traits: elastic.Traits(), - Run: func(t testing.TB) nosql.Database { + Run: func(tb testing.TB) nosql.Database { name := "docker.elastic.co/elasticsearch/elasticsearch" pool, err := dockertest.NewPool("") if err != nil { - t.Fatal(err) + tb.Fatal(err) } cont, err := pool.Run(name, vers, nil) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = cont.Close() }) @@ -53,22 +53,22 @@ func ElasticVersion(vers string) nosqltest.Database { ctx := context.Background() err = pool.Retry(func() error { - cli, err := edriver.NewClient(edriver.SetURL(addr)) - if err != nil { - return err + cli, er := edriver.NewClient(edriver.SetURL(addr)) + if er != nil { + return er } - _, _, err = cli.Ping(addr).Do(ctx) - return err + _, _, er = cli.Ping(addr).Do(ctx) + return er }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } db, err := elastic.Dial(addr, "test", nil) if err != nil { - t.Fatal(addr, err) + tb.Fatal(addr, err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = db.Close() }) return db diff --git a/legacy/nosql/mongo/mongo.go b/legacy/nosql/mongo/mongo.go index 8a44237..dbe9481 100644 --- a/legacy/nosql/mongo/mongo.go +++ b/legacy/nosql/mongo/mongo.go @@ -3,6 +3,7 @@ package mongo import ( "context" "encoding/base64" + "errors" "fmt" "net/url" "strings" @@ -97,9 +98,9 @@ func Dial(addr, dbName string, opt nosql.Options) (*DB, error) { type collection struct { c *mongo.Collection - compPK bool // compose PK from existing keys; if false, use _id instead of target field - primary nosql.Index secondary []nosql.Index + primary nosql.Index + compPK bool // compose PK from existing keys; if false, use _id instead of target field } type DB struct { @@ -109,8 +110,7 @@ type DB struct { } func (db *DB) Close() error { - db.sess.Disconnect(context.TODO()) - return nil + return db.sess.Disconnect(context.TODO()) } func (db *DB) EnsureIndex(ctx context.Context, col string, primary nosql.Index, secondary []nosql.Index) error { @@ -205,7 +205,7 @@ func fromBsonValue(v interface{}) nosql.Value { } return arr case primitive.ObjectID: - return nosql.String(objidString(v)) + return nosql.String(objIDString(v)) case primitive.M: return fromBsonDoc(v) case primitive.A: @@ -314,7 +314,7 @@ func getOrGenID(key nosql.Key) (nosql.Key, string) { var mid string if key == nil { // TODO: maybe allow to pass custom key types as nosql.Key - oid := objidString(primitive.NewObjectID()) + oid := objIDString(primitive.NewObjectID()) mid = oid key = nosql.Key{oid} } else { @@ -334,7 +334,7 @@ func (c *collection) convIns(key nosql.Key, d nosql.Document) (nosql.Key, primit return key, m } -func objidString(id primitive.ObjectID) string { +func objIDString(id primitive.ObjectID) string { return base64.StdEncoding.EncodeToString(id[:]) } @@ -363,7 +363,7 @@ func (db *DB) FindByKey(ctx context.Context, col string, key nosql.Key) (nosql.D res := c.c.FindOne(ctx, primitive.M{"_id": compKey(key)}) var m primitive.M - if err := res.Decode(&m); err == mongo.ErrNoDocuments { + if err := res.Decode(&m); errors.Is(err, mongo.ErrNoDocuments) { return nil, nosql.ErrNotFound } else if err != nil { return nil, err @@ -439,8 +439,8 @@ func mergeFilters(dst, src primitive.M) { type Query struct { c *collection - limit int query primitive.M + limit int } func (q *Query) WithFields(filters ...nosql.FieldFilter) nosql.Query { @@ -533,9 +533,8 @@ func (it *Iterator) Next(ctx context.Context) bool { if !it.it.Next(ctx) { return false } - err := it.it.Decode(&elem) - if err == nil { + if err := it.it.Decode(&elem); err == nil { it.res = elem } @@ -618,9 +617,9 @@ func (d *Delete) Do(ctx context.Context) error { type Update struct { col *collection - key nosql.Key upsert primitive.M update primitive.M + key nosql.Key } func (u *Update) Inc(field string, dn int) nosql.Update { @@ -673,11 +672,11 @@ func (db *DB) BatchInsert(col string) nosql.DocWriter { const batchSize = 100 type inserter struct { + err error col *collection buf []interface{} ikeys []nosql.Key keys []nosql.Key - err error } func (w *inserter) WriteDoc(ctx context.Context, key nosql.Key, d nosql.Document) error { diff --git a/legacy/nosql/mongo/test/mongotest.go b/legacy/nosql/mongo/test/mongotest.go index abb28da..05ccbad 100644 --- a/legacy/nosql/mongo/test/mongotest.go +++ b/legacy/nosql/mongo/test/mongotest.go @@ -25,43 +25,42 @@ func init() { func MongoVersion(vers string) nosqltest.Database { return nosqltest.Database{ Traits: mongo.Traits(), - Run: func(t testing.TB) nosql.Database { + Run: func(tb testing.TB) nosql.Database { pool, err := dockertest.NewPool("") if err != nil { - t.Fatal(err) + tb.Fatal(err) } cont, err := pool.Run("mongo", vers, nil) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = cont.Close() }) addr := fmt.Sprintf("mongodb://%s", cont.GetHostPort("27017/tcp")) err = pool.Retry(func() error { - sess, err := gomongo.NewClient(options.Client().ApplyURI(addr)) - if err != nil { - return err + sess, er := gomongo.NewClient(options.Client().ApplyURI(addr)) + if er != nil { + return er } defer sess.Disconnect(context.TODO()) - err = sess.Connect(context.TODO()) - - if err != nil { - return err + er = sess.Connect(context.TODO()) + if er != nil { + return er } return nil }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } qs, err := mongo.Dial(addr, "test", nil) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = qs.Close() }) return qs diff --git a/legacy/nosql/nosql.go b/legacy/nosql/nosql.go index f8aef16..7163d07 100644 --- a/legacy/nosql/nosql.go +++ b/legacy/nosql/nosql.go @@ -78,24 +78,24 @@ type Database interface { type FilterOp int func (op FilterOp) String() string { - name := "" switch op { case Equal: - name = "Equal" + return "Equal" case NotEqual: - name = "NotEqual" + return "NotEqual" case GT: - name = "GT" + return "GT" case GTE: - name = "GTE" + return "GTE" case LT: - name = "LT" + return "LT" case LTE: - name = "LTE" + return "LTE" + case Regexp: + return "Regexp" default: return fmt.Sprintf("FilterOp(%d)", int(op)) } - return name } func (op FilterOp) GoString() string { @@ -114,9 +114,9 @@ const ( // FieldFilter represents a single field comparison operation. type FieldFilter struct { + Value Value // value that will be compared with field of the document Path []string // path is a path to specific field in the document Filter FilterOp // comparison operation - Value Value // value that will be compared with field of the document } func (f FieldFilter) Matches(doc Document) bool { @@ -241,9 +241,9 @@ func BatchInsert(db Database, col string) DocWriter { type seqInsert struct { db Database + err error col string keys []Key - err error } func (w *seqInsert) WriteDoc(ctx context.Context, key Key, d Document) error { diff --git a/legacy/nosql/nosqltest/nosqltest.go b/legacy/nosql/nosqltest/nosqltest.go index 87f8361..235a758 100644 --- a/legacy/nosql/nosqltest/nosqltest.go +++ b/legacy/nosql/nosqltest/nosqltest.go @@ -15,8 +15,8 @@ import ( ) type Database struct { + Run func(tb testing.TB) nosql.Database Traits nosql.Traits - Run func(t testing.TB) nosql.Database } func TestNoSQL(t *testing.T, gen Database) { @@ -47,7 +47,7 @@ func TestNoSQL(t *testing.T, gen Database) { } } -func BenchmarkNoSQL(t *testing.B, gen Database) { +func BenchmarkNoSQL(b *testing.B, gen Database) { // TODO } @@ -56,9 +56,9 @@ func init() { } type keyType struct { + Gen func() nosql.Key Name string Fields []string - Gen func() nosql.Key } func (kt keyType) SetKey(d nosql.Document, k nosql.Key) { @@ -115,8 +115,8 @@ var keyTypes = []keyType{ } var testsNoSQLKey = []struct { - name string t func(t *testing.T, c tableConf) + name string }{ {name: "ensure", t: testEnsure}, {name: "insert", t: testInsert}, @@ -129,16 +129,16 @@ type tableConf struct { ctx context.Context db nosql.Database col string - tr nosql.Traits kt keyType + tr nosql.Traits } -func (c tableConf) ensurePK(t testing.TB, secondary ...nosql.Index) { +func (c tableConf) ensurePK(tb testing.TB, secondary ...nosql.Index) { err := c.db.EnsureIndex(c.ctx, c.col, nosql.Index{ Fields: c.kt.Fields, Type: nosql.StringExact, }, secondary) - require.NoError(t, err) + require.NoError(tb, err) } func (c tableConf) FindByKey(key nosql.Key) (nosql.Document, error) { @@ -154,11 +154,11 @@ func (c tableConf) fixDoc(k nosql.Key, d nosql.Document) { fixDoc(&c.tr, d) } -func (c tableConf) expectAll(t testing.TB, docs []nosql.Document) { - iterateExpect(t, c.kt, c.db.Query(c.col), docs) +func (c tableConf) expectAll(tb testing.TB, docs []nosql.Document) { + iterateExpect(tb, c.kt, c.db.Query(c.col), docs) } -func (c tableConf) insertDocs(t testing.TB, n int, fnc func(i int) nosql.Document) ([]nosql.Key, []nosql.Document) { +func (c tableConf) insertDocs(tb testing.TB, n int, fnc func(i int) nosql.Document) ([]nosql.Key, []nosql.Document) { var docs []nosql.Document w := nosql.BatchInsert(c.db, c.col) defer w.Close() @@ -169,18 +169,18 @@ func (c tableConf) insertDocs(t testing.TB, n int, fnc func(i int) nosql.Documen key = c.kt.Gen() } err := w.WriteDoc(c.ctx, key, doc) - require.NoError(t, err) + require.NoError(tb, err) docs = append(docs, doc) } err := w.Flush(c.ctx) - require.NoError(t, err) + require.NoError(tb, err) keys := w.Keys() for i := range docs { c.fixDoc(keys[i], docs[i]) } - c.expectAll(t, docs) + c.expectAll(tb, docs) return keys, docs } @@ -273,7 +273,7 @@ func (s docsAndKeys) Swap(i, j int) { s.Keys[i], s.Keys[j] = s.Keys[j], s.Keys[i] } -func iterateExpect(t testing.TB, kt keyType, qu nosql.Query, exp []nosql.Document) { +func iterateExpect(tb testing.TB, kt keyType, qu nosql.Query, exp []nosql.Document) { ctx := context.TODO() it := qu.Iterate() @@ -286,7 +286,8 @@ func iterateExpect(t testing.TB, kt keyType, qu nosql.Query, exp []nosql.Documen keys = append(keys, it.Key()) got = append(got, it.Doc()) } - require.NoError(t, it.Err()) + + require.NoError(tb, it.Err()) sorter := byFields(kt.Fields) exp = append([]nosql.Document{}, exp...) @@ -294,20 +295,23 @@ func iterateExpect(t testing.TB, kt keyType, qu nosql.Query, exp []nosql.Documen return sorter.Less(exp[i], exp[j]) }) var expKeys []nosql.Key - for _, d := range exp { - expKeys = append(expKeys, sorter.Key(d)) + if len(exp) > 0 { + expKeys = make([]nosql.Key, 0, len(exp)) + for _, d := range exp { + expKeys = append(expKeys, sorter.Key(d)) + } } sort.Sort(docsAndKeys{ LessFunc: sorter.Less, Docs: got, Keys: keys, }) - require.Equal(t, exp, got) - require.Equal(t, expKeys, keys) + require.Equal(tb, exp, got) + require.Equal(tb, expKeys, keys) n, err := qu.Count(ctx) - require.NoError(t, err) - require.Equal(t, int64(len(exp)), int64(n)) + require.NoError(tb, err) + require.Equal(tb, int64(len(exp)), int64(n)) } func testEnsure(t *testing.T, c tableConf) { @@ -327,8 +331,8 @@ func testInsert(t *testing.T, c tableConf) { c.expectAll(t, nil) type insert struct { - Key nosql.Key Doc nosql.Document + Key nosql.Key } k1 := c.kt.Gen() @@ -355,8 +359,8 @@ func testInsert(t *testing.T, c tableConf) { } for i := range ins { in := &ins[i] - k, err := c.Insert(in.Key, in.Doc) - require.NoError(t, err) + k, er := c.Insert(in.Key, in.Doc) + require.NoError(t, er) if in.Key == nil { require.NotNil(t, k) in.Key = k @@ -365,10 +369,10 @@ func testInsert(t *testing.T, c tableConf) { } } - var docs []nosql.Document + docs := make([]nosql.Document, 0, len(ins)) for _, in := range ins { - doc, err := c.FindByKey(in.Key) - require.NoError(t, err, "find %#v", in.Key) + doc, er := c.FindByKey(in.Key) + require.NoError(t, er, "find %#v", in.Key) c.fixDoc(in.Key, in.Doc) require.Equal(t, in.Doc, doc, "got: %#v", doc) docs = append(docs, in.Doc) @@ -416,7 +420,7 @@ func testUpdate(t *testing.T, c tableConf) { "n": nosql.Int(2), }, } - var keys []nosql.Key + keys := make([]nosql.Key, 0, len(docs)) for range docs { keys = append(keys, c.kt.Gen()) } diff --git a/legacy/nosql/nosqltest/registry.go b/legacy/nosql/nosqltest/registry.go index 1208673..9076faf 100644 --- a/legacy/nosql/nosqltest/registry.go +++ b/legacy/nosql/nosqltest/registry.go @@ -8,8 +8,8 @@ import ( ) type Registration struct { - nosql.Registration Versions []Version + nosql.Registration } type Version struct { @@ -63,7 +63,7 @@ func ByName(name string) *Registration { } func allNames() []string { - var names []string + names := make([]string, 0, len(registry)) for name := range registry { names = append(names, name) } diff --git a/legacy/nosql/registry.go b/legacy/nosql/registry.go index 0ddc784..66d190a 100644 --- a/legacy/nosql/registry.go +++ b/legacy/nosql/registry.go @@ -11,9 +11,9 @@ type OpenFunc func(addr, ns string, opt Options) (Database, error) // Registration is an information about the database driver. type Registration struct { - base.Registration New, Open OpenFunc - Traits Traits + base.Registration + Traits Traits } var registry = make(map[string]Registration) diff --git a/legacy/nosql/value_test.go b/legacy/nosql/value_test.go index 0878f69..5b6dac8 100644 --- a/legacy/nosql/value_test.go +++ b/legacy/nosql/value_test.go @@ -1,34 +1,35 @@ -package nosql +package nosql_test import ( "testing" + "github.com/hidal-go/hidalgo/legacy/nosql" "github.com/stretchr/testify/require" ) var filterMatch = []struct { - f FieldFilter - d Document + d nosql.Document + f nosql.FieldFilter exp bool }{ { - f: FieldFilter{Path: []string{"value", "str"}, Filter: GT, Value: String("f")}, - d: Document{"value": Document{"str": String("bob")}}, + f: nosql.FieldFilter{Path: []string{"value", "str"}, Filter: nosql.GT, Value: nosql.String("f")}, + d: nosql.Document{"value": nosql.Document{"str": nosql.String("bob")}}, exp: false, }, { - f: FieldFilter{Path: []string{"value", "str"}, Filter: Equal, Value: String("f")}, - d: Document{"value": Document{"str": String("bob")}}, + f: nosql.FieldFilter{Path: []string{"value", "str"}, Filter: nosql.Equal, Value: nosql.String("f")}, + d: nosql.Document{"value": nosql.Document{"str": nosql.String("bob")}}, exp: false, }, { - f: FieldFilter{Path: []string{"value", "str"}, Filter: Equal, Value: String("bob")}, - d: Document{"value": Document{"str": String("bob")}}, + f: nosql.FieldFilter{Path: []string{"value", "str"}, Filter: nosql.Equal, Value: nosql.String("bob")}, + d: nosql.Document{"value": nosql.Document{"str": nosql.String("bob")}}, exp: true, }, { - f: FieldFilter{Path: []string{"value", "str"}, Filter: NotEqual, Value: String("bob")}, - d: Document{"value1": Document{"str": String("bob")}}, + f: nosql.FieldFilter{Path: []string{"value", "str"}, Filter: nosql.NotEqual, Value: nosql.String("bob")}, + d: nosql.Document{"value1": nosql.Document{"str": nosql.String("bob")}}, exp: true, }, } diff --git a/tuple/datastore/datastore.go b/tuple/datastore/datastore.go index 30c935d..14963e8 100644 --- a/tuple/datastore/datastore.go +++ b/tuple/datastore/datastore.go @@ -3,6 +3,7 @@ package datastore import ( "context" "encoding/hex" + "errors" "fmt" "time" @@ -62,7 +63,7 @@ func (t *tableInfo) Open(tx tuple.Tx) (tuple.Table, error) { func (s *TupleStore) Table(ctx context.Context, name string) (tuple.TableInfo, error) { var t tableObject err := s.c.Get(ctx, s.tableKey(name), &t) - if err == datastore.ErrNoSuchEntity { + if errors.Is(err, datastore.ErrNoSuchEntity) { return nil, tuple.ErrTableNotFound } else if err != nil { return nil, err @@ -77,8 +78,8 @@ func (s *TupleStore) Table(ctx context.Context, name string) (tuple.TableInfo, e func (s *TupleStore) ListTables(ctx context.Context) ([]tuple.TableInfo, error) { q := datastore.NewQuery(kindTable).Ancestor(s.metaRoot()) var tables []tableObject - _, err := s.c.GetAll(ctx, q, &tables) - if err != nil { + + if _, err := s.c.GetAll(ctx, q, &tables); err != nil { return nil, err } out := make([]tuple.TableInfo, 0, len(tables)) @@ -162,15 +163,13 @@ func (tx *Tx) CreateTable(ctx context.Context, table tuple.Header) (tuple.Table, } k := tx.s.tableKey(table.Name) _, err = tx.s.c.RunInTransaction(ctx, func(tx *datastore.Transaction) error { - var t tableObject - err := tx.Get(k, &t) - if err == nil { + er := tx.Get(k, &tableObject{}) + if er == nil { return tuple.ErrTableExists - } else if err != nil && err != datastore.ErrNoSuchEntity { - return err + } else if !errors.Is(er, datastore.ErrNoSuchEntity) { + return er } - t = tableObject{Data: data} - _, err = tx.Put(k, &t) + _, err = tx.Put(k, &tableObject{Data: data}) return err }) if err != nil { @@ -225,9 +224,8 @@ func (tbl *Table) Clear(ctx context.Context) error { } } -func (tbl *Table) key(key tuple.Key, auto bool) *datastore.Key { +func (tbl *Table) key(key tuple.Key, auto bool) (k *datastore.Key) { kind := tbl.h.Name - var k *datastore.Key for i, c := range tbl.h.Key { v := key[i] switch c.Type.(type) { @@ -253,19 +251,19 @@ func (tbl *Table) key(key tuple.Key, auto bool) *datastore.Key { } func (tbl *Table) parseKey(key *datastore.Key) (tuple.Key, error) { - k := make(tuple.Key, len(tbl.h.Key)) - for i := len(k) - 1; i >= 0; i-- { + keys := make(tuple.Key, len(tbl.h.Key)) + for i := len(keys) - 1; i >= 0; i-- { if key == nil { return nil, fmt.Errorf("short key") } c := tbl.h.Key[i] switch c.Type.(type) { case values.StringType: - k[i] = values.String(key.Name) + keys[i] = values.String(key.Name) case values.IntType: - k[i] = values.Int(key.ID) + keys[i] = values.Int(key.ID) case values.UIntType: - k[i] = values.UInt(key.ID) + keys[i] = values.UInt(key.ID) default: d, err := hex.DecodeString(key.Name) if err != nil { @@ -276,11 +274,11 @@ func (tbl *Table) parseKey(key *datastore.Key) (tuple.Key, error) { if err != nil { return nil, err } - k[i] = v.Sortable() + keys[i] = v.Sortable() } key = key.Parent } - return k, nil + return keys, nil } var _ datastore.PropertyLoadSaver = (*payload)(nil) @@ -396,8 +394,8 @@ func (p *payload) Save() ([]datastore.Property, error) { }) } for i, c := range p.h.Data { - v := p.t.Data[i] var val interface{} + v := p.t.Data[i] if v != nil { switch c.Type.(type) { case values.BytesType: @@ -438,7 +436,7 @@ func (tbl *Table) GetTuple(ctx context.Context, key tuple.Key) (tuple.Data, erro p := &payload{h: &tbl.h} p.t.Key = key err := tbl.cli().Get(ctx, tbl.key(key, false), p) - if err == datastore.ErrNoSuchEntity { + if errors.Is(err, datastore.ErrNoSuchEntity) { return nil, tuple.ErrNotFound } else if err != nil { return nil, err @@ -482,13 +480,14 @@ func (tbl *Table) InsertTuple(ctx context.Context, t tuple.Tuple) (tuple.Key, er return nil, err } k := tbl.key(t.Key, true) - if err := tx.Get(k, &payload{h: &tbl.h}); err == nil { - tx.Rollback() + + if er := tx.Get(k, &payload{h: &tbl.h}); er == nil { + _ = tx.Rollback() return nil, tuple.ErrExists } pk, err := tx.Put(k, &payload{h: &tbl.h, t: t}) if err != nil { - tx.Rollback() + _ = tx.Rollback() return nil, err } c, err := tx.Commit() @@ -522,7 +521,9 @@ func (tbl *Table) UpdateTuple(ctx context.Context, t tuple.Tuple, opt *tuple.Upd return err } k := tbl.key(t.Key, false) - if err := tx.Get(k, &payload{h: &tbl.h}); err == datastore.ErrNoSuchEntity { + + err = tx.Get(k, &payload{h: &tbl.h}) + if errors.Is(err, datastore.ErrNoSuchEntity) { return tuple.ErrNotFound } _, err = tx.Put(k, &payload{h: &tbl.h, t: t}) @@ -579,14 +580,13 @@ func (tbl *Table) Scan(opt *tuple.ScanOptions) tuple.Iterator { } type Iterator struct { - tbl *Table + err error q *datastore.Query - keysOnly bool f *tuple.Filter - - it *datastore.Iterator - t tuple.Tuple - err error + it *datastore.Iterator + tbl *Table + t tuple.Tuple + keysOnly bool } func (it *Iterator) Reset() { @@ -634,7 +634,7 @@ func (it *Iterator) Next(ctx context.Context) bool { } func (it *Iterator) Err() error { - if it.err == iterator.Done { + if errors.Is(it.err, iterator.Done) { return nil } return it.err diff --git a/tuple/datastore/datastore_test.go b/tuple/datastore/datastore_test.go index 23509af..dc87f51 100644 --- a/tuple/datastore/datastore_test.go +++ b/tuple/datastore/datastore_test.go @@ -1,4 +1,4 @@ -package datastore +package datastore_test import ( "context" @@ -9,14 +9,15 @@ import ( "github.com/ory/dockertest" "github.com/hidal-go/hidalgo/tuple" + ds "github.com/hidal-go/hidalgo/tuple/datastore" "github.com/hidal-go/hidalgo/tuple/tupletest" ) func TestDatastore(t *testing.T) { - tupletest.RunTest(t, func(t testing.TB) tuple.Store { + tupletest.RunTest(t, func(tb testing.TB) tuple.Store { pool, err := dockertest.NewPool("") if err != nil { - t.Fatal(err) + tb.Fatal(err) } const ( @@ -35,29 +36,31 @@ func TestDatastore(t *testing.T) { }, }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = cont.Close() }) ctx := context.Background() host := cont.GetHostPort("8080/tcp") if host == "" { - t.Fatal("empty host") + tb.Fatal("empty host") } + if err = os.Setenv("DATASTORE_EMULATOR_HOST", host); err != nil { - t.Fatal(err) + tb.Fatal(err) } else if host := os.Getenv("DATASTORE_EMULATOR_HOST"); host == "" { - t.Fatal("set env failed") + tb.Fatal("set env failed") } cli, err := datastore.NewClient(ctx, proj) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = cli.Close() }) - return OpenClient(cli) + + return ds.OpenClient(cli) }, nil) } diff --git a/tuple/kv/downgrade.go b/tuple/kv/downgrade.go index abaa9ab..e33d6bc 100644 --- a/tuple/kv/downgrade.go +++ b/tuple/kv/downgrade.go @@ -2,6 +2,7 @@ package tuplekv import ( "context" + "errors" "fmt" "github.com/hidal-go/hidalgo/filter" @@ -17,7 +18,7 @@ func NewKV(ctx context.Context, db tuple.Store, table string) (flat.KV, error) { } defer tx.Close() _, err = tx.Table(ctx, table) - if err == tuple.ErrTableNotFound { + if errors.Is(err, tuple.ErrTableNotFound) { _, err = tx.CreateTable(ctx, tuple.Header{ Name: table, Key: []tuple.KeyField{ @@ -97,7 +98,7 @@ func flatData(b flat.Value) tuple.Data { func (tx *flatTx) Get(ctx context.Context, key flat.Key) (flat.Value, error) { row, err := tx.tbl.GetTuple(ctx, flatKey(key)) - if err == tuple.ErrNotFound { + if errors.Is(err, tuple.ErrNotFound) { return nil, flat.ErrNotFound } else if err != nil { return nil, err @@ -159,10 +160,10 @@ var ( ) type flatIterator struct { - tx *flatTx - pref flat.Key it tuple.Iterator err error + tx *flatTx + pref flat.Key } func (it *flatIterator) Reset() { diff --git a/tuple/kv/upgrade.go b/tuple/kv/upgrade.go index 6c6891d..f891527 100644 --- a/tuple/kv/upgrade.go +++ b/tuple/kv/upgrade.go @@ -3,6 +3,7 @@ package tuplekv import ( "context" "encoding/binary" + "errors" "fmt" "io" @@ -19,13 +20,14 @@ func New(kv kv.KV) tuple.Store { } func tupleErr(err error) error { - switch err { - case kv.ErrNotFound: + switch { + case errors.Is(err, kv.ErrNotFound): return tuple.ErrNotFound - case kv.ErrReadOnly: + case errors.Is(err, kv.ErrReadOnly): return tuple.ErrReadOnly + default: + return err } - return err } type tupleStore struct { @@ -71,7 +73,7 @@ func (db *tupleStore) tableAuto(name string) kv.Key { func (db *tupleStore) tableWith(ctx context.Context, tx kv.Tx, name string) (*tupleTableInfo, error) { // TODO: cache data, err := tx.Get(ctx, db.tableSchema(name)) - if err == kv.ErrNotFound { + if errors.Is(err, kv.ErrNotFound) { return nil, tuple.ErrTableNotFound } else if err != nil { return nil, tupleErr(err) @@ -195,7 +197,7 @@ func (tx *tupleTx) CreateTable(ctx context.Context, table tuple.Header) (tuple.T _, err := tx.tx.Get(ctx, key) if err == nil { return nil, tuple.ErrExists - } else if err != nil && err != kv.ErrNotFound { + } else if !errors.Is(err, kv.ErrNotFound) { return nil, tupleErr(err) } data, err := tuplepb.MarshalTable(&table) @@ -291,7 +293,7 @@ func (tbl *tupleTable) decodeKey(key kv.Key) (tuple.Key, error) { v := f.Type.NewSortable() err := v.UnmarshalSortable(key[i]) if err != nil { - return nil, fmt.Errorf("cannot decode tuple key: %v", err) + return nil, fmt.Errorf("cannot decode tuple key: %w", err) } row[i] = v.Sortable() } @@ -326,7 +328,7 @@ func (tbl *tupleTable) decodeTuple(data kv.Value) (tuple.Data, error) { sz, n := binary.Uvarint(data) data = data[n:] if n == 0 { - return nil, fmt.Errorf("cannot decode tuple data: %v", io.ErrUnexpectedEOF) + return nil, fmt.Errorf("cannot decode tuple data: %w", io.ErrUnexpectedEOF) } else if sz > uint64(len(data)) { return nil, fmt.Errorf("invalid tuple field size: %d vs %d", sz, len(data)) } @@ -337,7 +339,7 @@ func (tbl *tupleTable) decodeTuple(data kv.Value) (tuple.Data, error) { v := f.Type.New() err := v.UnmarshalBinary(head) if err != nil { - return nil, fmt.Errorf("cannot decode tuple field: %v", err) + return nil, fmt.Errorf("cannot decode tuple field: %w", err) } row[i] = v.Value() } @@ -349,7 +351,7 @@ func (tbl *tupleTable) GetTuple(ctx context.Context, key tuple.Key) (tuple.Data, return nil, err } data, err := tbl.tx.tx.Get(ctx, tbl.row(key)) - if err == kv.ErrNotFound { + if errors.Is(err, kv.ErrNotFound) { return nil, tuple.ErrNotFound } else if err != nil { return nil, tupleErr(err) @@ -386,7 +388,7 @@ func (tbl *tupleTable) GetTupleBatch(ctx context.Context, key []tuple.Key) ([]tu func (tbl *tupleTable) nextAuto(ctx context.Context) (tuple.Key, error) { key := tbl.auto() v, err := tbl.tx.tx.Get(ctx, key) - if err == kv.ErrNotFound { + if errors.Is(err, kv.ErrNotFound) { // first - set to 0 v = kv.Value{0} } else if err != nil { @@ -424,7 +426,7 @@ func (tbl *tupleTable) InsertTuple(ctx context.Context, t tuple.Tuple) (tuple.Ke _, err := tbl.tx.tx.Get(ctx, key) if err == nil { return nil, tuple.ErrExists - } else if err != nil && err != kv.ErrNotFound { + } else if !errors.Is(err, kv.ErrNotFound) { return nil, tupleErr(err) } val, err := tbl.encodeTuple(t.Data) @@ -450,7 +452,7 @@ func (tbl *tupleTable) UpdateTuple(ctx context.Context, t tuple.Tuple, opt *tupl } if !opt.Upsert { _, err := tbl.tx.tx.Get(ctx, key) - if err == kv.ErrNotFound { + if errors.Is(err, kv.ErrNotFound) { return tuple.ErrNotFound } else if err != nil { return tupleErr(err) diff --git a/tuple/kv/upgrade_test.go b/tuple/kv/upgrade_test.go index b7be352..0a06428 100644 --- a/tuple/kv/upgrade_test.go +++ b/tuple/kv/upgrade_test.go @@ -11,7 +11,7 @@ import ( ) func TestKV2Tuple(t *testing.T) { - tupletest.RunTest(t, func(t testing.TB) tuple.Store { + tupletest.RunTest(t, func(_ testing.TB) tuple.Store { kdb := btree.New() db := tuplekv.New(flat.Upgrade(kdb)) return db diff --git a/tuple/sql/builder.go b/tuple/sql/builder.go index 9945c6a..bc48e2e 100644 --- a/tuple/sql/builder.go +++ b/tuple/sql/builder.go @@ -11,9 +11,9 @@ func (d *Dialect) NewBuilder() *Builder { type Builder struct { d *Dialect - pi int buf *bytes.Buffer args []interface{} + pi int } func (b *Builder) Reset() { diff --git a/tuple/sql/dialect.go b/tuple/sql/dialect.go index 8e60184..4f82fc6 100644 --- a/tuple/sql/dialect.go +++ b/tuple/sql/dialect.go @@ -10,6 +10,10 @@ import ( type ErrorFunc func(err error) error type Dialect struct { + QuoteIdentifierFunc func(s string) string + Placeholder func(i int) string + ColumnCommentInline func(s string) string + ColumnCommentSet func(b *Builder, tbl, col, s string) Errors ErrorFunc BytesType string StringType string @@ -18,8 +22,6 @@ type Dialect struct { TimeType string StringTypeCollation string AutoType string - QuoteIdentifierFunc func(s string) string - Placeholder func(i int) string // DefaultSchema will be used to query table metadata. // If not set, defaults to the database name. DefaultSchema string @@ -37,9 +39,7 @@ type Dialect struct { OnConflict bool // Returning indicates that INSERT queries needs an RETURNING keyword to return last // inserted id. - Returning bool - ColumnCommentInline func(s string) string - ColumnCommentSet func(b *Builder, tbl, col, s string) + Returning bool } func (d *Dialect) SetDefaults() { @@ -69,12 +69,12 @@ func (d *Dialect) QuoteIdentifier(s string) string { if q := d.QuoteIdentifierFunc; q != nil { return q(s) } - return "`" + strings.Replace(s, "`", "", -1) + "`" + return "`" + strings.ReplaceAll(s, "`", "") + "`" } func (d *Dialect) QuoteString(s string) string { // only used when setting comments, so it's pretty naive - return "'" + strings.Replace(s, "'", "''", -1) + "'" + return "'" + strings.ReplaceAll(s, "'", "''") + "'" } func (d *Dialect) sqlType(t values.Type, key bool) string { diff --git a/tuple/sql/mysql/mysql.go b/tuple/sql/mysql/mysql.go index eaf7136..3d543ba 100644 --- a/tuple/sql/mysql/mysql.go +++ b/tuple/sql/mysql/mysql.go @@ -37,7 +37,7 @@ func init() { ListColumns: `SELECT column_name, column_type, is_nullable, column_key, column_comment FROM information_schema.columns WHERE table_schema = ? AND table_name = ?`, QuoteIdentifierFunc: func(s string) string { - return "`" + strings.Replace(s, "`", "", -1) + "`" + return "`" + strings.ReplaceAll(s, "`", "") + "`" }, ColumnCommentInline: func(s string) string { return "COMMENT " + s diff --git a/tuple/sql/mysql/test/mysqltest.go b/tuple/sql/mysql/test/mysqltest.go index a67a426..4e75522 100644 --- a/tuple/sql/mysql/test/mysqltest.go +++ b/tuple/sql/mysql/test/mysqltest.go @@ -15,7 +15,7 @@ var versions = []string{ } func init() { - var vers []sqltest.Version + vers := make([]sqltest.Version, 0, len(versions)) for _, v := range versions { vers = append(vers, sqltest.Version{ Name: v, Factory: MySQLVersion(v), @@ -28,19 +28,19 @@ func MySQLVersion(vers string) sqltest.Database { const image = "mysql" return sqltest.Database{ Recreate: false, - Run: func(t testing.TB) string { + Run: func(tb testing.TB) string { pool, err := dockertest.NewPool("") if err != nil { - t.Fatal(err) + tb.Fatal(err) } cont, err := pool.Run(image, vers, []string{ "MYSQL_ROOT_PASSWORD=root", }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = cont.Close() }) @@ -56,7 +56,7 @@ func MySQLVersion(vers string) sqltest.Database { return cli.Ping() }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } return addr }, diff --git a/tuple/sql/postgres/test/postgrestest.go b/tuple/sql/postgres/test/postgrestest.go index 7c41adc..1579cc4 100644 --- a/tuple/sql/postgres/test/postgrestest.go +++ b/tuple/sql/postgres/test/postgrestest.go @@ -15,7 +15,7 @@ var versions = []string{ } func init() { - var vers []sqltest.Version + vers := make([]sqltest.Version, 0, len(versions)) for _, v := range versions { vers = append(vers, sqltest.Version{ Name: v, Factory: PostgresVersion(v), @@ -28,19 +28,19 @@ func PostgresVersion(vers string) sqltest.Database { const image = "postgres" return sqltest.Database{ Recreate: false, - Run: func(t testing.TB) string { + Run: func(tb testing.TB) string { pool, err := dockertest.NewPool("") if err != nil { - t.Fatal(err) + tb.Fatal(err) } cont, err := pool.Run(image, vers, []string{ "POSTGRES_PASSWORD=postgres", }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = cont.Close() }) @@ -56,7 +56,7 @@ func PostgresVersion(vers string) sqltest.Database { return cli.Ping() }) if err != nil { - t.Fatal(err) + tb.Fatal(err) } return addr }, diff --git a/tuple/sql/registry.go b/tuple/sql/registry.go index ab785f9..7c8414d 100644 --- a/tuple/sql/registry.go +++ b/tuple/sql/registry.go @@ -11,10 +11,10 @@ type DSNFunc func(addr, ns string) (string, error) // Registration is an information about the database driver. type Registration struct { - base.Registration - Driver string - DSN DSNFunc Dialect Dialect + DSN DSNFunc + Driver string + base.Registration } var registry = make(map[string]Registration) diff --git a/tuple/sql/sql.go b/tuple/sql/sql.go index d2239b3..b673761 100644 --- a/tuple/sql/sql.go +++ b/tuple/sql/sql.go @@ -3,6 +3,7 @@ package sqltuple import ( "context" "database/sql" + "errors" "fmt" "log" "strconv" @@ -64,8 +65,7 @@ func (s *sqlStore) convError(err error) error { if s.dia.Errors != nil { err = s.dia.Errors(err) } - switch err { - case ErrTableNotFound: + if errors.Is(err, ErrTableNotFound) { return tuple.ErrTableNotFound } return err @@ -567,7 +567,7 @@ func (tbl *sqlTable) GetTuple(ctx context.Context, key tuple.Key) (tuple.Data, e b.Write(" LIMIT 1") row := tbl.tx.db.queryRow(ctx, tbl.tx.tx, b.String(), b.Args()...) data, err := tbl.scanPayload(row) - if err == sql.ErrNoRows { + if errors.Is(err, sql.ErrNoRows) { return nil, tuple.ErrNotFound } else if err != nil { return nil, err @@ -765,7 +765,7 @@ func (tbl *sqlTable) DeleteTuples(ctx context.Context, f *tuple.Filter) error { return it.Err() } -func (tbl *sqlTable) scan(open rowsFunc, keysOnly bool, f *tuple.Filter) tuple.Iterator { +func (tbl *sqlTable) scan(open rowsFunc, keysOnly bool, f *tuple.Filter) *sqlIterator { return &sqlIterator{tbl: tbl, open: open, f: f, keysOnly: keysOnly} } @@ -816,15 +816,13 @@ func (tbl *sqlTable) Scan(opt *tuple.ScanOptions) tuple.Iterator { type rowsFunc func(ctx context.Context) (*sql.Rows, error) type sqlIterator struct { - tbl *sqlTable - + err error rows *sql.Rows open rowsFunc - keysOnly bool f *tuple.Filter - - t *tuple.Tuple - err error + t *tuple.Tuple + tbl *sqlTable + keysOnly bool } func (it *sqlIterator) Reset() { diff --git a/tuple/sql/sqltest/registry.go b/tuple/sql/sqltest/registry.go index e76df78..c6d8863 100644 --- a/tuple/sql/sqltest/registry.go +++ b/tuple/sql/sqltest/registry.go @@ -13,8 +13,8 @@ type Registration struct { } type Version struct { - Name string Factory Database + Name string } var registry = make(map[string][]Version) @@ -63,7 +63,7 @@ func ByName(name string) *Registration { } func allNames() []string { - var names []string + names := make([]string, 0, len(registry)) for name := range registry { names = append(names, name) } diff --git a/tuple/sql/sqltest/sqltest.go b/tuple/sql/sqltest/sqltest.go index e8761df..b439c20 100644 --- a/tuple/sql/sqltest/sqltest.go +++ b/tuple/sql/sqltest/sqltest.go @@ -14,8 +14,8 @@ import ( ) type Database struct { + Run func(tb testing.TB) string Recreate bool - Run func(t testing.TB) string } func TestSQL(t *testing.T, name string, gen Database) { @@ -24,35 +24,35 @@ func TestSQL(t *testing.T, name string, gen Database) { if !recreate { addr = gen.Run(t) } - tupletest.RunTest(t, func(t testing.TB) tuple.Store { + tupletest.RunTest(t, func(tb testing.TB) tuple.Store { db := fmt.Sprintf("db_%x", rand.Int()) addr := addr if recreate { - addr = gen.Run(t) + addr = gen.Run(tb) } conn, err := sqltuple.OpenSQL(name, addr, "") if err != nil { - require.NoError(t, err) + require.NoError(tb, err) } _, err = conn.Exec(`CREATE DATABASE ` + db) conn.Close() if err != nil { - require.NoError(t, err) + require.NoError(tb, err) } conn, err = sqltuple.OpenSQL(name, addr, db) if err != nil { - require.NoError(t, err) + require.NoError(tb, err) } - t.Cleanup(func() { + tb.Cleanup(func() { conn.Close() if !recreate { - conn, err := sqltuple.OpenSQL(name, addr, "") + conn, err = sqltuple.OpenSQL(name, addr, "") if err == nil { _, err = conn.Exec(`DROP DATABASE ` + db) conn.Close() } if err != nil { - t.Errorf("cannot remove test database: %v", err) + tb.Errorf("cannot remove test database: %v", err) } } }) diff --git a/tuple/tuplepb/tuplepb_test.go b/tuple/tuplepb/tuplepb_test.go index 5c20536..1bb9aa7 100644 --- a/tuple/tuplepb/tuplepb_test.go +++ b/tuple/tuplepb/tuplepb_test.go @@ -1,4 +1,4 @@ -package tuplepb +package tuplepb_test import ( "testing" @@ -6,6 +6,7 @@ import ( "github.com/stretchr/testify/require" "github.com/hidal-go/hidalgo/tuple" + "github.com/hidal-go/hidalgo/tuple/tuplepb" "github.com/hidal-go/hidalgo/values" ) @@ -23,10 +24,10 @@ func TestTableEncoding(t *testing.T) { }, } - data, err := MarshalTable(tbl) + data, err := tuplepb.MarshalTable(tbl) require.NoError(t, err) - tbl2, err := UnmarshalTable(data) + tbl2, err := tuplepb.UnmarshalTable(data) require.NoError(t, err) require.Equal(t, tbl, tbl2) } diff --git a/tuple/tupletest/helpers.go b/tuple/tupletest/helpers.go index fd1728b..ca7cceb 100644 --- a/tuple/tupletest/helpers.go +++ b/tuple/tupletest/helpers.go @@ -6,8 +6,8 @@ import ( "github.com/hidal-go/hidalgo/tuple" ) -func NewTest(t testing.TB, db tuple.Store) *Test { - return &Test{t: t, db: db} +func NewTest(tb testing.TB, db tuple.Store) *Test { + return &Test{t: tb, db: db} } type Test struct { diff --git a/tuple/tupletest/tupletest.go b/tuple/tupletest/tupletest.go index 729f479..8240314 100644 --- a/tuple/tupletest/tupletest.go +++ b/tuple/tupletest/tupletest.go @@ -20,7 +20,7 @@ import ( // Func is a constructor for database implementations. // It returns an empty database and a function to destroy it. -type Func func(t testing.TB) tuple.Store +type Func func(tb testing.TB) tuple.Store type Options struct { NoLocks bool // not safe for concurrent writes @@ -38,15 +38,15 @@ func RunTest(t *testing.T, fnc Func, opts *Options) { }) } t.Run("kv", func(t *testing.T) { - kvtest.RunTest(t, func(t testing.TB) hkv.KV { - db := fnc(t) + kvtest.RunTest(t, func(tb testing.TB) hkv.KV { + db := fnc(tb) ctx := context.TODO() kdb, err := tuplekv.NewKV(ctx, db, "kv") if err != nil { - require.NoError(t, err) + require.NoError(tb, err) } - t.Cleanup(func() { + tb.Cleanup(func() { _ = kdb.Close() }) return flat.Upgrade(kdb) @@ -58,8 +58,8 @@ func RunTest(t *testing.T, fnc Func, opts *Options) { } var testList = []struct { - name string test func(t *testing.T, db tuple.Store) + name string }{ {name: "basic", test: basic}, {name: "typed", test: typed}, @@ -125,6 +125,7 @@ func typed(t *testing.T, db tuple.Store) { // FIXME: test nanoseconds on backends that support it values.AsTime(time.Unix(123, 456789000)), } + var payloads []values.Value for _, tp := range sortable { payloads = append(payloads, tp) @@ -314,7 +315,7 @@ func tables(t *testing.T, db tuple.Store) { }) } -func tablesSimple(t testing.TB, db tuple.Store) { +func tablesSimple(tb testing.TB, db tuple.Store) { ctx := context.Background() const name = "test1" @@ -330,7 +331,7 @@ func tablesSimple(t testing.TB, db tuple.Store) { newTx := func(rw bool) tuple.Tx { tx, err := db.Tx(rw) - require.NoError(t, err) + require.NoError(tb, err) return tx } @@ -338,70 +339,70 @@ func tablesSimple(t testing.TB, db tuple.Store) { notExists := func() { tbl, err := tx.Table(ctx, name) - require.Equal(t, tuple.ErrTableNotFound, err) - require.Nil(t, tbl) + require.Equal(tb, tuple.ErrTableNotFound, err) + require.Nil(tb, tbl) } // access table when it not exists notExists() list, err := tx.ListTables(ctx) - require.NoError(t, err) - require.Empty(t, list) + require.NoError(tb, err) + require.Empty(tb, list) // create table on read-only transaction _, err = tx.CreateTable(ctx, schema) - require.Equal(t, tuple.ErrReadOnly, err) + require.Equal(tb, tuple.ErrReadOnly, err) notExists() err = tx.Close() - require.NoError(t, err) + require.NoError(tb, err) // reopen read-write transaction tx = newTx(true) // table should not exist after failed creation tbl, err := tx.Table(ctx, name) - require.Equal(t, tuple.ErrTableNotFound, err) - require.Nil(t, tbl) + require.Equal(tb, tuple.ErrTableNotFound, err) + require.Nil(tb, tbl) tbl, err = tx.CreateTable(ctx, schema) - require.NoError(t, err) - require.NotNil(t, tbl) + require.NoError(tb, err) + require.NotNil(tb, tbl) // TODO: check create + rollback err = tx.Commit(ctx) - require.NoError(t, err) + require.NoError(tb, err) tx = newTx(true) tbl, err = tx.Table(ctx, name) - require.NoError(t, err) - assert.Equal(t, schema, tbl.Header()) + require.NoError(tb, err) + assert.Equal(tb, schema, tbl.Header()) err = tbl.Drop(ctx) - require.NoError(t, err) + require.NoError(tb, err) tbl, err = tx.Table(ctx, name) - require.Equal(t, tuple.ErrTableNotFound, err) - require.Nil(t, tbl) + require.Equal(tb, tuple.ErrTableNotFound, err) + require.Nil(tb, tbl) err = tx.Commit(ctx) - require.NoError(t, err) + require.NoError(tb, err) tx = newTx(false) notExists() err = tx.Close() - require.NoError(t, err) + require.NoError(tb, err) // TODO: test multiple tables // TODO: test different headers (only keys, only values) } -func tablesAuto(t testing.TB, db tuple.Store) { +func tablesAuto(tb testing.TB, db tuple.Store) { ctx := context.Background() const name = "test2" @@ -417,27 +418,27 @@ func tablesAuto(t testing.TB, db tuple.Store) { newTx := func(rw bool) tuple.Tx { tx, err := db.Tx(rw) - require.NoError(t, err) + require.NoError(tb, err) return tx } tx := newTx(true) tbl, err := tx.CreateTable(ctx, schema) - require.NoError(t, err) - require.NotNil(t, tbl) + require.NoError(tb, err) + require.NotNil(tb, tbl) err = tx.Commit(ctx) - require.NoError(t, err) + require.NoError(tb, err) tx = newTx(false) tbl, err = tx.Table(ctx, name) - require.NoError(t, err) - assert.Equal(t, schema, tbl.Header()) + require.NoError(tb, err) + assert.Equal(tb, schema, tbl.Header()) err = tx.Close() - require.NoError(t, err) + require.NoError(tb, err) } func auto(t *testing.T, db tuple.Store) { diff --git a/values/values_test.go b/values/values_test.go index 12daa0a..fba2230 100644 --- a/values/values_test.go +++ b/values/values_test.go @@ -100,8 +100,8 @@ func TestMarshalBinary(t *testing.T) { } var casesCompare = []struct { - name string a, b Sortable + name string exp int }{ {name: "nil == nil", a: nil, b: nil, exp: 0},