Skip to content

Commit

Permalink
GODRIVER-3339 Separate Many and One for UpdateOptions and `Dele…
Browse files Browse the repository at this point in the history
…teOptions`
  • Loading branch information
qingyang-hu committed Sep 17, 2024
1 parent 884fb42 commit 875fbb2
Show file tree
Hide file tree
Showing 6 changed files with 426 additions and 156 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -403,7 +403,7 @@ func executeDeleteOne(ctx context.Context, operation *operation) (*operationResu
}

var filter bson.Raw
opts := options.Delete()
opts := options.DeleteOne()

elems, err := operation.Arguments.Elements()
if err != nil {
Expand Down Expand Up @@ -457,7 +457,7 @@ func executeDeleteMany(ctx context.Context, operation *operation) (*operationRes
}

var filter bson.Raw
opts := options.Delete()
opts := options.DeleteMany()

elems, err := operation.Arguments.Elements()
if err != nil {
Expand Down Expand Up @@ -1316,7 +1316,7 @@ func executeUpdateOne(ctx context.Context, operation *operation) (*operationResu
return nil, err
}

updateArgs, err := createUpdateArguments(operation.Arguments)
updateArgs, err := createUpdateArguments[options.UpdateOneOptions](operation.Arguments)
if err != nil {
return nil, err
}
Expand All @@ -1335,7 +1335,7 @@ func executeUpdateMany(ctx context.Context, operation *operation) (*operationRes
return nil, err
}

updateArgs, err := createUpdateArguments(operation.Arguments)
updateArgs, err := createUpdateArguments[options.UpdateManyOptions](operation.Arguments)
if err != nil {
return nil, err
}
Expand Down
46 changes: 33 additions & 13 deletions internal/integration/unified/crud_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ package unified

import (
"fmt"
"reflect"
"strings"

"go.mongodb.org/mongo-driver/v2/bson"
"go.mongodb.org/mongo-driver/v2/internal/bsonutil"
Expand All @@ -20,65 +22,83 @@ func newMissingArgumentError(arg string) error {
return fmt.Errorf("operation arguments document is missing required field %q", arg)
}

type updateArguments struct {
type updateArguments[Options options.UpdateManyOptions | options.UpdateOneOptions] struct {
filter bson.Raw
update interface{}
opts *options.UpdateOptionsBuilder
opts options.Lister[Options]
}

func createUpdateArguments(args bson.Raw) (*updateArguments, error) {
ua := &updateArguments{
opts: options.Update(),
func createUpdateArguments[Options options.UpdateManyOptions | options.UpdateOneOptions](
args bson.Raw,
) (*updateArguments[Options], error) {
ua := &updateArguments[Options]{}
var builder reflect.Value
switch any((*Options)(nil)).(type) {
case *options.UpdateManyOptions:
builder = reflect.ValueOf(options.UpdateMany())
case *options.UpdateOneOptions:
builder = reflect.ValueOf(options.UpdateOne())
}
var err error

elems, _ := args.Elements()
for _, elem := range elems {
key := elem.Key()
val := elem.Value()

var arg reflect.Value
switch key {
case "arrayFilters":
ua.opts.SetArrayFilters(
arg = reflect.ValueOf(
bsonutil.RawToInterfaces(bsonutil.RawArrayToDocuments(val.Array())...),
)
case "bypassDocumentValidation":
ua.opts.SetBypassDocumentValidation(val.Boolean())
arg = reflect.ValueOf(val.Boolean())
case "collation":
collation, err := createCollation(val.Document())
if err != nil {
return nil, fmt.Errorf("error creating collation: %w", err)
}
ua.opts.SetCollation(collation)
arg = reflect.ValueOf(collation)
case "comment":
ua.opts.SetComment(val)
arg = reflect.ValueOf(val)
case "filter":
ua.filter = val.Document()
case "hint":
hint, err := createHint(val)
if err != nil {
return nil, fmt.Errorf("error creating hint: %w", err)
}
ua.opts.SetHint(hint)
arg = reflect.ValueOf(hint)
case "let":
ua.opts.SetLet(val.Document())
arg = reflect.ValueOf(val.Document())
case "update":
var err error
ua.update, err = createUpdateValue(val)
if err != nil {
return nil, fmt.Errorf("error processing update value: %w", err)
}
case "upsert":
ua.opts.SetUpsert(val.Boolean())
arg = reflect.ValueOf(val.Boolean())
default:
return nil, fmt.Errorf("unrecognized update option %q", key)
}
if arg.IsValid() {
fn := builder.MethodByName(
fmt.Sprintf("Set%s%s", strings.ToUpper(string(key[0])), key[1:]),
)
if !fn.IsValid() {
return nil, fmt.Errorf("unrecognized update option %q", key)
}
fn.Call([]reflect.Value{arg})
}
}
if ua.filter == nil {
return nil, newMissingArgumentError("filter")
}
if ua.update == nil {
return nil, newMissingArgumentError("update")
}
ua.opts = builder.Interface().(options.Lister[Options])

return ua, nil
}
Expand Down
120 changes: 62 additions & 58 deletions mongo/bulk_write.go
Original file line number Diff line number Diff line change
Expand Up @@ -336,44 +336,37 @@ func (bw *bulkWrite) runUpdate(ctx context.Context, batch bulkWriteBatch) (opera

switch converted := model.(type) {
case *ReplaceOneModel:
doc, err = createUpdateDoc(
converted.Filter,
converted.Replacement,
converted.Hint,
nil,
converted.Collation,
converted.Upsert,
false,
false,
bw.collection.bsonOpts,
bw.collection.registry)
doc, err = updateDoc{
filter: converted.Filter,
update: converted.Replacement,
hint: converted.Hint,
collation: converted.Collation,
upsert: converted.Upsert,
}.marshal(bw.collection.bsonOpts, bw.collection.registry)
hasHint = hasHint || (converted.Hint != nil)
case *UpdateOneModel:
doc, err = createUpdateDoc(
converted.Filter,
converted.Update,
converted.Hint,
converted.ArrayFilters,
converted.Collation,
converted.Upsert,
false,
true,
bw.collection.bsonOpts,
bw.collection.registry)
doc, err = updateDoc{
filter: converted.Filter,
update: converted.Update,
hint: converted.Hint,
arrayFilters: converted.ArrayFilters,
collation: converted.Collation,
upsert: converted.Upsert,
checkDollarKey: true,
}.marshal(bw.collection.bsonOpts, bw.collection.registry)
hasHint = hasHint || (converted.Hint != nil)
hasArrayFilters = hasArrayFilters || (converted.ArrayFilters != nil)
case *UpdateManyModel:
doc, err = createUpdateDoc(
converted.Filter,
converted.Update,
converted.Hint,
converted.ArrayFilters,
converted.Collation,
converted.Upsert,
true,
true,
bw.collection.bsonOpts,
bw.collection.registry)
doc, err = updateDoc{
filter: converted.Filter,
update: converted.Update,
hint: converted.Hint,
arrayFilters: converted.ArrayFilters,
collation: converted.Collation,
upsert: converted.Upsert,
multi: true,
checkDollarKey: true,
}.marshal(bw.collection.bsonOpts, bw.collection.registry)
hasHint = hasHint || (converted.Hint != nil)
hasArrayFilters = hasArrayFilters || (converted.ArrayFilters != nil)
}
Expand Down Expand Up @@ -423,59 +416,70 @@ func (bw *bulkWrite) runUpdate(ctx context.Context, batch bulkWriteBatch) (opera
return op.Result(), err
}

func createUpdateDoc(
filter interface{},
update interface{},
hint interface{},
arrayFilters []interface{},
collation *options.Collation,
upsert *bool,
multi bool,
checkDollarKey bool,
bsonOpts *options.BSONOptions,
registry *bson.Registry,
) (bsoncore.Document, error) {
f, err := marshal(filter, bsonOpts, registry)
type updateDoc struct {
filter interface{}
update interface{}
hint interface{}
sort interface{}
arrayFilters []interface{}
collation *options.Collation
upsert *bool
multi bool
checkDollarKey bool
}

func (doc updateDoc) marshal(bsonOpts *options.BSONOptions, registry *bson.Registry) (bsoncore.Document, error) {
f, err := marshal(doc.filter, bsonOpts, registry)
if err != nil {
return nil, err
}

uidx, updateDoc := bsoncore.AppendDocumentStart(nil)
updateDoc = bsoncore.AppendDocumentElement(updateDoc, "q", f)

u, err := marshalUpdateValue(update, bsonOpts, registry, checkDollarKey)
u, err := marshalUpdateValue(doc.update, bsonOpts, registry, doc.checkDollarKey)
if err != nil {
return nil, err
}

updateDoc = bsoncore.AppendValueElement(updateDoc, "u", u)

if multi {
updateDoc = bsoncore.AppendBooleanElement(updateDoc, "multi", multi)
if doc.multi {
updateDoc = bsoncore.AppendBooleanElement(updateDoc, "multi", doc.multi)
}
if doc.sort != nil {
if isUnorderedMap(doc.sort) {
return nil, ErrMapForOrderedArgument{"sort"}
}
s, err := marshal(doc.sort, bsonOpts, registry)
if err != nil {
return nil, err
}
updateDoc = bsoncore.AppendDocumentElement(updateDoc, "sort", s)
}

if arrayFilters != nil {
if doc.arrayFilters != nil {
reg := registry
arr, err := marshalValue(arrayFilters, bsonOpts, reg)
arr, err := marshalValue(doc.arrayFilters, bsonOpts, reg)
if err != nil {
return nil, err
}
updateDoc = bsoncore.AppendArrayElement(updateDoc, "arrayFilters", arr.Data)
}

if collation != nil {
updateDoc = bsoncore.AppendDocumentElement(updateDoc, "collation", bsoncore.Document(toDocument(collation)))
if doc.collation != nil {
updateDoc = bsoncore.AppendDocumentElement(updateDoc, "collation", bsoncore.Document(toDocument(doc.collation)))
}

if upsert != nil {
updateDoc = bsoncore.AppendBooleanElement(updateDoc, "upsert", *upsert)
if doc.upsert != nil {
updateDoc = bsoncore.AppendBooleanElement(updateDoc, "upsert", *doc.upsert)
}

if hint != nil {
if isUnorderedMap(hint) {
if doc.hint != nil {
if isUnorderedMap(doc.hint) {
return nil, ErrMapForOrderedArgument{"hint"}
}
hintVal, err := marshalValue(hint, bsonOpts, registry)
hintVal, err := marshalValue(doc.hint, bsonOpts, registry)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit 875fbb2

Please sign in to comment.