WriteModel.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. /* Copyright 2010-present MongoDB Inc.
  2. *
  3. * Licensed under the Apache License, Version 2.0 (the "License");
  4. * you may not use this file except in compliance with the License.
  5. * You may obtain a copy of the License at
  6. *
  7. * http://www.apache.org/licenses/LICENSE-2.0
  8. *
  9. * Unless required by applicable law or agreed to in writing, software
  10. * distributed under the License is distributed on an "AS IS" BASIS,
  11. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. * See the License for the specific language governing permissions and
  13. * limitations under the License.
  14. */
  15. using System;
  16. using MongoDB.Bson;
  17. using MongoDB.Driver.Core.Operations;
  18. using System.Collections.Generic;
  19. using System.Linq;
  20. namespace MongoDB.Driver
  21. {
  22. /// <summary>
  23. /// Base class for a write model.
  24. /// </summary>
  25. /// <typeparam name="TDocument">The type of the document.</typeparam>
  26. #if NET452
  27. [Serializable]
  28. #endif
  29. public abstract class WriteModel<TDocument>
  30. {
  31. // static methods
  32. // These static methods are only called from the Legacy
  33. // API, so there is type safety in how they got allowed
  34. // into the system, meaning that even though
  35. // some things below seem unsafe, they are in a roundabout
  36. // way. In addition, we know that there will always
  37. // be one level of BsonDocumentWrapper for everything, even
  38. // when the type is already a BsonDocument :(.
  39. internal static WriteModel<TDocument> FromCore(WriteRequest request)
  40. {
  41. switch (request.RequestType)
  42. {
  43. case WriteRequestType.Delete:
  44. return ConvertDeleteRequest((DeleteRequest)request);
  45. case WriteRequestType.Insert:
  46. return ConvertInsertRequest((InsertRequest)request);
  47. case WriteRequestType.Update:
  48. return ConvertUpdateRequest((UpdateRequest)request);
  49. default:
  50. throw new NotSupportedException();
  51. }
  52. }
  53. private static WriteModel<TDocument> ConvertDeleteRequest(DeleteRequest request)
  54. {
  55. if (request.Limit == 1)
  56. {
  57. return new DeleteOneModel<TDocument>(UnwrapFilter(request.Filter))
  58. {
  59. Collation = request.Collation
  60. };
  61. }
  62. return new DeleteManyModel<TDocument>(UnwrapFilter(request.Filter))
  63. {
  64. Collation = request.Collation
  65. };
  66. }
  67. private static WriteModel<TDocument> ConvertInsertRequest(InsertRequest request)
  68. {
  69. var document = (TDocument)Unwrap(request.Document);
  70. return new InsertOneModel<TDocument>(document);
  71. }
  72. private static WriteModel<TDocument> ConvertUpdateRequest(UpdateRequest request)
  73. {
  74. if (request.IsMulti)
  75. {
  76. return new UpdateManyModel<TDocument>(UnwrapFilter(request.Filter), UnwrapUpdate(request.Update))
  77. {
  78. ArrayFilters = request.ArrayFilters == null ? null : new List<ArrayFilterDefinition>(request.ArrayFilters.Select(f => new BsonDocumentArrayFilterDefinition<BsonValue>(f))),
  79. Collation = request.Collation,
  80. IsUpsert = request.IsUpsert
  81. };
  82. }
  83. var firstElement = request.Update.GetElement(0).Name;
  84. if (firstElement.StartsWith("$"))
  85. {
  86. return new UpdateOneModel<TDocument>(UnwrapFilter(request.Filter), UnwrapUpdate(request.Update))
  87. {
  88. ArrayFilters = request.ArrayFilters == null ? null : new List<ArrayFilterDefinition>(request.ArrayFilters.Select(f => new BsonDocumentArrayFilterDefinition<BsonValue>(f))),
  89. Collation = request.Collation,
  90. IsUpsert = request.IsUpsert
  91. };
  92. }
  93. return ConvertToReplaceOne(request);
  94. }
  95. private static WriteModel<TDocument> ConvertToReplaceOne(UpdateRequest request)
  96. {
  97. var document = (TDocument)Unwrap(request.Update);
  98. if (request.ArrayFilters != null)
  99. {
  100. throw new ArgumentException("ReplaceOne does not support arrayFilters.", nameof(request));
  101. }
  102. return new ReplaceOneModel<TDocument>(UnwrapFilter(request.Filter), document)
  103. {
  104. Collation = request.Collation,
  105. IsUpsert = request.IsUpsert
  106. };
  107. }
  108. private static FilterDefinition<TDocument> UnwrapFilter(BsonDocument filter)
  109. {
  110. var wrapper = filter as BsonDocumentWrapper;
  111. if (wrapper != null)
  112. {
  113. if (wrapper.Wrapped is BsonDocument)
  114. {
  115. return new BsonDocumentFilterDefinition<TDocument>((BsonDocument)wrapper.Wrapped);
  116. }
  117. return new ObjectFilterDefinition<TDocument>(wrapper.Wrapped);
  118. }
  119. return new BsonDocumentFilterDefinition<TDocument>(filter);
  120. }
  121. private static UpdateDefinition<TDocument> UnwrapUpdate(BsonDocument update)
  122. {
  123. var wrapper = update as BsonDocumentWrapper;
  124. if (wrapper != null)
  125. {
  126. if (wrapper.Wrapped is BsonDocument)
  127. {
  128. return new BsonDocumentUpdateDefinition<TDocument>((BsonDocument)wrapper.Wrapped);
  129. }
  130. return new ObjectUpdateDefinition<TDocument>(wrapper.Wrapped);
  131. }
  132. return new BsonDocumentUpdateDefinition<TDocument>(update);
  133. }
  134. private static object Unwrap(BsonDocument wrapper)
  135. {
  136. return ((BsonDocumentWrapper)wrapper).Wrapped;
  137. }
  138. // constructors
  139. // only MongoDB can define new write models.
  140. internal WriteModel()
  141. {
  142. }
  143. // properties
  144. /// <summary>
  145. /// Gets the type of the model.
  146. /// </summary>
  147. public abstract WriteModelType ModelType { get; }
  148. }
  149. }