예제 #1
0
        public AndQuery MakeAndQuery(AtomicQuery atomicQuery)
        {
            var q = new AndQuery();

            q.Elements.Add(atomicQuery);
            return(q);
        }
예제 #2
0
        public OrQuery MakeOrQuery(AtomicQuery atomicQuery)
        {
            var orQuery  = new OrQuery(_typeDescription.FullTypeName);
            var andQuery = new AndQuery();

            andQuery.Elements.Add(atomicQuery);
            orQuery.Elements.Add(andQuery);
            return(orQuery);
        }
예제 #3
0
        /// <summary>
        ///     Parse a string like "key == value" or "key &gt; value"
        /// </summary>
        /// <param name="queryString"></param>
        /// <returns></returns>
        private AtomicQuery StringToQuery(string queryString)
        {
            var expression = new Regex("(\\w+)\\s*(==|=|<=|<|>|>=|CONTAINS)\\s*((\\w|-|\\.)+)");
            var match      = expression.Match(queryString);

            if (!match.Success || match.Captures.Count != 1 || match.Groups.Count != 5)
            {
                throw new ArgumentException($"Invalid query string {queryString}");
            }


            var left = match.Groups[1].Value;

            left = left.Trim();
            var oper = match.Groups[2].Value;

            oper = oper.Trim();
            var right = match.Groups[3].Value;

            right = right.Trim();

            KeyInfo keyInfo = null;

            if (_typeDescription.PrimaryKeyField.Name.ToUpper() == left.ToUpper())
            {
                keyInfo = _typeDescription.PrimaryKeyField;
            }

            if (keyInfo == null)
            {
                foreach (var uniqueField in _typeDescription.UniqueKeyFields)
                {
                    if (uniqueField.Name.ToUpper() == left.ToUpper())
                    {
                        keyInfo = uniqueField;
                    }
                }
            }

            if (keyInfo == null)
            {
                if (_typeDescription.IndexFields != null)
                {
                    foreach (var indexField in _typeDescription.IndexFields)
                    {
                        if (indexField.Name.ToUpper() == left.ToUpper())
                        {
                            keyInfo = indexField;
                        }
                    }
                }
            }

            if (keyInfo == null)
            {
                foreach (var indexField in _typeDescription.ListFields)
                {
                    if (indexField.Name.ToUpper() == left.ToUpper())
                    {
                        keyInfo = indexField;
                    }
                }
            }

            if (keyInfo == null)
            {
                throw new ArgumentException(left + " is not an index field");
            }


            KeyValue keyValue;

            if (keyInfo.KeyDataType == KeyDataType.IntKey)
            {
                // special processing for dates(must be in yyyy-mm-dd format)
                var parts = right.Split('-');
                if (parts.Length == 3)
                {
                    var date = DateTime.Parse(right);

                    keyValue = new KeyValue(date.Ticks, keyInfo);
                }
                else
                {
                    if (right.Contains(".")) // floating point value
                    {
                        if (!decimal.TryParse(right, out var floatValue))
                        {
                            throw new ArgumentException(right + " can not be converted to float");
                        }

                        keyValue = KeyInfo.ValueToKeyValue(floatValue, keyInfo);
                    }
                    else // integer value
                    {
                        if (!long.TryParse(right, out var longValue))
                        {
                            throw new ArgumentException(right + " can not be converted to long");
                        }


                        keyValue = KeyInfo.ValueToKeyValue(longValue, keyInfo);
                    }
                }
            }
            else
            {
                keyValue = new KeyValue(right, keyInfo);
            }


            QueryOperator op;

            switch (oper.ToLower())
            {
            case "=":
            case "==":
                op = QueryOperator.Eq;
                break;

            case "<":
                op = QueryOperator.Lt;
                break;

            case "<=":
                op = QueryOperator.Le;
                break;

            case ">":
                op = QueryOperator.Gt;
                break;

            case ">=":
                op = QueryOperator.Ge;
                break;

            case "CONTAINS":
                op = QueryOperator.In;
                break;

            default:
                throw new ArgumentException("unknown operator: ", oper);
            }

            var result = new AtomicQuery(keyValue, op);

            return(result);
        }
예제 #4
0
        public static void OptimizeQuery(OrQuery rootExpression)
        {
            // convert < and > into BETWEEN operator. Much more afficient

            foreach (var andQuery in rootExpression.Elements)
            {
                var multipleTests = andQuery.Elements.GroupBy(q => q.IndexName).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.IndexName))
                                        .ToList();

                    foreach (var multipleTest in multipleTests)
                    {
                        if (multipleTest.Count() != 2)
                        {
                            throw new CacheException($"Inconsistent query on index {multipleTest.Key}");
                        }

                        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 concverted to "a BETWEEN x, y"

                        if (q1.Operator != QueryOperator.In && q1.Operator != QueryOperator.In)
                        {
                            if (q1.Value < q2.Value)
                            {
                                if (q1.Operator == QueryOperator.Ge)
                                {
                                    if (q2.Operator == QueryOperator.Le)
                                    {
                                        var between = new AtomicQuery(q1.Value, q2.Value);
                                        atomicQueries.Add(between);
                                        optimized = true;
                                    }
                                }
                            }
                            else if (q1.Value > q2.Value)
                            {
                                if (q1.Operator == QueryOperator.Le)
                                {
                                    if (q2.Operator == QueryOperator.Ge)
                                    {
                                        var between = new AtomicQuery(q2.Value, q1.Value);
                                        atomicQueries.Add(between);
                                        optimized = true;
                                    }
                                }
                            }
                        }

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

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