/* Copyright 2010-present MongoDB Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.Linq.Expressions; using MongoDB.Bson; using MongoDB.Bson.IO; using MongoDB.Bson.Serialization; using MongoDB.Driver.Core.Misc; namespace MongoDB.Driver { /// /// Extension methods for UpdateDefinition. /// public static class UpdateDefinitionExtensions { /// /// Combines an existing update with an add to set operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition AddToSet(this UpdateDefinition update, FieldDefinition field, TItem value) { var builder = Builders.Update; return builder.Combine(update, builder.AddToSet(field, value)); } /// /// Combines an existing update with an add to set operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition AddToSet(this UpdateDefinition update, Expression>> field, TItem value) { var builder = Builders.Update; return builder.Combine(update, builder.AddToSet(field, value)); } /// /// Combines an existing update with an add to set operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The values. /// /// A combined update. /// public static UpdateDefinition AddToSetEach(this UpdateDefinition update, FieldDefinition field, IEnumerable values) { var builder = Builders.Update; return builder.Combine(update, builder.AddToSetEach(field, values)); } /// /// Combines an existing update with an add to set operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The values. /// /// A combined update. /// public static UpdateDefinition AddToSetEach(this UpdateDefinition update, Expression>> field, IEnumerable values) { var builder = Builders.Update; return builder.Combine(update, builder.AddToSetEach(field, values)); } /// /// Combines an existing update with a bitwise and operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition BitwiseAnd(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.BitwiseAnd(field, value)); } /// /// Combines an existing update with a bitwise and operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition BitwiseAnd(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.BitwiseAnd(field, value)); } /// /// Combines an existing update with a bitwise or operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition BitwiseOr(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.BitwiseOr(field, value)); } /// /// Combines an existing update with a bitwise or operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition BitwiseOr(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.BitwiseOr(field, value)); } /// /// Combines an existing update with a bitwise xor operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition BitwiseXor(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.BitwiseXor(field, value)); } /// /// Combines an existing update with a bitwise xor operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition BitwiseXor(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.BitwiseXor(field, value)); } /// /// Combines an existing update with a current date operator. /// /// The type of the document. /// The update. /// The field. /// The type. /// /// A combined update. /// public static UpdateDefinition CurrentDate(this UpdateDefinition update, FieldDefinition field, UpdateDefinitionCurrentDateType? type = null) { var builder = Builders.Update; return builder.Combine(update, builder.CurrentDate(field, type)); } /// /// Combines an existing update with a current date operator. /// /// The type of the document. /// The update. /// The field. /// The type. /// /// A combined update. /// public static UpdateDefinition CurrentDate(this UpdateDefinition update, Expression> field, UpdateDefinitionCurrentDateType? type = null) { var builder = Builders.Update; return builder.Combine(update, builder.CurrentDate(field, type)); } /// /// Combines an existing update with an increment operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Inc(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Inc(field, value)); } /// /// Combines an existing update with an increment operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Inc(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Inc(field, value)); } /// /// Combines an existing update with a max operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Max(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Max(field, value)); } /// /// Combines an existing update with a max operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Max(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Max(field, value)); } /// /// Combines an existing update with a min operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Min(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Min(field, value)); } /// /// Combines an existing update with a min operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Min(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Min(field, value)); } /// /// Combines an existing update with a multiply operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Mul(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Mul(field, value)); } /// /// Combines an existing update with a multiply operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Mul(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Mul(field, value)); } /// /// Combines an existing update with a pop operator. /// /// The type of the document. /// The update. /// The field. /// /// A combined update. /// public static UpdateDefinition PopFirst(this UpdateDefinition update, FieldDefinition field) { var builder = Builders.Update; return builder.Combine(update, builder.PopFirst(field)); } /// /// Combines an existing update with a pop operator. /// /// The type of the document. /// The update. /// The field. /// /// A combined update. /// public static UpdateDefinition PopFirst(this UpdateDefinition update, Expression> field) { var builder = Builders.Update; return builder.Combine(update, builder.PopFirst(field)); } /// /// Combines an existing update with a pop operator. /// /// The type of the document. /// The update. /// The field. /// /// A combined update. /// public static UpdateDefinition PopLast(this UpdateDefinition update, FieldDefinition field) { var builder = Builders.Update; return builder.Combine(update, builder.PopLast(field)); } /// /// Combines an existing update with a pop operator. /// /// The type of the document. /// The update. /// The field. /// /// A combined update. /// public static UpdateDefinition PopLast(this UpdateDefinition update, Expression> field) { var builder = Builders.Update; return builder.Combine(update, builder.PopLast(field)); } /// /// Combines an existing update with a pull operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Pull(this UpdateDefinition update, FieldDefinition field, TItem value) { var builder = Builders.Update; return builder.Combine(update, builder.Pull(field, value)); } /// /// Combines an existing update with a pull operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Pull(this UpdateDefinition update, Expression>> field, TItem value) { var builder = Builders.Update; return builder.Combine(update, builder.Pull(field, value)); } /// /// Combines an existing update with a pull operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The values. /// /// A combined update. /// public static UpdateDefinition PullAll(this UpdateDefinition update, FieldDefinition field, IEnumerable values) { var builder = Builders.Update; return builder.Combine(update, builder.PullAll(field, values)); } /// /// Combines an existing update with a pull operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The values. /// /// A combined update. /// public static UpdateDefinition PullAll(this UpdateDefinition update, Expression>> field, IEnumerable values) { var builder = Builders.Update; return builder.Combine(update, builder.PullAll(field, values)); } /// /// Combines an existing update with a pull operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The filter. /// /// A combined update. /// public static UpdateDefinition PullFilter(this UpdateDefinition update, FieldDefinition field, FilterDefinition filter) { var builder = Builders.Update; return builder.Combine(update, builder.PullFilter(field, filter)); } /// /// Combines an existing update with a pull operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The filter. /// /// A combined update. /// public static UpdateDefinition PullFilter(this UpdateDefinition update, Expression>> field, FilterDefinition filter) { var builder = Builders.Update; return builder.Combine(update, builder.PullFilter(field, filter)); } /// /// Combines an existing update with a pull operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The filter. /// /// A combined update. /// public static UpdateDefinition PullFilter(this UpdateDefinition update, Expression>> field, Expression> filter) { var builder = Builders.Update; return builder.Combine(update, builder.PullFilter(field, filter)); } /// /// Combines an existing update with a push operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Push(this UpdateDefinition update, FieldDefinition field, TItem value) { var builder = Builders.Update; return builder.Combine(update, builder.Push(field, value)); } /// /// Combines an existing update with a push operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Push(this UpdateDefinition update, Expression>> field, TItem value) { var builder = Builders.Update; return builder.Combine(update, builder.Push(field, value)); } /// /// Combines an existing update with a push operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The values. /// The slice. /// The position. /// The sort. /// /// A combined update. /// public static UpdateDefinition PushEach(this UpdateDefinition update, FieldDefinition field, IEnumerable values, int? slice = null, int? position = null, SortDefinition sort = null) { var builder = Builders.Update; return builder.Combine(update, builder.PushEach(field, values, slice, position, sort)); } /// /// Combines an existing update with a push operator. /// /// The type of the document. /// The type of the item. /// The update. /// The field. /// The values. /// The slice. /// The position. /// The sort. /// /// A combined update. /// public static UpdateDefinition PushEach(this UpdateDefinition update, Expression>> field, IEnumerable values, int? slice = null, int? position = null, SortDefinition sort = null) { var builder = Builders.Update; return builder.Combine(update, builder.PushEach(field, values, slice, position, sort)); } /// /// Combines an existing update with a field renaming operator. /// /// The type of the document. /// The update. /// The field. /// The new name. /// /// A combined update. /// public static UpdateDefinition Rename(this UpdateDefinition update, FieldDefinition field, string newName) { var builder = Builders.Update; return builder.Combine(update, builder.Rename(field, newName)); } /// /// Combines an existing update with a field renaming operator. /// /// The type of the document. /// The update. /// The field. /// The new name. /// /// A combined update. /// public static UpdateDefinition Rename(this UpdateDefinition update, Expression> field, string newName) { var builder = Builders.Update; return builder.Combine(update, builder.Rename(field, newName)); } /// /// Combines an existing update with a set operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Set(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Set(field, value)); } /// /// Combines an existing update with a set operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition Set(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.Set(field, value)); } /// /// Combines an existing update with a set on insert operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition SetOnInsert(this UpdateDefinition update, FieldDefinition field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.SetOnInsert(field, value)); } /// /// Combines an existing update with a set on insert operator. /// /// The type of the document. /// The type of the field. /// The update. /// The field. /// The value. /// /// A combined update. /// public static UpdateDefinition SetOnInsert(this UpdateDefinition update, Expression> field, TField value) { var builder = Builders.Update; return builder.Combine(update, builder.SetOnInsert(field, value)); } /// /// Combines an existing update with an unset operator. /// /// The type of the document. /// The update. /// The field. /// /// A combined update. /// public static UpdateDefinition Unset(this UpdateDefinition update, FieldDefinition field) { var builder = Builders.Update; return builder.Combine(update, builder.Unset(field)); } /// /// Combines an existing update with an unset operator. /// /// The type of the document. /// The update. /// The field. /// /// A combined update. /// public static UpdateDefinition Unset(this UpdateDefinition update, Expression> field) { var builder = Builders.Update; return builder.Combine(update, builder.Unset(field)); } } /// /// The type to use for a $currentDate operator. /// public enum UpdateDefinitionCurrentDateType { /// /// A date. /// Date, /// /// A timestamp. /// Timestamp } /// /// A builder for an . /// /// The type of the document. public sealed class UpdateDefinitionBuilder { /// /// Creates an add to set operator. /// /// The type of the item. /// The field. /// The value. /// An add to set operator. public UpdateDefinition AddToSet(FieldDefinition field, TItem value) { return new AddToSetUpdateDefinition( field, new[] { value }); } /// /// Creates an add to set operator. /// /// The type of the item. /// The field. /// The value. /// An add to set operator. public UpdateDefinition AddToSet(Expression>> field, TItem value) { return AddToSet(new ExpressionFieldDefinition(field), value); } /// /// Creates an add to set operator. /// /// The type of the item. /// The field. /// The values. /// An add to set operator. public UpdateDefinition AddToSetEach(FieldDefinition field, IEnumerable values) { return new AddToSetUpdateDefinition(field, values); } /// /// Creates an add to set operator. /// /// The type of the item. /// The field. /// The values. /// An add to set operator. public UpdateDefinition AddToSetEach(Expression>> field, IEnumerable values) { return AddToSetEach(new ExpressionFieldDefinition(field), values); } /// /// Creates a bitwise and operator. /// /// The type of the field. /// The field. /// The value. /// A bitwise and operator. public UpdateDefinition BitwiseAnd(FieldDefinition field, TField value) { return new BitwiseOperatorUpdateDefinition("and", field, value); } /// /// Creates a bitwise and operator. /// /// The type of the field. /// The field. /// The value. /// A bitwise and operator. public UpdateDefinition BitwiseAnd(Expression> field, TField value) { return BitwiseAnd(new ExpressionFieldDefinition(field), value); } /// /// Creates a bitwise or operator. /// /// The type of the field. /// The field. /// The value. /// A bitwise or operator. public UpdateDefinition BitwiseOr(FieldDefinition field, TField value) { return new BitwiseOperatorUpdateDefinition("or", field, value); } /// /// Creates a bitwise or operator. /// /// The type of the field. /// The field. /// The value. /// A bitwise or operator. public UpdateDefinition BitwiseOr(Expression> field, TField value) { return BitwiseOr(new ExpressionFieldDefinition(field), value); } /// /// Creates a bitwise xor operator. /// /// The type of the field. /// The field. /// The value. /// A bitwise xor operator. public UpdateDefinition BitwiseXor(FieldDefinition field, TField value) { return new BitwiseOperatorUpdateDefinition("xor", field, value); } /// /// Creates a bitwise xor operator. /// /// The type of the field. /// The field. /// The value. /// A bitwise xor operator. public UpdateDefinition BitwiseXor(Expression> field, TField value) { return BitwiseXor(new ExpressionFieldDefinition(field), value); } /// /// Creates a combined update. /// /// The updates. /// A combined update. public UpdateDefinition Combine(params UpdateDefinition[] updates) { return Combine((IEnumerable>)updates); } /// /// Creates a combined update. /// /// The updates. /// A combined update. public UpdateDefinition Combine(IEnumerable> updates) { return new CombinedUpdateDefinition(updates); } /// /// Creates a current date operator. /// /// The field. /// The type. /// A current date operator. public UpdateDefinition CurrentDate(FieldDefinition field, UpdateDefinitionCurrentDateType? type = null) { BsonValue value; if (type.HasValue) { switch (type.Value) { case UpdateDefinitionCurrentDateType.Date: value = new BsonDocument("$type", "date"); break; case UpdateDefinitionCurrentDateType.Timestamp: value = new BsonDocument("$type", "timestamp"); break; default: throw new InvalidOperationException("Unknown value for " + typeof(UpdateDefinitionCurrentDateType)); } } else { value = true; } return new OperatorUpdateDefinition("$currentDate", field, value); } /// /// Creates a current date operator. /// /// The field. /// The type. /// A current date operator. public UpdateDefinition CurrentDate(Expression> field, UpdateDefinitionCurrentDateType? type = null) { return CurrentDate(new ExpressionFieldDefinition(field), type); } /// /// Creates an increment operator. /// /// The type of the field. /// The field. /// The value. /// An increment operator. public UpdateDefinition Inc(FieldDefinition field, TField value) { return new OperatorUpdateDefinition("$inc", field, value); } /// /// Creates an increment operator. /// /// The type of the field. /// The field. /// The value. /// An increment operator. public UpdateDefinition Inc(Expression> field, TField value) { return Inc(new ExpressionFieldDefinition(field), value); } /// /// Creates a max operator. /// /// The type of the field. /// The field. /// The value. /// A max operator. public UpdateDefinition Max(FieldDefinition field, TField value) { return new OperatorUpdateDefinition("$max", field, value); } /// /// Creates a max operator. /// /// The type of the field. /// The field. /// The value. /// A max operator. public UpdateDefinition Max(Expression> field, TField value) { return Max(new ExpressionFieldDefinition(field), value); } /// /// Creates a min operator. /// /// The type of the field. /// The field. /// The value. /// A min operator. public UpdateDefinition Min(FieldDefinition field, TField value) { return new OperatorUpdateDefinition("$min", field, value); } /// /// Creates a min operator. /// /// The type of the field. /// The field. /// The value. /// A min operator. public UpdateDefinition Min(Expression> field, TField value) { return Min(new ExpressionFieldDefinition(field), value); } /// /// Creates a multiply operator. /// /// The type of the field. /// The field. /// The value. /// A multiply operator. public UpdateDefinition Mul(FieldDefinition field, TField value) { return new OperatorUpdateDefinition("$mul", field, value); } /// /// Creates a multiply operator. /// /// The type of the field. /// The field. /// The value. /// A multiply operator. public UpdateDefinition Mul(Expression> field, TField value) { return Mul(new ExpressionFieldDefinition(field), value); } /// /// Creates a pop operator. /// /// The field. /// A pop operator. public UpdateDefinition PopFirst(FieldDefinition field) { return new OperatorUpdateDefinition("$pop", field, -1); } /// /// Creates a pop first operator. /// /// The field. /// A pop first operator. public UpdateDefinition PopFirst(Expression> field) { return PopFirst(new ExpressionFieldDefinition(field)); } /// /// Creates a pop operator. /// /// The field. /// A pop operator. public UpdateDefinition PopLast(FieldDefinition field) { return new OperatorUpdateDefinition("$pop", field, 1); } /// /// Creates a pop first operator. /// /// The field. /// A pop first operator. public UpdateDefinition PopLast(Expression> field) { return PopLast(new ExpressionFieldDefinition(field)); } /// /// Creates a pull operator. /// /// The type of the item. /// The field. /// The value. /// A pull operator. public UpdateDefinition Pull(FieldDefinition field, TItem value) { return new PullUpdateDefinition(field, new[] { value }); } /// /// Creates a pull operator. /// /// The type of the item. /// The field. /// The value. /// A pull operator. public UpdateDefinition Pull(Expression>> field, TItem value) { return Pull(new ExpressionFieldDefinition(field), value); } /// /// Creates a pull operator. /// /// The type of the item. /// The field. /// The values. /// A pull operator. public UpdateDefinition PullAll(FieldDefinition field, IEnumerable values) { return new PullUpdateDefinition(field, values); } /// /// Creates a pull operator. /// /// The type of the item. /// The field. /// The values. /// A pull operator. public UpdateDefinition PullAll(Expression>> field, IEnumerable values) { return PullAll(new ExpressionFieldDefinition(field), values); } /// /// Creates a pull operator. /// /// The type of the item. /// The field. /// The filter. /// A pull operator. public UpdateDefinition PullFilter(FieldDefinition field, FilterDefinition filter) { return new PullUpdateDefinition(field, filter); } /// /// Creates a pull operator. /// /// The type of the item. /// The field. /// The filter. /// A pull operator. public UpdateDefinition PullFilter(Expression>> field, FilterDefinition filter) { return PullFilter(new ExpressionFieldDefinition(field), filter); } /// /// Creates a pull operator. /// /// The type of the item. /// The field. /// The filter. /// A pull operator. public UpdateDefinition PullFilter(Expression>> field, Expression> filter) { return PullFilter(new ExpressionFieldDefinition(field), new ExpressionFilterDefinition(filter)); } /// /// Creates a push operator. /// /// The type of the item. /// The field. /// The value. /// A push operator. public UpdateDefinition Push(FieldDefinition field, TItem value) { return new PushUpdateDefinition(field, new[] { value }); } /// /// Creates a push operator. /// /// The type of the item. /// The field. /// The value. /// A push operator. public UpdateDefinition Push(Expression>> field, TItem value) { return Push(new ExpressionFieldDefinition(field), value); } /// /// Creates a push operator. /// /// The type of the item. /// The field. /// The values. /// The slice. /// The position. /// The sort. /// A push operator. public UpdateDefinition PushEach(FieldDefinition field, IEnumerable values, int? slice = null, int? position = null, SortDefinition sort = null) { return new PushUpdateDefinition(field, values, slice, position, sort); } /// /// Creates a push operator. /// /// The type of the item. /// The field. /// The values. /// The slice. /// The position. /// The sort. /// A push operator. public UpdateDefinition PushEach(Expression>> field, IEnumerable values, int? slice = null, int? position = null, SortDefinition sort = null) { return PushEach(new ExpressionFieldDefinition(field), values, slice, position, sort); } /// /// Creates a field renaming operator. /// /// The field. /// The new name. /// A field rename operator. public UpdateDefinition Rename(FieldDefinition field, string newName) { return new OperatorUpdateDefinition("$rename", field, newName); } /// /// Creates a field renaming operator. /// /// The field. /// The new name. /// A field rename operator. public UpdateDefinition Rename(Expression> field, string newName) { return Rename(new ExpressionFieldDefinition(field), newName); } /// /// Creates a set operator. /// /// The type of the field. /// The field. /// The value. /// A set operator. public UpdateDefinition Set(FieldDefinition field, TField value) { return new OperatorUpdateDefinition("$set", field, value); } /// /// Creates a set operator. /// /// The type of the field. /// The field. /// The value. /// A set operator. public UpdateDefinition Set(Expression> field, TField value) { return Set(new ExpressionFieldDefinition(field), value); } /// /// Creates a set on insert operator. /// /// The type of the field. /// The field. /// The value. /// A set on insert operator. public UpdateDefinition SetOnInsert(FieldDefinition field, TField value) { return new OperatorUpdateDefinition("$setOnInsert", field, value); } /// /// Creates a set on insert operator. /// /// The type of the field. /// The field. /// The value. /// A set on insert operator. public UpdateDefinition SetOnInsert(Expression> field, TField value) { return SetOnInsert(new ExpressionFieldDefinition(field), value); } /// /// Creates an unset operator. /// /// The field. /// An unset operator. public UpdateDefinition Unset(FieldDefinition field) { return new OperatorUpdateDefinition("$unset", field, 1); } /// /// Creates an unset operator. /// /// The field. /// An unset operator. public UpdateDefinition Unset(Expression> field) { return Unset(new ExpressionFieldDefinition(field)); } } internal sealed class AddToSetUpdateDefinition : UpdateDefinition { private readonly FieldDefinition _field; private readonly List _values; public AddToSetUpdateDefinition(FieldDefinition field, IEnumerable values) { _field = Ensure.IsNotNull(field, nameof(field)); _values = Ensure.IsNotNull(values, nameof(values)).ToList(); } public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry) { var renderedField = _field.Render(documentSerializer, serializerRegistry); IBsonSerializer itemSerializer; if (renderedField.FieldSerializer != null) { var arraySerializer = renderedField.FieldSerializer as IBsonArraySerializer; BsonSerializationInfo itemSerializationInfo; if (arraySerializer == null || !arraySerializer.TryGetItemSerializationInfo(out itemSerializationInfo)) { var message = string.Format("The serializer for field '{0}' must implement IBsonArraySerializer and provide item serialization info.", renderedField.FieldName); throw new InvalidOperationException(message); } itemSerializer = itemSerializationInfo.Serializer; } else { itemSerializer = serializerRegistry.GetSerializer(); } var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { var context = BsonSerializationContext.CreateRoot(bsonWriter); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("$addToSet"); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); if (_values.Count == 1) { itemSerializer.Serialize(context, _values[0]); } else { bsonWriter.WriteStartDocument(); bsonWriter.WriteName("$each"); bsonWriter.WriteStartArray(); foreach (var value in _values) { itemSerializer.Serialize(context, value); } bsonWriter.WriteEndArray(); bsonWriter.WriteEndDocument(); } bsonWriter.WriteEndDocument(); bsonWriter.WriteEndDocument(); } return document; } } internal sealed class CombinedUpdateDefinition : UpdateDefinition { private readonly List> _updates; public CombinedUpdateDefinition(IEnumerable> updates) { _updates = Ensure.IsNotNull(updates, nameof(updates)).ToList(); } public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry) { var document = new BsonDocument(); foreach (var update in _updates) { var renderedUpdate = update.Render(documentSerializer, serializerRegistry); foreach (var element in renderedUpdate.Elements) { BsonValue currentOperatorValue; if (document.TryGetValue(element.Name, out currentOperatorValue)) { // last one wins document[element.Name] = ((BsonDocument)currentOperatorValue) .Merge((BsonDocument)element.Value, overwriteExistingElements: true); } else { document.Add(element); } } } return document; } } internal sealed class BitwiseOperatorUpdateDefinition : UpdateDefinition { private readonly string _operatorName; private readonly FieldDefinition _field; private readonly TField _value; public BitwiseOperatorUpdateDefinition(string operatorName, FieldDefinition field, TField value) { _operatorName = Ensure.IsNotNull(operatorName, nameof(operatorName)); _field = Ensure.IsNotNull(field, nameof(field)); _value = value; } public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry) { var renderedField = _field.Render(documentSerializer, serializerRegistry); var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { var context = BsonSerializationContext.CreateRoot(bsonWriter); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("$bit"); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(_operatorName); renderedField.ValueSerializer.Serialize(context, _value); bsonWriter.WriteEndDocument(); bsonWriter.WriteEndDocument(); bsonWriter.WriteEndDocument(); } return document; } } internal sealed class OperatorUpdateDefinition : UpdateDefinition { private readonly string _operatorName; private readonly FieldDefinition _field; private readonly BsonValue _value; public OperatorUpdateDefinition(string operatorName, FieldDefinition field, BsonValue value) { _operatorName = Ensure.IsNotNull(operatorName, nameof(operatorName)); _field = Ensure.IsNotNull(field, nameof(field)); _value = value; } public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry) { var renderedField = _field.Render(documentSerializer, serializerRegistry); return new BsonDocument(_operatorName, new BsonDocument(renderedField.FieldName, _value)); } } internal sealed class OperatorUpdateDefinition : UpdateDefinition { private readonly string _operatorName; private readonly FieldDefinition _field; private readonly TField _value; public OperatorUpdateDefinition(string operatorName, FieldDefinition field, TField value) { _operatorName = Ensure.IsNotNull(operatorName, nameof(operatorName)); _field = Ensure.IsNotNull(field, nameof(field)); _value = value; } public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry) { var renderedField = _field.Render(documentSerializer, serializerRegistry); var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { var context = BsonSerializationContext.CreateRoot(bsonWriter); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(_operatorName); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); renderedField.ValueSerializer.Serialize(context, _value); bsonWriter.WriteEndDocument(); bsonWriter.WriteEndDocument(); } return document; } } internal sealed class PullUpdateDefinition : UpdateDefinition { private readonly FieldDefinition _field; private readonly FilterDefinition _filter; private readonly List _values; public PullUpdateDefinition(FieldDefinition field, FilterDefinition filter) { _field = Ensure.IsNotNull(field, nameof(field)); _filter = Ensure.IsNotNull(filter, nameof(filter)); } public PullUpdateDefinition(FieldDefinition field, IEnumerable values) { _field = Ensure.IsNotNull(field, nameof(field)); _values = Ensure.IsNotNull(values, nameof(values)).ToList(); } public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry) { var renderedField = _field.Render(documentSerializer, serializerRegistry); IBsonSerializer itemSerializer; if (renderedField.FieldSerializer != null) { var arraySerializer = renderedField.FieldSerializer as IBsonArraySerializer; BsonSerializationInfo itemSerializationInfo; if (arraySerializer == null || !arraySerializer.TryGetItemSerializationInfo(out itemSerializationInfo)) { var message = string.Format("The serializer for field '{0}' must implement IBsonArraySerializer and provide item serialization info.", renderedField.FieldName); throw new InvalidOperationException(message); } itemSerializer = itemSerializationInfo.Serializer; } else { itemSerializer = serializerRegistry.GetSerializer(); } if (_filter != null) { var renderedFilter = _filter.Render((IBsonSerializer)itemSerializer, serializerRegistry); return new BsonDocument("$pull", new BsonDocument(renderedField.FieldName, renderedFilter)); } else { var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { var context = BsonSerializationContext.CreateRoot(bsonWriter); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(_values.Count == 1 ? "$pull" : "$pullAll"); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); if (_values.Count == 1) { itemSerializer.Serialize(context, _values[0]); } else { bsonWriter.WriteStartArray(); foreach (var value in _values) { itemSerializer.Serialize(context, value); } bsonWriter.WriteEndArray(); } bsonWriter.WriteEndDocument(); bsonWriter.WriteEndDocument(); } return document; } } } internal sealed class PushUpdateDefinition : UpdateDefinition { private readonly FieldDefinition _field; private readonly int? _position; private readonly int? _slice; private SortDefinition _sort; private readonly List _values; public PushUpdateDefinition(FieldDefinition field, IEnumerable values, int? slice = null, int? position = null, SortDefinition sort = null) { _field = Ensure.IsNotNull(field, nameof(field)); _values = Ensure.IsNotNull(values, nameof(values)).ToList(); _slice = slice; _position = position; _sort = sort; } public override BsonDocument Render(IBsonSerializer documentSerializer, IBsonSerializerRegistry serializerRegistry) { var renderedField = _field.Render(documentSerializer, serializerRegistry); IBsonSerializer itemSerializer; if (renderedField.FieldSerializer != null) { var arraySerializer = renderedField.FieldSerializer as IBsonArraySerializer; BsonSerializationInfo itemSerializationInfo; if (arraySerializer == null || !arraySerializer.TryGetItemSerializationInfo(out itemSerializationInfo)) { var message = string.Format("The serializer for field '{0}' must implement IBsonArraySerializer and provide item serialization info.", renderedField.FieldName); throw new InvalidOperationException(message); } itemSerializer = itemSerializationInfo.Serializer; } else { itemSerializer = serializerRegistry.GetSerializer(); } var document = new BsonDocument(); using (var bsonWriter = new BsonDocumentWriter(document)) { var context = BsonSerializationContext.CreateRoot(bsonWriter); bsonWriter.WriteStartDocument(); bsonWriter.WriteName("$push"); bsonWriter.WriteStartDocument(); bsonWriter.WriteName(renderedField.FieldName); if (!_slice.HasValue && !_position.HasValue && _sort == null && _values.Count == 1) { itemSerializer.Serialize(context, _values[0]); } else { bsonWriter.WriteStartDocument(); bsonWriter.WriteName("$each"); bsonWriter.WriteStartArray(); foreach (var value in _values) { itemSerializer.Serialize(context, value); } bsonWriter.WriteEndArray(); if (_slice.HasValue) { bsonWriter.WriteName("$slice"); bsonWriter.WriteInt32(_slice.Value); } if (_position.HasValue) { bsonWriter.WriteName("$position"); bsonWriter.WriteInt32(_position.Value); } bsonWriter.WriteEndDocument(); } bsonWriter.WriteEndDocument(); bsonWriter.WriteEndDocument(); } if (_sort != null) { document["$push"][renderedField.FieldName]["$sort"] = _sort.Render((IBsonSerializer)itemSerializer, serializerRegistry); } return document; } } }