Example #1
0
 //----------------------------------------------------------------------------------------
 /// <summary>
 /// Return a List of custom objects filtered by the filter parameter.
 /// </summary>
 /// <param name="filter">A FilterExpression representing the desired filter.</param>
 /// <returns>A new List of custom objects with the requested Records</returns>
 ///
 public List <T> SelectRecords <T>(FilterExpression filter)
     where T : class, new()
 {
     return(SelectRecords <T>(filter, null, null, false));
 }
Example #2
0
 //----------------------------------------------------------------------------------------
 /// <summary>
 /// Return a List of custom objects filtered by the filter parameter. Only the specified Fields
 /// will be in the Table.
 /// </summary>
 /// <param name="filter">A FilterExpression representing the desired filter.</param>
 /// <param name="fieldList">The desired fields to be in the returned Table</param>
 /// <param name="orderByList">A list of one or more fields to order the returned table by,
 /// or null for default order. If an orderByField is prefixed with "!", that field will sorted
 /// in reverse order.</param>
 /// <returns>A new List of custom objects with the requested Records and Fields ordered by the specified fields.</returns>
 ///
 public List <T> SelectRecords <T>(FilterExpression filter, string[] fieldList, string[] orderByList)
     where T : class, new()
 {
     return(SelectRecords <T>(filter, fieldList, orderByList, false));
 }
        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);
            }
        }