Skip to content

Commit

Permalink
Release Sieve 2.5.0 (#151)
Browse files Browse the repository at this point in the history
* Setup release 2.5.0 with automated build and pre-releases

* #80 added support for escaping pipe control characters (#113)

* #80 added support for escaping comma and pipe control characters

* Update SieveModel.cs

Fix build. Accidentally broken by resolving conflicts.

* Migrate UnitTests to xUnit

Co-authored-by: Clayton Andersen <[email protected]>
Co-authored-by: ITDancer13 <[email protected]>
Co-authored-by: ITDancer139 <[email protected]>

* SieveProcessor.Options made protected property (#134)

Mapper assignment in constructor is moved to a null-coalescing member pair (a field and a property)
"IncludeScopes" switch is removed from appSettings.{env}.json files

* Revert to _mapper assignment in constructor. (#140)

* reverting fix (#142)

* Revert to _mapper assignment in constructor.

* reverting fix

* pass filter values as parameters (#112)

make GetClosureOverConstant really work

* Make ApplyFiltering, ApplySorting and ApplyPagination protected virtual #139 (#144)

* stop excluding null values when filtering using notEqual (#114)

* stop excluding null values when filtering using notEqual
* add IgnoreNullsOnNotEqual config field, to enable/disable the new feature

Co-authored-by: AnasZakarneh <[email protected]>

Co-authored-by: Clayton Andersen <[email protected]>
Co-authored-by: Clayton Andersen <[email protected]>
Co-authored-by: ITDancer139 <[email protected]>
Co-authored-by: Hasan Manzak <[email protected]>
Co-authored-by: alicak <[email protected]>
Co-authored-by: AnasZakarneh <[email protected]>
Co-authored-by: AnasZakarneh <[email protected]>
  • Loading branch information
8 people authored Aug 29, 2021
1 parent 83a2c1a commit e83d213
Show file tree
Hide file tree
Showing 14 changed files with 226 additions and 46 deletions.
4 changes: 1 addition & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,10 @@
name: ci

on:
push:
branches:
- master
pull_request:
branches:
- master
- 'releases/*'

jobs:
ubuntu-latest:
Expand Down
33 changes: 33 additions & 0 deletions .github/workflows/ci_publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# ------------------------------------------------------------------------------
# <auto-generated>
#
# This code was generated.
#
# - To turn off auto-generation set:
#
# [GitHubActions (AutoGenerate = false)]
#
# - To trigger manual generation invoke:
#
# nuke --generate-configuration GitHubActions_ci_publish --host GitHubActions
#
# </auto-generated>
# ------------------------------------------------------------------------------

name: ci_publish

on:
push:
branches:
- 'releases/*'

jobs:
ubuntu-latest:
name: ubuntu-latest
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v1
- name: Run './build.cmd CiPublish'
run: ./build.cmd CiPublish
env:
NUGET_API_KEY: ${{ secrets.NUGET_API_KEY }}
7 changes: 7 additions & 0 deletions .nuke/build.schema.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@
"type": "boolean",
"description": "Disables displaying the NUKE logo"
},
"NUGET_API_KEY": {
"type": "string"
},
"Plan": {
"type": "boolean",
"description": "Shows the execution plan (HTML)"
Expand All @@ -65,9 +68,11 @@
"type": "string",
"enum": [
"Ci",
"CiPublish",
"Clean",
"Compile",
"Package",
"Publish",
"Restore",
"Test"
]
Expand All @@ -84,9 +89,11 @@
"type": "string",
"enum": [
"Ci",
"CiPublish",
"Clean",
"Compile",
"Package",
"Publish",
"Restore",
"Test"
]
Expand Down
3 changes: 3 additions & 0 deletions GitVersion.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
branches:
release:
mode: ContinuousDeployment
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ Then you can add the configuration:
"CaseSensitive": "boolean: should property names be case-sensitive? Defaults to false",
"DefaultPageSize": "int number: optional number to fallback to when no page argument is given. Set <=0 to disable paging if no pageSize is specified (default).",
"MaxPageSize": "int number: maximum allowed page size. Set <=0 to make infinite (default)",
"ThrowExceptions": "boolean: should Sieve throw exceptions instead of silently failing? Defaults to false"
"ThrowExceptions": "boolean: should Sieve throw exceptions instead of silently failing? Defaults to false",
"IgnoreNullsOnNotEqual": "boolean: ignore null values when filtering using is not equal operator? Default to true"
}
}
```
Expand Down
1 change: 0 additions & 1 deletion Sieve.Sample/appsettings.Development.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
{
"Logging": {
"IncludeScopes": false,
"LogLevel": {
"Default": "Debug",
"System": "Information",
Expand Down
4 changes: 2 additions & 2 deletions Sieve.Sample/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
},
"Sieve": {
"CaseSensitive": false,
"DefaultPageSize": 10
"DefaultPageSize": 10,
"IgnoreNullsOnNotEqual": true
},
"Logging": {
"IncludeScopes": false,
"Debug": {
"LogLevel": {
"Default": "Warning"
Expand Down
8 changes: 6 additions & 2 deletions Sieve/Models/FilterTerm.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ public class FilterTerm : IFilterTerm, IEquatable<FilterTerm>
public FilterTerm() { }

private const string EscapedPipePattern = @"(?<!($|[^\\])(\\\\)*?\\)\|";
private const string PipeToEscape = @"\|";

private static readonly string[] Operators = new string[] {
"!@=*",
Expand Down Expand Up @@ -36,7 +37,11 @@ public string Filter
var filterSplits = value.Split(Operators, StringSplitOptions.RemoveEmptyEntries)
.Select(t => t.Trim()).ToArray();
Names = Regex.Split(filterSplits[0], EscapedPipePattern).Select(t => t.Trim()).ToArray();
Values = filterSplits.Length > 1 ? Regex.Split(filterSplits[1], EscapedPipePattern).Select(t => t.Trim()).ToArray() : null;
Values = filterSplits.Length > 1
? Regex.Split(filterSplits[1], EscapedPipePattern)
.Select(t => t.Replace(PipeToEscape, "|").Trim())
.ToArray()
: null;
Operator = Array.Find(Operators, o => value.Contains(o)) ?? "==";
OperatorParsed = GetOperatorParsed(Operator);
OperatorIsCaseInsensitive = Operator.EndsWith("*");
Expand Down Expand Up @@ -90,6 +95,5 @@ public bool Equals(FilterTerm other)
&& Values.SequenceEqual(other.Values)
&& Operator == other.Operator;
}

}
}
2 changes: 1 addition & 1 deletion Sieve/Models/SieveModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
Expand Down
4 changes: 3 additions & 1 deletion Sieve/Models/SieveOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,7 @@ public class SieveOptions
public int MaxPageSize { get; set; } = 0;

public bool ThrowExceptions { get; set; } = false;

public bool IgnoreNullsOnNotEqual { get; set; } = true;
}
}
}
53 changes: 27 additions & 26 deletions Sieve/Services/SieveProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ public class SieveProcessor<TSieveModel, TFilterTerm, TSortTerm> : ISieveProcess
where TSortTerm : ISortTerm, new()
{
private const string NullFilterValue = "null";
private readonly IOptions<SieveOptions> _options;
private readonly ISieveCustomSortMethods _customSortMethods;
private readonly ISieveCustomFilterMethods _customFilterMethods;
private readonly SievePropertyMapper _mapper = new SievePropertyMapper();
Expand All @@ -78,7 +77,7 @@ public SieveProcessor(IOptions<SieveOptions> options,
ISieveCustomFilterMethods customFilterMethods)
{
_mapper = MapProperties(_mapper);
_options = options;
Options = options;
_customSortMethods = customSortMethods;
_customFilterMethods = customFilterMethods;
}
Expand All @@ -87,24 +86,26 @@ public SieveProcessor(IOptions<SieveOptions> options,
ISieveCustomSortMethods customSortMethods)
{
_mapper = MapProperties(_mapper);
_options = options;
Options = options;
_customSortMethods = customSortMethods;
}

public SieveProcessor(IOptions<SieveOptions> options,
ISieveCustomFilterMethods customFilterMethods)
{
_mapper = MapProperties(_mapper);
_options = options;
Options = options;
_customFilterMethods = customFilterMethods;
}

public SieveProcessor(IOptions<SieveOptions> options)
{
_mapper = MapProperties(_mapper);
_options = options;
Options = options;
}

protected IOptions<SieveOptions> Options { get; }

/// <summary>
/// Apply filtering, sorting, and pagination parameters found in `model` to `source`
/// </summary>
Expand Down Expand Up @@ -148,7 +149,7 @@ public IQueryable<TEntity> Apply<TEntity>(TSieveModel model, IQueryable<TEntity>
}
catch (Exception ex)
{
if (!_options.Value.ThrowExceptions)
if (!Options.Value.ThrowExceptions)
{
return result;
}
Expand All @@ -162,7 +163,7 @@ public IQueryable<TEntity> Apply<TEntity>(TSieveModel model, IQueryable<TEntity>
}
}

private IQueryable<TEntity> ApplyFiltering<TEntity>(TSieveModel model, IQueryable<TEntity> result,
protected virtual IQueryable<TEntity> ApplyFiltering<TEntity>(TSieveModel model, IQueryable<TEntity> result,
object[] dataForCustomMethods = null)
{
if (model?.GetFiltersParsed() == null)
Expand Down Expand Up @@ -216,10 +217,13 @@ private IQueryable<TEntity> ApplyFiltering<TEntity>(TSieveModel model, IQueryabl
expression = Expression.Not(expression);
}

var filterValueNullCheck = GetFilterValueNullCheck(parameter, fullPropertyName, isFilterTermValueNull);
if (filterValueNullCheck != null)
if (expression.NodeType != ExpressionType.NotEqual || Options.Value.IgnoreNullsOnNotEqual)
{
expression = Expression.AndAlso(filterValueNullCheck, expression);
var filterValueNullCheck = GetFilterValueNullCheck(parameter, fullPropertyName, isFilterTermValueNull);
if (filterValueNullCheck != null)
{
expression = Expression.AndAlso(filterValueNullCheck, expression);
}
}

innerExpression = innerExpression == null
Expand Down Expand Up @@ -253,8 +257,7 @@ private IQueryable<TEntity> ApplyFiltering<TEntity>(TSieveModel model, IQueryabl
: result.Where(Expression.Lambda<Func<TEntity, bool>>(outerExpression, parameter));
}

private static Expression GetFilterValueNullCheck(Expression parameter, string fullPropertyName,
bool isFilterTermValueNull)
private static Expression GetFilterValueNullCheck(Expression parameter, string fullPropertyName, bool isFilterTermValueNull)
{
var (propertyValue, nullCheck) = GetPropertyValueAndNullCheckExpression(parameter, fullPropertyName);

Expand Down Expand Up @@ -336,15 +339,13 @@ private static Expression GetExpression(TFilterTerm filterTerm, dynamic filterVa
}

// Workaround to ensure that the filter value gets passed as a parameter in generated SQL from EF Core
// See https://github.com/aspnet/EntityFrameworkCore/issues/3361
// Expression.Constant passed the target type to allow Nullable comparison
// See http://bradwilson.typepad.com/blog/2008/07/creating-nullab.html
private static Expression GetClosureOverConstant<T>(T constant, Type targetType)
{
return Expression.Constant(constant, targetType);
Expression<Func<T>> hoistedConstant = () => constant;
return Expression.Convert(hoistedConstant.Body, targetType);
}

private IQueryable<TEntity> ApplySorting<TEntity>(TSieveModel model, IQueryable<TEntity> result,
protected virtual IQueryable<TEntity> ApplySorting<TEntity>(TSieveModel model, IQueryable<TEntity> result,
object[] dataForCustomMethods = null)
{
if (model?.GetSortsParsed() == null)
Expand Down Expand Up @@ -373,11 +374,11 @@ private IQueryable<TEntity> ApplySorting<TEntity>(TSieveModel model, IQueryable<
return result;
}

private IQueryable<TEntity> ApplyPagination<TEntity>(TSieveModel model, IQueryable<TEntity> result)
protected virtual IQueryable<TEntity> ApplyPagination<TEntity>(TSieveModel model, IQueryable<TEntity> result)
{
var page = model?.Page ?? 1;
var pageSize = model?.PageSize ?? _options.Value.DefaultPageSize;
var maxPageSize = _options.Value.MaxPageSize > 0 ? _options.Value.MaxPageSize : pageSize;
var pageSize = model?.PageSize ?? Options.Value.DefaultPageSize;
var maxPageSize = Options.Value.MaxPageSize > 0 ? Options.Value.MaxPageSize : pageSize;

if (pageSize <= 0)
{
Expand All @@ -399,14 +400,14 @@ protected virtual SievePropertyMapper MapProperties(SievePropertyMapper mapper)
string name)
{
var property = _mapper.FindProperty<TEntity>(canSortRequired, canFilterRequired, name,
_options.Value.CaseSensitive);
Options.Value.CaseSensitive);
if (property.Item1 != null)
{
return property;
}

var prop = FindPropertyBySieveAttribute<TEntity>(canSortRequired, canFilterRequired, name,
_options.Value.CaseSensitive);
Options.Value.CaseSensitive);
return (prop?.Name, prop);
}

Expand All @@ -426,7 +427,7 @@ private IQueryable<TEntity> ApplyCustomMethod<TEntity>(IQueryable<TEntity> resul
{
var customMethod = parent?.GetType()
.GetMethodExt(name,
_options.Value.CaseSensitive
Options.Value.CaseSensitive
? BindingFlags.Default
: BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance,
typeof(IQueryable<TEntity>));
Expand All @@ -437,7 +438,7 @@ private IQueryable<TEntity> ApplyCustomMethod<TEntity>(IQueryable<TEntity> resul
// Find generic methods `public IQueryable<T> Filter<T>(IQueryable<T> source, ...)`
var genericCustomMethod = parent?.GetType()
.GetMethodExt(name,
_options.Value.CaseSensitive
Options.Value.CaseSensitive
? BindingFlags.Default
: BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance,
typeof(IQueryable<>));
Expand Down Expand Up @@ -481,11 +482,11 @@ private IQueryable<TEntity> ApplyCustomMethod<TEntity>(IQueryable<TEntity> resul
var incompatibleCustomMethods =
parent?
.GetType()
.GetMethods(_options.Value.CaseSensitive
.GetMethods(Options.Value.CaseSensitive
? BindingFlags.Default
: BindingFlags.IgnoreCase | BindingFlags.Public | BindingFlags.Instance)
.Where(method => string.Equals(method.Name, name,
_options.Value.CaseSensitive
Options.Value.CaseSensitive
? StringComparison.InvariantCulture
: StringComparison.InvariantCultureIgnoreCase))
.ToList()
Expand Down
Loading

0 comments on commit e83d213

Please sign in to comment.