Skip to content

Commit 35351c9

Browse files
committed
updates
1 parent 4d88edf commit 35351c9

File tree

11 files changed

+209
-96
lines changed

11 files changed

+209
-96
lines changed

internal/integration/client_test.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import (
2828
"go.mongodb.org/mongo-driver/v2/mongo"
2929
"go.mongodb.org/mongo-driver/v2/mongo/options"
3030
"go.mongodb.org/mongo-driver/v2/mongo/readpref"
31+
"go.mongodb.org/mongo-driver/v2/mongo/writeconcern"
3132
"go.mongodb.org/mongo-driver/v2/x/bsonx/bsoncore"
3233
"go.mongodb.org/mongo-driver/v2/x/mongo/driver"
3334
"go.mongodb.org/mongo-driver/v2/x/mongo/driver/wiremessage"
@@ -718,6 +719,77 @@ func TestClient(t *testing.T) {
718719
})
719720
}
720721
})
722+
mtBulkWriteOpts := mtest.NewOptions().MinServerVersion("8.0").AtlasDataLake(false).ClientType(mtest.Pinned)
723+
mt.RunOpts("bulk write with nil filter", mtBulkWriteOpts, func(mt *mtest.T) {
724+
mt.Parallel()
725+
726+
testCases := []struct {
727+
name string
728+
models *mongo.ClientWriteModels
729+
}{
730+
{
731+
name: "DeleteOne",
732+
models: (&mongo.ClientWriteModels{}).AppendDeleteOne("foo", "bar", mongo.NewClientDeleteOneModel()),
733+
},
734+
{
735+
name: "DeleteMany",
736+
models: (&mongo.ClientWriteModels{}).AppendDeleteMany("foo", "bar", mongo.NewClientDeleteManyModel()),
737+
},
738+
{
739+
name: "UpdateOne",
740+
models: (&mongo.ClientWriteModels{}).AppendUpdateOne("foo", "bar", mongo.NewClientUpdateOneModel()),
741+
},
742+
{
743+
name: "UpdateMany",
744+
models: (&mongo.ClientWriteModels{}).AppendUpdateMany("foo", "bar", mongo.NewClientUpdateManyModel()),
745+
},
746+
}
747+
for _, tc := range testCases {
748+
tc := tc
749+
750+
mt.Run(tc.name, func(mt *mtest.T) {
751+
mt.Parallel()
752+
753+
_, err := mt.Client.BulkWrite(context.Background(), tc.models)
754+
require.ErrorContains(mt, err, "filter is required")
755+
})
756+
}
757+
})
758+
mt.RunOpts("bulk write with write concern", mtBulkWriteOpts, func(mt *mtest.T) {
759+
mt.Parallel()
760+
761+
testCases := []struct {
762+
name string
763+
opts *options.ClientBulkWriteOptionsBuilder
764+
want bool
765+
}{
766+
{
767+
name: "unacknowledged",
768+
opts: options.ClientBulkWrite().SetWriteConcern(writeconcern.Unacknowledged()).SetOrdered(false),
769+
want: false,
770+
},
771+
{
772+
name: "acknowledged",
773+
want: true,
774+
},
775+
}
776+
for _, tc := range testCases {
777+
tc := tc
778+
779+
mt.Run(tc.name, func(mt *mtest.T) {
780+
mt.Parallel()
781+
782+
var models *mongo.ClientWriteModels
783+
784+
insertOneModel := mongo.NewClientInsertOneModel().SetDocument(bson.D{{"x", 1}})
785+
models = (&mongo.ClientWriteModels{}).AppendInsertOne("foo", "bar", insertOneModel)
786+
res, err := mt.Client.BulkWrite(context.Background(), models, tc.opts)
787+
require.NoError(mt, err, "BulkWrite error: %v", err)
788+
require.NotNil(mt, res, "expected a ClientBulkWriteResult")
789+
assert.Equal(mt, res.Acknowledged, tc.want, "expected Acknowledged: %v, got: %v", tc.want, res.Acknowledged)
790+
})
791+
}
792+
})
721793
}
722794

723795
func TestClient_BSONOptions(t *testing.T) {

internal/integration/collection_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1713,6 +1713,41 @@ func TestCollection(t *testing.T) {
17131713
})
17141714
}
17151715
})
1716+
mt.Run("error on nil filter", func(mt *mtest.T) {
1717+
mt.Parallel()
1718+
1719+
testCases := []struct {
1720+
name string
1721+
model mongo.WriteModel
1722+
}{
1723+
{
1724+
name: "DeleteOne",
1725+
model: mongo.NewDeleteOneModel(),
1726+
},
1727+
{
1728+
name: "DeleteMany",
1729+
model: mongo.NewDeleteManyModel(),
1730+
},
1731+
{
1732+
name: "UpdateOne",
1733+
model: mongo.NewUpdateOneModel().SetUpdate(bson.D{{"$set", bson.D{{"x", 1}}}}),
1734+
},
1735+
{
1736+
name: "UpdateMany",
1737+
model: mongo.NewUpdateManyModel().SetUpdate(bson.D{{"$set", bson.D{{"x", 1}}}}),
1738+
},
1739+
}
1740+
for _, tc := range testCases {
1741+
tc := tc
1742+
1743+
mt.Run(tc.name, func(mt *mtest.T) {
1744+
mt.Parallel()
1745+
1746+
_, err := mt.Coll.BulkWrite(context.Background(), []mongo.WriteModel{tc.model})
1747+
assert.ErrorContains(mt, err, "filter is required")
1748+
})
1749+
}
1750+
})
17161751
mt.Run("correct model in errors", func(mt *mtest.T) {
17171752
models := []mongo.WriteModel{
17181753
mongo.NewUpdateOneModel().SetFilter(bson.M{}).SetUpdate(bson.M{

mongo/bulk_write.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package mongo
99
import (
1010
"context"
1111
"errors"
12+
"fmt"
1213

1314
"go.mongodb.org/mongo-driver/v2/bson"
1415
"go.mongodb.org/mongo-driver/v2/mongo/options"
@@ -296,6 +297,9 @@ func createDeleteDoc(
296297
) (bsoncore.Document, error) {
297298
f, err := marshal(filter, bsonOpts, registry)
298299
if err != nil {
300+
if filter == nil {
301+
return nil, fmt.Errorf("%w: filter is required", err)
302+
}
299303
return nil, err
300304
}
301305

@@ -428,6 +432,9 @@ type updateDoc struct {
428432
func (doc updateDoc) marshal(bsonOpts *options.BSONOptions, registry *bson.Registry) (bsoncore.Document, error) {
429433
f, err := marshal(doc.filter, bsonOpts, registry)
430434
if err != nil {
435+
if doc.filter == nil {
436+
return nil, fmt.Errorf("%w: filter is required", err)
437+
}
431438
return nil, err
432439
}
433440

mongo/bulk_write_models.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ type WriteModel interface {
2020
}
2121

2222
// InsertOneModel is used to insert a single document in a BulkWrite operation.
23+
//
24+
// See corresponding setter methods for documentation.
2325
type InsertOneModel struct {
2426
Document interface{}
2527
}
@@ -40,6 +42,8 @@ func (iom *InsertOneModel) SetDocument(doc interface{}) *InsertOneModel {
4042
func (*InsertOneModel) writeModel() {}
4143

4244
// DeleteOneModel is used to delete at most one document in a BulkWriteOperation.
45+
//
46+
// See corresponding setter methods for documentation.
4347
type DeleteOneModel struct {
4448
Filter interface{}
4549
Collation *options.Collation
@@ -80,6 +84,8 @@ func (dom *DeleteOneModel) SetHint(hint interface{}) *DeleteOneModel {
8084
func (*DeleteOneModel) writeModel() {}
8185

8286
// DeleteManyModel is used to delete multiple documents in a BulkWrite operation.
87+
//
88+
// See corresponding setter methods for documentation.
8389
type DeleteManyModel struct {
8490
Filter interface{}
8591
Collation *options.Collation
@@ -119,6 +125,8 @@ func (dmm *DeleteManyModel) SetHint(hint interface{}) *DeleteManyModel {
119125
func (*DeleteManyModel) writeModel() {}
120126

121127
// ReplaceOneModel is used to replace at most one document in a BulkWrite operation.
128+
//
129+
// See corresponding setter methods for documentation.
122130
type ReplaceOneModel struct {
123131
Collation *options.Collation
124132
Upsert *bool
@@ -176,6 +184,8 @@ func (rom *ReplaceOneModel) SetUpsert(upsert bool) *ReplaceOneModel {
176184
func (*ReplaceOneModel) writeModel() {}
177185

178186
// UpdateOneModel is used to update at most one document in a BulkWrite operation.
187+
//
188+
// See corresponding setter methods for documentation.
179189
type UpdateOneModel struct {
180190
Collation *options.Collation
181191
Upsert *bool
@@ -241,6 +251,8 @@ func (uom *UpdateOneModel) SetUpsert(upsert bool) *UpdateOneModel {
241251
func (*UpdateOneModel) writeModel() {}
242252

243253
// UpdateManyModel is used to update multiple documents in a BulkWrite operation.
254+
//
255+
// See corresponding setter methods for documentation.
244256
type UpdateManyModel struct {
245257
Collation *options.Collation
246258
Upsert *bool

mongo/client.go

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -895,10 +895,14 @@ func (c *Client) createBaseCursorOptions() driver.CursorOptions {
895895
// BulkWrite performs a client-level bulk write operation.
896896
func (c *Client) BulkWrite(ctx context.Context, models *ClientWriteModels,
897897
opts ...options.Lister[options.ClientBulkWriteOptions]) (*ClientBulkWriteResult, error) {
898-
// TODO: Remove once DRIVERS-2888 is implemented.
898+
// TODO(GODRIVER-3403): Remove after support for QE with Client.bulkWrite.
899899
if c.isAutoEncryptionSet {
900900
return nil, errors.New("bulkWrite does not currently support automatic encryption")
901901
}
902+
903+
if models == nil {
904+
return nil, ErrNilValue
905+
}
902906
bwo, err := mongoutil.NewOptions(opts...)
903907
if err != nil {
904908
return nil, err
@@ -962,14 +966,9 @@ func (c *Client) BulkWrite(ctx context.Context, models *ClientWriteModels,
962966
} else if !acknowledged {
963967
return nil, errors.New("cannot request unacknowledged write concern and verbose results")
964968
}
965-
if err = op.execute(ctx); err != nil {
966-
return nil, replaceErrors(err)
967-
}
968-
var results *ClientBulkWriteResult
969-
if acknowledged {
970-
results = &op.result
971-
}
972-
return results, nil
969+
err = op.execute(ctx)
970+
op.result.Acknowledged = acknowledged
971+
return &op.result, replaceErrors(err)
973972
}
974973

975974
// newLogger will use the LoggerOptions to create an internal logger and publish

mongo/client_bulk_write.go

Lines changed: 19 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"bytes"
1111
"context"
1212
"errors"
13+
"fmt"
1314
"io"
1415
"strconv"
1516

@@ -81,19 +82,16 @@ func (bw *clientBulkWrite) execute(ctx context.Context) error {
8182
Name: driverutil.BulkWriteOp,
8283
}.Execute(ctx)
8384
var exception *ClientBulkWriteException
84-
switch tt := err.(type) {
85-
case CommandError:
85+
86+
var ce CommandError
87+
if errors.As(err, &ce) {
8688
exception = &ClientBulkWriteException{
8789
TopLevelError: &WriteError{
88-
Code: int(tt.Code),
89-
Message: tt.Message,
90-
Raw: tt.Raw,
90+
Code: int(ce.Code),
91+
Message: ce.Message,
92+
Raw: ce.Raw,
9193
},
9294
}
93-
default:
94-
if errors.Is(err, driver.ErrUnacknowledgedWrite) {
95-
err = nil
96-
}
9795
}
9896
if len(batches.writeConcernErrors) > 0 || len(batches.writeErrors) > 0 {
9997
if exception == nil {
@@ -521,9 +519,9 @@ func (mb *modelBatches) appendDeleteResult(cur *cursorInfo, raw bson.Raw) bool {
521519
}
522520

523521
if mb.result.DeleteResults == nil {
524-
mb.result.DeleteResults = make(map[int]ClientDeleteResult)
522+
mb.result.DeleteResults = make(map[int]ClientBulkWriteDeleteResult)
525523
}
526-
mb.result.DeleteResults[idx] = ClientDeleteResult{int64(cur.N)}
524+
mb.result.DeleteResults[idx] = ClientBulkWriteDeleteResult{int64(cur.N)}
527525

528526
return true
529527
}
@@ -540,9 +538,9 @@ func (mb *modelBatches) appendInsertResult(cur *cursorInfo, raw bson.Raw) bool {
540538
}
541539

542540
if mb.result.InsertResults == nil {
543-
mb.result.InsertResults = make(map[int]ClientInsertResult)
541+
mb.result.InsertResults = make(map[int]ClientBulkWriteInsertResult)
544542
}
545-
mb.result.InsertResults[idx] = ClientInsertResult{mb.newIDMap[idx]}
543+
mb.result.InsertResults[idx] = ClientBulkWriteInsertResult{mb.newIDMap[idx]}
546544

547545
return true
548546
}
@@ -559,9 +557,9 @@ func (mb *modelBatches) appendUpdateResult(cur *cursorInfo, raw bson.Raw) bool {
559557
}
560558

561559
if mb.result.UpdateResults == nil {
562-
mb.result.UpdateResults = make(map[int]ClientUpdateResult)
560+
mb.result.UpdateResults = make(map[int]ClientBulkWriteUpdateResult)
563561
}
564-
result := ClientUpdateResult{
562+
result := ClientBulkWriteUpdateResult{
565563
MatchedCount: int64(cur.N),
566564
}
567565
if cur.NModified != nil {
@@ -624,6 +622,9 @@ func (d *clientUpdateDoc) marshal(bsonOpts *options.BSONOptions, registry *bson.
624622

625623
f, err := marshal(d.filter, bsonOpts, registry)
626624
if err != nil {
625+
if d.filter == nil {
626+
return nil, fmt.Errorf("%w: filter is required", err)
627+
}
627628
return nil, err
628629
}
629630
doc = bsoncore.AppendDocumentElement(doc, "filter", f)
@@ -684,6 +685,9 @@ func (d *clientDeleteDoc) marshal(bsonOpts *options.BSONOptions, registry *bson.
684685

685686
f, err := marshal(d.filter, bsonOpts, registry)
686687
if err != nil {
688+
if d.filter == nil {
689+
return nil, fmt.Errorf("%w: filter is required", err)
690+
}
687691
return nil, err
688692
}
689693
doc = bsoncore.AppendDocumentElement(doc, "filter", f)

0 commit comments

Comments
 (0)