From ca484d53a24bbd288a7ae62d51737534fe4d8df4 Mon Sep 17 00:00:00 2001 From: Prabhjot Singh Sethi Date: Tue, 5 Aug 2025 16:12:32 +0000 Subject: [PATCH] Handle offset and limits for FindMany response Signed-off-by: Prabhjot Singh Sethi --- db/mongo.go | 12 ++++- db/mongo_test.go | 99 +++++++++++++++++++++++++++++++++++++++++ db/store.go | 2 +- table/cached_generic.go | 7 ++- table/generic.go | 7 ++- 5 files changed, 120 insertions(+), 7 deletions(-) diff --git a/db/mongo.go b/db/mongo.go index f48154b..2a5c3f6 100644 --- a/db/mongo.go +++ b/db/mongo.go @@ -151,11 +151,19 @@ func (c *mongoCollection) FindOne(ctx context.Context, key any, data any) error // Find multiple entries from the store collection for the given filter, where the data // value is returned as a list based on the object type passed to it -func (c *mongoCollection) FindMany(ctx context.Context, filter any, data any) error { +func (c *mongoCollection) FindMany(ctx context.Context, filter any, data any, opts ...any) error { if filter == nil { filter = bson.D{} } - cursor, err := c.col.Find(ctx, filter) + var findOpts []options.Lister[options.FindOptions] + for _, opt := range opts { + val, ok := opt.(options.Lister[options.FindOptions]) + if !ok { + return errors.Wrapf(errors.InvalidArgument, "Invalid option type %T passed to FindMany", opt) + } + findOpts = append(findOpts, val) + } + cursor, err := c.col.Find(ctx, filter, findOpts...) if err != nil { return interpretMongoError(err) } diff --git a/db/mongo_test.go b/db/mongo_test.go index 3309640..3342df3 100644 --- a/db/mongo_test.go +++ b/db/mongo_test.go @@ -5,12 +5,14 @@ package db import ( "context" + "fmt" "reflect" "testing" "time" "go.mongodb.org/mongo-driver/v2/bson" "go.mongodb.org/mongo-driver/v2/mongo" + "go.mongodb.org/mongo-driver/v2/mongo/options" ) type MyKey struct { @@ -106,6 +108,103 @@ func Test_ClientConnection(t *testing.T) { } }) + t.Run("Find_many_with_offset_limits", func(t *testing.T) { + config := &MongoConfig{ + Host: "localhost", + Port: "27017", + Username: "root", + Password: "password", + } + + client, err := NewMongoClient(config) + + if err != nil { + t.Errorf("failed to connect to mongo DB Error: %s", err) + return + } + + s := client.GetDataStore("test") + + col := s.GetCollection("collection1") + + key := &MyKey{ + Name: "test-key", + } + data := &MyData{ + Desc: "sample-description", + Val: &InternaData{ + Test: "abc", + }, + } + + key1 := &MyKey{ + Name: "test-key-1", + } + + key2 := &MyKey{ + Name: "test-key-2", + } + + err = col.InsertOne(context.Background(), key, data) + if err != nil { + t.Errorf("failed to insert an entry to collection Error: %s", err) + } + + err = col.InsertOne(context.Background(), key1, data) + if err != nil { + t.Errorf("failed to insert an entry to collection Error: %s", err) + } + + err = col.InsertOne(context.Background(), key2, data) + if err != nil { + t.Errorf("failed to insert an entry to collection Error: %s", err) + } + + val := &MyData{} + err = col.FindOne(context.Background(), key2, val) + if err != nil { + t.Errorf("failed to find the entry Error: %s", err) + } + fmt.Printf("found entry :%v", *val) + + list := []*MyData{} + opts := options.Find().SetLimit(2).SetSkip(2) + err = col.FindMany(context.Background(), nil, &list, opts) + if err != nil { + t.Errorf("failed to find the entry Error: %s", err) + } + + if len(list) != 1 { + t.Errorf("Expected 1 entries in table but got %d", len(list)) + } + + list = []*MyData{} + opts = options.Find().SetLimit(2).SetSkip(0) + err = col.FindMany(context.Background(), nil, &list, opts) + if err != nil { + t.Errorf("failed to find the entry Error: %s", err) + } + + if len(list) != 2 { + t.Errorf("Expected 2 entries in table but got %d", len(list)) + } + + err = col.DeleteOne(context.Background(), key) + if err != nil { + t.Errorf("failed to delete entry using key Error: %s", err) + } + + err = col.DeleteOne(context.Background(), key1) + if err != nil { + t.Errorf("failed to delete entry using key Error: %s", err) + } + + err = col.DeleteOne(context.Background(), key2) + if err != nil { + t.Errorf("failed to delete entry using key Error: %s", err) + } + }) + t.Run("InValid_Port", func(t *testing.T) { config := &MongoConfig{ Host: "localhost", diff --git a/db/store.go b/db/store.go index 35f5407..fb85eab 100644 --- a/db/store.go +++ b/db/store.go @@ -39,7 +39,7 @@ type StoreCollection interface { // Find multiple entries from the store collection for the given filter, where the data // value is returned as a list based on the object type passed to it - FindMany(ctx context.Context, filter any, data any) error + FindMany(ctx context.Context, filter any, data any, opts ...any) error // Return count of entries matching the provided filter Count(ctx context.Context, filter any) (int64, error) diff --git a/table/cached_generic.go b/table/cached_generic.go index a14e31c..5bfe52a 100644 --- a/table/cached_generic.go +++ b/table/cached_generic.go @@ -9,6 +9,8 @@ import ( "reflect" "sync" + "go.mongodb.org/mongo-driver/v2/mongo/options" + "github.com/go-core-stack/core/db" "github.com/go-core-stack/core/errors" "github.com/go-core-stack/core/reconciler" @@ -194,12 +196,13 @@ func (t *CachedTable[K, E]) DBFind(ctx context.Context, key *K) (*E, error) { // DBFindMany retrieves multiple entries matching the provided filter from database. // Returns a slice of entries and error if none found or if the table is not initialized. -func (t *CachedTable[K, E]) DBFindMany(ctx context.Context, filter any) ([]*E, error) { +func (t *CachedTable[K, E]) DBFindMany(ctx context.Context, filter any, offset, limit int32) ([]*E, error) { if t.col == nil { return nil, errors.Wrapf(errors.InvalidArgument, "Table not initialized") } var data []*E - err := t.col.FindMany(ctx, filter, &data) + opts := options.Find().SetLimit(int64(limit)).SetSkip(int64(offset)) + err := t.col.FindMany(ctx, filter, &data, opts) if err != nil { return nil, errors.Wrapf(errors.NotFound, "failed to find any entry: %s", err) } diff --git a/table/generic.go b/table/generic.go index c1c550a..2b7d3b7 100644 --- a/table/generic.go +++ b/table/generic.go @@ -8,6 +8,8 @@ import ( "log" "reflect" + "go.mongodb.org/mongo-driver/v2/mongo/options" + "github.com/go-core-stack/core/db" "github.com/go-core-stack/core/errors" "github.com/go-core-stack/core/reconciler" @@ -193,12 +195,13 @@ func (t *Table[K, E]) Find(ctx context.Context, key *K) (*E, error) { // FindMany retrieves multiple entries matching the provided filter. // Returns a slice of entries and error if none found or if the table is not initialized. -func (t *Table[K, E]) FindMany(ctx context.Context, filter any) ([]*E, error) { +func (t *Table[K, E]) FindMany(ctx context.Context, filter any, offset, limit int32) ([]*E, error) { if t.col == nil { return nil, errors.Wrapf(errors.InvalidArgument, "Table not initialized") } var data []*E - err := t.col.FindMany(ctx, filter, &data) + opts := options.Find().SetLimit(int64(limit)).SetSkip(int64(offset)) + err := t.col.FindMany(ctx, filter, &data, opts) if err != nil { return nil, errors.Wrapf(errors.NotFound, "failed to find any entry: %s", err) }