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