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); } }
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); }
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); }