private static Dictionary <string, QuerySpan> GetSpans(QuerySpan tokens) { if (tokens.First().Type != ODataTokenType.Identifier) { throw new InvalidOperationException(); } var span = new QuerySpan(tokens.List, tokens.First().Text, tokens.Start + 2); var result = new Dictionary <string, QuerySpan>(StringComparer.OrdinalIgnoreCase) { [span.Name] = span }; for (var i = tokens.Start + 1; i < tokens.Start + tokens.Length; i++) { if (tokens.List[i].Type == ODataTokenType.Semicolon) { span.Length = i - span.Start; if ((i + 1) < tokens.Start + tokens.Length) { i++; if (tokens.List[i].Type != ODataTokenType.Identifier) { throw new InvalidOperationException(); } span = new QuerySpan(tokens.List, tokens.List[i].Text, i + 2); result[span.Name] = span; } } } span.Length = tokens.Start + tokens.Length - span.Start; return(result); }
public static List <SegmentInfo> Create(QuerySpan tokens) { var result = new List <SegmentInfo>(); var last = tokens.Start + tokens.Length; for (var i = tokens.Start; i < last; i++) { if (tokens.List[i].Type == ODataTokenType.Identifier) { var segment = new SegmentInfo(tokens.List[i].Text); if ((i + 1) < last && tokens.List[i + 1].Type == ODataTokenType.OpenParen) { segment._args = new List <ODataToken>(); i += 2; while (i < last && tokens.List[i].Type != ODataTokenType.CloseParen) { if (tokens.List[i].Type != ODataTokenType.Comma) { segment._args.Add(tokens.List[i]); } i++; } } result.Add(segment); } } return(result); }
private static IEnumerable <IExpression> GetExpressions(QueryItem table, QuerySpan tokens, ParseContext context) { for (var i = tokens.Start; i < tokens.Start + tokens.Length; i++) { var token = tokens.List[i]; switch (token.Type) { case ODataTokenType.Parameter: yield return(new ParameterReference(token.Text.Substring(1), false)); break; case ODataTokenType.Date: case ODataTokenType.TimeOfDay: var dateText = token.Text; if (dateText.StartsWith("datetime'")) { dateText = dateText.Substring(9).TrimEnd('\''); } if (!ZonedDateTime.TryParse(dateText, table.Context.GetTimeZone(), out var date)) { throw new InvalidOperationException(); } yield return(new DateTimeLiteral(date.LocalDateTime)); break; case ODataTokenType.Decimal: yield return(new FloatLiteral((double)((decimal)token.AsPrimitive()))); break; case ODataTokenType.Single: yield return(new FloatLiteral((double)((float)token.AsPrimitive()))); break; case ODataTokenType.Double: case ODataTokenType.NaN: case ODataTokenType.NegInfinity: case ODataTokenType.PosInfinity: yield return(new FloatLiteral((double)token.AsPrimitive())); break; case ODataTokenType.False: yield return(new BooleanLiteral(false)); break; case ODataTokenType.Guid: yield return(new StringLiteral(((Guid)token.AsPrimitive()).ToArasId())); break; case ODataTokenType.Integer: yield return(new IntegerLiteral((int)token.AsPrimitive())); break; case ODataTokenType.Long: yield return(new IntegerLiteral((long)token.AsPrimitive())); break; case ODataTokenType.String: yield return(new StringLiteral((string)token.AsPrimitive())); break; case ODataTokenType.True: yield return(new BooleanLiteral(true)); break; case ODataTokenType.Null: yield return(new NullLiteral()); break; case ODataTokenType.Identifier: if (string.Equals(context.Name, "$compute", StringComparison.OrdinalIgnoreCase) && string.Equals(tokens.List[i].Text, "as", StringComparison.OrdinalIgnoreCase)) { yield return(new SelectExpression()); } else { yield return(TryGetProperty(tokens.List, ref i, table, context)); } break; case ODataTokenType.And: yield return(new AndOperator()); break; case ODataTokenType.Or: yield return(new OrOperator()); break; case ODataTokenType.Equal: yield return(new EqualsOperator()); break; case ODataTokenType.NotEqual: yield return(new NotEqualsOperator()); break; case ODataTokenType.LessThan: yield return(new LessThanOperator()); break; case ODataTokenType.LessThanOrEqual: yield return(new LessThanOrEqualsOperator()); break; case ODataTokenType.GreaterThan: yield return(new GreaterThanOperator()); break; case ODataTokenType.GreaterThanOrEqual: yield return(new GreaterThanOrEqualsOperator()); break; case ODataTokenType.In: yield return(new InOperator()); break; case ODataTokenType.Add: yield return(new AdditionOperator()); break; case ODataTokenType.Subtract: yield return(new SubtractionOperator()); break; case ODataTokenType.Multiply: yield return(new MultiplicationOperator()); break; case ODataTokenType.Divide: yield return(new DivisionOperator()); break; case ODataTokenType.Modulo: yield return(new ModulusOperator()); break; case ODataTokenType.Not: yield return(new NotOperator()); break; case ODataTokenType.Negate: yield return(new NegationOperator()); break; case ODataTokenType.Star: yield return(new AllProperties(table)); break; case ODataTokenType.OpenParen: yield return(new ListExpression()); break; case ODataTokenType.CloseParen: yield return(new EndParen()); break; case ODataTokenType.Comma: yield return(new Comma()); break; case ODataTokenType.Base64: case ODataTokenType.Binary: case ODataTokenType.Duration: case ODataTokenType.Has: case ODataTokenType.Navigation: throw new NotSupportedException(); default: //return new IgnoredNode(token); break; } } }
private static IEnumerable <IExpression> GetProperties(QueryItem table, QuerySpan tokens, IServerContext context, ParseContext parseContext) { var depth = 0; var span = new QuerySpan(tokens.List, "", tokens.Start); var spans = new List <QuerySpan>() { span }; for (var i = tokens.Start; i < tokens.Start + tokens.Length; i++) { if (tokens.List[i].Text == "(") { if (depth == 0) { span.Length = i - span.Start; span = new QuerySpan(tokens.List, "(", i + 1); spans.Add(span); } depth++; } else if (tokens.List[i].Text == ")") { depth--; if (depth == 0) { span.Length = i - span.Start; span = new QuerySpan(tokens.List, "", i + 1); spans.Add(span); } } } span.Length = tokens.Start + tokens.Length - span.Start; var last = default(IExpression); foreach (var s in spans) { if (s.Name == "(") { if (!(last is PropertyReference prop)) { throw new InvalidOperationException(); } var newTable = GetExpansionTable(prop); var dict = GetSpans(s); ProcessSpans(tokens.List, newTable, dict, context); } else { foreach (var expr in GetExpressions(table, s, parseContext)) { if (expr is PropertyReference || expr is AllProperties) { yield return(expr); } last = expr; } } } }
public static QueryItem Parse(string uri, IServerContext context, ODataVersion version = ODataVersion.All) { var tokens = new List <ODataToken>(); var spans = new Dictionary <string, QuerySpan>(StringComparer.OrdinalIgnoreCase); var span = default(QuerySpan); var table = new QueryItem(context); var segments = default(List <SegmentInfo>); using (var tokenizer = new ODataTokenizer(uri, version)) { var i = 0; while (tokenizer.MoveNext()) { tokens.Add(tokenizer.Current); if (tokenizer.Current.Type == ODataTokenType.Question) { segments = SegmentInfo.Create(new QuerySpan(tokens, "", 0) { Length = tokens.Count - 1 }); } else if (tokenizer.Current.Type == ODataTokenType.QueryName) { if (span != null) { span.Length = i - span.Start - 1; } span = new QuerySpan(tokens, tokenizer.Current.Text, i + 2); spans[span.Name] = span; } i++; } if (span != null) { span.Length = i - span.Start; } } if (segments == null) { segments = SegmentInfo.Create(new QuerySpan(tokens, "", 0) { Length = tokens.Count }); } if (segments.Any(s => string.Equals(s.Name, "$entity", StringComparison.OrdinalIgnoreCase))) { if (!(spans.TryGetValue("$id", out var idInfo) || spans.TryGetValue("id", out idInfo))) { throw new InvalidOperationException(); } var s = idInfo.Start; if (idInfo.List[s].Text.StartsWith("http", StringComparison.OrdinalIgnoreCase) && idInfo.List[s].Text.EndsWith(":") && idInfo.Length > 3 && idInfo.List[s + 1].Type == ODataTokenType.Navigation && idInfo.List[s + 2].Type == ODataTokenType.Navigation) { s += 3; while (idInfo.List[s].Type != ODataTokenType.Navigation) { s++; } s++; } var idSpan = new QuerySpan(idInfo.List, "", s) { Length = idInfo.Length - (s - idInfo.Start) }; segments = SegmentInfo.Create(idSpan); } var end = segments.Count - 1; if (string.Equals(segments.Last().Name, "$value", StringComparison.OrdinalIgnoreCase)) { end -= 2; } else if (segments.Last().Name[0] == '$') { end--; } var start = end; for (var i = 0; i <= end; i++) { if (segments[i].Args.All(a => a.Type == ODataTokenType.String) && segments[i].Args.Count() == 1) { start = i; break; } } table.Type = segments[start].Name; ProcessSpans(tokens, table, spans, context); if (segments[start].Args.Any()) { if (start == end) { table.Where = new EqualsOperator() { Left = new PropertyReference("id", table), Right = new StringLiteral((string)segments[start].Args.Single().AsPrimitive()) }.Normalize(); } else if (start + 1 == end) { table.Type = segments[end].Name; table.AddCondition(new EqualsOperator() { Left = new PropertyReference("source_id", table), Right = new StringLiteral((string)segments[start].Args.Single().AsPrimitive()) }.Normalize()); } else { throw new InvalidOperationException(); } if (string.Equals(segments.Last().Name, "$value", StringComparison.OrdinalIgnoreCase)) { table.Select.Clear(); table.Select.Add(new SelectExpression() { Expression = new PropertyReference(segments[end + 1].Name, table) }); } } if (string.Equals(segments.Last().Name, "$count", StringComparison.OrdinalIgnoreCase)) { table.Select.Clear(); table.Select.Add(new SelectExpression() { Expression = new CountAggregate() { TablePath = { table } } }); } table.RebalanceCriteria(); return(table); }