示例#1
0
        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);
        }
示例#2
0
            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);
            }
示例#3
0
        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;
                }
            }
        }
示例#4
0
        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;
                    }
                }
            }
        }
示例#5
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);
        }