Skip to content

Commit 78bc6dd

Browse files
committed
Merge branch 'main' into felipe_retry_change_stream
2 parents 983efad + c0c8966 commit 78bc6dd

File tree

4 files changed

+358
-258
lines changed

4 files changed

+358
-258
lines changed

internal/util/collections.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package util
2+
3+
import (
4+
"context"
5+
6+
"github.com/10gen/migration-verifier/option"
7+
"github.com/pkg/errors"
8+
"go.mongodb.org/mongo-driver/bson"
9+
"go.mongodb.org/mongo-driver/bson/primitive"
10+
"go.mongodb.org/mongo-driver/mongo"
11+
)
12+
13+
// CollectionSpec is like mongo.CollectionSpecification except:
14+
// - IDIndex is a bson.Raw rather than mongo.IndexSpecification.
15+
// - It can detect unexpected fields.
16+
type CollectionSpec struct {
17+
Name string
18+
Type string
19+
Options bson.Raw
20+
Info struct {
21+
ReadOnly bool `bson:"readOnly"`
22+
UUID primitive.Binary
23+
24+
Extra map[string]any
25+
}
26+
IDIndex bson.Raw `bson:"idIndex"`
27+
28+
Extra map[string]any
29+
}
30+
31+
// FullName returns the collection's full namespace.
32+
func FullName(collection *mongo.Collection) string {
33+
return collection.Database().Name() + "." + collection.Name()
34+
}
35+
36+
// GetCollectionSpecIfExists returns the given collection’s specification,
37+
// or empty if the collection doesn’t exist. If any unexpected properties
38+
// exist in the collection specification then an error is returned.
39+
func GetCollectionSpecIfExists(
40+
ctx context.Context,
41+
coll *mongo.Collection,
42+
) (option.Option[CollectionSpec], error) {
43+
cursor, err := coll.Database().ListCollections(ctx, bson.M{"name": coll.Name()})
44+
if err != nil {
45+
return option.None[CollectionSpec](), errors.Wrapf(
46+
err,
47+
"failed to fetch %#q's specification",
48+
FullName(coll),
49+
)
50+
}
51+
52+
var specs []CollectionSpec
53+
err = cursor.All(ctx, &specs)
54+
if err != nil {
55+
return option.None[CollectionSpec](), errors.Wrapf(
56+
err,
57+
"failed to parse %#q's specification",
58+
FullName(coll),
59+
)
60+
}
61+
62+
switch len(specs) {
63+
case 0:
64+
return option.None[CollectionSpec](), nil
65+
case 1:
66+
if len(specs[0].Extra) > 0 || len(specs[0].Info.Extra) > 0 {
67+
return option.None[CollectionSpec](), errors.Wrapf(
68+
err,
69+
"%#q's specification (%v) contains unrecognized fields",
70+
FullName(coll),
71+
specs[0],
72+
)
73+
}
74+
75+
return option.Some(specs[0]), nil
76+
}
77+
78+
return option.None[CollectionSpec](), errors.Wrapf(
79+
err,
80+
"received multiple results (%v) when fetching %#q's specification",
81+
specs,
82+
FullName(coll),
83+
)
84+
}

0 commit comments

Comments
 (0)