diff --git a/core/option/options.go b/core/option/options.go index 6bca059e92..28fb6a4ea3 100644 --- a/core/option/options.go +++ b/core/option/options.go @@ -256,6 +256,7 @@ var ( _ InsertOptioner = (*OptOrdered)(nil) _ InsertOptioner = (*OptWriteConcern)(nil) _ ListDatabasesOptioner = OptNameOnly(false) + _ ListCollectionsOptioner = OptNameOnly(false) _ ListIndexesOptioner = OptBatchSize(0) _ ReplaceOptioner = (*OptBypassDocumentValidation)(nil) _ ReplaceOptioner = (*OptCollation)(nil) @@ -734,4 +735,5 @@ func (opt OptNameOnly) Option(d *bson.Document) error { return nil } -func (OptNameOnly) listDatabasesOption() {} +func (OptNameOnly) listDatabasesOption() {} +func (OptNameOnly) listCollectionsOption() {} diff --git a/mongo/database.go b/mongo/database.go index 43ca0054ca..cec18b87a1 100644 --- a/mongo/database.go +++ b/mongo/database.go @@ -13,6 +13,7 @@ import ( "github.com/mongodb/mongo-go-driver/core/command" "github.com/mongodb/mongo-go-driver/core/description" "github.com/mongodb/mongo-go-driver/core/dispatch" + "github.com/mongodb/mongo-go-driver/core/option" "github.com/mongodb/mongo-go-driver/core/readconcern" "github.com/mongodb/mongo-go-driver/core/readpref" "github.com/mongodb/mongo-go-driver/core/writeconcern" @@ -90,3 +91,21 @@ func (db *Database) Drop(ctx context.Context) error { } return nil } + +// ListCollections list collections from mongodb database. +func (db *Database) ListCollections(ctx context.Context, filter *bson.Document, options ...option.ListCollectionsOptioner) (command.Cursor, error) { + if ctx == nil { + ctx = context.Background() + } + cmd := command.ListCollections{ + DB: db.name, + Filter: filter, + Opts: options, + } + cursor, err := dispatch.ListCollections(ctx, cmd, db.client.topology, db.readSelector) + if err != nil && !command.IsNotFound(err) { + return nil, err + } + return cursor, nil + +} diff --git a/mongo/database_internal_test.go b/mongo/database_internal_test.go index 28ec7b19fe..dd6530bedb 100644 --- a/mongo/database_internal_test.go +++ b/mongo/database_internal_test.go @@ -11,6 +11,7 @@ import ( "testing" "github.com/mongodb/mongo-go-driver/bson" + "github.com/mongodb/mongo-go-driver/core/option" "github.com/mongodb/mongo-go-driver/internal/testutil" "github.com/stretchr/testify/require" ) @@ -70,3 +71,79 @@ func TestDatabase_Drop(t *testing.T) { require.NotContains(t, list, name) } + +func TestDatabase_ListCollections(t *testing.T) { + t.Parallel() + dbName := "db_list_collection" + db := createTestDatabase(t, &dbName) + collName := "list_collections_name" + coll := db.Collection(collName) + require.Equal(t, coll.Name(), collName) + require.NotNil(t, coll) + cursor, err := db.ListCollections(context.Background(), nil) + require.NoError(t, err) + + next := bson.NewDocument() + + for cursor.Next(context.Background()) { + err = cursor.Decode(next) + require.NoError(t, err) + + elem, err := next.LookupErr("name") + require.NoError(t, err) + if elem.Type() != bson.TypeString { + t.Errorf("Incorrect type for 'name'. got %v; want %v", elem.Type(), bson.TypeString) + t.FailNow() + } + if elem.StringValue() != collName { + t.Errorf("Incorrect collection name. got %s: want %s", elem.StringValue(), collName) + t.FailNow() + } + //Because we run it without nameOnly parameter we should check if another parameter is exist + docType, err := next.LookupErr("type") + require.NoError(t, err) + if docType.StringValue() != "collections" { + t.Errorf("Incorrect cursor type. got %s: want %s", docType.StringValue(), "collections") + t.FailNow() + } + } + defer func() { + err := db.Drop(context.Background()) + require.NoError(t, err) + }() +} + +func TestDatabase_ListCollectionsOptions(t *testing.T) { + t.Parallel() + dbName := "db_list_collection_options" + db := createTestDatabase(t, &dbName) + collName := "list_collections_options" + coll := db.Collection(collName) + require.Equal(t, coll.Name(), collName) + require.NotNil(t, coll) + cursor, err := db.ListCollections(context.Background(), nil, option.OptNameOnly(true)) + require.NoError(t, err) + + next := bson.NewDocument() + + for cursor.Next(context.Background()) { + err = cursor.Decode(next) + require.NoError(t, err) + + elem, err := next.LookupErr("name") + require.NoError(t, err) + + if elem.StringValue() != collName { + t.Errorf("Incorrect collection name. got %s: want %s", elem.StringValue(), collName) + t.FailNow() + } + + //Because we run it with name only parameter we should check that there are no other parameters + _, err = next.LookupErr("type") + require.Error(t, err) + } + defer func() { + err := db.Drop(context.Background()) + require.NoError(t, err) + }() +}