Skip to content

Commit

Permalink
Add fields to listCollections.cursor response (#3809)
Browse files Browse the repository at this point in the history
Closes #2815.
  • Loading branch information
henvic authored Dec 8, 2023
1 parent 13d2680 commit 26b27de
Show file tree
Hide file tree
Showing 3 changed files with 148 additions and 2 deletions.
39 changes: 39 additions & 0 deletions integration/commands_administration_compat_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -292,3 +292,42 @@ func TestCommandsAdministrationCompatDBStatsFreeStorage(t *testing.T) {
})
}
}

func TestCommandsAdministrationCompatListCollections(t *testing.T) {
t.Parallel()
ctx, targetCollections, compatCollections := setup.SetupCompat(t)

require.Greater(t, len(targetCollections), 2)

filter := bson.D{{
Key: "name", Value: bson.D{{
Key: "$in", Value: bson.A{
targetCollections[0].Name(),
targetCollections[len(targetCollections)-1].Name(),
},
}},
}}

target, err := targetCollections[0].Database().ListCollections(ctx, filter)
require.NoError(t, err)
var targetRes []bson.D
err = target.All(ctx, &targetRes)
require.NoError(t, err)
docTarget := ConvertDocument(t, targetRes[0])

compat, err := compatCollections[0].Database().ListCollections(ctx, filter)
require.NoError(t, err)
var compatRes []bson.D
err = compat.All(ctx, &compatRes)
require.NoError(t, err)
docCompat := ConvertDocument(t, compatRes[0])

assert.Equal(t, target.RemainingBatchLength(), compat.RemainingBatchLength())

// Check idIndex
targetIDIndex := must.NotFail(docTarget.Get("idIndex"))
compatIDIndex := must.NotFail(docCompat.Get("idIndex"))

assert.NotEmpty(t, targetIDIndex)
assert.Equal(t, targetIDIndex, compatIDIndex)
}
84 changes: 84 additions & 0 deletions integration/commands_administration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,6 +296,90 @@ func TestCommandsAdministrationListDatabases(t *testing.T) {

func TestCommandsAdministrationListCollections(t *testing.T) {
t.Parallel()

ctx, c := setup.Setup(t, shareddata.Scalars)
db := c.Database()

for name, tc := range map[string]struct {
capped bool
sizeInBytes int64
maxDocuments int64
}{
"uncapped": {},
"Size": {
capped: true,
sizeInBytes: 256,
},
"SizeRounded": {
capped: true,
sizeInBytes: 1000,
},
"MaxDocuments": {
capped: true,
sizeInBytes: 100,
maxDocuments: 10,
},
} {
name, tc := name, tc
t.Run(name, func(t *testing.T) {
t.Parallel()

cName := testutil.CollectionName(t) + name
opts := options.CreateCollection()

if tc.capped {
opts.SetCapped(true)
}
if tc.sizeInBytes > 0 {
opts.SetSizeInBytes(tc.sizeInBytes)
}
if tc.maxDocuments > 0 {
opts.SetMaxDocuments(tc.maxDocuments)
}

err := db.CreateCollection(ctx, cName, opts)
assert.NoError(t, err)

cursor, err := db.ListCollections(ctx, bson.D{
{Key: "name", Value: cName},
})
assert.NoError(t, err)

var actual []bson.D
assert.NoError(t, cursor.All(ctx, &actual))
assert.Len(t, actual, 1)

doc := ConvertDocument(t, actual[0])
info := must.NotFail(doc.Get("info")).(*types.Document)

uuid := must.NotFail(info.Get("uuid"))
assert.IsType(t, uuid.(types.Binary).Subtype, types.BinaryUUID)

options := must.NotFail(doc.Get("options")).(*types.Document)

if tc.capped {
assert.True(t, must.NotFail(options.Get("capped")).(bool))
} else {
assert.False(t, options.Has("capped"))
}

if tc.sizeInBytes > 0 {
// Actual values might be larger depending on backend implementations.
//
// And of different types:
// TODO https://github.com/FerretDB/FerretDB/issues/3582
assert.True(t, options.Has("size"), "capped size must exist")
}

if tc.maxDocuments > 0 {
assert.EqualValues(t, tc.maxDocuments, must.NotFail(options.Get("max")), "capped documents")
}
})
}
}

func TestCommandsAdministrationListCollectionNames(t *testing.T) {
t.Parallel()
ctx, targetCollections, compatCollections := setup.SetupCompat(t)

require.Greater(t, len(targetCollections), 2)
Expand Down
27 changes: 25 additions & 2 deletions internal/handler/msg_listcollections.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,23 +81,46 @@ func (h *Handler) MsgListCollections(ctx context.Context, msg *wire.OpMsg) (*wir
d := must.NotFail(types.NewDocument(
"name", collection.Name,
"type", "collection",
"idIndex", must.NotFail(types.NewDocument(
"v", int32(2),
"key", must.NotFail(types.NewDocument("_id", int32(1))),
"name", "_id_",
)),
))

options := must.NotFail(types.NewDocument())
info := must.NotFail(types.NewDocument("readOnly", false))

if collection.Capped() {
options.Set("capped", true)
}

if collection.CappedSize > 0 {
options.Set("size", collection.CappedSize)
}

if collection.CappedDocuments > 0 {
options.Set("max", collection.CappedDocuments)
}

d.Set("options", options)

if collection.UUID != "" {
uuid, err := uuid.Parse(collection.UUID)
if err != nil {
return nil, lazyerrors.Error(err)
}

path := types.NewStaticPath("info", "uuid")
uuidBinary := types.Binary{
Subtype: types.BinaryUUID,
B: must.NotFail(uuid.MarshalBinary()),
}

must.NoError(d.SetByPath(path, uuidBinary))
info.Set("uuid", uuidBinary)
}

d.Set("info", info)

matches, err := common.FilterDocument(d, filter)
if err != nil {
return nil, lazyerrors.Error(err)
Expand Down

0 comments on commit 26b27de

Please sign in to comment.