Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

GODRIVER-3285 Allow update to supply sort option. #1797

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/integration/unified/bulkwrite_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ func createBulkWriteModel(rawModel bson.Raw) (mongo.WriteModel, error) {
if err != nil {
return nil, fmt.Errorf("error creating update: %w", err)
}
case "sort":
sort, err := createSort(val)
if err != nil {
return nil, fmt.Errorf("error creating sort: %w", err)
}
uom.SetSort(sort)
case "upsert":
uom.SetUpsert(val.Boolean())
default:
Expand Down Expand Up @@ -249,6 +255,12 @@ func createBulkWriteModel(rawModel bson.Raw) (mongo.WriteModel, error) {
return nil, fmt.Errorf("error creating hint: %w", err)
}
rom.SetHint(hint)
case "sort":
sort, err := createSort(val)
if err != nil {
return nil, fmt.Errorf("error creating sort: %w", err)
}
rom.SetSort(sort)
case "replacement":
replacement = val.Document()
case "upsert":
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1291,6 +1291,12 @@ func executeReplaceOne(ctx context.Context, operation *operation) (*operationRes
return nil, fmt.Errorf("error creating hint: %w", err)
}
opts.SetHint(hint)
case "sort":
sort, err := createSort(val)
if err != nil {
return nil, fmt.Errorf("error creating sort: %w", err)
}
opts.SetSort(sort)
case "replacement":
replacement = val.Document()
case "upsert":
Expand Down
14 changes: 14 additions & 0 deletions internal/integration/unified/crud_helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,8 @@ func createUpdateOneArguments(args bson.Raw) (*updateArguments, *options.UpdateO
}
case "upsert":
opts.SetUpsert(val.Boolean())
case "sort":
opts.SetSort(val.Document())
default:
return nil, nil, fmt.Errorf("unrecognized update option %q", key)
}
Expand Down Expand Up @@ -212,3 +214,15 @@ func createHint(val bson.RawValue) (interface{}, error) {
}
return hint, nil
}

func createSort(val bson.RawValue) (interface{}, error) {
var sort interface{}

switch val.Type {
case bson.TypeEmbeddedDocument:
sort = val.Document()
default:
return nil, fmt.Errorf("unrecognized sort value type %s", val.Type)
}
return sort, nil
}
13 changes: 13 additions & 0 deletions mongo/bulk_write.go
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,7 @@ func (bw *bulkWrite) runUpdate(ctx context.Context, batch bulkWriteBatch) (opera
filter: converted.Filter,
update: converted.Replacement,
hint: converted.Hint,
sort: converted.Sort,
collation: converted.Collation,
upsert: converted.Upsert,
}.marshal(bw.collection.bsonOpts, bw.collection.registry)
Expand All @@ -349,6 +350,7 @@ func (bw *bulkWrite) runUpdate(ctx context.Context, batch bulkWriteBatch) (opera
filter: converted.Filter,
update: converted.Update,
hint: converted.Hint,
sort: converted.Sort,
arrayFilters: converted.ArrayFilters,
collation: converted.Collation,
upsert: converted.Upsert,
Expand Down Expand Up @@ -420,6 +422,7 @@ type updateDoc struct {
filter interface{}
update interface{}
hint interface{}
sort interface{}
arrayFilters []interface{}
collation *options.Collation
upsert *bool
Expand All @@ -446,6 +449,16 @@ func (doc updateDoc) marshal(bsonOpts *options.BSONOptions, registry *bson.Regis
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 doc.arrayFilters != nil {
reg := registry
Expand Down
18 changes: 18 additions & 0 deletions mongo/bulk_write_models.go
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ type ReplaceOneModel struct {
Filter interface{}
Replacement interface{}
Hint interface{}
Sort interface{}
}

// NewReplaceOneModel creates a new ReplaceOneModel.
Expand Down Expand Up @@ -173,6 +174,14 @@ func (rom *ReplaceOneModel) SetUpsert(upsert bool) *ReplaceOneModel {
return rom
}

// SetSort specifies which document the operation replaces if the query matches multiple documents. The first document
// matched by the sort order will be replaced. This option is only valid for MongoDB versions >= 8.0. The driver will
// return an error if the sort parameter is a multi-key map. The default value is nil.
func (rom *ReplaceOneModel) SetSort(sort interface{}) *ReplaceOneModel {
rom.Sort = &sort
return rom
}

func (*ReplaceOneModel) writeModel() {}

// UpdateOneModel is used to update at most one document in a BulkWrite operation.
Expand All @@ -183,6 +192,7 @@ type UpdateOneModel struct {
Update interface{}
ArrayFilters []interface{}
Hint interface{}
Sort interface{}
}

// NewUpdateOneModel creates a new UpdateOneModel.
Expand Down Expand Up @@ -238,6 +248,14 @@ func (uom *UpdateOneModel) SetUpsert(upsert bool) *UpdateOneModel {
return uom
}

// SetSort specifies which document the operation updates if the query matches multiple documents. The first document
// matched by the sort order will be updated. This option is only valid for MongoDB versions >= 8.0. The driver will
// return an error if the sort parameter is a multi-key map. The default value is nil.
func (uom *UpdateOneModel) SetSort(sort interface{}) *UpdateOneModel {
uom.Sort = sort
return uom
}

func (*UpdateOneModel) writeModel() {}

// UpdateManyModel is used to update multiple documents in a BulkWrite operation.
Expand Down
8 changes: 5 additions & 3 deletions mongo/collection.go
Original file line number Diff line number Diff line change
Expand Up @@ -610,6 +610,7 @@ func (coll *Collection) updateOrReplace(
multi bool,
expectedRr returnResult,
checkDollarKey bool,
sort interface{},
args *options.UpdateManyOptions,
) (*UpdateResult, error) {

Expand All @@ -623,6 +624,7 @@ func (coll *Collection) updateOrReplace(
filter: filter,
update: update,
hint: args.Hint,
sort: sort,
arrayFilters: args.ArrayFilters,
collation: args.Collation,
upsert: args.Upsert,
Expand Down Expand Up @@ -775,7 +777,7 @@ func (coll *Collection) UpdateOne(
Let: args.Let,
}

return coll.updateOrReplace(ctx, f, update, false, rrOne, true, updateOptions)
return coll.updateOrReplace(ctx, f, update, false, rrOne, true, args.Sort, updateOptions)
}

// UpdateMany executes an update command to update documents in the collection.
Expand Down Expand Up @@ -811,7 +813,7 @@ func (coll *Collection) UpdateMany(
return nil, fmt.Errorf("failed to construct options from builder: %w", err)
}

return coll.updateOrReplace(ctx, f, update, true, rrMany, true, args)
return coll.updateOrReplace(ctx, f, update, true, rrMany, true, nil, args)
}

// ReplaceOne executes an update command to replace at most one document in the collection.
Expand Down Expand Up @@ -865,7 +867,7 @@ func (coll *Collection) ReplaceOne(
Comment: args.Comment,
}

return coll.updateOrReplace(ctx, f, r, false, rrOne, false, updateOptions)
return coll.updateOrReplace(ctx, f, r, false, rrOne, false, args.Sort, updateOptions)
}

// Aggregate executes an aggregate command against the collection and returns a cursor over the resulting documents.
Expand Down
16 changes: 16 additions & 0 deletions mongo/options/replaceoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ type ReplaceOptions struct {
Hint interface{}
Upsert *bool
Let interface{}
Sort interface{}
}

// ReplaceOptionsBuilder contains options to configure replace operations. Each
Expand Down Expand Up @@ -122,3 +123,18 @@ func (ro *ReplaceOptionsBuilder) SetLet(l interface{}) *ReplaceOptionsBuilder {

return ro
}

// SetSort sets the value for the Sort field. Specifies a document specifying which document should
// be replaced if the filter used by the operation matches multiple documents in the collection. If
// set, the first document in the sorted order will be replaced. This option is only valid for MongoDB
// versions >= 8.0. The driver will return an error if the sort parameter is a multi-key map. The
// default value is nil.
func (ro *ReplaceOptionsBuilder) SetSort(s interface{}) *ReplaceOptionsBuilder {
ro.Opts = append(ro.Opts, func(opts *ReplaceOptions) error {
opts.Sort = s

return nil
})

return ro
}
16 changes: 16 additions & 0 deletions mongo/options/updateoptions.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ type UpdateOneOptions struct {
Hint interface{}
Upsert *bool
Let interface{}
Sort interface{}
}

// UpdateOneOptionsBuilder contains options to configure UpdateOne operations.
Expand Down Expand Up @@ -137,6 +138,21 @@ func (uo *UpdateOneOptionsBuilder) SetLet(l interface{}) *UpdateOneOptionsBuilde
return uo
}

// SetSort sets the value for the Sort field. Specifies a document specifying which document should
// be updated if the filter used by the operation matches multiple documents in the collection. If
// set, the first document in the sorted order will be updated. This option is only valid for MongoDB
// versions >= 8.0. The driver will return an error if the sort parameter is a multi-key map. The
// default value is nil.
func (uo *UpdateOneOptionsBuilder) SetSort(s interface{}) *UpdateOneOptionsBuilder {
uo.Opts = append(uo.Opts, func(opts *UpdateOneOptions) error {
opts.Sort = s

return nil
})

return uo
}

// UpdateManyOptions represents arguments that can be used to configure UpdateMany
// operations.
//
Expand Down
Loading
Loading