/* 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; }
}
}