MongoDatabaseImpl.cs 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394
  1. /* Copyright 2010-2016 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 System.Collections.Generic;
  17. using System.Linq;
  18. using System.Reflection;
  19. using System.Threading;
  20. using System.Threading.Tasks;
  21. using MongoDB.Bson;
  22. using MongoDB.Bson.IO;
  23. using MongoDB.Bson.Serialization;
  24. using MongoDB.Driver.Core.Bindings;
  25. using MongoDB.Driver.Core.Clusters;
  26. using MongoDB.Driver.Core.Misc;
  27. using MongoDB.Driver.Core.Operations;
  28. using MongoDB.Driver.Core.WireProtocol.Messages.Encoders;
  29. namespace MongoDB.Driver
  30. {
  31. internal sealed class MongoDatabaseImpl : MongoDatabaseBase
  32. {
  33. // private fields
  34. private readonly IMongoClient _client;
  35. private readonly ICluster _cluster;
  36. private readonly DatabaseNamespace _databaseNamespace;
  37. private readonly IOperationExecutor _operationExecutor;
  38. private readonly MongoDatabaseSettings _settings;
  39. // constructors
  40. public MongoDatabaseImpl(IMongoClient client, DatabaseNamespace databaseNamespace, MongoDatabaseSettings settings, ICluster cluster, IOperationExecutor operationExecutor)
  41. {
  42. _client = Ensure.IsNotNull(client, nameof(client));
  43. _databaseNamespace = Ensure.IsNotNull(databaseNamespace, nameof(databaseNamespace));
  44. _settings = Ensure.IsNotNull(settings, nameof(settings)).Freeze();
  45. _cluster = Ensure.IsNotNull(cluster, nameof(cluster));
  46. _operationExecutor = Ensure.IsNotNull(operationExecutor, nameof(operationExecutor));
  47. }
  48. // public properties
  49. public override IMongoClient Client
  50. {
  51. get { return _client; }
  52. }
  53. public override DatabaseNamespace DatabaseNamespace
  54. {
  55. get { return _databaseNamespace; }
  56. }
  57. public override MongoDatabaseSettings Settings
  58. {
  59. get { return _settings; }
  60. }
  61. // public methods
  62. public override void CreateCollection(string name, CreateCollectionOptions options, CancellationToken cancellationToken)
  63. {
  64. Ensure.IsNotNullOrEmpty(name, nameof(name));
  65. if (options == null)
  66. {
  67. CreateCollectionHelper<BsonDocument>(name, null, cancellationToken);
  68. return;
  69. }
  70. if (options.GetType() == typeof(CreateCollectionOptions))
  71. {
  72. var genericOptions = CreateCollectionOptions<BsonDocument>.CoercedFrom(options);
  73. CreateCollectionHelper<BsonDocument>(name, genericOptions, cancellationToken);
  74. return;
  75. }
  76. var genericMethodDefinition = typeof(MongoDatabaseImpl).GetTypeInfo().GetMethod("CreateCollectionHelper", BindingFlags.NonPublic | BindingFlags.Instance);
  77. var documentType = options.GetType().GetTypeInfo().GetGenericArguments()[0];
  78. var methodInfo = genericMethodDefinition.MakeGenericMethod(documentType);
  79. methodInfo.Invoke(this, new object[] { name, options, cancellationToken });
  80. }
  81. public override Task CreateCollectionAsync(string name, CreateCollectionOptions options, CancellationToken cancellationToken)
  82. {
  83. Ensure.IsNotNullOrEmpty(name, nameof(name));
  84. if (options == null)
  85. {
  86. return CreateCollectionHelperAsync<BsonDocument>(name, null, cancellationToken);
  87. }
  88. if (options.GetType() == typeof(CreateCollectionOptions))
  89. {
  90. var genericOptions = CreateCollectionOptions<BsonDocument>.CoercedFrom(options);
  91. return CreateCollectionHelperAsync<BsonDocument>(name, genericOptions, cancellationToken);
  92. }
  93. var genericMethodDefinition = typeof(MongoDatabaseImpl).GetTypeInfo().GetMethod("CreateCollectionHelperAsync", BindingFlags.NonPublic | BindingFlags.Instance);
  94. var documentType = options.GetType().GetTypeInfo().GetGenericArguments()[0];
  95. var methodInfo = genericMethodDefinition.MakeGenericMethod(documentType);
  96. return (Task)methodInfo.Invoke(this, new object[] { name, options, cancellationToken });
  97. }
  98. public override void CreateView<TDocument, TResult>(string viewName, string viewOn, PipelineDefinition<TDocument, TResult> pipeline, CreateViewOptions<TDocument> options = null, CancellationToken cancellationToken = default(CancellationToken))
  99. {
  100. Ensure.IsNotNull(viewName, nameof(viewName));
  101. Ensure.IsNotNull(viewOn, nameof(viewOn));
  102. Ensure.IsNotNull(pipeline, nameof(pipeline));
  103. options = options ?? new CreateViewOptions<TDocument>();
  104. var operation = CreateCreateViewOperation(viewName, viewOn, pipeline, options);
  105. ExecuteWriteOperation(operation, cancellationToken);
  106. }
  107. public override Task CreateViewAsync<TDocument, TResult>(string viewName, string viewOn, PipelineDefinition<TDocument, TResult> pipeline, CreateViewOptions<TDocument> options = null, CancellationToken cancellationToken = default(CancellationToken))
  108. {
  109. Ensure.IsNotNull(viewName, nameof(viewName));
  110. Ensure.IsNotNull(viewOn, nameof(viewOn));
  111. Ensure.IsNotNull(pipeline, nameof(pipeline));
  112. options = options ?? new CreateViewOptions<TDocument>();
  113. var operation = CreateCreateViewOperation(viewName, viewOn, pipeline, options);
  114. return ExecuteWriteOperationAsync(operation, cancellationToken);
  115. }
  116. public override void DropCollection(string name, CancellationToken cancellationToken)
  117. {
  118. Ensure.IsNotNullOrEmpty(name, nameof(name));
  119. var operation = CreateDropCollectionOperation(name);
  120. ExecuteWriteOperation(operation, cancellationToken);
  121. }
  122. public override Task DropCollectionAsync(string name, CancellationToken cancellationToken)
  123. {
  124. Ensure.IsNotNullOrEmpty(name, nameof(name));
  125. var operation = CreateDropCollectionOperation(name);
  126. return ExecuteWriteOperationAsync(operation, cancellationToken);
  127. }
  128. public override IMongoCollection<TDocument> GetCollection<TDocument>(string name, MongoCollectionSettings settings)
  129. {
  130. Ensure.IsNotNullOrEmpty(name, nameof(name));
  131. settings = settings == null ?
  132. new MongoCollectionSettings() :
  133. settings.Clone();
  134. settings.ApplyDefaultValues(_settings);
  135. return new MongoCollectionImpl<TDocument>(this, new CollectionNamespace(_databaseNamespace, name), settings, _cluster, _operationExecutor);
  136. }
  137. public override IAsyncCursor<BsonDocument> ListCollections(ListCollectionsOptions options, CancellationToken cancellationToken)
  138. {
  139. options = options ?? new ListCollectionsOptions();
  140. var operation = CreateListCollectionsOperation(options);
  141. return ExecuteReadOperation(operation, ReadPreference.Primary, cancellationToken);
  142. }
  143. public override Task<IAsyncCursor<BsonDocument>> ListCollectionsAsync(ListCollectionsOptions options, CancellationToken cancellationToken)
  144. {
  145. options = options ?? new ListCollectionsOptions();
  146. var operation = CreateListCollectionsOperation(options);
  147. return ExecuteReadOperationAsync(operation, ReadPreference.Primary, cancellationToken);
  148. }
  149. public override void RenameCollection(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken)
  150. {
  151. Ensure.IsNotNullOrEmpty(oldName, nameof(oldName));
  152. Ensure.IsNotNullOrEmpty(newName, nameof(newName));
  153. options = options ?? new RenameCollectionOptions();
  154. var operation = CreateRenameCollectionOperation(oldName, newName, options);
  155. ExecuteWriteOperation(operation, cancellationToken);
  156. }
  157. public override Task RenameCollectionAsync(string oldName, string newName, RenameCollectionOptions options, CancellationToken cancellationToken)
  158. {
  159. Ensure.IsNotNullOrEmpty(oldName, nameof(oldName));
  160. Ensure.IsNotNullOrEmpty(newName, nameof(newName));
  161. options = options ?? new RenameCollectionOptions();
  162. var operation = CreateRenameCollectionOperation(oldName, newName, options);
  163. return ExecuteWriteOperationAsync(operation, cancellationToken);
  164. }
  165. public override TResult RunCommand<TResult>(Command<TResult> command, ReadPreference readPreference = null, CancellationToken cancellationToken = default(CancellationToken))
  166. {
  167. Ensure.IsNotNull(command, nameof(command));
  168. readPreference = readPreference ?? ReadPreference.Primary;
  169. var operation = CreateRunCommandOperation(command);
  170. return ExecuteReadOperation(operation, readPreference, cancellationToken);
  171. }
  172. public override Task<TResult> RunCommandAsync<TResult>(Command<TResult> command, ReadPreference readPreference = null, CancellationToken cancellationToken = default(CancellationToken))
  173. {
  174. Ensure.IsNotNull(command, nameof(command));
  175. readPreference = readPreference ?? ReadPreference.Primary;
  176. var operation = CreateRunCommandOperation(command);
  177. return ExecuteReadOperationAsync(operation, readPreference, cancellationToken);
  178. }
  179. public override IMongoDatabase WithReadConcern(ReadConcern readConcern)
  180. {
  181. Ensure.IsNotNull(readConcern, nameof(readConcern));
  182. var newSettings = _settings.Clone();
  183. newSettings.ReadConcern = readConcern;
  184. return new MongoDatabaseImpl(_client, _databaseNamespace, newSettings, _cluster, _operationExecutor);
  185. }
  186. public override IMongoDatabase WithReadPreference(ReadPreference readPreference)
  187. {
  188. Ensure.IsNotNull(readPreference, nameof(readPreference));
  189. var newSettings = _settings.Clone();
  190. newSettings.ReadPreference = readPreference;
  191. return new MongoDatabaseImpl(_client, _databaseNamespace, newSettings, _cluster, _operationExecutor);
  192. }
  193. public override IMongoDatabase WithWriteConcern(WriteConcern writeConcern)
  194. {
  195. Ensure.IsNotNull(writeConcern, nameof(writeConcern));
  196. var newSettings = _settings.Clone();
  197. newSettings.WriteConcern = writeConcern;
  198. return new MongoDatabaseImpl(_client, _databaseNamespace, newSettings, _cluster, _operationExecutor);
  199. }
  200. // private methods
  201. private void CreateCollectionHelper<TDocument>(string name, CreateCollectionOptions<TDocument> options, CancellationToken cancellationToken)
  202. {
  203. options = options ?? new CreateCollectionOptions<TDocument>();
  204. var operation = CreateCreateCollectionOperation(name, options);
  205. ExecuteWriteOperation(operation, cancellationToken);
  206. }
  207. private Task CreateCollectionHelperAsync<TDocument>(string name, CreateCollectionOptions<TDocument> options, CancellationToken cancellationToken)
  208. {
  209. options = options ?? new CreateCollectionOptions<TDocument>();
  210. var operation = CreateCreateCollectionOperation(name, options);
  211. return ExecuteWriteOperationAsync(operation, cancellationToken);
  212. }
  213. private CreateCollectionOperation CreateCreateCollectionOperation(string name, CreateCollectionOptions options)
  214. {
  215. options = options ?? new CreateCollectionOptions();
  216. var messageEncoderSettings = GetMessageEncoderSettings();
  217. return new CreateCollectionOperation(new CollectionNamespace(_databaseNamespace, name), messageEncoderSettings)
  218. {
  219. AutoIndexId = options.AutoIndexId,
  220. Collation = options.Collation,
  221. Capped = options.Capped,
  222. MaxDocuments = options.MaxDocuments,
  223. MaxSize = options.MaxSize,
  224. NoPadding = options.NoPadding,
  225. StorageEngine = options.StorageEngine,
  226. UsePowerOf2Sizes = options.UsePowerOf2Sizes,
  227. WriteConcern = _settings.WriteConcern
  228. };
  229. }
  230. private CreateCollectionOperation CreateCreateCollectionOperation<TDocument>(string name, CreateCollectionOptions<TDocument> options)
  231. {
  232. var messageEncoderSettings = GetMessageEncoderSettings();
  233. BsonDocument validator = null;
  234. if (options.Validator != null)
  235. {
  236. var serializerRegistry = options.SerializerRegistry ?? BsonSerializer.SerializerRegistry;
  237. var documentSerializer = options.DocumentSerializer ?? serializerRegistry.GetSerializer<TDocument>();
  238. validator = options.Validator.Render(documentSerializer, serializerRegistry);
  239. }
  240. return new CreateCollectionOperation(new CollectionNamespace(_databaseNamespace, name), messageEncoderSettings)
  241. {
  242. AutoIndexId = options.AutoIndexId,
  243. Capped = options.Capped,
  244. Collation = options.Collation,
  245. IndexOptionDefaults = options.IndexOptionDefaults?.ToBsonDocument(),
  246. MaxDocuments = options.MaxDocuments,
  247. MaxSize = options.MaxSize,
  248. NoPadding = options.NoPadding,
  249. StorageEngine = options.StorageEngine,
  250. UsePowerOf2Sizes = options.UsePowerOf2Sizes,
  251. ValidationAction = options.ValidationAction,
  252. ValidationLevel = options.ValidationLevel,
  253. Validator = validator,
  254. WriteConcern = _settings.WriteConcern
  255. };
  256. }
  257. private CreateViewOperation CreateCreateViewOperation<TDocument, TResult>(string viewName, string viewOn, PipelineDefinition<TDocument, TResult> pipeline, CreateViewOptions<TDocument> options)
  258. {
  259. var serializerRegistry = options.SerializerRegistry ?? BsonSerializer.SerializerRegistry;
  260. var documentSerializer = options.DocumentSerializer ?? serializerRegistry.GetSerializer<TDocument>();
  261. var pipelineDocuments = pipeline.Render(documentSerializer, serializerRegistry).Documents;
  262. return new CreateViewOperation(_databaseNamespace, viewName, viewOn, pipelineDocuments, GetMessageEncoderSettings())
  263. {
  264. Collation = options.Collation,
  265. WriteConcern = _settings.WriteConcern
  266. };
  267. }
  268. private DropCollectionOperation CreateDropCollectionOperation(string name)
  269. {
  270. var collectionNamespace = new CollectionNamespace(_databaseNamespace, name);
  271. var messageEncoderSettings = GetMessageEncoderSettings();
  272. return new DropCollectionOperation(collectionNamespace, messageEncoderSettings)
  273. {
  274. WriteConcern = _settings.WriteConcern
  275. };
  276. }
  277. private ListCollectionsOperation CreateListCollectionsOperation(ListCollectionsOptions options)
  278. {
  279. var messageEncoderSettings = GetMessageEncoderSettings();
  280. return new ListCollectionsOperation(_databaseNamespace, messageEncoderSettings)
  281. {
  282. Filter = options.Filter?.Render(_settings.SerializerRegistry.GetSerializer<BsonDocument>(), _settings.SerializerRegistry)
  283. };
  284. }
  285. private RenameCollectionOperation CreateRenameCollectionOperation(string oldName, string newName, RenameCollectionOptions options)
  286. {
  287. var messageEncoderSettings = GetMessageEncoderSettings();
  288. return new RenameCollectionOperation(
  289. new CollectionNamespace(_databaseNamespace, oldName),
  290. new CollectionNamespace(_databaseNamespace, newName),
  291. messageEncoderSettings)
  292. {
  293. DropTarget = options.DropTarget,
  294. WriteConcern = _settings.WriteConcern
  295. };
  296. }
  297. private ReadCommandOperation<TResult> CreateRunCommandOperation<TResult>(Command<TResult> command)
  298. {
  299. var renderedCommand = command.Render(_settings.SerializerRegistry);
  300. var messageEncoderSettings = GetMessageEncoderSettings();
  301. return new ReadCommandOperation<TResult>(_databaseNamespace, renderedCommand.Document, renderedCommand.ResultSerializer, messageEncoderSettings);
  302. }
  303. private T ExecuteReadOperation<T>(IReadOperation<T> operation, ReadPreference readPreference, CancellationToken cancellationToken)
  304. {
  305. using (var binding = new ReadPreferenceBinding(_cluster, readPreference))
  306. {
  307. return _operationExecutor.ExecuteReadOperation(binding, operation, cancellationToken);
  308. }
  309. }
  310. private async Task<T> ExecuteReadOperationAsync<T>(IReadOperation<T> operation, ReadPreference readPreference, CancellationToken cancellationToken)
  311. {
  312. using (var binding = new ReadPreferenceBinding(_cluster, readPreference))
  313. {
  314. return await _operationExecutor.ExecuteReadOperationAsync(binding, operation, cancellationToken).ConfigureAwait(false);
  315. }
  316. }
  317. private T ExecuteWriteOperation<T>(IWriteOperation<T> operation, CancellationToken cancellationToken)
  318. {
  319. using (var binding = new WritableServerBinding(_cluster))
  320. {
  321. return _operationExecutor.ExecuteWriteOperation(binding, operation, cancellationToken);
  322. }
  323. }
  324. private async Task<T> ExecuteWriteOperationAsync<T>(IWriteOperation<T> operation, CancellationToken cancellationToken)
  325. {
  326. using (var binding = new WritableServerBinding(_cluster))
  327. {
  328. return await _operationExecutor.ExecuteWriteOperationAsync(binding, operation, cancellationToken).ConfigureAwait(false);
  329. }
  330. }
  331. private MessageEncoderSettings GetMessageEncoderSettings()
  332. {
  333. return new MessageEncoderSettings
  334. {
  335. { MessageEncoderSettingsName.GuidRepresentation, _settings.GuidRepresentation },
  336. { MessageEncoderSettingsName.ReadEncoding, _settings.ReadEncoding ?? Utf8Encodings.Strict },
  337. { MessageEncoderSettingsName.WriteEncoding, _settings.WriteEncoding ?? Utf8Encodings.Strict }
  338. };
  339. }
  340. }
  341. }