Skip to content

Commit 813c368

Browse files
Divjot Arorarfblue2
authored andcommitted
Add mongo/dbopt
GODRIVER-272 Change-Id: Ie3af88a02a1bf64ab0a07a5a74438215382cdf1e
1 parent b5643d5 commit 813c368

File tree

6 files changed

+423
-23
lines changed

6 files changed

+423
-23
lines changed

core/command/list_collections.go

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import (
1212
"github.com/mongodb/mongo-go-driver/bson"
1313
"github.com/mongodb/mongo-go-driver/core/description"
1414
"github.com/mongodb/mongo-go-driver/core/option"
15+
"github.com/mongodb/mongo-go-driver/core/readpref"
1516
"github.com/mongodb/mongo-go-driver/core/wiremessage"
1617
)
1718

@@ -23,8 +24,9 @@ type ListCollections struct {
2324
Filter *bson.Document
2425
Opts []option.ListCollectionsOptioner
2526

26-
result Cursor
27-
err error
27+
result Cursor
28+
ReadPref *readpref.ReadPref
29+
err error
2830
}
2931

3032
// Encode will encode this command into a wire message for the given server description.
@@ -45,7 +47,7 @@ func (lc *ListCollections) Encode(desc description.SelectedServer) (wiremessage.
4547
}
4648
}
4749

48-
return (&Command{DB: lc.DB, Command: cmd, isWrite: true}).Encode(desc)
50+
return (&Command{DB: lc.DB, Command: cmd, isWrite: true, ReadPref: lc.ReadPref}).Encode(desc)
4951
}
5052

5153
// Decode will decode the wire message using the provided server description. Errors during decoding

mongo/client.go

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"github.com/mongodb/mongo-go-driver/core/topology"
2222
"github.com/mongodb/mongo-go-driver/core/writeconcern"
2323
"github.com/mongodb/mongo-go-driver/mongo/clientopt"
24+
"github.com/mongodb/mongo-go-driver/mongo/dbopt"
2425
)
2526

2627
const defaultLocalThreshold = 15 * time.Millisecond
@@ -212,8 +213,8 @@ func readPreferenceFromConnString(cs *connstring.ConnString) (*readpref.ReadPref
212213
}
213214

214215
// Database returns a handle for a given database.
215-
func (c *Client) Database(name string) *Database {
216-
return newDatabase(c, name)
216+
func (c *Client) Database(name string, opts ...dbopt.Option) *Database {
217+
return newDatabase(c, name, opts...)
217218
}
218219

219220
// ConnectionString returns the connection string of the cluster the client is connected to.

mongo/database.go

Lines changed: 34 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import (
1818
"github.com/mongodb/mongo-go-driver/core/readpref"
1919
"github.com/mongodb/mongo-go-driver/core/writeconcern"
2020
"github.com/mongodb/mongo-go-driver/mongo/collectionopt"
21+
"github.com/mongodb/mongo-go-driver/mongo/dbopt"
2122
)
2223

2324
// Database performs operations on a given database.
@@ -31,13 +32,33 @@ type Database struct {
3132
writeSelector description.ServerSelector
3233
}
3334

34-
func newDatabase(client *Client, name string) *Database {
35+
func newDatabase(client *Client, name string, opts ...dbopt.Option) *Database {
36+
dbOpt, err := dbopt.BundleDatabase(opts...).Unbundle()
37+
if err != nil {
38+
return nil
39+
}
40+
41+
rc := client.readConcern
42+
if dbOpt.ReadConcern != nil {
43+
rc = dbOpt.ReadConcern
44+
}
45+
46+
rp := client.readPreference
47+
if dbOpt.ReadPreference != nil {
48+
rp = dbOpt.ReadPreference
49+
}
50+
51+
wc := client.writeConcern
52+
if dbOpt.WriteConcern != nil {
53+
wc = dbOpt.WriteConcern
54+
}
55+
3556
db := &Database{
3657
client: client,
3758
name: name,
38-
readPreference: client.readPreference,
39-
readConcern: client.readConcern,
40-
writeConcern: client.writeConcern,
59+
readPreference: rp,
60+
readConcern: rc,
61+
writeConcern: wc,
4162
}
4263

4364
db.readSelector = description.CompositeSelector([]description.ServerSelector{
@@ -73,7 +94,11 @@ func (db *Database) RunCommand(ctx context.Context, runCommand interface{}) (bso
7394
ctx = context.Background()
7495
}
7596

76-
cmd := command.Command{DB: db.Name(), Command: runCommand}
97+
cmd := command.Command{
98+
DB: db.Name(),
99+
Command: runCommand,
100+
ReadPref: db.readPreference,
101+
}
77102
return dispatch.Command(ctx, cmd, db.client.topology, db.writeSelector)
78103
}
79104

@@ -99,9 +124,10 @@ func (db *Database) ListCollections(ctx context.Context, filter *bson.Document,
99124
ctx = context.Background()
100125
}
101126
cmd := command.ListCollections{
102-
DB: db.name,
103-
Filter: filter,
104-
Opts: options,
127+
DB: db.name,
128+
Filter: filter,
129+
Opts: options,
130+
ReadPref: db.readPreference,
105131
}
106132
cursor, err := dispatch.ListCollections(ctx, cmd, db.client.topology, db.readSelector)
107133
if err != nil && !command.IsNotFound(err) {

mongo/database_internal_test.go

Lines changed: 82 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,18 +15,22 @@ import (
1515

1616
"github.com/mongodb/mongo-go-driver/bson"
1717
"github.com/mongodb/mongo-go-driver/bson/objectid"
18+
"github.com/mongodb/mongo-go-driver/core/readconcern"
19+
"github.com/mongodb/mongo-go-driver/core/readpref"
20+
"github.com/mongodb/mongo-go-driver/core/writeconcern"
1821
"github.com/mongodb/mongo-go-driver/internal/testutil"
22+
"github.com/mongodb/mongo-go-driver/mongo/dbopt"
1923
"github.com/stretchr/testify/require"
2024
)
2125

22-
func createTestDatabase(t *testing.T, name *string) *Database {
26+
func createTestDatabase(t *testing.T, name *string, opts ...dbopt.Option) *Database {
2327
if name == nil {
2428
db := testutil.DBName(t)
2529
name = &db
2630
}
2731

2832
client := createTestClient(t)
29-
return client.Database(*name)
33+
return client.Database(*name, opts...)
3034
}
3135

3236
func TestDatabase_initialize(t *testing.T) {
@@ -39,6 +43,70 @@ func TestDatabase_initialize(t *testing.T) {
3943
require.NotNil(t, db.client)
4044
}
4145

46+
func compareDbs(t *testing.T, expected *Database, got *Database) {
47+
switch {
48+
case expected.readPreference != got.readPreference:
49+
t.Errorf("expected read preference %#v. got %#v", expected.readPreference, got.readPreference)
50+
case expected.readConcern != got.readConcern:
51+
t.Errorf("expected read concern %#v. got %#v", expected.readConcern, got.readConcern)
52+
case expected.writeConcern != got.writeConcern:
53+
t.Errorf("expected write concern %#v. got %#v", expected.writeConcern, got.writeConcern)
54+
}
55+
}
56+
57+
func TestDatabase_Options(t *testing.T) {
58+
name := "testDb_options"
59+
rpPrimary := readpref.Primary()
60+
rpSecondary := readpref.Secondary()
61+
wc1 := writeconcern.New(writeconcern.W(5))
62+
wc2 := writeconcern.New(writeconcern.W(10))
63+
rcLocal := readconcern.Local()
64+
rcMajority := readconcern.Majority()
65+
66+
opts := []dbopt.Option{dbopt.ReadPreference(rpPrimary), dbopt.ReadConcern(rcLocal), dbopt.WriteConcern(wc1),
67+
dbopt.ReadPreference(rpSecondary), dbopt.ReadConcern(rcMajority), dbopt.WriteConcern(wc2)}
68+
69+
expectedDb := &Database{
70+
readConcern: rcMajority,
71+
readPreference: rpSecondary,
72+
writeConcern: wc2,
73+
}
74+
75+
t.Run("IndividualOptions", func(t *testing.T) {
76+
// if options specified multiple times, last instance should take precedence
77+
db := createTestDatabase(t, &name, opts...)
78+
compareDbs(t, expectedDb, db)
79+
})
80+
81+
t.Run("Bundle", func(t *testing.T) {
82+
db := createTestDatabase(t, &name, dbopt.BundleDatabase(opts...))
83+
compareDbs(t, expectedDb, db)
84+
})
85+
}
86+
87+
func TestDatabase_InheritOptions(t *testing.T) {
88+
name := "testDb_options_inherit"
89+
client := createTestClient(t)
90+
91+
rpPrimary := readpref.Primary()
92+
rcLocal := readconcern.Local()
93+
client.readPreference = rpPrimary
94+
client.readConcern = rcLocal
95+
96+
wc1 := writeconcern.New(writeconcern.W(10))
97+
db := client.Database(name, dbopt.WriteConcern(wc1))
98+
99+
// db should inherit read preference and read concern from client
100+
switch {
101+
case db.readPreference != rpPrimary:
102+
t.Errorf("expected read preference primary. got %#v", db.readPreference)
103+
case db.readConcern != rcLocal:
104+
t.Errorf("expected read concern local. got %#v", db.readConcern)
105+
case db.writeConcern != wc1:
106+
t.Errorf("expected write concern %#v. got %#v", wc1, db.writeConcern)
107+
}
108+
}
109+
42110
func TestDatabase_RunCommand(t *testing.T) {
43111
t.Parallel()
44112

@@ -190,20 +258,24 @@ func listCollectionsTest(db *Database, cappedOnly bool) error {
190258
}
191259

192260
func TestDatabase_ListCollections(t *testing.T) {
193-
// TODO(GODRIVER-272): Add tests for the replica_set topology using the secondary read preference
194261
t.Parallel()
262+
rpPrimary := readpref.Primary()
263+
rpSecondary := readpref.Secondary()
195264

196265
var listCollectionsTable = []struct {
197266
name string
198267
expectedTopology string
199268
cappedOnly bool
269+
rp *readpref.ReadPref
200270
}{
201-
{"standalone_nofilter", "server", false},
202-
{"standalone_filter", "server", true},
203-
{"replicaset_nofilter", "replica_set", false},
204-
{"replicaset_filter", "replica_set", true},
205-
{"sharded_nofilter", "sharded_cluster", false},
206-
{"sharded_filter", "sharded_cluster", true},
271+
{"standalone_nofilter", "server", false, rpPrimary},
272+
{"standalone_filter", "server", true, rpPrimary},
273+
{"replicaset_nofilter", "replica_set", false, rpPrimary},
274+
{"replicaset_filter", "replica_set", true, rpPrimary},
275+
{"replicaset_secondary_nofilter", "replica_set", false, rpSecondary},
276+
{"replicaset_secondary_filter", "replica_set", true, rpSecondary},
277+
{"sharded_nofilter", "sharded_cluster", false, rpPrimary},
278+
{"sharded_filter", "sharded_cluster", true, rpPrimary},
207279
}
208280

209281
for _, tt := range listCollectionsTable {
@@ -212,7 +284,7 @@ func TestDatabase_ListCollections(t *testing.T) {
212284
t.Skip()
213285
}
214286
dbName := "db_list_collections"
215-
db := createTestDatabase(t, &dbName)
287+
db := createTestDatabase(t, &dbName, dbopt.ReadPreference(tt.rp))
216288

217289
defer func() {
218290
err := db.Drop(context.Background())

0 commit comments

Comments
 (0)