/* 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 MongoDB.Bson; using MongoDB.Driver.Core.Operations; using System.Collections.Generic; using System.Linq; namespace MongoDB.Driver { /// /// Base class for a write model. /// /// The type of the document. #if NET452 [Serializable] #endif public abstract class WriteModel { // static methods // These static methods are only called from the Legacy // API, so there is type safety in how they got allowed // into the system, meaning that even though // some things below seem unsafe, they are in a roundabout // way. In addition, we know that there will always // be one level of BsonDocumentWrapper for everything, even // when the type is already a BsonDocument :(. internal static WriteModel FromCore(WriteRequest request) { switch (request.RequestType) { case WriteRequestType.Delete: return ConvertDeleteRequest((DeleteRequest)request); case WriteRequestType.Insert: return ConvertInsertRequest((InsertRequest)request); case WriteRequestType.Update: return ConvertUpdateRequest((UpdateRequest)request); default: throw new NotSupportedException(); } } private static WriteModel ConvertDeleteRequest(DeleteRequest request) { if (request.Limit == 1) { return new DeleteOneModel(UnwrapFilter(request.Filter)) { Collation = request.Collation }; } return new DeleteManyModel(UnwrapFilter(request.Filter)) { Collation = request.Collation }; } private static WriteModel ConvertInsertRequest(InsertRequest request) { var document = (TDocument)Unwrap(request.Document); return new InsertOneModel(document); } private static WriteModel ConvertUpdateRequest(UpdateRequest request) { if (request.IsMulti) { return new UpdateManyModel(UnwrapFilter(request.Filter), UnwrapUpdate(request.Update)) { ArrayFilters = request.ArrayFilters == null ? null : new List(request.ArrayFilters.Select(f => new BsonDocumentArrayFilterDefinition(f))), Collation = request.Collation, IsUpsert = request.IsUpsert }; } var firstElement = request.Update.GetElement(0).Name; if (firstElement.StartsWith("$")) { return new UpdateOneModel(UnwrapFilter(request.Filter), UnwrapUpdate(request.Update)) { ArrayFilters = request.ArrayFilters == null ? null : new List(request.ArrayFilters.Select(f => new BsonDocumentArrayFilterDefinition(f))), Collation = request.Collation, IsUpsert = request.IsUpsert }; } return ConvertToReplaceOne(request); } private static WriteModel ConvertToReplaceOne(UpdateRequest request) { var document = (TDocument)Unwrap(request.Update); if (request.ArrayFilters != null) { throw new ArgumentException("ReplaceOne does not support arrayFilters.", nameof(request)); } return new ReplaceOneModel(UnwrapFilter(request.Filter), document) { Collation = request.Collation, IsUpsert = request.IsUpsert }; } private static FilterDefinition UnwrapFilter(BsonDocument filter) { var wrapper = filter as BsonDocumentWrapper; if (wrapper != null) { if (wrapper.Wrapped is BsonDocument) { return new BsonDocumentFilterDefinition((BsonDocument)wrapper.Wrapped); } return new ObjectFilterDefinition(wrapper.Wrapped); } return new BsonDocumentFilterDefinition(filter); } private static UpdateDefinition UnwrapUpdate(BsonDocument update) { var wrapper = update as BsonDocumentWrapper; if (wrapper != null) { if (wrapper.Wrapped is BsonDocument) { return new BsonDocumentUpdateDefinition((BsonDocument)wrapper.Wrapped); } return new ObjectUpdateDefinition(wrapper.Wrapped); } return new BsonDocumentUpdateDefinition(update); } private static object Unwrap(BsonDocument wrapper) { return ((BsonDocumentWrapper)wrapper).Wrapped; } // constructors // only MongoDB can define new write models. internal WriteModel() { } // properties /// /// Gets the type of the model. /// public abstract WriteModelType ModelType { get; } } }