public void Add(BoolOpEnum boolOp, object searchExpressionOrGroup) { if (searchExpressionOrGroup is FilterExpression) { ((FilterExpression)searchExpressionOrGroup).BoolOp = boolOp; } else if (searchExpressionOrGroup is FilterExpressionGroup) { ((FilterExpressionGroup)searchExpressionOrGroup).BoolOp = boolOp; } this._expressions.Add(searchExpressionOrGroup); }
public void Add(BoolOpEnum boolOp, object searchExpressionOrGroup) { // set the BoolOp into the expression or group if (searchExpressionOrGroup is FilterExpression) { ((FilterExpression)searchExpressionOrGroup).BoolOp = boolOp; } else if (searchExpressionOrGroup is FilterExpressionGroup) { ((FilterExpressionGroup)searchExpressionOrGroup).BoolOp = boolOp; } _expressions.Add(searchExpressionOrGroup); }
private static void parseExpression(string filter, ref int pos, FilterExpressionGroup parentSrchExpGrp) { ParseState left = ParseState.Left; bool flag = false; bool flag2 = false; bool flag3 = false; string fieldName = null; object searchVal = null; StringBuilder builder = new StringBuilder(); EqualityEnum equal = EqualityEnum.Equal; MatchTypeEnum useCase = MatchTypeEnum.UseCase; BoolOpEnum and = BoolOpEnum.And; int startIndex = pos; while (pos < filter.Length) { if (!char.IsWhiteSpace(filter[pos])) { break; } pos++; } while (pos < filter.Length) { switch (left) { case ParseState.Left: { if (filter[pos] == '[') { flag = true; pos++; startIndex = pos; } if (flag) { if (filter[pos] == ']') { fieldName = filter.Substring(startIndex, pos - startIndex).Trim(); pos++; } } else if (filter[pos] == '(') { pos++; FilterExpressionGroup searchExpressionOrGroup = new FilterExpressionGroup(); parentSrchExpGrp.Add(and, searchExpressionOrGroup); parseExpression(filter, ref pos, searchExpressionOrGroup); left = ParseState.BoolOp; } else if (char.IsWhiteSpace(filter[pos]) || ((!char.IsLetterOrDigit(filter[pos]) && (filter[pos] != '_')) && (filter[pos] != '~'))) { fieldName = filter.Substring(startIndex, pos - startIndex).Trim(); } if (fieldName != null) { if (fieldName[0] == '~') { fieldName = fieldName.Substring(1); useCase = MatchTypeEnum.IgnoreCase; } left = ParseState.CompareOp; } else { pos++; } continue; } case ParseState.CompareOp: { while ((pos < filter.Length) && char.IsWhiteSpace(filter[pos])) { pos++; } if (char.IsLetter(filter[pos])) { if ((pos + 4) >= filter.Length) { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } if (((char.ToUpper(filter[pos]) == 'N') && (char.ToUpper(filter[pos + 1]) == 'O')) && ((char.ToUpper(filter[pos + 2]) == 'T') && char.IsWhiteSpace(filter[pos + 3]))) { pos += 3; flag3 = true; continue; } if (((char.ToUpper(filter[pos]) == 'I') && (char.ToUpper(filter[pos + 1]) == 'N')) && (char.IsWhiteSpace(filter[pos + 2]) || (filter[pos + 2] == '('))) { pos += 2; if (char.IsWhiteSpace(filter[pos])) { while ((pos < filter.Length) && char.IsWhiteSpace(filter[pos])) { pos++; } if (filter[pos] != '(') { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos - 4)), FileDbExceptionsEnum.InvalidFilterConstruct); } } equal = flag3 ? EqualityEnum.NotIn : EqualityEnum.In; } else { if (((char.ToUpper(filter[pos]) != 'L') || (char.ToUpper(filter[pos + 1]) != 'I')) || (((char.ToUpper(filter[pos + 2]) != 'K') || (char.ToUpper(filter[pos + 3]) != 'E')) || !char.IsWhiteSpace(filter[pos + 4]))) { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos - 4)), FileDbExceptionsEnum.InvalidFilterConstruct); } pos += 4; equal = flag3 ? EqualityEnum.NotLike : EqualityEnum.Like; } } else if (filter[pos] == '!') { int num2 = pos + 1; pos = num2; if (num2 >= filter.Length) { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } if (filter[pos] != '=') { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } equal = EqualityEnum.NotEqual; } else if (filter[pos] == '=') { equal = EqualityEnum.Equal; } else if (filter[pos] == '<') { if ((pos + 1) >= filter.Length) { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } if (filter[pos + 1] == '>') { pos++; equal = EqualityEnum.NotEqual; } else if (filter[pos + 1] == '=') { pos++; equal = EqualityEnum.LessThanOrEqual; } else { equal = EqualityEnum.LessThan; } } else { if (filter[pos] != '>') { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } if ((pos + 1) >= filter.Length) { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } if (filter[pos + 1] == '=') { pos++; equal = EqualityEnum.GreaterThanOrEqual; } else { equal = EqualityEnum.GreaterThan; } } pos++; left = ParseState.Right; continue; } default: if (left != ParseState.Right) { goto Label_0681; } switch (equal) { case EqualityEnum.In: case EqualityEnum.NotIn: goto Label_05EB; } if (flag2) { if (filter[pos] == '\'') { if (((pos + 1) >= filter.Length) || (filter[pos + 1] != '\'')) { flag2 = false; searchVal = builder.ToString(); builder.Length = 0; FilterExpression searchExpressionOrGroup = new FilterExpression(fieldName, searchVal, equal, useCase); parentSrchExpGrp.Add(and, searchExpressionOrGroup); fieldName = null; left = ParseState.BoolOp; goto Label_0676; } pos++; } builder.Append(filter[pos]); } else { if (builder.Length == 0) { while ((pos < filter.Length) && char.IsWhiteSpace(filter[pos])) { pos++; } } if ((builder.Length > 0) && ((filter[pos] == ')') || char.IsWhiteSpace(filter[pos]))) { searchVal = builder.ToString(); builder.Length = 0; FilterExpression searchExpressionOrGroup = new FilterExpression(fieldName, searchVal, equal, useCase); parentSrchExpGrp.Add(and, searchExpressionOrGroup); if (filter[pos] == ')') { return; } fieldName = null; left = ParseState.BoolOp; } else if ((builder.Length == 0) && (filter[pos] == '\'')) { flag2 = true; } else { builder.Append(filter[pos]); } } goto Label_0676; } Label_05E5: pos++; Label_05EB: if ((pos < filter.Length) && char.IsWhiteSpace(filter[pos])) { goto Label_05E5; } if (filter[pos] == '(') { pos++; } int num3 = pos; while ((num3 < filter.Length) && (filter[num3] != ')')) { num3++; } if (num3 >= filter.Length) { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } searchVal = parseInVals(filter.Substring(pos, num3 - pos), useCase); pos = num3; Label_0676: pos++; continue; Label_0681: if (builder.Length == 0) { while ((pos < filter.Length) && char.IsWhiteSpace(filter[pos])) { pos++; } } if (filter[pos] == ')') { return; } if (char.IsWhiteSpace(filter[pos])) { if (builder.Length == 0) { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } string strA = builder.ToString(); builder.Length = 0; if (string.Compare(strA, "AND", StringComparison.OrdinalIgnoreCase) == 0) { and = BoolOpEnum.And; } else { if (string.Compare(strA, "OR", StringComparison.OrdinalIgnoreCase) != 0) { throw new FileDbException(string.Format("Invalid Filter construct near '{0}'", filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } and = BoolOpEnum.Or; } left = ParseState.Left; while ((pos < filter.Length) && char.IsWhiteSpace(filter[pos])) { pos++; } startIndex = pos; flag = false; } else { builder.Append(filter[pos]); pos++; } } if (left == ParseState.Right) { if ((equal != EqualityEnum.In) && (equal != EqualityEnum.NotIn)) { searchVal = builder.ToString(); builder.Length = 0; } FilterExpression searchExpressionOrGroup = new FilterExpression(fieldName, searchVal, equal, useCase); parentSrchExpGrp.Add(and, searchExpressionOrGroup); } }
static void parseExpression(string filter, ref int pos, FilterExpressionGroup parentSrchExpGrp) { ParseState state = ParseState.Left; bool hasBracket = false, inString = false, isNot = false; string fieldName = null; object searchVal = null; var sbTemp = new StringBuilder(); ComparisonOperatorEnum comparisonOp = ComparisonOperatorEnum.Equal; MatchTypeEnum matchType = MatchTypeEnum.UseCase; BoolOpEnum curBoolOp = BoolOpEnum.And; int startPos = pos; // skip past any leading spaces while (pos < filter.Length && char.IsWhiteSpace(filter[pos])) { pos++; } for ( ; pos < filter.Length;) { ////////////////////////////////////////////////////////// #region Left if (state == ParseState.Left) { if (filter[pos] == '[') // field names with ' ' in them must be wrapped with brackets { hasBracket = true; pos++; startPos = pos; } if (hasBracket) { // look for ending bracket if (filter[pos] == ']') { fieldName = filter.Substring(startPos, pos - startPos).Trim(); pos++; // skip past bracket } } else // no bracket - look for non-alpha { if (filter[pos] == '(') { // start of a new FilterExpressionGroup pos++; var newSrchExpGrp = new FilterExpressionGroup(); parentSrchExpGrp.Add(curBoolOp, newSrchExpGrp); parseExpression(filter, ref pos, newSrchExpGrp); state = ParseState.BoolOp; } else if (filter[pos] == '~') // eg. ~LastName { matchType = MatchTypeEnum.IgnoreCase; } else if (char.IsWhiteSpace(filter[pos]) || (!char.IsLetterOrDigit(filter[pos]) && filter[pos] != '_' && filter[pos] != '~')) // field names with spaces in them must be wrapped with brackets { fieldName = filter.Substring(startPos, pos - startPos).Trim(); } } if (fieldName != null) { if (fieldName[0] == '~') { fieldName = fieldName.Substring(1); matchType = MatchTypeEnum.IgnoreCase; } state = ParseState.CompareOp; } else { pos++; } } #endregion Left ////////////////////////////////////////////////////////// #region CompareOp else if (state == ParseState.CompareOp) { // skip whitespace while (pos < filter.Length && char.IsWhiteSpace(filter[pos])) { pos++; } if (char.IsLetter(filter[pos])) // REGEX { // should be CONTAINS, REGEX, IN or NOT //if( pos + 4 >= filter.Length ) // throwInvalidFilterConstruct( filter, pos ); try { // NOT if (char.ToUpper(filter[pos]) == 'N' && char.ToUpper(filter[pos + 1]) == 'O' && char.ToUpper(filter[pos + 2]) == 'T' && char.IsWhiteSpace(filter[pos + 3])) { pos += 3; isNot = true; continue; } // IN else if (char.ToUpper(filter[pos]) == 'I' && char.ToUpper(filter[pos + 1]) == 'N' && (char.IsWhiteSpace(filter[pos + 2]) || filter[pos + 2] == '(')) { pos += 2; if (char.IsWhiteSpace(filter[pos])) // skip whitespace { while (pos < filter.Length && char.IsWhiteSpace(filter[pos])) { pos++; } if (filter[pos] != '(') { throwInvalidFilterConstruct(filter, pos - 2); } } comparisonOp = ComparisonOperatorEnum.In; } // REGEX else if (char.ToUpper(filter[pos]) == 'R' && char.ToUpper(filter[pos + 1]) == 'E' && char.ToUpper(filter[pos + 2]) == 'G' && char.ToUpper(filter[pos + 3]) == 'E' && char.ToUpper(filter[pos + 4]) == 'X' && char.IsWhiteSpace(filter[pos + 5])) { pos += 5; comparisonOp = ComparisonOperatorEnum.Regex; } // CONTAINS else if (char.ToUpper(filter[pos]) == 'C' && char.ToUpper(filter[pos + 1]) == 'O' && char.ToUpper(filter[pos + 2]) == 'N' && char.ToUpper(filter[pos + 3]) == 'T' && char.ToUpper(filter[pos + 4]) == 'A' && char.ToUpper(filter[pos + 5]) == 'I' && char.ToUpper(filter[pos + 6]) == 'N' && char.ToUpper(filter[pos + 7]) == 'S' && char.IsWhiteSpace(filter[pos + 8])) { pos += 8; comparisonOp = ComparisonOperatorEnum.Contains; } else { throwInvalidFilterConstruct(filter, pos - 2); } } catch (Exception ex) { throwInvalidFilterConstruct(filter, pos - 2); } } // alternative way to specify ignore case search (other way is to prefix a fieldname with ~) else if (filter[pos] == '~') // ~= { matchType = MatchTypeEnum.IgnoreCase; if (++pos >= filter.Length) { throwInvalidFilterConstruct(filter, pos); } // next char must be = if (filter[pos] != '=') { throwInvalidFilterConstruct(filter, pos); } comparisonOp = ComparisonOperatorEnum.Equal; } else if (filter[pos] == '!') // != { if (++pos >= filter.Length) { throwInvalidFilterConstruct(filter, pos); } // next char must be = if (filter[pos] != '=') { throwInvalidFilterConstruct(filter, pos); } comparisonOp = ComparisonOperatorEnum.Equal; isNot = true; } else if (filter[pos] == '=') { comparisonOp = ComparisonOperatorEnum.Equal; } else if (filter[pos] == '<') // <, <= or <> { if (pos + 1 >= filter.Length) { throwInvalidFilterConstruct(filter, pos); } if (filter[pos + 1] == '>') { pos++; comparisonOp = ComparisonOperatorEnum.Equal; isNot = true; } else if (filter[pos + 1] == '=') { pos++; comparisonOp = ComparisonOperatorEnum.LessThanOrEqual; } else { comparisonOp = ComparisonOperatorEnum.LessThan; } } else if (filter[pos] == '>') // > or >= { if (pos + 1 >= filter.Length) { throwInvalidFilterConstruct(filter, pos); } if (filter[pos + 1] == '=') { pos++; comparisonOp = ComparisonOperatorEnum.GreaterThanOrEqual; } else { comparisonOp = ComparisonOperatorEnum.GreaterThan; } } else { throwInvalidFilterConstruct(filter, pos); } pos++; state = ParseState.Right; } #endregion CompareOp ////////////////////////////////////////////////////////// #region Right else if (state == ParseState.Right) { if (comparisonOp == ComparisonOperatorEnum.In) //|| comparisonOp == EqualityEnum.NotIn ) { // skip whitespace while (pos < filter.Length && char.IsWhiteSpace(filter[pos])) { pos++; } // filter[pos] should look like this now: (val1, val2, val3) // or like this: ('val1', 'val2', 'val3') if (filter[pos] == '(') { pos++; } // find the end int endPos = pos; while (endPos < filter.Length && filter[endPos] != ')') { endPos++; } if (endPos >= filter.Length) { throw new FileDbException(string.Format(FileDbException.InvalidFilterConstruct, filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } string inVals = filter.Substring(pos, endPos - pos); searchVal = parseInVals(inVals, matchType); pos = endPos; } else { if (!inString) { // skip whitespace only if we haven't found anything yet if (sbTemp.Length == 0) { while (pos < filter.Length && char.IsWhiteSpace(filter[pos])) { pos++; } } // look for end of ExpressionGroup if (sbTemp.Length > 0 && (filter[pos] == ')' || char.IsWhiteSpace(filter[pos]))) { // Expression completed searchVal = sbTemp.ToString(); sbTemp.Length = 0; var srchExp = new FilterExpression(fieldName, searchVal, comparisonOp, matchType, isNot); parentSrchExpGrp.Add(curBoolOp, srchExp); if (filter[pos] == ')') { return; } fieldName = null; state = ParseState.BoolOp; } else if (sbTemp.Length == 0 && filter[pos] == '\'') { // just starting to get the value inString = /*isString=*/ true; } else { sbTemp.Append(filter[pos]); } } else // inString == true { if (filter[pos] == '\'') { //Debug.Assert( sbTemp.Length > 0 ); -- it could be empty, eg. myfield = '' // if the next char is NOT another ' (escaped) then the string is completed if ((pos + 1 < filter.Length) && filter[pos + 1] == '\'') { pos++; } else { inString = false; searchVal = sbTemp.ToString(); sbTemp.Length = 0; var srchExp = new FilterExpression(fieldName, searchVal, comparisonOp, matchType, isNot); parentSrchExpGrp.Add(curBoolOp, srchExp); fieldName = null; state = ParseState.BoolOp; goto Advance; } } sbTemp.Append(filter[pos]); } } Advance: // advance pos++; } #endregion Right ////////////////////////////////////////////////////////// #region Next else // if( state == ParseState.BoolOp ) { Debug.Assert(state == ParseState.BoolOp); if (sbTemp.Length == 0) { // skip whitespace while (pos < filter.Length && char.IsWhiteSpace(filter[pos])) { pos++; } } if (filter[pos] == ')') { return; // we must be finished } if (char.IsWhiteSpace(filter[pos])) { // we must be finished if (sbTemp.Length == 0) { throw new FileDbException(string.Format(FileDbException.InvalidFilterConstruct, filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } string sOp = sbTemp.ToString(); sbTemp.Length = 0; if (string.Compare(sOp, "AND", StringComparison.OrdinalIgnoreCase) == 0) { curBoolOp = BoolOpEnum.And; } else if (string.Compare(sOp, "OR", StringComparison.OrdinalIgnoreCase) == 0) { curBoolOp = BoolOpEnum.Or; } else { throw new FileDbException(string.Format(FileDbException.InvalidFilterConstruct, filter.Substring(pos)), FileDbExceptionsEnum.InvalidFilterConstruct); } state = ParseState.Left; // start over on next expression // skip whitespace while (pos < filter.Length && char.IsWhiteSpace(filter[pos])) { pos++; } // reset vars startPos = pos; hasBracket = false; } else { sbTemp.Append(filter[pos]); pos++; } } #endregion Next } // for... // did we just complete an Expression? if (state == ParseState.Right) { if (comparisonOp != ComparisonOperatorEnum.In) //&& comparisonOp != EqualityEnum.NotIn ) { searchVal = sbTemp.ToString(); if (!inString && string.Compare((string)searchVal, "null", StringComparison.OrdinalIgnoreCase) == 0) { searchVal = null; } sbTemp.Length = 0; } var srchExp = new FilterExpression(fieldName, searchVal, comparisonOp, matchType, isNot); parentSrchExpGrp.Add(curBoolOp, srchExp); } }