Beispiel #1
0
        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);
        }