예제 #1
0
        private bool Operator(bool fieldRequired, out QueryExpression op)
        {
            OperatorType type;
            FieldToken   field = null;

            if (Scanner.TryScan("true"))
            {
                type = OperatorType.True;
            }
            else
            {
                if (fieldRequired && Field(out field) == false)
                {
                    op = null;
                    return(false);
                }

                if (Scanner.TryScan(OperatorStartMatches, out var match) == false)
                {
                    if (fieldRequired == false)
                    {
                        op = null;
                        return(false);
                    }
                    ThrowParseException("Invalid operator expected any of (In, Between, =, <, >, <=, >=)");
                }

                switch (match)
                {
                case "<":
                    type = OperatorType.LessThan;
                    break;

                case ">":
                    type = OperatorType.GreaterThan;
                    break;

                case "<=":
                    type = OperatorType.LessThanEqual;
                    break;

                case ">=":
                    type = OperatorType.GreaterThanEqual;
                    break;

                case "=":
                case "==":
                    type = OperatorType.Equal;
                    break;

                case "!=":
                case "<>":
                    type = OperatorType.NotEqual;
                    break;

                case "BETWEEN":
                    type = OperatorType.Between;
                    break;

                case "IN":
                    type = OperatorType.In;
                    break;

                case "ALL IN":
                    type = OperatorType.AllIn;
                    break;

                case "(":
                    type = OperatorType.Method;
                    break;

                default:
                    op = null;
                    return(false);
                }
            }

            switch (type)
            {
            case OperatorType.True:
                op = new QueryExpression
                {
                    Type = type
                };
                return(true);

            case OperatorType.Method:
                var method = Method(field, op: out op);

                if (method && Operator(false, out var methodOperator))
                {
                    if (op.Arguments == null)
                    {
                        op.Arguments = new List <object>();
                    }

                    op.Arguments.Add(methodOperator);
                    return(true);
                }

                return(method);

            case OperatorType.Between:
                if (Value(out var fst) == false)
                {
                    ThrowParseException("parsing Between, expected value (1st)");
                }
                if (Scanner.TryScan("AND") == false)
                {
                    ThrowParseException("parsing Between, expected AND");
                }
                if (Value(out var snd) == false)
                {
                    ThrowParseException("parsing Between, expected value (2nd)");
                }

                if (fst.Type != snd.Type)
                {
                    ThrowQueryException(
                        $"Invalid Between expression, values must have the same type but got {fst.Type} and {snd.Type}");
                }

                op = new QueryExpression
                {
                    Field  = field,
                    Type   = OperatorType.Between,
                    First  = fst,
                    Second = snd
                };
                return(true);

            case OperatorType.In:
            case OperatorType.AllIn:
                if (Scanner.TryScan('(') == false)
                {
                    ThrowParseException("parsing In, expected '('");
                }

                var list = new List <ValueToken>();
                do
                {
                    if (Scanner.TryScan(')'))
                    {
                        break;
                    }

                    if (list.Count != 0)
                    {
                        if (Scanner.TryScan(',') == false)
                        {
                            ThrowParseException("parsing In expression, expected ','");
                        }
                    }

                    if (Value(out var inVal) == false)
                    {
                        ThrowParseException("parsing In, expected a value");
                    }

                    if (list.Count > 0)
                    {
                        if (list[0].Type != inVal.Type)
                        {
                            ThrowQueryException(
                                $"Invalid In expression, all values must have the same type, expected {list[0].Type} but got {inVal.Type}");
                        }
                    }
                    list.Add(inVal);
                } while (true);

                op = new QueryExpression
                {
                    Field  = field,
                    Type   = type,
                    Values = list
                };

                return(true);

            default:
                if (Value(out var val) == false)
                {
                    ThrowParseException($"parsing {type} expression, expected a value (operators only work on scalar / parameters values)");
                }

                op = new QueryExpression
                {
                    Field = field,
                    Type  = type,
                    Value = val
                };
                return(true);
            }
        }
예제 #2
0
        internal bool Field(out FieldToken token)
        {
            var tokenStart  = -1;
            var tokenLength = 0;
            var escapeChars = 0;
            var part        = 0;
            var isQuoted    = false;

            while (true)
            {
                if (Scanner.Identifier(beginning: part++ == 0) == false)
                {
                    if (Scanner.String())
                    {
                        isQuoted     = true;
                        escapeChars += Scanner.EscapeChars;
                    }
                    else
                    {
                        token = null;
                        return(false);
                    }
                }
                if (part == 1 && isQuoted == false)
                {
                    // need to ensure that this isn't a keyword
                    if (Scanner.CurrentTokenMatchesAnyOf(AliasKeywords))
                    {
                        Scanner.GoBack(Scanner.TokenLength);
                        token = null;
                        return(false);
                    }
                }
                if (tokenStart == -1)
                {
                    tokenStart = Scanner.TokenStart;
                }
                tokenLength += Scanner.TokenLength;

                if (Scanner.TryScan('['))
                {
                    switch (Scanner.TryNumber())
                    {
                    case NumberToken.Long:
                    case null:
                        if (Scanner.TryScan(']') == false)
                        {
                            ThrowParseException("Expected to find closing ]");
                        }
                        tokenLength = Scanner.Position - tokenStart;
                        break;

                    case NumberToken.Double:
                        ThrowParseException("Array indexer must be integer, but got double");
                        break;
                    }
                }

                if (Scanner.TryScan('.') == false)
                {
                    break;
                }

                tokenLength += 1;
            }

            token = new FieldToken
            {
                EscapeChars = escapeChars,
                TokenLength = tokenLength,
                TokenStart  = tokenStart,
                IsQuoted    = isQuoted
            };
            return(true);
        }
예제 #3
0
        private (FieldToken From, FieldToken Alias, QueryExpression Filter, bool Index) FromClause()
        {
            if (Scanner.TryScan("FROM") == false)
            {
                ThrowParseException("Expected FROM clause");
            }

            FieldToken      field;
            QueryExpression filter = null;
            bool            index  = false;
            bool            isQuoted;

            if (Scanner.TryScan("INDEX"))
            {
                isQuoted = false;
                if (!Scanner.Identifier() && !(isQuoted = Scanner.String()))
                {
                    ThrowParseException("Expected FROM INDEX source");
                }

                field = new FieldToken
                {
                    TokenLength = Scanner.TokenLength,
                    TokenStart  = Scanner.TokenStart,
                    EscapeChars = Scanner.EscapeChars,
                    IsQuoted    = isQuoted
                };

                index = true;
            }
            else
            {
                isQuoted = false;
                if (!Scanner.Identifier() && !(isQuoted = Scanner.String()))
                {
                    ThrowParseException("Expected FROM source");
                }

                field = new FieldToken
                {
                    TokenLength = Scanner.TokenLength,
                    TokenStart  = Scanner.TokenStart,
                    EscapeChars = Scanner.EscapeChars,
                    IsQuoted    = isQuoted
                };

                if (Scanner.TryScan('(')) // FROM  Collection ( filter )
                {
                    if (Expression(out filter) == false)
                    {
                        ThrowParseException("Expected filter in filtered FORM clause");
                    }

                    if (Scanner.TryScan(')') == false)
                    {
                        ThrowParseException("Expected closing parenthesis in filtered FORM clause after filter");
                    }
                }
            }


            Alias(false, out var alias);

            return(field, alias, filter, index);
        }