Skip to content

Commit 841984a

Browse files
CSHARP-2570: Add the ability to specify a pipeline to an update command.
1 parent 3419231 commit 841984a

22 files changed

+781
-78
lines changed

src/MongoDB.Driver.Core/Core/Operations/BulkUpdateOperationEmulator.cs

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,16 +15,10 @@
1515

1616
using System;
1717
using System.Collections.Generic;
18-
using System.Linq;
1918
using System.Threading;
2019
using System.Threading.Tasks;
21-
using MongoDB.Bson;
22-
using MongoDB.Bson.IO;
2320
using MongoDB.Driver.Core.Bindings;
24-
using MongoDB.Driver.Core.Connections;
25-
using MongoDB.Driver.Core.Misc;
2621
using MongoDB.Driver.Core.Operations.ElementNameValidators;
27-
using MongoDB.Driver.Core.WireProtocol;
2822
using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
2923

3024
namespace MongoDB.Driver.Core.Operations
@@ -57,7 +51,7 @@ protected override WriteConcernResult ExecuteProtocol(IChannelHandle channel, Up
5751
MessageEncoderSettings,
5852
WriteConcern,
5953
request.Filter,
60-
request.Update,
54+
request.Update.AsBsonDocument,
6155
ElementNameValidatorFactory.ForUpdateType(request.UpdateType),
6256
request.IsMulti,
6357
request.IsUpsert,
@@ -80,7 +74,7 @@ protected override Task<WriteConcernResult> ExecuteProtocolAsync(IChannelHandle
8074
MessageEncoderSettings,
8175
WriteConcern,
8276
request.Filter,
83-
request.Update,
77+
request.Update.AsBsonDocument,
8478
ElementNameValidatorFactory.ForUpdateType(request.UpdateType),
8579
request.IsMulti,
8680
request.IsUpsert,

src/MongoDB.Driver.Core/Core/Operations/FindOneAndUpdateOperation.cs

Lines changed: 36 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,6 @@
1515

1616
using System;
1717
using System.Collections.Generic;
18-
using System.Linq;
19-
using System.Text;
20-
using System.Threading.Tasks;
2118
using MongoDB.Bson;
2219
using MongoDB.Bson.IO;
2320
using MongoDB.Bson.Serialization;
@@ -45,7 +42,7 @@ public class FindOneAndUpdateOperation<TResult> : FindAndModifyOperationBase<TRe
4542
private BsonDocument _projection;
4643
private ReturnDocument _returnDocument;
4744
private BsonDocument _sort;
48-
private readonly BsonDocument _update;
45+
private readonly BsonValue _update;
4946

5047
// constructors
5148
/// <summary>
@@ -56,15 +53,11 @@ public class FindOneAndUpdateOperation<TResult> : FindAndModifyOperationBase<TRe
5653
/// <param name="update">The update.</param>
5754
/// <param name="resultSerializer">The result serializer.</param>
5855
/// <param name="messageEncoderSettings">The message encoder settings.</param>
59-
public FindOneAndUpdateOperation(CollectionNamespace collectionNamespace, BsonDocument filter, BsonDocument update, IBsonSerializer<TResult> resultSerializer, MessageEncoderSettings messageEncoderSettings)
56+
public FindOneAndUpdateOperation(CollectionNamespace collectionNamespace, BsonDocument filter, BsonValue update, IBsonSerializer<TResult> resultSerializer, MessageEncoderSettings messageEncoderSettings)
6057
: base(collectionNamespace, resultSerializer, messageEncoderSettings)
6158
{
6259
_filter = Ensure.IsNotNull(filter, nameof(filter));
63-
_update = Ensure.IsNotNull(update, nameof(update));
64-
if (_update.ElementCount == 0)
65-
{
66-
throw new ArgumentException("Updates must have at least 1 update operator.", nameof(update));
67-
}
60+
_update = EnsureUpdateIsValid(update);
6861
_returnDocument = ReturnDocument.Before;
6962
}
7063

@@ -170,7 +163,7 @@ public BsonDocument Sort
170163
/// <value>
171164
/// The update specification.
172165
/// </value>
173-
public BsonDocument Update
166+
public BsonValue Update
174167
{
175168
get { return _update; }
176169
}
@@ -206,6 +199,38 @@ protected override IElementNameValidator GetCommandValidator()
206199
return Validator.Instance;
207200
}
208201

202+
// private methods
203+
private BsonValue EnsureUpdateIsValid(BsonValue update)
204+
{
205+
Ensure.IsNotNull(update, nameof(update));
206+
207+
switch (update)
208+
{
209+
case BsonDocument document:
210+
{
211+
if (document.ElementCount == 0)
212+
{
213+
throw new ArgumentException("Updates must have at least 1 update operator.", nameof(update));
214+
}
215+
216+
break;
217+
}
218+
case BsonArray array:
219+
{
220+
if (array.Count == 0)
221+
{
222+
throw new ArgumentException("Updates must have at least 1 update operator in a pipeline.", nameof(update));
223+
}
224+
225+
break;
226+
}
227+
default:
228+
throw new ArgumentException("Updates must be BsonDocument or BsonArray.", nameof(update));
229+
}
230+
231+
return update;
232+
}
233+
209234
private class Validator : IElementNameValidator
210235
{
211236
public readonly static Validator Instance = new Validator();

src/MongoDB.Driver.Core/Core/Operations/RetryableUpdateCommandOperation.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ private void SerializeUpdate(BsonSerializationContext context, BsonSerialization
187187
try
188188
{
189189
var position = writer.Position;
190-
BsonDocumentSerializer.Instance.Serialize(context, request.Update);
190+
BsonValueSerializer.Instance.Serialize(context, request.Update);
191191
if (request.UpdateType == UpdateType.Update && writer.Position == position + 8)
192192
{
193193
throw new BsonSerializationException("Update documents cannot be empty.");

src/MongoDB.Driver.Core/Core/Operations/UpdateOpcodeOperation.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -222,7 +222,7 @@ private WriteConcernResult ExecuteProtocol(IChannelHandle channel, CancellationT
222222
_messageEncoderSettings,
223223
_writeConcern,
224224
_request.Filter,
225-
_request.Update,
225+
_request.Update.AsBsonDocument,
226226
ElementNameValidatorFactory.ForUpdateType(_request.UpdateType),
227227
_request.IsMulti,
228228
_request.IsUpsert,
@@ -245,7 +245,7 @@ private Task<WriteConcernResult> ExecuteProtocolAsync(IChannelHandle channel, Ca
245245
_messageEncoderSettings,
246246
_writeConcern,
247247
_request.Filter,
248-
_request.Update,
248+
_request.Update.AsBsonDocument,
249249
ElementNameValidatorFactory.ForUpdateType(_request.UpdateType),
250250
_request.IsMulti,
251251
_request.IsUpsert,

src/MongoDB.Driver.Core/Core/Operations/UpdateRequest.cs

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public sealed class UpdateRequest : WriteRequest
3232
private readonly BsonDocument _filter;
3333
private bool _isMulti;
3434
private bool _isUpsert;
35-
private readonly BsonDocument _update;
35+
private readonly BsonValue _update;
3636
private UpdateType _updateType;
3737

3838
// constructors
@@ -42,16 +42,12 @@ public sealed class UpdateRequest : WriteRequest
4242
/// <param name="updateType">The update type.</param>
4343
/// <param name="filter">The filter.</param>
4444
/// <param name="update">The update.</param>
45-
public UpdateRequest(UpdateType updateType, BsonDocument filter, BsonDocument update)
45+
public UpdateRequest(UpdateType updateType, BsonDocument filter, BsonValue update)
4646
: base(WriteRequestType.Update)
4747
{
4848
_updateType = updateType;
4949
_filter = Ensure.IsNotNull(filter, nameof(filter));
50-
_update = Ensure.IsNotNull(update, nameof(update));
51-
if (updateType == UpdateType.Update && _update.ElementCount == 0)
52-
{
53-
throw new ArgumentException("Updates must have at least 1 update operator.", nameof(update));
54-
}
50+
_update = EnsureUpdateIsValid(update, updateType);
5551
}
5652

5753
// properties
@@ -111,7 +107,7 @@ public bool IsUpsert
111107
/// <summary>
112108
/// Gets the update specification.
113109
/// </summary>
114-
public BsonDocument Update
110+
public BsonValue Update
115111
{
116112
get { return _update; }
117113
}
@@ -130,5 +126,42 @@ public override bool IsRetryable(ConnectionDescription connectionDescription)
130126
{
131127
return !_isMulti;
132128
}
129+
130+
// private methods
131+
private BsonValue EnsureUpdateIsValid(BsonValue update, UpdateType updateType)
132+
{
133+
Ensure.IsNotNull(update, nameof(update));
134+
135+
if (updateType == UpdateType.Update)
136+
{
137+
switch (update)
138+
{
139+
case BsonDocument document:
140+
{
141+
if (document.ElementCount == 0)
142+
{
143+
throw new ArgumentException("Updates must have at least 1 update operator.",
144+
nameof(update));
145+
}
146+
147+
break;
148+
}
149+
case BsonArray array:
150+
{
151+
if (array.Count == 0)
152+
{
153+
throw new ArgumentException("Updates must have at least 1 update operator in a pipeline.",
154+
nameof(update));
155+
}
156+
157+
break;
158+
}
159+
default:
160+
throw new ArgumentException("Updates must be BsonDocument or BsonArray.", nameof(update));
161+
}
162+
}
163+
164+
return update;
165+
}
133166
}
134167
}

src/MongoDB.Driver/MongoCollectionImpl.cs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -171,6 +171,11 @@ public override MongoCollectionSettings Settings
171171
{
172172
throw new ArgumentException("Must contain at least 1 request.", "requests");
173173
}
174+
foreach (var request in requests)
175+
{
176+
request.ThrowIfNotValid();
177+
}
178+
174179
options = options ?? new BulkWriteOptions();
175180

176181
var operation = CreateBulkWriteOperation(session, requests, options);
@@ -198,6 +203,11 @@ public override MongoCollectionSettings Settings
198203
{
199204
throw new ArgumentException("Must contain at least 1 request.", "requests");
200205
}
206+
foreach (var request in requests)
207+
{
208+
request.ThrowIfNotValid();
209+
}
210+
201211
options = options ?? new BulkWriteOptions();
202212

203213
var operation = CreateBulkWriteOperation(session, requests, options);
@@ -430,6 +440,11 @@ public override MongoCollectionSettings Settings
430440
Ensure.IsNotNull(update, nameof(update));
431441
options = options ?? new FindOneAndUpdateOptions<TDocument, TProjection>();
432442

443+
if (update is PipelineUpdateDefinition<TDocument> && (options.ArrayFilters != null && options.ArrayFilters.Any()))
444+
{
445+
throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update.");
446+
}
447+
433448
var operation = CreateFindOneAndUpdateOperation(filter, update, options);
434449
return ExecuteWriteOperation(session, operation, cancellationToken);
435450
}
@@ -446,6 +461,11 @@ public override MongoCollectionSettings Settings
446461
Ensure.IsNotNull(update, nameof(update));
447462
options = options ?? new FindOneAndUpdateOptions<TDocument, TProjection>();
448463

464+
if (update is PipelineUpdateDefinition<TDocument> && (options.ArrayFilters != null && options.ArrayFilters.Any()))
465+
{
466+
throw new NotSupportedException("An arrayfilter is not supported in the pipeline-style update.");
467+
}
468+
449469
var operation = CreateFindOneAndUpdateOperation(filter, update, options);
450470
return ExecuteWriteOperationAsync(session, operation, cancellationToken);
451471
}

0 commit comments

Comments
 (0)