Ejemplo n.º 1
0
        private IExpression ProcessFilter(XElement elem, FilterSettings settings, PropertyReference prop)
        {
            var elemName = elem.Name.LocalName.ToLowerInvariant();

            switch (elemName)
            {
            case "property":
                return(settings.ItemCallback(elem.Attribute("query_items_xpath")?.Value)
                       .GetProperty(new[] { elem.Attribute("name")?.Value }));

            case "constant":
                if (long.TryParse(elem.Value, out var lng) ||
                    double.TryParse(elem.Value, out var dbl) ||
                    DateTime.TryParse(elem.Value, out var date))
                {
                    return(new ObjectLiteral(elem.Value, prop, _context));
                }
                else if (elem.Value.IndexOf('$') >= 0)
                {
                    return(ReplaceParameters(elem.Value));
                }
                else
                {
                    return(new StringLiteral(elem.Value));
                }

            case "count":
                var path = elem.Element("query_reference_path").Value.Split('/');

                var result = new CountAggregate();
                foreach (var table in path.Select(s => settings.Joins[s].Right))
                {
                    result.TablePath.Add(table);
                }
                return(result);

            case "eq":
            case "ne":
            case "gt":
            case "ge":
            case "lt":
            case "le":
            case "like":
                var left  = ProcessFilter(elem.Elements().First(), settings, prop);
                var right = ProcessFilter(elem.Elements().ElementAt(1), settings, left as PropertyReference);

                if (left is CountAggregate cnt &&
                    right is IntegerLiteral iLit &&
                    Parents(elem)
                    .All(p => string.Equals(p.Name.LocalName, "condition", StringComparison.OrdinalIgnoreCase) ||
                         string.Equals(p.Name.LocalName, "and", StringComparison.OrdinalIgnoreCase)) &&
                    ((elemName == "gt" && iLit.Value == 0) ||
                     (elemName == "ge" && iLit.Value == 1)))
                {
                    var refPath = elem.Element("count").Element("query_reference_path").Value.Split('/');
                    foreach (var join in refPath.Select(s => settings.Joins[s]))
                    {
                        join.Type = JoinType.Inner;
                    }
                    return(IgnoreNode.Instance);
                }

                switch (elemName)
                {
                case "eq":
                    return(new EqualsOperator()
                    {
                        Left = left, Right = right
                    }.Normalize());

                case "ne":
                    return(new NotEqualsOperator()
                    {
                        Left = left, Right = right
                    }.Normalize());

                case "gt":
                    return(new GreaterThanOperator()
                    {
                        Left = left, Right = right
                    }.Normalize());

                case "ge":
                    return(new GreaterThanOrEqualsOperator()
                    {
                        Left = left, Right = right
                    }.Normalize());

                case "lt":
                    return(new LessThanOperator()
                    {
                        Left = left, Right = right
                    }.Normalize());

                case "le":
                    return(new LessThanOrEqualsOperator()
                    {
                        Left = left, Right = right
                    }.Normalize());

                case "like":
                    right = AmlLikeParser.Instance.Parse(right.ToString());
                    return(new LikeOperator()
                    {
                        Left = left, Right = right
                    }.Normalize());

                default:
                    throw new InvalidOperationException();
                }

            case "null":
                return(new IsOperator()
                {
                    Left = ProcessFilter(elem.Elements().First(), settings, prop),
                    Right = IsOperand.Null
                }.Normalize());

            case "and":
            case "or":
                var children = elem.Elements()
                               .Select(e => ProcessFilter(e, settings, prop))
                               .ToArray();
                if (children.Length < 1)
                {
                    throw new InvalidOperationException();
                }
                else if (children.Length == 1)
                {
                    return(children[0]);
                }
                else if (string.Equals(elem.Name.LocalName, "and", StringComparison.OrdinalIgnoreCase))
                {
                    var expr = new AndOperator()
                    {
                        Left  = children[0],
                        Right = children[1]
                    }.Normalize();
                    for (var i = 2; i < children.Length; i++)
                    {
                        expr = new AndOperator()
                        {
                            Left  = expr,
                            Right = children[i]
                        }.Normalize();
                    }
                    return(expr);
                }
                else if (string.Equals(elem.Name.LocalName, "or", StringComparison.OrdinalIgnoreCase))
                {
                    var expr = new OrOperator()
                    {
                        Left  = children[0],
                        Right = children[1]
                    }.Normalize();
                    for (var i = 2; i < children.Length; i++)
                    {
                        expr = new OrOperator()
                        {
                            Left  = expr,
                            Right = children[i]
                        }.Normalize();
                    }
                    return(expr);
                }
                break;

            case "not":
                return(new NotOperator()
                {
                    Arg = ProcessFilter(elem.Elements().First(), settings, prop)
                }.Normalize());

            case "condition":
                return(ProcessFilter(elem.Elements().First(), settings, prop));
            }
            throw new InvalidOperationException();
        }