Skip to content

Commit 1383b3d

Browse files
authored
Merge pull request #82 from trenoncourt/develop
merge develop into master
2 parents 4598d9c + 1640150 commit 1383b3d

File tree

7 files changed

+113
-23
lines changed

7 files changed

+113
-23
lines changed

README.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,13 @@ AQ settings can be overriden in attribute too
129129
- Filtering: [/products?**nameContains=frame&color=red,black**](/products?nameContains=frame&color=red,black)
130130
- Paging: [/products?**page=2&pagesize=10**](/products?page=2&pagesize=10)
131131

132+
## And / Or management
133+
134+
- In a single filter, properties are managed with **OR**, eg `prop1=a,b,c`
135+
- If you want single filter with **AND** you need to add the same filter, eg `prop1=a&prop1=b&prop1=c`
136+
- If multiple filters are provided, there are managed with **AND**, eg `prop1=a&prop2=a&prop3Contains=b`
137+
- If you want multiple filters with **OR**, you must provide all filters before the *=*, eg `prop1StartsWith,prop2:i,prop3Contains:i=a,b,c`
138+
132139
## Selection
133140

134141
- Select all properties of level zero without relations: [/products?**select=_**](/products?**select=_)

src/AutoQueryable/AutoQueryable.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<PropertyGroup>
33
<Description>AutoQueryable add auto querying functionality like OData with best url practices to Asp.Net Core.</Description>
44
<AssemblyTitle>AutoQueryable add auto querying functionality like OData with best url practices to Asp.Net Core.</AssemblyTitle>
5-
<Version>2.0.5-beta</Version>
5+
<Version>2.0.11-beta</Version>
66
<Authors>Thibaut Renoncourt, Nils Goovaerts</Authors>
77
<TargetFramework>netstandard1.3</TargetFramework>
88
<AssemblyName>AutoQueryable</AssemblyName>

src/AutoQueryable/Core/Models/AutoQueryHandler.cs

Lines changed: 41 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,11 @@ public dynamic GetAutoQuery<T>(IQueryable<T> query) where T : class
4949

5050
GetClauses<T>();
5151
var criterias = _profile.IsClauseAllowed(ClauseType.Filter) ? GetCriterias<T>().ToList() : null;
52-
53-
var queryResult = QueryBuilder.Build(ClauseValueManager, _criteriaFilterManager, query, criterias, _profile);
5452

55-
TotalCountQuery = QueryBuilder.TotalCountQuery;
53+
query = QueryBuilder.AddCriterias(query, criterias, _criteriaFilterManager);
54+
TotalCountQuery = query;
55+
var queryResult = QueryBuilder.Build(ClauseValueManager, query, _profile);
56+
5657

5758
return queryResult;
5859
}
@@ -111,18 +112,50 @@ public IEnumerable<Criteria> GetCriterias<T>() where T : class
111112
foreach (var qPart in _queryStringAccessor.QueryStringParts.Where(q => !q.IsHandled))
112113
{
113114
var q = WebUtility.UrlDecode(qPart.Value);
114-
var criteria = GetCriteria<T>(q);
115-
116-
if (criteria != null)
115+
116+
int subIndex = q.IndexOf('=');
117+
if (subIndex == -1)
118+
{
119+
subIndex = q.IndexOf('>');
120+
}
121+
if (subIndex == -1)
122+
{
123+
subIndex = q.IndexOf('<');
124+
}
125+
List<string> orEntries = q.Substring(0, subIndex).Split(new[] {','}, StringSplitOptions.RemoveEmptyEntries).Select(s => s + q.Substring(subIndex, q.Length - subIndex)).ToList();
126+
if (orEntries.Count <= 1)
127+
{
128+
var criteria = GetCriteria<T>(orEntries[0].Trim());
129+
if (criteria != null)
130+
{
131+
yield return criteria;
132+
}
133+
continue;
134+
}
135+
136+
List<Criteria> criterias = new List<Criteria>();
137+
for (int i = 0; i < orEntries.Count; i++)
117138
{
118-
yield return criteria;
139+
var criteria = GetCriteria<T>(orEntries[i].Trim());
140+
if (i > 0)
141+
{
142+
criteria.Or = true;
143+
}
144+
if (criteria != null)
145+
{
146+
criterias.Add(criteria);
147+
}
119148
}
149+
if (criterias.Count == 0) continue;
150+
yield return new Criteria
151+
{
152+
Criterias = criterias
153+
};
120154
}
121155
}
122156

123157
private Criteria GetCriteria<T>(string q) where T : class
124158
{
125-
126159
var filter = _criteriaFilterManager.FindFilter(q);
127160
if (filter == null)
128161
{

src/AutoQueryable/Core/Models/Criteria.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,7 @@ public class Criteria
88
public List<string> ColumnPath { get; set; }
99
public IQueryableFilter Filter { get; set; }
1010
public string[] Values { get; set; }
11+
public bool Or { get; set; }
12+
public List<Criteria> Criterias { get; set; }
1113
}
1214
}

src/AutoQueryable/Extensions/TypeBuilderExtension.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ public static class TypeBuilderExtension
99
private static void AddProperty(this TypeBuilder typeBuilder, string propName, PropertyAttributes attributes, Type propertyType) {
1010
const MethodAttributes getSetAttr = MethodAttributes.Public | MethodAttributes.HideBySig | MethodAttributes.SpecialName;
1111

12-
var field = typeBuilder.DefineField(propName, propertyType, FieldAttributes.Private);
12+
var field = typeBuilder.DefineField("_" + propName, propertyType, FieldAttributes.Private);
1313

1414
var property = typeBuilder.DefineProperty(propName, attributes, propertyType, new Type[] { });
1515

src/AutoQueryable/Helpers/QueryBuilder.cs

Lines changed: 59 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -16,17 +16,21 @@ namespace AutoQueryable.Helpers
1616
{
1717
public static class QueryBuilder
1818
{
19-
public static IQueryable<dynamic> TotalCountQuery { get; private set; }
20-
21-
public static dynamic Build<T>(IClauseValueManager clauseValueManager, ICriteriaFilterManager criteriaFilterManager, IQueryable<T> query, ICollection<Criteria> criterias, IAutoQueryableProfile profile) where T : class
19+
public static IQueryable<T> AddCriterias<T>(IQueryable<T> query, ICollection<Criteria> criterias, ICriteriaFilterManager criteriaFilterManager) where T : class
2220
{
2321
if (criterias != null && criterias.Any())
2422
{
25-
query = _addCriterias(criteriaFilterManager, query, criterias);
23+
return _addCriterias(criteriaFilterManager, query, criterias);
2624
}
25+
26+
return query;
27+
}
28+
29+
public static dynamic Build<T>(IClauseValueManager clauseValueManager, IQueryable<T> query, IAutoQueryableProfile profile) where T : class
30+
{
31+
var totalCountQuery = query;
2732
query = _addOrderBy(query, clauseValueManager.OrderBy, profile);
2833

29-
TotalCountQuery = query;
3034
if(clauseValueManager.First)
3135
{
3236
return query.FirstOrDefault();
@@ -55,7 +59,7 @@ public static dynamic Build<T>(IClauseValueManager clauseValueManager, ICriteria
5559
}
5660
}
5761

58-
return queryProjection.HandleWrapping(clauseValueManager);
62+
return queryProjection.HandleWrapping(clauseValueManager, totalCountQuery);
5963
}
6064

6165
private static IQueryable<T> _handlePaging<T>(IClauseValueManager clauseValueManager, IQueryable<T> query, IAutoQueryableProfile profile) where T : class
@@ -96,7 +100,7 @@ private static IQueryable<T> _handlePaging<T>(IClauseValueManager clauseValueMan
96100
return query;
97101
}
98102

99-
public static dynamic HandleWrapping<TEntity>(this IQueryable<TEntity> query, IClauseValueManager clauseValueManager) where TEntity : class
103+
public static dynamic HandleWrapping<TEntity>(this IQueryable<TEntity> query, IClauseValueManager clauseValueManager, IQueryable<TEntity> totalCountQuery) where TEntity : class
100104
{
101105
if(!clauseValueManager.WrapWith.Any() || clauseValueManager.First)
102106
{
@@ -114,7 +118,7 @@ public static dynamic HandleWrapping<TEntity>(this IQueryable<TEntity> query, IC
114118
}
115119
else if (wrapperPart == WrapperAlias.TotalCount)
116120
{
117-
wrapper.Add(WrapperAlias.TotalCount, TotalCountQuery.Count());
121+
wrapper.Add(WrapperAlias.TotalCount, totalCountQuery.Count());
118122
}
119123
}
120124

@@ -207,9 +211,37 @@ private static IQueryable<T> _addCriterias<T>(ICriteriaFilterManager criteriaFil
207211
Expression whereExpression = null;
208212
foreach (var c in criterias)
209213
{
210-
var expression = BuildWhereExpression(criteriaFilterManager, parentEntity, c, c.ColumnPath.ToArray());
214+
if (c.Criterias != null && c.Criterias.Count > 0)
215+
{
216+
if (c.Criterias.Count == 1)
217+
{
218+
var expression = BuildWhereExpression(criteriaFilterManager, parentEntity, c.Criterias.First(), c.Criterias.First().ColumnPath.ToArray());
219+
whereExpression = whereExpression == null ? expression : Expression.AndAlso(whereExpression, expression);
220+
}
211221

212-
whereExpression = whereExpression == null ? expression : Expression.AndAlso(whereExpression, expression);
222+
List<Expression> expressions = new List<Expression>();
223+
foreach (var criteria in c.Criterias)
224+
{
225+
expressions.Add(BuildWhereExpression(criteriaFilterManager, parentEntity, criteria, criteria.ColumnPath.ToArray()));
226+
}
227+
Expression currentExpression = null;
228+
foreach (var expression in expressions)
229+
{
230+
if (currentExpression == null)
231+
{
232+
currentExpression = expression;
233+
continue;
234+
}
235+
currentExpression = Expression.OrElse(expression, currentExpression);
236+
}
237+
238+
whereExpression = whereExpression == null ? currentExpression : Expression.AndAlso(whereExpression, currentExpression); // TODO
239+
}
240+
else
241+
{
242+
var expression = BuildWhereExpression(criteriaFilterManager, parentEntity, c, c.ColumnPath.ToArray());
243+
whereExpression = whereExpression == null ? expression : Expression.AndAlso(whereExpression, expression);
244+
}
213245
}
214246

215247
return source.Where(Expression.Lambda<Func<T, bool>>(whereExpression, parentEntity));
@@ -237,15 +269,29 @@ private static IQueryable<T> _addOrderBy<T>(IQueryable<T> source, Dictionary<str
237269
{
238270
PropertyName = v.Name
239271
});
272+
var i = 0;
240273
foreach (var column in columns)
241274
{
242275
var desc = orderClause.FirstOrDefault(o => string.Equals(o.Key, column.PropertyName, StringComparison.OrdinalIgnoreCase)).Value;
276+
string method;
243277
if(desc){
244-
source = source.Call(QueryableMethods.OrderByDescending, column.PropertyName);
245-
}else
278+
method = QueryableMethods.OrderByDescending;
279+
if (i > 0)
280+
{
281+
method = QueryableMethods.ThenByDescending;
282+
}
283+
}
284+
else
246285
{
247-
source = source.Call(QueryableMethods.OrderBy, column.PropertyName);
286+
method = QueryableMethods.OrderBy;
287+
if (i > 0)
288+
{
289+
method = QueryableMethods.ThenBy;
290+
}
248291
}
292+
293+
source = source.Call(method, column.PropertyName);
294+
i++;
249295
}
250296
return source;
251297
}

src/AutoQueryable/Models/Constants/QueryableMethods.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
public static class QueryableMethods
44
{
55
public const string OrderBy = "OrderBy";
6+
public const string ThenBy = "ThenBy";
67
public const string OrderByDescending = "OrderByDescending";
8+
public const string ThenByDescending = "ThenByDescending";
79
}
810
}

0 commit comments

Comments
 (0)