PageRenderTime 2937ms CodeModel.GetById 35ms RepoModel.GetById 1ms app.codeStats 0ms

/Raven.Client.Lightweight/Linq/LinqExtensions.cs

https://github.com/behailus/ravendb
C# | 290 lines | 168 code | 31 blank | 91 comment | 8 complexity | 1332e215760e1e7dbb8f39a2977b453a MD5 | raw file
  1. //-----------------------------------------------------------------------
  2. // <copyright file="LinqExtensions.cs" company="Hibernating Rhinos LTD">
  3. // Copyright (c) Hibernating Rhinos LTD. All rights reserved.
  4. // </copyright>
  5. //-----------------------------------------------------------------------
  6. using System;
  7. using System.Collections;
  8. using System.Collections.Generic;
  9. using System.ComponentModel;
  10. using System.Linq;
  11. #if !NET_3_5
  12. using System.Threading.Tasks;
  13. #endif
  14. using Raven.Abstractions.Data;
  15. using Raven.Client.Connection;
  16. namespace Raven.Client.Linq
  17. {
  18. using System.Linq.Expressions;
  19. using Newtonsoft.Json;
  20. using Newtonsoft.Json.Linq;
  21. ///<summary>
  22. /// Extensions to the linq syntax
  23. ///</summary>
  24. public static partial class LinqExtensions
  25. {
  26. /// <summary>
  27. /// Project using a different type
  28. /// </summary>
  29. public static IQueryable<TResult> As<TResult>(this IQueryable queryable)
  30. {
  31. var ofType = queryable.OfType<TResult>();
  32. var results = queryable.Provider.CreateQuery<TResult>(ofType.Expression);
  33. var ravenQueryInspector = ((RavenQueryInspector<TResult>)results);
  34. ravenQueryInspector.Customize(x => x.CreateQueryForSelectedFields<TResult>(null));
  35. return results;
  36. }
  37. /// <summary>
  38. /// Project using a different type
  39. /// </summary>
  40. public static IRavenQueryable<TResult> AsProjection<TResult>(this IQueryable queryable)
  41. {
  42. var ofType = queryable.OfType<TResult>();
  43. var results = queryable.Provider.CreateQuery<TResult>(ofType.Expression);
  44. var ravenQueryInspector = ((RavenQueryInspector<TResult>)results);
  45. ravenQueryInspector.FieldsToFetch(typeof(TResult).GetProperties().Select(x => x.Name));
  46. ravenQueryInspector.Customize(x => x.CreateQueryForSelectedFields<TResult>(null));
  47. return (IRavenQueryable<TResult>)results;
  48. }
  49. #if !SILVERLIGHT
  50. /// <summary>
  51. /// Suggest alternative values for the queried term
  52. /// </summary>
  53. public static SuggestionQueryResult Suggest(this IQueryable queryable)
  54. {
  55. return Suggest(queryable, new SuggestionQuery());
  56. }
  57. /// <summary>
  58. /// Suggest alternative values for the queried term
  59. /// </summary>
  60. public static SuggestionQueryResult Suggest(this IQueryable queryable, SuggestionQuery query)
  61. {
  62. var ravenQueryInspector = ((IRavenQueryInspector)queryable);
  63. SetSuggestionQueryFieldAndTerm(ravenQueryInspector,query);
  64. return ravenQueryInspector.DatabaseCommands.Suggest(ravenQueryInspector.IndexQueried, query);
  65. }
  66. #endif
  67. private static void SetSuggestionQueryFieldAndTerm(IRavenQueryInspector queryInspector, SuggestionQuery query)
  68. {
  69. var lastEqualityTerm = queryInspector.GetLastEqualityTerm();
  70. if (lastEqualityTerm.Key == null)
  71. throw new InvalidOperationException("Could not suggest on a query that doesn't have a single equality check");
  72. query.Field = lastEqualityTerm.Key;
  73. query.Term = lastEqualityTerm.Value;
  74. }
  75. #if !NET_3_5
  76. /// <summary>
  77. /// Suggest alternative values for the queried term
  78. /// </summary>
  79. public static Task<SuggestionQueryResult> SuggestAsync(this IQueryable queryable, SuggestionQuery query)
  80. {
  81. var ravenQueryInspector = ((IRavenQueryInspector)queryable);
  82. SetSuggestionQueryFieldAndTerm(ravenQueryInspector, query);
  83. return ravenQueryInspector.AsyncDatabaseCommands.SuggestAsync(ravenQueryInspector.IndexQueried, query);
  84. }
  85. /// <summary>
  86. /// Suggest alternative values for the queried term
  87. /// </summary>
  88. public static Task<SuggestionQueryResult> SuggestAsync(this IQueryable queryable)
  89. {
  90. return SuggestAsync(queryable, new SuggestionQuery());
  91. }
  92. #endif
  93. /// <summary>
  94. /// Marker method for allowing complex (multi entity) queries on the server.
  95. /// </summary>
  96. public static IEnumerable<TResult> WhereEntityIs<TResult>(this IEnumerable<object> queryable, params string[] names)
  97. {
  98. throw new NotSupportedException("This method is provided solely to allow query translation on the server");
  99. }
  100. /// <summary>
  101. /// Marker method for allowing complex (multi entity) queries on the server.
  102. /// </summary>
  103. public static TResult IfEntityIs<TResult>(this object queryable, string name)
  104. {
  105. throw new NotSupportedException("This method is provided solely to allow query translation on the server");
  106. }
  107. /// <summary>
  108. /// Marker method for allowing hierarchical queries on the server.
  109. /// </summary>
  110. public static IEnumerable<TResult> Hierarchy<TResult>(this TResult item, string path)
  111. {
  112. throw new NotSupportedException("This method is provided solely to allow query translation on the server");
  113. }
  114. /// <summary>
  115. /// Marker method for allowing hierarchical queries on the server.
  116. /// </summary>
  117. public static IEnumerable<TResult> Hierarchy<TResult>(this TResult item, Func<TResult, IEnumerable<TResult>> path)
  118. {
  119. throw new NotSupportedException("This method is provided solely to allow query translation on the server");
  120. }
  121. #if !NET_3_5
  122. /// <summary>
  123. /// Register the query as a lazy query in the session and return a lazy
  124. /// instance that will evaluate the query only when needed
  125. /// </summary>
  126. public static Lazy<IEnumerable<T>> Lazily<T>(this IQueryable<T> source)
  127. {
  128. return Lazily(source, null);
  129. }
  130. /// <summary>
  131. /// Register the query as a lazy query in the session and return a lazy
  132. /// instance that will evaluate the query only when needed
  133. /// As well as a function to execute when the value is evaluated
  134. /// </summary>
  135. public static Lazy<IEnumerable<T>> Lazily<T>(this IQueryable<T> source, Action<IEnumerable<T>> onEval)
  136. {
  137. var provider = source.Provider as IRavenQueryProvider;
  138. if (provider == null)
  139. throw new ArgumentException("You can only use Raven Queryable with Lazily");
  140. return provider.Lazily(source.Expression, onEval);
  141. }
  142. /// <summary>
  143. /// Returns a list of results for a query asynchronously.
  144. /// </summary>
  145. public static Task<IList<T>> ToListAsync<T>(this IQueryable<T> source)
  146. {
  147. var provider = source.Provider as IRavenQueryProvider;
  148. if(provider == null)
  149. throw new ArgumentException("You can only use Raven Queryable with ToListAsync");
  150. var documentQuery = provider.ToAsyncLuceneQuery<T>(source.Expression);
  151. provider.MoveAfterQueryExecuted(documentQuery);
  152. return documentQuery.ToListAsync()
  153. .ContinueWith(task => task.Result.Item2);
  154. }
  155. /// <summary>
  156. /// Returns the total count of results for a query asynchronously.
  157. /// </summary>
  158. public static Task<int> CountAsync<T>(this IQueryable<T> source)
  159. {
  160. var provider = source.Provider as IRavenQueryProvider;
  161. if (provider == null)
  162. throw new ArgumentException("You can only use Raven Queryable with CountAsync");
  163. var documentQuery = provider
  164. .ToAsyncLuceneQuery<T>(source.Expression)
  165. .Take(0);
  166. provider.MoveAfterQueryExecuted(documentQuery);
  167. return documentQuery.ToListAsync()
  168. .ContinueWith(task => task.Result.Item1.TotalResults);
  169. }
  170. #endif
  171. /// <summary>
  172. /// Includes the specified path in the query, loading the document specified in that path
  173. /// </summary>
  174. /// <param name="path">The path.</param>
  175. public static IRavenQueryable<T> Include<T>(this IRavenQueryable<T> source, Expression<Func<T, object>> path)
  176. {
  177. source.Customize(x => x.Include(path));
  178. return source;
  179. }
  180. /// <summary>
  181. /// Filters a sequence of values based on a predicate.
  182. /// </summary>
  183. public static IRavenQueryable<T> Where<T>(this IRavenQueryable<T> source, Expression<Func<T, bool>> prediate)
  184. {
  185. return (IRavenQueryable<T>)Queryable.Where(source, prediate);
  186. }
  187. /// <summary>
  188. /// Filters a sequence of values based on a predicate.
  189. /// </summary>
  190. public static IRavenQueryable<T> Where<T>(this IRavenQueryable<T> source, Expression<Func<T, int, bool>> prediate)
  191. {
  192. return (IRavenQueryable<T>)Queryable.Where(source, prediate);
  193. }
  194. /// <summary>
  195. /// Sorts the elements of a sequence in ascending order according to a key.
  196. /// </summary>
  197. public static IRavenQueryable<T> OrderBy<T, TK>(this IRavenQueryable<T> source, Expression<Func<T, TK>> keySelector)
  198. {
  199. return (IRavenQueryable<T>)Queryable.OrderBy(source, keySelector);
  200. }
  201. /// <summary>
  202. /// Sorts the elements of a sequence in ascending order according to a key.
  203. /// </summary>
  204. public static IRavenQueryable<T> OrderBy<T, TK>(this IRavenQueryable<T> source, Expression<Func<T, TK>> keySelector, IComparer<TK> comparer)
  205. {
  206. return (IRavenQueryable<T>)Queryable.OrderBy(source, keySelector, comparer);
  207. }
  208. /// <summary>
  209. /// Sorts the elements of a sequence in descending order according to a key.
  210. /// </summary>
  211. public static IRavenQueryable<T> OrderByDescending<T, TK>(this IRavenQueryable<T> source, Expression<Func<T, TK>> keySelector)
  212. {
  213. return (IRavenQueryable<T>)Queryable.OrderByDescending(source, keySelector);
  214. }
  215. /// <summary>
  216. /// Sorts the elements of a sequence in descending order according to a key.
  217. /// </summary>
  218. public static IRavenQueryable<T> OrderByDescending<T, TK>(this IRavenQueryable<T> source, Expression<Func<T, TK>> keySelector, IComparer<TK> comparer)
  219. {
  220. return (IRavenQueryable<T>)Queryable.OrderByDescending(source, keySelector, comparer);
  221. }
  222. /// <summary>
  223. /// Projects each element of a sequence into a new form.
  224. /// </summary>
  225. public static IRavenQueryable<TResult> Select<TSource, TResult>(this IRavenQueryable<TSource> source, Expression<Func<TSource, TResult>> selector)
  226. {
  227. return (IRavenQueryable<TResult>)Queryable.Select(source, selector);
  228. }
  229. /// <summary>
  230. /// Projects each element of a sequence into a new form.
  231. /// </summary>
  232. public static IRavenQueryable<TResult> Select<TSource, TResult>(this IRavenQueryable<TSource> source, Expression<Func<TSource,int, TResult>> selector)
  233. {
  234. return (IRavenQueryable<TResult>)Queryable.Select(source, selector);
  235. }
  236. /// <summary>
  237. /// implementation of In operator
  238. /// </summary>
  239. public static bool In<T>(this T field, IEnumerable<T> values)
  240. {
  241. return values.Any(value => field.Equals(value));
  242. }
  243. /// <summary>
  244. /// implementation of In operator
  245. /// </summary>
  246. public static bool In<T>(this T field, params T[] values)
  247. {
  248. return values.Any(value => field.Equals(value));
  249. }
  250. /// <summary>
  251. /// Bypasses a specified number of elements in a sequence and then returns the remaining elements.
  252. /// </summary>
  253. /// Summary:
  254. public static IRavenQueryable<TSource> Skip<TSource>(this IRavenQueryable<TSource> source, int count)
  255. {
  256. return (IRavenQueryable<TSource>)Queryable.Skip(source,count);
  257. }
  258. }
  259. }