Beispiel #1
0
        /// <summary>
        ///     Build a simple atomic query (one value and unary operator)
        /// </summary>
        /// <param name="metadata">The metadata of the value</param>
        /// <param name="value"></param>
        /// <param name="oper"></param>
        public AtomicQuery([NotNull] KeyInfo metadata, [NotNull] KeyValue value, QueryOperator oper = QueryOperator.Eq)
        {
            if (metadata == null)
            {
                throw new ArgumentNullException(nameof(metadata));
            }

            if (value == null)
            {
                throw new ArgumentNullException(nameof(value));
            }

            // only scalar operators can be used here
            if (oper == QueryOperator.In || oper == QueryOperator.NotIn || oper.IsRangeOperator())
            {
                throw new ArgumentException("invalid operator");
            }

            if (value.KeyName != metadata.Name)
            {
                throw new ArgumentException("Mismatch between value and metadata");
            }

            Metadata = metadata;
            Value    = value;
            Operator = oper;
        }
Beispiel #2
0
        /// <summary>
        ///     Check if the operators are compatible to define a subset relationship
        ///     Non trivial compatibility cases:
        ///     a &lt; b is subset of a &lt;= b
        ///     a &gt; b is subset of a &gt;= b
        ///     a = b is subset of a oper c if b oper c
        /// </summary>
        /// <param name="left"></param>
        /// <param name="right"></param>
        /// <returns></returns>
        private static bool AreOperatorsCompatibleWithSubset(QueryOperator left, QueryOperator right)
        {
            if (left == right)
            {
                return(true);
            }

            if (left.IsRangeOperator() && right.IsRangeOperator())
            {
                return(true);
            }

            if (left == QueryOperator.NotContains || left == QueryOperator.NotEq || left == QueryOperator.StrContains ||
                left == QueryOperator.StrEndsWith || left == QueryOperator.StrStartsWith)
            {
                return(false);
            }

            if (right == QueryOperator.NotContains || right == QueryOperator.NotEq || right == QueryOperator.StrContains ||
                right == QueryOperator.StrEndsWith || right == QueryOperator.StrStartsWith)
            {
                return(false);
            }



            if (right == QueryOperator.Eq)
            {
                return(false);
            }

            if (left == QueryOperator.Eq)
            {
                return(true);
            }

            if (left == QueryOperator.Gt && right == QueryOperator.Ge)
            {
                return(true);
            }

            if (left == QueryOperator.Lt && right == QueryOperator.Le)
            {
                return(true);
            }

            return(false);
        }
Beispiel #3
0
        /// <summary>
        ///     Build a query of the type BETWEEN value value2
        /// </summary>
        /// <param name="metadata"></param>
        /// <param name="value"></param>
        /// <param name="value2"></param>
        /// <param name="oper">A range operator like <see cref="QueryOperator.GeLe"/></param>
        public AtomicQuery([NotNull] KeyInfo metadata, [NotNull] KeyValue value, [NotNull] KeyValue value2, QueryOperator oper = QueryOperator.GeLe)
        {
            Metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
            Value    = value ?? throw new ArgumentNullException(nameof(value));
            Value2   = value2 ?? throw new ArgumentNullException(nameof(value2));

            if (!oper.IsRangeOperator())
            {
                throw new ArgumentException("Only range operators can be used with two values");
            }

            if (value.KeyName != metadata.Name)
            {
                throw new ArgumentException("Mismatch between value and metadata");
            }

            if (value2.KeyName != metadata.Name)
            {
                throw new ArgumentException("Mismatch between value and metadata");
            }

            Operator = oper; //the one and only binary operator
        }
Beispiel #4
0
        public override ISet <PackedObject> GetMany(IList <KeyValue> values, QueryOperator op = QueryOperator.Eq)
        {
            if (_insideFeedSession)
            {
                throw new InvalidOperationException(
                          "Illegal operation during a feed session (GetMany was called).");
            }

            if (values.Count == 0)
            {
                throw new ArgumentException("Empty list of keys passed to GetMany on index " + Name);
            }

            if (values.Count > 2 && op != QueryOperator.In)
            {
                throw new ArgumentException("More than two keys passed to GetMany on ordered index  " + Name);
            }

            if (values.Count == 2 && !op.IsRangeOperator())
            {
                throw new ArgumentException("Two keys passed to GetMany on ordered index " + Name + " for operator " +
                                            op);
            }


            var result = new HashSet <PackedObject>();

            if (op == QueryOperator.In)
            {
                foreach (var value in values)
                {
                    FindAllEq(value, result);
                }

                return(result);
            }

            switch (op)
            {
            case QueryOperator.Le:
                FindAllLe(values[0], result);
                break;

            case QueryOperator.Lt:
                FindAllLs(values[0], result);
                break;

            case QueryOperator.Eq:
                FindAllEq(values[0], result);
                break;

            case QueryOperator.Ge:
                FindAllGe(values[0], result);
                break;

            case QueryOperator.Gt:
                FindAllGt(values[0], result);
                break;

            //range operators
            case QueryOperator.GeLe:
                FindAllGeLe(values[0], values[1], result);
                break;

            case QueryOperator.GeLt:
                FindAllGeLt(values[0], values[1], result);
                break;

            case QueryOperator.GtLt:
                FindAllGtLt(values[0], values[1], result);
                break;

            case QueryOperator.GtLe:
                FindAllGtLe(values[0], values[1], result);
                break;
            }

            return(result);
        }
Beispiel #5
0
        public override int GetCount(IList <KeyValue> values, QueryOperator op = QueryOperator.Eq)
        {
            if (values.Count == 0)
            {
                throw new ArgumentException("Empty list of keys passed to GetCount on index " + Name);
            }


            if (values.Count > 2)
            {
                throw new ArgumentException("More than two keys passed to GetCount on ordered index  " + Name);
            }

            if (values.Count == 2 && !op.IsRangeOperator())
            {
                throw new ArgumentException("Two keys passed to GetCount on ordered index " + Name + " for operator " +
                                            op);
            }


            if (op == QueryOperator.In)
            {
                return(int.MaxValue); // can not count efficiently so do not use me as index
            }
            var result = 0;

            switch (op)
            {
            case QueryOperator.Le:
                result = CountAllLe(values[0]);
                break;

            case QueryOperator.Lt:
                result = CountAllLs(values[0]);
                break;

            case QueryOperator.Eq:
                result = CountAllEq(values[0]);
                break;

            case QueryOperator.Ge:
                result = CountAllGe(values[0]);
                break;

            case QueryOperator.Gt:
                result = CountAllGt(values[0]);
                break;

            case QueryOperator.GeLe:
                result = CountAllGeLe(values[0], values[1]);
                break;

            case QueryOperator.GeLt:
                result = CountAllGeLt(values[0], values[1]);
                break;

            case QueryOperator.GtLe:
                result = CountAllGtLe(values[0], values[1]);
                break;

            case QueryOperator.GtLt:
                result = CountAllGtLt(values[0], values[1]);
                break;
            }

            return(result);
        }
Beispiel #6
0
        public static void OptimizeQuery(OrQuery rootExpression)
        {
            // convert < and > into BETWEEN operator. Much more efficient

            foreach (var andQuery in rootExpression.Elements)
            {
                var multipleTests = andQuery.Elements.Where(q => q.IsComparison).GroupBy(q => q.PropertyName).Where(g => g.Count() > 1).ToList();

                if (multipleTests.Count > 0)
                {
                    // these ones will not be changed
                    var atomicQueries = andQuery.Elements.Where(q => multipleTests.All(mt => mt.Key != q.PropertyName))
                                        .ToList();

                    foreach (var multipleTest in multipleTests)
                    {
                        if (multipleTest.Count() == 2)
                        {
                            var q1 = multipleTest.First();
                            var q2 = multipleTest.Last();

                            // multiple atomic queries for the same index do not make sense
                            if (q1.Operator == QueryOperator.Eq)
                            {
                                throw new CacheException($"Inconsistent query on index {multipleTest.Key}");
                            }

                            if (q2.Operator == QueryOperator.Eq)
                            {
                                throw new CacheException($"Inconsistent query on index {multipleTest.Key}");
                            }


                            var optimized = false;

                            // a >= x && a <=y will be converted to "a BETWEEN x, y"

                            if (q1.Operator != QueryOperator.In && q1.Operator != QueryOperator.In)
                            {
                                if (q1.Value < q2.Value)
                                {
                                    QueryOperator oper = QueryOperator.Eq;
                                    if (q1.Operator == QueryOperator.Ge)
                                    {
                                        if (q2.Operator == QueryOperator.Le)
                                        {
                                            oper = QueryOperator.GeLe;
                                        }
                                    }
                                    if (q1.Operator == QueryOperator.Gt)
                                    {
                                        if (q2.Operator == QueryOperator.Le)
                                        {
                                            oper = QueryOperator.GtLe;
                                        }
                                    }
                                    if (q1.Operator == QueryOperator.Gt)
                                    {
                                        if (q2.Operator == QueryOperator.Lt)
                                        {
                                            oper = QueryOperator.GtLt;
                                        }
                                    }
                                    if (q1.Operator == QueryOperator.Ge)
                                    {
                                        if (q2.Operator == QueryOperator.Lt)
                                        {
                                            oper = QueryOperator.GeLt;
                                        }
                                    }

                                    if (oper.IsRangeOperator())
                                    {
                                        var between = new AtomicQuery(q1.Metadata, q1.Value, q2.Value, oper);
                                        atomicQueries.Add(between);
                                        optimized = true;
                                    }
                                }
                                else if (q1.Value > q2.Value)
                                {
                                    QueryOperator oper = QueryOperator.Eq;

                                    if (q1.Operator == QueryOperator.Le)
                                    {
                                        if (q2.Operator == QueryOperator.Ge)
                                        {
                                            oper = QueryOperator.GeLe;
                                        }
                                    }
                                    if (q1.Operator == QueryOperator.Lt)
                                    {
                                        if (q2.Operator == QueryOperator.Ge)
                                        {
                                            oper = QueryOperator.GeLt;
                                        }
                                    }
                                    if (q1.Operator == QueryOperator.Le)
                                    {
                                        if (q2.Operator == QueryOperator.Gt)
                                        {
                                            oper = QueryOperator.GtLe;
                                        }
                                    }
                                    if (q1.Operator == QueryOperator.Lt)
                                    {
                                        if (q2.Operator == QueryOperator.Gt)
                                        {
                                            oper = QueryOperator.GtLt;
                                        }
                                    }

                                    var between = new AtomicQuery(q1.Metadata, q2.Value, q1.Value, oper);
                                    atomicQueries.Add(between);
                                    optimized = true;
                                }
                            }

                            if (!optimized)
                            {
                                // keep the original expressions
                                atomicQueries.Add(q1);
                                atomicQueries.Add(q2);
                            }
                        }
                    }

                    andQuery.Elements.Clear();
                    andQuery.Elements.AddRange(atomicQueries);
                }
            }
        }