diff --git a/README.md b/README.md index 75d66e2..38dc21e 100644 --- a/README.md +++ b/README.md @@ -89,14 +89,14 @@ func example() { myObjects.Insert(wtxn, &MyObject{3, "c"}) // Modify an object - if obj, _, found := myObjects.First(wtxn, IDIndex.Query(1)); found { + if obj, _, found := myObjects.Get(wtxn, IDIndex.Query(1)); found { objCopy := *obj objCopy.Foo = "d" myObjects.Insert(wtxn, &objCopy) } // Delete an object - if obj, _, found := myObjects.First(wtxn, IDIndex.Query(2)); found { + if obj, _, found := myObjects.Get(wtxn, IDIndex.Query(2)); found { myObjects.Delete(wtxn, obj) } @@ -111,7 +111,7 @@ func example() { // Query the objects with a snapshot of the database. txn := db.ReadTxn() - if obj, _, found := myObjects.First(wtxn, IDIndex.Query(1)); found { + if obj, _, found := myObjects.Get(wtxn, IDIndex.Query(1)); found { ... } @@ -314,33 +314,39 @@ var ( found bool watch <-chan struct{} ) -// First returns the first matching object in the query. -obj, revision, found = myObjects.First(txn, IDIndex.Query(42)) +// Get returns the first matching object in the query. +obj, revision, found = myObjects.Get(txn, IDIndex.Query(42)) if found { // obj points to the object we inserted earlier. // revision is the "table revision" for the object. Revisions are // incremented for a table on every insertion or deletion. } -// FirstWatch is the same as First, but also gives us a watch +// GetWatch is the same as Get, but also gives us a watch // channel that we can use to wait on the object to appear or to // change. -obj, revision, watch, found = myObjects.FirstWatch(txn, IDIndex.Query(42)) +obj, revision, watch, found = myObjects.GetWatch(txn, IDIndex.Query(42)) <-watch // closes when object with ID '42' is inserted or deleted ``` ### Iterating -`Get` can be used to iterate over all objects that match the query. +`List` can be used to iterate over all objects that match the query. ```go var iter statedb.Iterator[*MyObject] -// Get returns all matching objects as an iterator. The iterator is lazy +// List returns all matching objects as an iterator. The iterator is lazy // and one can stop reading at any time without worrying about the rest. -iter, watch = myObjects.Get(txn, TagsIndex.Query("hello")) +iter := myObjects.List(txn, TagsIndex.Query("hello")) for obj, revision, ok := iter.Next(); ok; obj, revision, ok = iter.Next() { // ... } -<-watch // closes when an object with tag "hello" is inserted or deleted + +// ListWatch is like List, but also returns a watch channel. +iter, watch := myObjects.ListWatch(txn, TagsIndex.Query("hello")) +for obj, revision, ok := iter.Next(); ok; obj, revision, ok = iter.Next() { ... } + +// closes when an object with tag "hello" is inserted or deleted +<-watch ``` `Prefix` can be used to iterate over objects that match a given prefix. @@ -461,7 +467,7 @@ wtxn := db.WriteTxn(myObjects) // Now that we have the table written we can retrieve an object and none will // be able to modify it until we commit. -obj, revision, found := myObjects.First(wtxn, IDIndex.Query(42)) +obj, revision, found := myObjects.Get(wtxn, IDIndex.Query(42)) if !found { panic("it should be there, I swear!") } // We cannot just straight up modify 'obj' since someone might be reading it. @@ -498,7 +504,7 @@ txn := db.ReadTxn() // Look up the object we want to update and perform some slow calculation // to produce the desired new object. -obj, revision, found := myObjects.First(txn, IDIndex.Query(42)) +obj, revision, found := myObjects.Get(txn, IDIndex.Query(42)) obj = veryExpensiveCalculation(obj) // Now that we're ready to insert we can grab a WriteTxn. diff --git a/benchmarks_test.go b/benchmarks_test.go index 8b7f77a..29a31d4 100644 --- a/benchmarks_test.go +++ b/benchmarks_test.go @@ -293,7 +293,7 @@ func BenchmarkDB_RandomLookup(b *testing.B) { for j := 0; j < b.N; j++ { txn := db.ReadTxn() for _, q := range queries { - _, _, ok := table.First(txn, q) + _, _, ok := table.Get(txn, q) if !ok { b.Fatal("object not found") } @@ -319,7 +319,7 @@ func BenchmarkDB_SequentialLookup(b *testing.B) { txn := db.ReadTxn() for n := 0; n < b.N; n++ { for _, q := range queries { - _, _, ok := table.First(txn, q) + _, _, ok := table.Get(txn, q) if !ok { b.Fatalf("Object not found") } @@ -374,7 +374,7 @@ func BenchmarkDB_FullIteration_Get(b *testing.B) { txn := db.ReadTxn() for n := 0; n < b.N; n++ { for _, q := range queries { - _, _, ok := table.First(txn, q) + _, _, ok := table.Get(txn, q) if !ok { b.Fatalf("Object not found") } diff --git a/db_test.go b/db_test.go index cf908ba..dc021d3 100644 --- a/db_test.go +++ b/db_test.go @@ -580,7 +580,7 @@ func TestDB_Revision(t *testing.T) { require.Equal(t, writeRevision, readRevision, "committed transaction changed revision") } -func TestDB_GetFirstLast(t *testing.T) { +func TestDB_GetList(t *testing.T) { t.Parallel() db, table, _ := newTestDB(t, tagsIndex) @@ -597,8 +597,8 @@ func TestDB_GetFirstLast(t *testing.T) { require.NoError(t, err) } // Check that we can query the not-yet-committed write transaction. - obj, rev, ok := table.First(txn, idIndex.Query(1)) - require.True(t, ok, "expected First(1) to return result") + obj, rev, ok := table.Get(txn, idIndex.Query(1)) + require.True(t, ok, "expected Get(1) to return result") require.NotZero(t, rev, "expected non-zero revision") require.EqualValues(t, obj.ID, 1, "expected first obj.ID to equal 1") txn.Commit() @@ -606,40 +606,40 @@ func TestDB_GetFirstLast(t *testing.T) { txn := db.ReadTxn() - // Test Get against the ID index. - iter, _ := table.Get(txn, idIndex.Query(0)) + // Test List against the ID index. + iter := table.List(txn, idIndex.Query(0)) items := Collect(iter) require.Len(t, items, 0, "expected Get(0) to not return results") - iter, _ = table.Get(txn, idIndex.Query(1)) + iter = table.List(txn, idIndex.Query(1)) items = Collect(iter) require.Len(t, items, 1, "expected Get(1) to return result") require.EqualValues(t, items[0].ID, 1, "expected items[0].ID to equal 1") - iter, getWatch := table.Get(txn, idIndex.Query(2)) + iter, listWatch := table.ListWatch(txn, idIndex.Query(2)) items = Collect(iter) require.Len(t, items, 1, "expected Get(2) to return result") require.EqualValues(t, items[0].ID, 2, "expected items[0].ID to equal 2") - // Test First/FirstWatch against the ID index. - _, _, ok := table.First(txn, idIndex.Query(0)) - require.False(t, ok, "expected First(0) to not return result") + // Test Get/GetWatch against the ID index. + _, _, ok := table.Get(txn, idIndex.Query(0)) + require.False(t, ok, "expected Get(0) to not return result") - obj, rev, ok := table.First(txn, idIndex.Query(1)) - require.True(t, ok, "expected First(1) to return result") + obj, rev, ok := table.Get(txn, idIndex.Query(1)) + require.True(t, ok, "expected Get(1) to return result") require.NotZero(t, rev, "expected non-zero revision") require.EqualValues(t, obj.ID, 1, "expected first obj.ID to equal 1") - obj, rev, firstWatch, ok := table.FirstWatch(txn, idIndex.Query(2)) - require.True(t, ok, "expected FirstWatch(2) to return result") + obj, rev, getWatch, ok := table.GetWatch(txn, idIndex.Query(2)) + require.True(t, ok, "expected GetWatch(2) to return result") require.NotZero(t, rev, "expected non-zero revision") require.EqualValues(t, obj.ID, 2, "expected obj.ID to equal 2") select { - case <-firstWatch: - t.Fatalf("FirstWatch channel closed before changes") case <-getWatch: - t.Fatalf("Get channel closed before changes") + t.Fatalf("GetWatch channel closed before changes") + case <-listWatch: + t.Fatalf("List channel closed before changes") default: } @@ -651,28 +651,28 @@ func TestDB_GetFirstLast(t *testing.T) { wtxn.Commit() select { - case <-firstWatch: + case <-getWatch: case <-time.After(watchCloseTimeout): - t.Fatalf("FirstWatch channel not closed after change") + t.Fatalf("GetWatch channel not closed after change") } select { - case <-getWatch: + case <-listWatch: case <-time.After(watchCloseTimeout): - t.Fatalf("Get channel not closed after change") + t.Fatalf("List channel not closed after change") } // Since we modified the database, grab a fresh read transaction. txn = db.ReadTxn() - // Test First and Last against the tags multi-index which will + // Test Get and Last against the tags multi-index which will // return multiple results. - obj, rev, _, ok = table.FirstWatch(txn, tagsIndex.Query("even")) - require.True(t, ok, "expected First(even) to return result") + obj, rev, _, ok = table.GetWatch(txn, tagsIndex.Query("even")) + require.True(t, ok, "expected Get(even) to return result") require.NotZero(t, rev, "expected non-zero revision") require.ElementsMatch(t, obj.Tags.Slice(), []string{"even", "modified"}) require.EqualValues(t, 2, obj.ID) - iter, _ = table.Get(txn, tagsIndex.Query("odd")) + iter = table.List(txn, tagsIndex.Query("odd")) items = Collect(iter) require.Len(t, items, 5, "expected Get(odd) to return 5 items") for i, item := range items { @@ -696,8 +696,8 @@ func TestDB_CommitAbort(t *testing.T) { assert.Greater(t, expvarFloat(metrics.WriteTxnAcquisitionVar.Get("test-handle/test")), 0.0, "WriteTxnAcquisition") assert.Greater(t, expvarFloat(metrics.WriteTxnDurationVar.Get("test-handle/test")), 0.0, "WriteTxnDuration") - obj, rev, ok := table.First(db.ReadTxn(), idIndex.Query(123)) - require.True(t, ok, "expected First(1) to return result") + obj, rev, ok := table.Get(db.ReadTxn(), idIndex.Query(123)) + require.True(t, ok, "expected Get(1) to return result") require.NotZero(t, rev, "expected non-zero revision") require.EqualValues(t, obj.ID, 123, "expected obj.ID to equal 123") require.Zero(t, obj.Tags.Len(), "expected no tags") @@ -715,7 +715,7 @@ func TestDB_CommitAbort(t *testing.T) { // Check that insert after commit and insert after abort do not change the // table. - obj, newRev, ok := table.First(db.ReadTxn(), idIndex.Query(123)) + obj, newRev, ok := table.Get(db.ReadTxn(), idIndex.Query(123)) require.True(t, ok, "expected object to exist") require.Equal(t, rev, newRev, "expected unchanged revision") require.EqualValues(t, obj.ID, 123, "expected obj.ID to equal 123") @@ -745,7 +745,7 @@ func TestDB_CompareAndSwap_CompareAndDelete(t *testing.T) { table.Insert(wtxn, testObject{ID: 1}) wtxn.Commit() - obj, rev1, ok := table.First(db.ReadTxn(), idIndex.Query(1)) + obj, rev1, ok := table.Get(db.ReadTxn(), idIndex.Query(1)) require.True(t, ok) // Updating an object with matching revision number works @@ -757,7 +757,7 @@ func TestDB_CompareAndSwap_CompareAndDelete(t *testing.T) { require.EqualValues(t, 1, oldObj.ID) wtxn.Commit() - obj, _, ok = table.First(db.ReadTxn(), idIndex.Query(1)) + obj, _, ok = table.Get(db.ReadTxn(), idIndex.Query(1)) require.True(t, ok) require.Equal(t, 1, obj.Tags.Len()) v, _ := obj.Tags.All().Next() @@ -772,7 +772,7 @@ func TestDB_CompareAndSwap_CompareAndDelete(t *testing.T) { require.EqualValues(t, 1, oldObj.ID) wtxn.Commit() - obj, _, ok = table.First(db.ReadTxn(), idIndex.Query(1)) + obj, _, ok = table.Get(db.ReadTxn(), idIndex.Query(1)) require.True(t, ok) require.Equal(t, 1, obj.Tags.Len()) v, _ = obj.Tags.All().Next() @@ -787,7 +787,7 @@ func TestDB_CompareAndSwap_CompareAndDelete(t *testing.T) { require.EqualValues(t, 1, oldObj.ID) wtxn.Commit() - obj, rev2, ok := table.First(db.ReadTxn(), idIndex.Query(1)) + obj, rev2, ok := table.Get(db.ReadTxn(), idIndex.Query(1)) require.True(t, ok) require.Equal(t, 1, obj.Tags.Len()) v, _ = obj.Tags.All().Next() @@ -802,7 +802,7 @@ func TestDB_CompareAndSwap_CompareAndDelete(t *testing.T) { require.EqualValues(t, 1, oldObj.ID) wtxn.Commit() - _, _, ok = table.First(db.ReadTxn(), idIndex.Query(1)) + _, _, ok = table.Get(db.ReadTxn(), idIndex.Query(1)) require.False(t, ok) // Deleting non-existing object yields not found diff --git a/derive.go b/derive.go index 4474df1..aadfc86 100644 --- a/derive.go +++ b/derive.go @@ -68,7 +68,7 @@ type derive[In, Out any] struct { transform func(obj In, deleted bool) (Out, DeriveResult) } -func (d derive[In, Out]) loop(ctx context.Context, health cell.Health) error { +func (d derive[In, Out]) loop(ctx context.Context, _ cell.Health) error { out := d.OutTable txn := d.DB.WriteTxn(d.InTable) iter, err := d.InTable.Changes(txn) @@ -85,7 +85,7 @@ func (d derive[In, Out]) loop(ctx context.Context, health cell.Health) error { case DeriveInsert: _, _, err = out.Insert(wtxn, outObj) case DeriveUpdate: - _, _, found := out.First(wtxn, out.PrimaryIndexer().QueryFromObject(outObj)) + _, _, found := out.Get(wtxn, out.PrimaryIndexer().QueryFromObject(outObj)) if found { _, _, err = out.Insert(wtxn, outObj) } diff --git a/fuzz_test.go b/fuzz_test.go index 93626b0..a42e205 100644 --- a/fuzz_test.go +++ b/fuzz_test.go @@ -271,9 +271,9 @@ func allAction(ctx actionContext) { ctx.log.log("%s: All => %d found", ctx.table.Name(), len(statedb.Collect(iter))) } -func getAction(ctx actionContext) { +func listAction(ctx actionContext) { value := mkValue() - iter, _ := ctx.table.Get(ctx.txn, valueIndex.Query(value)) + iter := ctx.table.List(ctx.txn, valueIndex.Query(value)) ctx.log.log("%s: Get(%d)", ctx.table.Name(), value) for obj, _, ok := iter.Next(); ok; obj, _, ok = iter.Next() { if e, ok2 := ctx.txnLog.latest[tableAndID{ctx.table.Name(), obj.id}]; ok2 { @@ -296,25 +296,25 @@ func getAction(ctx actionContext) { } } -func firstAction(ctx actionContext) { +func getAction(ctx actionContext) { id := mkID() - obj, rev, ok := ctx.table.First(ctx.txn, idIndex.Query(id)) + obj, rev, ok := ctx.table.Get(ctx.txn, idIndex.Query(id)) if e, ok2 := ctx.txnLog.latest[tableAndID{ctx.table.Name(), id}]; ok2 { if e.act == actInsert { if !ok { - panic("First() returned not found, expected last inserted value") + panic("Get() returned not found, expected last inserted value") } if e.value != obj.value { - panic("First() did not return the last write") + panic("Get() did not return the last write") } } else if e.act == actDelete { if ok { - panic("First() returned value even though it was deleted") + panic("Get() returned value even though it was deleted") } } } - ctx.log.log("%s: First(%s) => rev=%d, ok=%v", ctx.table.Name(), id, rev, ok) + ctx.log.log("%s: Get(%s) => rev=%d, ok=%v", ctx.table.Name(), id, rev, ok) } func lowerboundAction(ctx actionContext) { @@ -358,10 +358,10 @@ var actions = []action{ deleteAction, deleteAction, deleteAction, deleteManyAction, deleteAllAction, - firstAction, firstAction, firstAction, firstAction, firstAction, - firstAction, firstAction, firstAction, firstAction, firstAction, - firstAction, firstAction, firstAction, firstAction, firstAction, getAction, getAction, getAction, getAction, getAction, + getAction, getAction, getAction, getAction, getAction, + getAction, getAction, getAction, getAction, getAction, + listAction, listAction, listAction, listAction, listAction, allAction, allAction, lowerboundAction, lowerboundAction, lowerboundAction, prefixAction, prefixAction, prefixAction, diff --git a/reconciler/benchmark/main.go b/reconciler/benchmark/main.go index e94e289..02a8978 100644 --- a/reconciler/benchmark/main.go +++ b/reconciler/benchmark/main.go @@ -188,7 +188,7 @@ func main() { // Wait for all to be reconciled by waiting for the last added objects to be marked // reconciled. This only works here since none of the operations fail. for { - obj, _, watch, ok := testObjects.FirstWatch(db.ReadTxn(), idIndex.Query(id-1)) + obj, _, watch, ok := testObjects.GetWatch(db.ReadTxn(), idIndex.Query(id-1)) if ok && obj.status.Kind == reconciler.StatusKindDone { break } diff --git a/reconciler/example/main.go b/reconciler/example/main.go index 2f845a1..6ab3abc 100644 --- a/reconciler/example/main.go +++ b/reconciler/example/main.go @@ -194,7 +194,7 @@ func registerHTTPServer( w.WriteHeader(http.StatusOK) case "DELETE": - memo, _, ok := memos.First(txn, MemoNameIndex.Query(name)) + memo, _, ok := memos.Get(txn, MemoNameIndex.Query(name)) if !ok { w.WriteHeader(http.StatusNotFound) return diff --git a/reconciler/incremental.go b/reconciler/incremental.go index 76cfc3e..7d6c5e1 100644 --- a/reconciler/incremental.go +++ b/reconciler/incremental.go @@ -183,7 +183,7 @@ func (round *incrementalRound[Obj]) processRetries() { } round.retries.Pop() - obj, rev, found := round.table.First(round.txn, round.primaryIndexer.QueryFromObject(robj.(Obj))) + obj, rev, found := round.table.Get(round.txn, round.primaryIndexer.QueryFromObject(robj.(Obj))) if found { status := round.config.GetObjectStatus(obj) if status.Kind != StatusKindError { diff --git a/reconciler/reconciler.go b/reconciler/reconciler.go index 3138898..e0e9a5f 100644 --- a/reconciler/reconciler.go +++ b/reconciler/reconciler.go @@ -95,8 +95,8 @@ func WaitForReconciliation[Obj any](ctx context.Context, db *statedb.DB, table s txn := db.ReadTxn() // See if there are any pending or error'd objects. - _, _, watchPending, okPending := table.FirstWatch(txn, statusIndex.Query(StatusKindPending)) - _, _, watchError, okError := table.FirstWatch(txn, statusIndex.Query(StatusKindError)) + _, _, watchPending, okPending := table.GetWatch(txn, statusIndex.Query(StatusKindPending)) + _, _, watchError, okError := table.GetWatch(txn, statusIndex.Query(StatusKindError)) if !okPending && !okError { return nil } diff --git a/reconciler/reconciler_test.go b/reconciler/reconciler_test.go index 7f19ebf..d93f441 100644 --- a/reconciler/reconciler_test.go +++ b/reconciler/reconciler_test.go @@ -508,12 +508,12 @@ func (h testHelper) markForDelete(id uint64) { func (h testHelper) expectStatus(id uint64, kind reconciler.StatusKind, err string) { cond := func() bool { - obj, _, ok := h.tbl.First(h.db.ReadTxn(), idIndex.Query(id)) + obj, _, ok := h.tbl.Get(h.db.ReadTxn(), idIndex.Query(id)) return ok && obj.status.Kind == kind && obj.status.Error == err } if !assert.Eventually(h.t, cond, time.Second, time.Millisecond) { actual := "" - obj, _, ok := h.tbl.First(h.db.ReadTxn(), idIndex.Query(id)) + obj, _, ok := h.tbl.Get(h.db.ReadTxn(), idIndex.Query(id)) if ok { actual = string(obj.status.Kind) } @@ -525,12 +525,12 @@ func (h testHelper) expectStatus(id uint64, kind reconciler.StatusKind, err stri func (h testHelper) expectNumUpdates(id uint64, n int) { cond := func() bool { - obj, _, ok := h.tbl.First(h.db.ReadTxn(), idIndex.Query(id)) + obj, _, ok := h.tbl.Get(h.db.ReadTxn(), idIndex.Query(id)) return ok && obj.updates == n } if !assert.Eventually(h.t, cond, time.Second, time.Millisecond) { actual := "" - obj, _, ok := h.tbl.First(h.db.ReadTxn(), idIndex.Query(id)) + obj, _, ok := h.tbl.Get(h.db.ReadTxn(), idIndex.Query(id)) if ok { actual = fmt.Sprintf("%d", obj.updates) } @@ -542,7 +542,7 @@ func (h testHelper) expectNumUpdates(id uint64, n int) { func (h testHelper) expectNotFound(id uint64) { h.t.Helper() cond := func() bool { - _, _, ok := h.tbl.First(h.db.ReadTxn(), idIndex.Query(id)) + _, _, ok := h.tbl.Get(h.db.ReadTxn(), idIndex.Query(id)) return !ok } require.Eventually(h.t, cond, time.Second, time.Millisecond, "expected object %d to not be found", id) diff --git a/regression_test.go b/regression_test.go index 09d5998..cc2d6c0 100644 --- a/regression_test.go +++ b/regression_test.go @@ -50,26 +50,26 @@ func Test_Regression_29324(t *testing.T) { // Exact match should only return "foo" txn := db.ReadTxn() - iter, _ := table.Get(txn, idIndex.Query("foo")) + iter := table.List(txn, idIndex.Query("foo")) items := Collect(iter) if assert.Len(t, items, 1, "Get(\"foo\") should return one match") { assert.EqualValues(t, "foo", items[0].ID) } // Partial match on prefix should not return anything - iter, _ = table.Get(txn, idIndex.Query("foob")) + iter = table.List(txn, idIndex.Query("foob")) items = Collect(iter) assert.Len(t, items, 0, "Get(\"foob\") should return nothing") // Query on non-unique index should only return exact match - iter, _ = table.Get(txn, tagIndex.Query("aa")) + iter = table.List(txn, tagIndex.Query("aa")) items = Collect(iter) if assert.Len(t, items, 1, "Get(\"aa\") on tags should return one match") { assert.EqualValues(t, "foo", items[0].ID) } // Partial match on prefix should not return anything on non-unique index - iter, _ = table.Get(txn, idIndex.Query("a")) + iter = table.List(txn, idIndex.Query("a")) items = Collect(iter) assert.Len(t, items, 0, "Get(\"a\") should return nothing") diff --git a/table.go b/table.go index a152467..5bd325c 100644 --- a/table.go +++ b/table.go @@ -197,12 +197,12 @@ func (t *genTable[Obj]) NumObjects(txn ReadTxn) int { return table.indexes[PrimaryIndexPos].tree.Len() } -func (t *genTable[Obj]) First(txn ReadTxn, q Query[Obj]) (obj Obj, revision uint64, ok bool) { - obj, revision, _, ok = t.FirstWatch(txn, q) +func (t *genTable[Obj]) Get(txn ReadTxn, q Query[Obj]) (obj Obj, revision uint64, ok bool) { + obj, revision, _, ok = t.GetWatch(txn, q) return } -func (t *genTable[Obj]) FirstWatch(txn ReadTxn, q Query[Obj]) (obj Obj, revision uint64, watch <-chan struct{}, ok bool) { +func (t *genTable[Obj]) GetWatch(txn ReadTxn, q Query[Obj]) (obj Obj, revision uint64, watch <-chan struct{}, ok bool) { indexTxn := txn.getTxn().mustIndexReadTxn(t, t.indexPos(q.index)) var iobj object if indexTxn.unique { @@ -261,7 +261,12 @@ func (t *genTable[Obj]) All(txn ReadTxn) (Iterator[Obj], <-chan struct{}) { return &iterator[Obj]{indexTxn.Iterator()}, watch } -func (t *genTable[Obj]) Get(txn ReadTxn, q Query[Obj]) (Iterator[Obj], <-chan struct{}) { +func (t *genTable[Obj]) List(txn ReadTxn, q Query[Obj]) Iterator[Obj] { + iter, _ := t.ListWatch(txn, q) + return iter +} + +func (t *genTable[Obj]) ListWatch(txn ReadTxn, q Query[Obj]) (Iterator[Obj], <-chan struct{}) { indexTxn := txn.getTxn().mustIndexReadTxn(t, t.indexPos(q.index)) iter, watch := indexTxn.Prefix(q.key) if indexTxn.unique { diff --git a/types.go b/types.go index dc7351b..cda0410 100644 --- a/types.go +++ b/types.go @@ -42,17 +42,20 @@ type Table[Obj any] interface { // channel that is closed when the table changes. All(ReadTxn) (Iterator[Obj], <-chan struct{}) - // Get returns an iterator for all objects matching the given query + // List returns an iterator for all objects matching the given query. + List(ReadTxn, Query[Obj]) Iterator[Obj] + + // ListWatch returns an iterator for all objects matching the given query // and a watch channel that is closed if the query results are // invalidated by a write to the table. - Get(ReadTxn, Query[Obj]) (Iterator[Obj], <-chan struct{}) + ListWatch(ReadTxn, Query[Obj]) (Iterator[Obj], <-chan struct{}) - // First returns the first matching object for the query. - First(ReadTxn, Query[Obj]) (obj Obj, rev Revision, found bool) + // Get returns the first matching object for the query. + Get(ReadTxn, Query[Obj]) (obj Obj, rev Revision, found bool) - // FirstWatch return the first matching object and a watch channel + // GetWatch return the first matching object and a watch channel // that is closed if the query is invalidated. - FirstWatch(ReadTxn, Query[Obj]) (obj Obj, rev Revision, watch <-chan struct{}, found bool) + GetWatch(ReadTxn, Query[Obj]) (obj Obj, rev Revision, watch <-chan struct{}, found bool) // LowerBound returns an iterator for objects that have a key // greater or equal to the query. The returned watch channel is closed