Line data Source code
1 : #region Copyright
2 : // // -----------------------------------------------------------------------
3 : // // <copyright company="Chinchilla Software Limited">
4 : // // Copyright Chinchilla Software Limited. All rights reserved.
5 : // // </copyright>
6 : // // -----------------------------------------------------------------------
7 : #endregion
8 :
9 : using System;
10 : using System.Linq;
11 : using Cqrs.Configuration;
12 : using Cqrs.Entities;
13 : using Cqrs.DataStores;
14 :
15 : namespace Cqrs.Repositories.Queries
16 : {
17 : /// <summary>
18 : /// Builds an <see cref="IQueryable"/> from a <typeparamref name="TQueryStrategy"/>.
19 : /// </summary>
20 : /// <typeparam name="TQueryStrategy">The <see cref="Type"/> of the <see cref="IQueryStrategy"/>.</typeparam>
21 : /// <typeparam name="TData">The <see cref="Type"/> of data to query.</typeparam>
22 : public abstract class QueryBuilder<TQueryStrategy, TData> : IQueryBuilder<TQueryStrategy, TData>
23 : where TQueryStrategy : IQueryStrategy
24 : where TData : Entity
25 1 : {
26 : /// <summary>
27 : /// Gets or set the <see cref="IDataStore{TData}"/> to use.
28 : /// </summary>
29 : protected IDataStore<TData> DataStore { get; private set; }
30 :
31 : /// <summary>
32 : /// Gets or set the <see cref="IDependencyResolver"/>.
33 : /// </summary>
34 : protected IDependencyResolver DependencyResolver { get; private set; }
35 :
36 : /// <summary>
37 : /// Instantiates a new instance of <see cref="QueryBuilder{TQueryStrategy,TData}"/>.
38 : /// </summary>
39 1 : protected QueryBuilder(IDataStore<TData> dataStore, IDependencyResolver dependencyResolver)
40 : {
41 : DataStore = dataStore;
42 : DependencyResolver = dependencyResolver;
43 : }
44 :
45 : #region Implementation of IQueryBuilder<UserQueryStrategy,User>
46 :
47 : /// <summary>
48 : /// Create an <see cref="IQueryable"/> of <typeparamref name="TData"/>
49 : /// that expects a single <typeparamref name="TData"/> item.
50 : /// </summary>
51 : /// <param name="singleResultQuery">The query.</param>
52 1 : public virtual IQueryable<TData> CreateQueryable(ISingleResultQuery<TQueryStrategy, TData> singleResultQuery)
53 : {
54 : IQueryable<TData> queryable = singleResultQuery.QueryStrategy.QueryPredicate == null ? GetEmptyQueryPredicate() : GeneratePredicate(singleResultQuery.QueryStrategy.QueryPredicate);
55 : ApplySorting(singleResultQuery.QueryStrategy, ref queryable);
56 : return queryable;
57 : }
58 :
59 : /// <summary>
60 : /// Create an <see cref="IQueryable"/> of <typeparamref name="TData"/>
61 : /// that expects a collection of <typeparamref name="TData"/> items.
62 : /// </summary>
63 : /// <param name="collectionResultQuery">The query.</param>
64 1 : public virtual IQueryable<TData> CreateQueryable(ICollectionResultQuery<TQueryStrategy, TData> collectionResultQuery)
65 : {
66 : IQueryable<TData> queryable = collectionResultQuery.QueryStrategy.QueryPredicate == null ? GetEmptyQueryPredicate() : GeneratePredicate(collectionResultQuery.QueryStrategy.QueryPredicate);
67 : ApplySorting(collectionResultQuery.QueryStrategy, ref queryable);
68 : return queryable;
69 : }
70 :
71 : #endregion
72 :
73 : /// <summary>
74 : /// Returns the <see cref="DataStore"/> itself.
75 : /// </summary>
76 1 : protected virtual IQueryable<TData> GetEmptyQueryPredicate()
77 : {
78 : return DataStore;
79 : }
80 :
81 : /// <summary>
82 : /// Builds an <see cref="IQueryable"/> from the <paramref name="queryPredicate"/> and an optional <paramref name="leftHandQueryable"/>.
83 : /// This recursively calls itself and may call <see cref="GeneratePredicateIsNotLogicallyDeleted"/>.
84 : /// </summary>
85 1 : protected virtual IQueryable<TData> GeneratePredicate(IQueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable = null)
86 : {
87 : var andQueryPredicate = queryPredicate as IAndQueryPredicate;
88 : if (andQueryPredicate != null)
89 : {
90 : IQueryable<TData> innerLeftHandQueryable = GeneratePredicate(andQueryPredicate.LeftQueryPredicate);
91 : return GeneratePredicate(andQueryPredicate.RightQueryPredicate, innerLeftHandQueryable);
92 : }
93 : var orQueryPredicate = queryPredicate as IOrQueryPredicate;
94 : if (orQueryPredicate != null)
95 : {
96 : IQueryable<TData> innerLeftHandQueryable = GeneratePredicate(orQueryPredicate.LeftQueryPredicate);
97 : return GeneratePredicate(orQueryPredicate.RightQueryPredicate, innerLeftHandQueryable);
98 : }
99 : var realQueryPredicate = queryPredicate as QueryPredicate;
100 : if (realQueryPredicate != null)
101 : {
102 : IQueryable<TData> result = GeneratePredicateIsNotLogicallyDeleted(realQueryPredicate, leftHandQueryable);
103 : return result ?? GeneratePredicate(realQueryPredicate, leftHandQueryable);
104 : }
105 : throw new InvalidOperationException(string.Format("The query predicate '{0}' is unable to be processed.", queryPredicate == null ? typeof(void) : queryPredicate.GetType()));
106 : }
107 :
108 : /// <summary>
109 : /// Builds the relevant <see cref="IQueryable"/> for <see cref="QueryStrategy.IsNotLogicallyDeleted"/>.
110 : /// </summary>
111 1 : protected virtual IQueryable<TData> GeneratePredicateIsNotLogicallyDeleted(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable = null)
112 : {
113 : var queryStrategy = GetNullQueryStrategy() as QueryStrategy;
114 :
115 : if (queryStrategy == null)
116 : return null;
117 :
118 : if (queryPredicate.Name != GetFunctionName(queryStrategy.IsNotLogicallyDeleted))
119 : return null;
120 :
121 : return (leftHandQueryable ?? GetEmptyQueryPredicate()).Where
122 : (
123 : entity => !entity.IsLogicallyDeleted
124 : );
125 : }
126 :
127 : /// <summary>
128 : /// Builds the relevant <see cref="IQueryable"/> for <see cref="QueryStrategy.WithPermissionScopeAny{TAuthenticationToken}"/>.
129 : /// </summary>
130 1 : protected virtual IQueryable<TData> GeneratePredicateWithPermissionScopeAny<TAuthenticationToken>(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable)
131 : {
132 : var queryStrategy = GetNullQueryStrategy() as QueryStrategy;
133 :
134 : if (queryStrategy == null)
135 : return null;
136 :
137 : if (queryPredicate.Name != GetFunctionNameOfType<TAuthenticationToken>(queryStrategy.WithPermissionScopeAny))
138 : return null;
139 :
140 : return OnGeneratePredicateWithPermissionScopeAny<TAuthenticationToken>(queryPredicate, leftHandQueryable);
141 : }
142 :
143 : /// <summary>
144 : /// Returns <paramref name="leftHandQueryable"/> or calls <see cref="GetEmptyQueryPredicate"/> if <paramref name="leftHandQueryable"/> is null.
145 : /// Override to build the relevant permission scope <see cref="IQueryable"/>.
146 : /// </summary>
147 1 : protected virtual IQueryable<TData> OnGeneratePredicateWithPermissionScopeAny<TAuthenticationToken>(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable)
148 : {
149 : return (leftHandQueryable ?? GetEmptyQueryPredicate());
150 : }
151 :
152 : /// <summary>
153 : /// Builds the relevant <see cref="IQueryable"/> for <see cref="QueryStrategy.WithPermissionScopeUser{TAuthenticationToken}"/>.
154 : /// </summary>
155 1 : protected virtual IQueryable<TData> GeneratePredicateWithPermissionScopeUser<TAuthenticationToken>(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable)
156 : {
157 : var queryStrategy = GetNullQueryStrategy() as QueryStrategy;
158 :
159 : if (queryStrategy == null)
160 : return null;
161 :
162 : if (queryPredicate.Name != GetFunctionNameOfType<TAuthenticationToken>(queryStrategy.WithPermissionScopeUser))
163 : return null;
164 :
165 : return OnGeneratePredicateWithPermissionScopeUser<TAuthenticationToken>(queryPredicate, leftHandQueryable);
166 : }
167 :
168 : /// <summary>
169 : /// Returns <paramref name="leftHandQueryable"/> or calls <see cref="GetEmptyQueryPredicate"/> if <paramref name="leftHandQueryable"/> is null.
170 : /// Override to build the relevant permission scope <see cref="IQueryable"/>.
171 : /// </summary>
172 1 : protected virtual IQueryable<TData> OnGeneratePredicateWithPermissionScopeUser<TAuthenticationToken>(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable)
173 : {
174 : return (leftHandQueryable ?? GetEmptyQueryPredicate());
175 : }
176 :
177 : /// <summary>
178 : /// Builds the relevant <see cref="IQueryable"/> for <see cref="QueryStrategy.WithPermissionScopeCompany{TAuthenticationToken}"/>.
179 : /// </summary>
180 1 : protected virtual IQueryable<TData> GeneratePredicateWithPermissionScopeCompany<TAuthenticationToken>(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable)
181 : {
182 : var queryStrategy = GetNullQueryStrategy() as QueryStrategy;
183 :
184 : if (queryStrategy == null)
185 : return null;
186 :
187 : if (queryPredicate.Name != GetFunctionNameOfType<TAuthenticationToken>(queryStrategy.WithPermissionScopeCompany))
188 : return null;
189 :
190 : return OnGeneratePredicateWithPermissionScopeCompany<TAuthenticationToken>(queryPredicate, leftHandQueryable);
191 : }
192 :
193 : /// <summary>
194 : /// Returns <paramref name="leftHandQueryable"/> or calls <see cref="GetEmptyQueryPredicate"/> if <paramref name="leftHandQueryable"/> is null.
195 : /// Override to build the relevant permission scope <see cref="IQueryable"/>.
196 : /// </summary>
197 1 : protected virtual IQueryable<TData> OnGeneratePredicateWithPermissionScopeCompany<TAuthenticationToken>(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable)
198 : {
199 : return (leftHandQueryable ?? GetEmptyQueryPredicate());
200 : }
201 :
202 : /// <summary>
203 : /// Builds the relevant <see cref="IQueryable"/> for <see cref="QueryStrategy.WithPermissionScopeCompanyAndUser{TAuthenticationToken}"/>.
204 : /// </summary>
205 1 : protected virtual IQueryable<TData> GeneratePredicateWithPermissionScopeCompanyAndUser<TAuthenticationToken>(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable)
206 : {
207 : var queryStrategy = GetNullQueryStrategy() as QueryStrategy;
208 :
209 : if (queryStrategy == null)
210 : return null;
211 :
212 : if (queryPredicate.Name != GetFunctionNameOfType<TAuthenticationToken>(queryStrategy.WithPermissionScopeCompanyAndUser))
213 : return null;
214 :
215 : return OnGeneratePredicateWithPermissionScopeCompanyAndUser<TAuthenticationToken>(queryPredicate, leftHandQueryable);
216 : }
217 :
218 : /// <summary>
219 : /// Returns <paramref name="leftHandQueryable"/> or calls <see cref="GetEmptyQueryPredicate"/> if <paramref name="leftHandQueryable"/> is null.
220 : /// Override to build the relevant permission scope <see cref="IQueryable"/>.
221 : /// </summary>
222 1 : protected virtual IQueryable<TData> OnGeneratePredicateWithPermissionScopeCompanyAndUser<TAuthenticationToken>(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable)
223 : {
224 : return (leftHandQueryable ?? GetEmptyQueryPredicate());
225 : }
226 :
227 : /// <summary>
228 : /// Override to build an <see cref="IQueryable"/> from the <paramref name="queryPredicate"/> and an optional <paramref name="leftHandQueryable"/>.
229 : /// </summary>
230 1 : protected abstract IQueryable<TData> GeneratePredicate(QueryPredicate queryPredicate, IQueryable<TData> leftHandQueryable = null);
231 :
232 : /// <summary>
233 : /// Gets the Name of the method in <paramref name="expression"/>
234 : /// </summary>
235 1 : protected virtual string GetFunctionNameOfType<TParameter1>(Func<TParameter1, IQueryPredicate> expression)
236 : {
237 : return expression.Method.Name;
238 : }
239 :
240 : /// <summary>
241 : /// Gets the Name of the method in <paramref name="expression"/>
242 : /// </summary>
243 1 : protected virtual string GetFunctionName<T>(Func<T> expression)
244 : {
245 : return expression.Method.Name;
246 : }
247 :
248 : /// <summary>
249 : /// Gets the Name of the method in <paramref name="expression"/>
250 : /// </summary>
251 1 : protected virtual string GetFunctionName<TParameter1>(Func<TParameter1, TQueryStrategy> expression)
252 : {
253 : return expression.Method.Name;
254 : }
255 :
256 : /// <summary>
257 : /// Gets the Name of the method in <paramref name="expression"/>
258 : /// </summary>
259 1 : protected virtual string GetFunctionName<TParameter1, TParameter2>(Func<TParameter1, TParameter2, TQueryStrategy> expression)
260 : {
261 : return expression.Method.Name;
262 : }
263 :
264 : /// <summary>
265 : /// Gets the Name of the method in <paramref name="expression"/>
266 : /// </summary>
267 1 : protected virtual string GetFunctionName<TParameter1, TParameter2, TParameter3>(Func<TParameter1, TParameter2, TParameter3, TQueryStrategy> expression)
268 : {
269 : return expression.Method.Name;
270 : }
271 :
272 : /// <summary>
273 : /// Gets the Name of the method in <paramref name="expression"/>
274 : /// </summary>
275 1 : protected virtual string GetFunctionName<TParameter1, TParameter2, TParameter3, TParameter4>(Func<TParameter1, TParameter2, TParameter3, TParameter4, TQueryStrategy> expression)
276 : {
277 : return expression.Method.Name;
278 : }
279 :
280 : /// <summary>
281 : /// Gets the Name of the method in <paramref name="expression"/>
282 : /// </summary>
283 1 : protected virtual string GetFunctionName<TParameter1, TParameter2, TParameter3, TParameter4, TParameter5>(Func<TParameter1, TParameter2, TParameter3, TParameter4, TParameter5, TQueryStrategy> expression)
284 : {
285 : return expression.Method.Name;
286 : }
287 :
288 : /// <summary>
289 : /// Uses <see cref="Activator.CreateInstance{T}"/> to create a new instance of <typeparamref name="TQueryStrategy"/>.
290 : /// </summary>
291 1 : protected virtual TQueryStrategy GetNullQueryStrategy()
292 : {
293 : try
294 : {
295 : return Activator.CreateInstance<TQueryStrategy>();
296 : }
297 : catch (MissingMethodException)
298 : {
299 : return DependencyResolver.Resolve<TQueryStrategy>();
300 : }
301 : }
302 :
303 : /// <summary>
304 : /// Override to build or apply any sorting required to <paramref name="queryable"/>
305 : /// </summary>
306 : /// <param name="queryStrategy">The <typeparamref name="TQueryStrategy"/> with sorting information.</param>
307 : /// <param name="queryable">The <see cref="IQueryable"/> to apply sorting to.</param>
308 1 : protected virtual void ApplySorting(TQueryStrategy queryStrategy, ref IQueryable<TData> queryable)
309 : {
310 : }
311 : }
312 : }
|