IFindFluentExtensions.cs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  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 System.Linq;
  17. using System.Linq.Expressions;
  18. using System.Threading;
  19. using System.Threading.Tasks;
  20. using MongoDB.Bson;
  21. using MongoDB.Bson.Serialization;
  22. using MongoDB.Driver.Core.Misc;
  23. namespace MongoDB.Driver
  24. {
  25. /// <summary>
  26. /// Extension methods for <see cref="IFindFluent{TDocument, TProjection}"/>
  27. /// </summary>
  28. public static class IFindFluentExtensions
  29. {
  30. /// <summary>
  31. /// Projects the result.
  32. /// </summary>
  33. /// <typeparam name="TDocument">The type of the document.</typeparam>
  34. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  35. /// <param name="find">The fluent find.</param>
  36. /// <param name="projection">The projection.</param>
  37. /// <returns>The fluent find interface.</returns>
  38. public static IFindFluent<TDocument, BsonDocument> Project<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, ProjectionDefinition<TDocument, BsonDocument> projection)
  39. {
  40. Ensure.IsNotNull(find, nameof(find));
  41. Ensure.IsNotNull(projection, nameof(projection));
  42. return find.Project<BsonDocument>(projection);
  43. }
  44. /// <summary>
  45. /// Projects the result.
  46. /// </summary>
  47. /// <typeparam name="TDocument">The type of the document.</typeparam>
  48. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  49. /// <typeparam name="TNewProjection">The type of the new projection.</typeparam>
  50. /// <param name="find">The fluent find.</param>
  51. /// <param name="projection">The projection.</param>
  52. /// <returns>The fluent find interface.</returns>
  53. public static IFindFluent<TDocument, TNewProjection> Project<TDocument, TProjection, TNewProjection>(this IFindFluent<TDocument, TProjection> find, Expression<Func<TDocument, TNewProjection>> projection)
  54. {
  55. Ensure.IsNotNull(find, nameof(find));
  56. Ensure.IsNotNull(projection, nameof(projection));
  57. return find.Project<TNewProjection>(new FindExpressionProjectionDefinition<TDocument, TNewProjection>(projection));
  58. }
  59. /// <summary>
  60. /// Sorts the results by an ascending field.
  61. /// </summary>
  62. /// <typeparam name="TDocument">The type of the document.</typeparam>
  63. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  64. /// <param name="find">The fluent find.</param>
  65. /// <param name="field">The field.</param>
  66. /// <returns>The fluent find interface.</returns>
  67. public static IOrderedFindFluent<TDocument, TProjection> SortBy<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, Expression<Func<TDocument, object>> field)
  68. {
  69. Ensure.IsNotNull(find, nameof(find));
  70. Ensure.IsNotNull(field, nameof(field));
  71. // We require an implementation of IFindFluent<TDocument, TProjection>
  72. // to also implement IOrderedFindFluent<TDocument, TProjection>
  73. return (IOrderedFindFluent<TDocument, TProjection>)find.Sort(
  74. new DirectionalSortDefinition<TDocument>(new ExpressionFieldDefinition<TDocument>(field), SortDirection.Ascending));
  75. }
  76. /// <summary>
  77. /// Sorts the results by a descending field.
  78. /// </summary>
  79. /// <typeparam name="TDocument">The type of the document.</typeparam>
  80. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  81. /// <param name="find">The fluent find.</param>
  82. /// <param name="field">The field.</param>
  83. /// <returns>The fluent find interface.</returns>
  84. public static IOrderedFindFluent<TDocument, TProjection> SortByDescending<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, Expression<Func<TDocument, object>> field)
  85. {
  86. Ensure.IsNotNull(find, nameof(find));
  87. Ensure.IsNotNull(field, nameof(field));
  88. // We require an implementation of IFindFluent<TDocument, TProjection>
  89. // to also implement IOrderedFindFluent<TDocument, TProjection>
  90. return (IOrderedFindFluent<TDocument, TProjection>)find.Sort(
  91. new DirectionalSortDefinition<TDocument>(new ExpressionFieldDefinition<TDocument>(field), SortDirection.Descending));
  92. }
  93. /// <summary>
  94. /// Adds an ascending field to the existing sort.
  95. /// </summary>
  96. /// <typeparam name="TDocument">The type of the document.</typeparam>
  97. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  98. /// <param name="find">The fluent find.</param>
  99. /// <param name="field">The field.</param>
  100. /// <returns>The fluent find interface.</returns>
  101. public static IOrderedFindFluent<TDocument, TProjection> ThenBy<TDocument, TProjection>(this IOrderedFindFluent<TDocument, TProjection> find, Expression<Func<TDocument, object>> field)
  102. {
  103. Ensure.IsNotNull(find, nameof(find));
  104. Ensure.IsNotNull(field, nameof(field));
  105. find.Options.Sort = new SortDefinitionBuilder<TDocument>().Combine(
  106. find.Options.Sort,
  107. new DirectionalSortDefinition<TDocument>(new ExpressionFieldDefinition<TDocument>(field), SortDirection.Ascending));
  108. return find;
  109. }
  110. /// <summary>
  111. /// Adds a descending field to the existing sort.
  112. /// </summary>
  113. /// <typeparam name="TDocument">The type of the document.</typeparam>
  114. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  115. /// <param name="find">The fluent find.</param>
  116. /// <param name="field">The field.</param>
  117. /// <returns>The fluent find interface.</returns>
  118. public static IOrderedFindFluent<TDocument, TProjection> ThenByDescending<TDocument, TProjection>(this IOrderedFindFluent<TDocument, TProjection> find, Expression<Func<TDocument, object>> field)
  119. {
  120. Ensure.IsNotNull(find, nameof(find));
  121. Ensure.IsNotNull(field, nameof(field));
  122. find.Options.Sort = new SortDefinitionBuilder<TDocument>().Combine(
  123. find.Options.Sort,
  124. new DirectionalSortDefinition<TDocument>(new ExpressionFieldDefinition<TDocument>(field), SortDirection.Descending));
  125. return find;
  126. }
  127. /// <summary>
  128. /// Get the first result.
  129. /// </summary>
  130. /// <typeparam name="TDocument">The type of the document.</typeparam>
  131. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  132. /// <param name="find">The fluent find.</param>
  133. /// <param name="cancellationToken">The cancellation token.</param>
  134. /// <returns>A Task whose result is the first result.</returns>
  135. public static TProjection First<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, CancellationToken cancellationToken = default(CancellationToken))
  136. {
  137. Ensure.IsNotNull(find, nameof(find));
  138. return IAsyncCursorSourceExtensions.First(find.Limit(1), cancellationToken);
  139. }
  140. /// <summary>
  141. /// Get the first result.
  142. /// </summary>
  143. /// <typeparam name="TDocument">The type of the document.</typeparam>
  144. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  145. /// <param name="find">The fluent find.</param>
  146. /// <param name="cancellationToken">The cancellation token.</param>
  147. /// <returns>A Task whose result is the first result.</returns>
  148. public static Task<TProjection> FirstAsync<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, CancellationToken cancellationToken = default(CancellationToken))
  149. {
  150. Ensure.IsNotNull(find, nameof(find));
  151. return IAsyncCursorSourceExtensions.FirstAsync(find.Limit(1), cancellationToken);
  152. }
  153. /// <summary>
  154. /// Get the first result or null.
  155. /// </summary>
  156. /// <typeparam name="TDocument">The type of the document.</typeparam>
  157. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  158. /// <param name="find">The fluent find.</param>
  159. /// <param name="cancellationToken">The cancellation token.</param>
  160. /// <returns>A Task whose result is the first result or null.</returns>
  161. public static TProjection FirstOrDefault<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, CancellationToken cancellationToken = default(CancellationToken))
  162. {
  163. Ensure.IsNotNull(find, nameof(find));
  164. return IAsyncCursorSourceExtensions.FirstOrDefault(find.Limit(1), cancellationToken);
  165. }
  166. /// <summary>
  167. /// Get the first result or null.
  168. /// </summary>
  169. /// <typeparam name="TDocument">The type of the document.</typeparam>
  170. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  171. /// <param name="find">The fluent find.</param>
  172. /// <param name="cancellationToken">The cancellation token.</param>
  173. /// <returns>A Task whose result is the first result or null.</returns>
  174. public static Task<TProjection> FirstOrDefaultAsync<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, CancellationToken cancellationToken = default(CancellationToken))
  175. {
  176. Ensure.IsNotNull(find, nameof(find));
  177. return IAsyncCursorSourceExtensions.FirstOrDefaultAsync(find.Limit(1), cancellationToken);
  178. }
  179. /// <summary>
  180. /// Gets a single result.
  181. /// </summary>
  182. /// <typeparam name="TDocument">The type of the document.</typeparam>
  183. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  184. /// <param name="find">The fluent find.</param>
  185. /// <param name="cancellationToken">The cancellation token.</param>
  186. /// <returns>A Task whose result is the single result.</returns>
  187. public static TProjection Single<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, CancellationToken cancellationToken = default(CancellationToken))
  188. {
  189. Ensure.IsNotNull(find, nameof(find));
  190. if (!find.Options.Limit.HasValue || find.Options.Limit.Value > 2)
  191. {
  192. find = find.Limit(2);
  193. }
  194. return IAsyncCursorSourceExtensions.Single(find, cancellationToken);
  195. }
  196. /// <summary>
  197. /// Gets a single result.
  198. /// </summary>
  199. /// <typeparam name="TDocument">The type of the document.</typeparam>
  200. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  201. /// <param name="find">The fluent find.</param>
  202. /// <param name="cancellationToken">The cancellation token.</param>
  203. /// <returns>A Task whose result is the single result.</returns>
  204. public static Task<TProjection> SingleAsync<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, CancellationToken cancellationToken = default(CancellationToken))
  205. {
  206. Ensure.IsNotNull(find, nameof(find));
  207. if (!find.Options.Limit.HasValue || find.Options.Limit.Value > 2)
  208. {
  209. find = find.Limit(2);
  210. }
  211. return IAsyncCursorSourceExtensions.SingleAsync(find, cancellationToken);
  212. }
  213. /// <summary>
  214. /// Gets a single result or null.
  215. /// </summary>
  216. /// <typeparam name="TDocument">The type of the document.</typeparam>
  217. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  218. /// <param name="find">The fluent find.</param>
  219. /// <param name="cancellationToken">The cancellation token.</param>
  220. /// <returns>A Task whose result is the single result or null.</returns>
  221. public static TProjection SingleOrDefault<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, CancellationToken cancellationToken = default(CancellationToken))
  222. {
  223. Ensure.IsNotNull(find, nameof(find));
  224. if (!find.Options.Limit.HasValue || find.Options.Limit.Value > 2)
  225. {
  226. find = find.Limit(2);
  227. }
  228. return IAsyncCursorSourceExtensions.SingleOrDefault(find, cancellationToken);
  229. }
  230. /// <summary>
  231. /// Gets a single result or null.
  232. /// </summary>
  233. /// <typeparam name="TDocument">The type of the document.</typeparam>
  234. /// <typeparam name="TProjection">The type of the projection (same as TDocument if there is no projection).</typeparam>
  235. /// <param name="find">The fluent find.</param>
  236. /// <param name="cancellationToken">The cancellation token.</param>
  237. /// <returns>A Task whose result is the single result or null.</returns>
  238. public static Task<TProjection> SingleOrDefaultAsync<TDocument, TProjection>(this IFindFluent<TDocument, TProjection> find, CancellationToken cancellationToken = default(CancellationToken))
  239. {
  240. Ensure.IsNotNull(find, nameof(find));
  241. if (!find.Options.Limit.HasValue || find.Options.Limit.Value > 2)
  242. {
  243. find = find.Limit(2);
  244. }
  245. return IAsyncCursorSourceExtensions.SingleOrDefaultAsync(find, cancellationToken);
  246. }
  247. }
  248. }