private static BasicFilterBase Clone(this BasicFilter criteria) { return(new BasicFilter { Field = criteria.Field, Operator = criteria.Operator, Value = criteria.Value, Value2 = criteria.Value2, Values = criteria.Values }); }
private BaseCriteria Convert(BasicFilter filter) { if (filter == null) { throw new ArgumentNullException("criteria"); } if (!filter.IsValid) { throw new ArgumentOutOfRangeException("InvalidFilterCriteria", filter.ToJson()); } if (_processCriteria != null) { var processed = _processCriteria(filter); if (!Object.ReferenceEquals(processed, null)) { if (processed.IsEmpty) { throw new ArgumentOutOfRangeException("EmptyFilterLine", filter.ToJson()); } return(processed); } } string fieldName = filter.Field; Field field = null; if (_row != null) { field = _row.FindField(fieldName); } // if filter fields list is specified, the fieldname must exist in this list, otherwise // it may be an hacking attempt, as user tries to filter a field that he is not // represented with IFilterField filterField = null; if (filterFields != null) { filterField = filterFields.ByNameOrTextual(fieldName); if (filterField == null && (field == null || field.Flags.HasFlag(FieldFlags.DenyFiltering))) { throw new ArgumentOutOfRangeException("UnknownFilterField", fieldName); } } //var type = GetFilterFieldType(field, fieldName); var fieldExpr = GetFieldExpression(field, fieldName); if (fieldExpr == null) { // field is not found anywhere, don't allow unknown fields as it may cause a script injection // attack or other types of security threats! throw new ArgumentOutOfRangeException("UnknownFilterField", filter.ToJson()); } bool isInteger = (filterField != null && (filterField.Handler == "Integer")) || (filterField == null && field != null && (field is Int16Field || field is Int32Field || field is Int64Field)); bool isDecimal = (filterField != null && (filterField.Handler == "Decimal")) || (filterField == null && field != null && (field is DoubleField || field is DecimalField)); bool isNumeric = isInteger || isDecimal; bool isDateTime = (filterField != null && (filterField.Handler == "Date")) || (filterField == null && field != null && (field is DateTimeField)); var op = filter.Operator; switch (op) { case FilterOp.True: return(new Criteria(fieldExpr) == 1); case FilterOp.False: return(new Criteria(fieldExpr) == 0); case FilterOp.IsNull: return(new Criteria(fieldExpr).IsNull()); case FilterOp.IsNotNull: return(new Criteria(fieldExpr).IsNotNull()); case FilterOp.Like: return(new Criteria(fieldExpr).Like(filter.Value)); case FilterOp.NotLike: return(new Criteria(fieldExpr).NotLike(filter.Value)); case FilterOp.Contains: return(new Criteria(fieldExpr).Contains(filter.Value)); case FilterOp.NotContains: return(new Criteria(fieldExpr).NotContains(filter.Value)); case FilterOp.StartsWith: return(new Criteria(fieldExpr).StartsWith(filter.Value)); case FilterOp.EndsWith: return(new Criteria(fieldExpr).EndsWith(filter.Value)); case FilterOp.IN: case FilterOp.NotIN: { var values = new List <object>(); foreach (var s in filter.Values) { if (isDecimal) { values.Add(ParseDoubleValue(s)); } else if (isInteger) { values.Add(ParseIntegerValue(field, s)); } else { values.Add(s); } } if (values.Count == 0) { throw new ArgumentOutOfRangeException("InvalidFilterLine", filter.ToJson()); } if (op == FilterOp.IN) { return(new Criteria(fieldExpr).In(values.ToArray())); } else { return(new Criteria(fieldExpr).NotIn(values.ToArray())); } } } // parse value1 and value2 string value1Text = filter.Value.TrimToEmpty(); string value2Text = filter.Value2.TrimToEmpty(); if ((op == FilterOp.BW || op == FilterOp.NotBW)) { if (value1Text.IsNullOrEmpty() || value2Text.IsNullOrEmpty()) { throw new ArgumentOutOfRangeException("InvalidFilterLine", filter.ToJson()); } if (isInteger) { return(new Criteria(fieldExpr) >= ParseIntegerValue(field, value1Text) & new Criteria(fieldExpr) <= ParseIntegerValue(field, value2Text)); } else if (isDecimal) { return(new Criteria(fieldExpr) >= ParseDoubleValue(value1Text) & new Criteria(fieldExpr) <= ParseDoubleValue(value2Text)); } else if (isDateTime) { var d1 = ParseDateTimeValue(value1Text); var d2 = ParseDateTimeValue(value2Text); if (d1.Date == d1 && d2.Date == d2) { if (op == FilterOp.BW) { return(new Criteria(fieldExpr) >= d1.Date & new Criteria(fieldExpr) < d2.Date.AddDays(1)); } else { return(~(new Criteria(fieldExpr) < d1.Date | new Criteria(fieldExpr) >= d2.Date.AddDays(1))); } } else { if (op == FilterOp.BW) { return(new Criteria(fieldExpr) >= d1 & new Criteria(fieldExpr) <= d2); } else { return(~((new Criteria(fieldExpr) < d1 | new Criteria(fieldExpr) > d2))); } } } else { if (op == FilterOp.BW) { return(new Criteria(fieldExpr) >= value1Text & new Criteria(fieldExpr) <= value2Text); } else { return(~((new Criteria(fieldExpr) < value2Text | new Criteria(fieldExpr) > value2Text))); } } } var result = new Criteria(fieldExpr); if (isInteger) { var i = ParseIntegerValue(field, value1Text); if (op == FilterOp.EQ) { return(result == i); } else if (op == FilterOp.NE) { return(result != i); } else if (op == FilterOp.GT) { return(result > i); } else if (op == FilterOp.GE) { return(result >= i); } else if (op == FilterOp.LT) { return(result < i); } else if (op == FilterOp.LE) { return(result <= i); } } else if (isDecimal) { var o = ParseIntegerValue(field, value1Text); if (op == FilterOp.EQ) { return(result == o); } else if (op == FilterOp.NE) { return(result != o); } else if (op == FilterOp.GT) { return(result > o); } else if (op == FilterOp.GE) { return(result >= o); } else if (op == FilterOp.LT) { return(result < o); } else if (op == FilterOp.LE) { return(result <= o); } } else if (isDateTime) { var d = ParseDateTimeValue(value1Text); if (d.Date == d) { if (op == FilterOp.EQ) { return(result >= d & result < d.AddDays(1)); } else if (op == FilterOp.NE) { return(~(result < d | result >= d.AddDays(1))); } else if (op == FilterOp.GT) { return(result >= d.AddDays(1)); } else if (op == FilterOp.GE) { return(result >= d); } else if (op == FilterOp.LT) { return(result < d); } else if (op == FilterOp.LE) { return(result < d.AddDays(1)); } } else { if (op == FilterOp.EQ) { return(result == d); } else if (op == FilterOp.NE) { return(result != d); } else if (op == FilterOp.GT) { return(result > d); } else if (op == FilterOp.GE) { return(result >= d); } else if (op == FilterOp.LT) { return(result < d); } else if (op == FilterOp.LE) { return(result <= d); } } } else { if (op == FilterOp.EQ) { return(result == value1Text); } else if (op == FilterOp.NE) { return(result != value1Text); } else if (op == FilterOp.GT) { return(result > value1Text); } else if (op == FilterOp.GE) { return(result >= value1Text); } else if (op == FilterOp.LT) { return(result < value1Text); } else if (op == FilterOp.LE) { return(result <= value1Text); } } throw new InvalidOperationException(); }
public static bool IsSame(this BasicFilterBase filter, BasicFilterBase other) { if (filter == null) { return(other == null); } var g = filter as BasicFilterGroup; if (g != null) { var go = other as BasicFilterGroup; if (go == null) { return(false); } if (g.Nodes.Count != go.Nodes.Count) { return(false); } for (var i = 0; i < g.Nodes.Count; i++) { if (!IsSame(g.Nodes[i], go.Nodes[i])) { return(false); } } } else { BasicFilter c = (BasicFilter)filter; BasicFilter co = other as BasicFilter; if (co == null) { return(false); } if (c.Field != co.Field) { return(false); } if (c.Operator != co.Operator) { return(false); } if (c.Value != co.Value) { return(false); } if (c.Value2 != co.Value2) { return(false); } if ((c.Values == null) != (co.Values == null)) { return(false); } if (c.Values != null) { if (c.Values.Length != co.Values.Length) { return(false); } for (var i = 0; i < c.Values.Length; i++) { if (c.Values[i] != co.Values[i]) { return(false); } } } } return(true); }
public static BasicFilterBase ToBasicFilter(this IList <FilterLine> lines) { if (lines == null) { throw new ArgumentNullException("lines"); } if (lines.Count == 0) { return(null); } bool inParens = false; // http://en.wikipedia.org/wiki/Shunting_yard_algorithm // http://en.wikipedia.org/wiki/Reverse_Polish_Notation List <BasicFilter> filters = new List <BasicFilter>(lines.Count); List <int> rpnOutput = new List <int>(lines.Count * 2); // will contain negative or indexes of items Stack <int> rpnStack = new Stack <int>(lines.Count * 2); int intLeftParen = -1; int intAnd = -2; int intOr = -3; int index = 0; foreach (FilterLine line in lines) { if (inParens && (line.RightParen || line.LeftParen)) { while (true) { var token = rpnStack.Pop(); if (token == intLeftParen) { break; } rpnOutput.Add(token); } inParens = false; } if (index > 0) { var token = line.OR ? intOr : intAnd; while (true) { if (rpnStack.Count == 0) { break; } var topToken = rpnStack.Peek(); if (topToken < intLeftParen && token <= topToken) { rpnOutput.Add(rpnStack.Pop()); } else { break; } } rpnStack.Push(token); } if (line.LeftParen) { rpnStack.Push(intLeftParen); } rpnOutput.Add(index); index++; } if (inParens) { while (true) { var token = rpnStack.Pop(); if (token == intLeftParen) { break; } rpnOutput.Add(token); } } while (rpnStack.Count > 0) { var token = rpnStack.Pop(); if (token == intLeftParen) { throw new InvalidOperationException("mismatched leftParen in RPN stack!"); } rpnOutput.Add(token); } var evaluationStack = new Stack <BasicFilterBase>(); foreach (var input in rpnOutput) { if (input >= 0) { BasicFilter item = new BasicFilter(); var line = lines[input]; item.Field = line.Field; item.Operator = line.Op; item.Value = line.Value; item.Values = line.Values; evaluationStack.Push(item); } else { if (evaluationStack.Count < 2) { throw new InvalidOperationException("RPN evaluation stack has less than two items!"); } LogicalOp op = input == intAnd ? LogicalOp.And : LogicalOp.Or; var right = evaluationStack.Pop(); var left = evaluationStack.Pop(); BasicFilterBase result = left.Merge(op, right); evaluationStack.Push(result); } } if (evaluationStack.Count > 1) { throw new InvalidOperationException("RPN evaluation stack has more than one item!"); } return(evaluationStack.Pop()); }