public AndQuery MakeAndQuery(AtomicQuery atomicQuery) { var q = new AndQuery(); q.Elements.Add(atomicQuery); return(q); }
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); }
/// <summary> /// Parse a string like "key == value" or "key > 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); }
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); } } }