public void OrQueries() { QueryBuilder builder = new QueryBuilder(typeof(TradeLike)); DomainDescription domainAll = new DomainDescription(typeof(TradeLike)); domainAll.IsFullyLoaded = true; OrQuery q = builder.GetManyWhere("VALUEDATE > 20100101"); Assert.IsTrue(q.IsSubsetOf(domainAll)); DomainDescription complexDomain = new DomainDescription(typeof(TradeLike)); AtomicQuery q2 = builder.MakeAtomicQuery("Folder", "AAA"); AtomicQuery q4 = builder.MakeAtomicQuery("ValueDate", QueryOperator.Gt, new DateTime(2001, 1, 1)); complexDomain.AddOrReplace(q2); complexDomain.AddOrReplace(q4); OrQuery qq = builder.GetManyWhere("FOLDER = AAA, VALUEDATE > 20010101"); Assert.IsTrue(qq.IsSubsetOf(complexDomain)); OrQuery qqq = builder.GetManyWhere("VALUEDATE >= 20010101"); Assert.IsFalse(qqq.IsSubsetOf(complexDomain)); AtomicQuery q3 = builder.MakeAtomicQuery("Folder", "BBB"); AndQuery q33 = builder.MakeAndQuery(q3); qq.Elements.Add(q33); //the query is now (FOLDER = AAA AND VALUEDATE > 20010101) OR (FOLDER = BBB ) ans is not a subset //any more Assert.IsFalse(qq.IsSubsetOf(complexDomain)); }
public void AndQueries() { QueryBuilder builder = new QueryBuilder(typeof(TradeLike)); DomainDescription domainAll = new DomainDescription(typeof(TradeLike)); domainAll.IsFullyLoaded = true; //check the trivial case of a complete domain (all queries are subsets of a complete domain) AndQuery q1 = builder.MakeAndQuery(builder.MakeAtomicQuery("Folder", "BBB")); Assert.IsTrue(q1.IsSubsetOf(domainAll)); //create a complex domain definition containing all data for Folder == AAA and for ValueDate > 20010101 DomainDescription complexDomain = new DomainDescription(typeof(TradeLike)); AtomicQuery q2 = builder.MakeAtomicQuery("Folder", "AAA"); AtomicQuery q3 = builder.MakeAtomicQuery("Folder", "BBB"); AtomicQuery q4 = builder.MakeAtomicQuery("ValueDate", QueryOperator.Gt, new DateTime(2001, 1, 1)); complexDomain.AddOrReplace(q2); complexDomain.AddOrReplace(q4); AndQuery q23 = builder.MakeAndQuery(); q23.Elements.Add(q2); q23.Elements.Add(q3); Assert.IsTrue(q23.IsSubsetOf(complexDomain)); AtomicQuery q5 = builder.MakeAtomicQuery("ValueDate", QueryOperator.Ge, new DateTime(2001, 1, 1)); AndQuery q55 = builder.MakeAndQuery(q5); Assert.IsFalse(q55.IsSubsetOf(complexDomain)); }
/// <summary> /// Optimistic synchronization using a timestamp property /// Works like an UpdateIf that checks the previous value of a property of type DateTime named "Timestamp" /// It also updates this property withe DateTime.Now /// If you use this you should never modify the timestamp manually /// </summary> /// <param name="newValue"></param> public void UpdateWithTimestampSynchronization(T newValue) { var prop = newValue.GetType().GetProperty("Timestamp"); if (prop == null) { throw new CacheException($"No Timestamp property found on type {typeof(T).Name}"); } if (!prop.CanWrite) { throw new CacheException($"The Timestamp property of type {typeof(T).Name} is not writable"); } var oldTimestamp = prop.GetValue(newValue); var kv = KeyInfo.ValueToKeyValue(oldTimestamp, new KeyInfo(KeyDataType.IntKey, KeyType.ScalarIndex, "Timestamp")); var q = new AtomicQuery(kv); var andQuery = new AndQuery(); andQuery.Elements.Add(q); var orq = new OrQuery(typeof(T)); orq.Elements.Add(andQuery); var now = DateTime.Now; var newTimestamp = now.AddTicks(1); // add one to be sure its different prop.SetValue(newValue, newTimestamp); _client.UpdateIf(newValue, orq); }
private void VisitAndExpression(BinaryExpression binaryExpression, AndQuery andExpression) { if (IsLeafExpression(binaryExpression.Left)) { andExpression.Elements.Add(VisitLeafExpression((BinaryExpression)binaryExpression.Left)); } else if (binaryExpression.Left.NodeType == ExpressionType.AndAlso) { VisitAndExpression((BinaryExpression)binaryExpression.Left, andExpression); } else if (binaryExpression.Left.NodeType == ExpressionType.Extension) { if (binaryExpression.Left is SubQueryExpression subQuery) { var leaf = new AtomicQuery(); andExpression.Elements.Add(leaf); VisitContainsExpression(subQuery, leaf); } } else { throw new NotSupportedException("Query too complex"); } if (IsLeafExpression(binaryExpression.Right)) { andExpression.Elements.Add(VisitLeafExpression((BinaryExpression)binaryExpression.Right)); } else if (binaryExpression.Right.NodeType == ExpressionType.Extension) { if (binaryExpression.Right is SubQueryExpression subQuery) { var leaf = new AtomicQuery(); andExpression.Elements.Add(leaf); VisitContainsExpression(subQuery, leaf); } } else { throw new NotSupportedException("Query too complex"); } }
public override void VisitWhereClause(WhereClause whereClause, QueryModel queryModel, int index) { if (whereClause.Predicate is BinaryExpression expression) { VisitBinaryExpression(expression, RootExpression); } else { if (whereClause.Predicate is SubQueryExpression subQuery) { AndQuery andExpression; if (!RootExpression.MultipleWhereClauses) { andExpression = new AndQuery(); RootExpression.Elements.Add(andExpression); } else // multiple where clauses are joined by AND { andExpression = RootExpression.Elements[0]; } var leaf = new AtomicQuery(); andExpression.Elements.Add(leaf); VisitContainsExpression(subQuery, leaf); } else { throw new NotSupportedException("Incorrect query"); } } RootExpression.MultipleWhereClauses = true; base.VisitWhereClause(whereClause, queryModel, index); }
/// <summary> /// Optimistic synchronization using a timestamp property /// Works like an UpdateIf that checks the previous value of a property of type DateTime named "Timestamp" /// It also updates this property withe DateTime.Now /// If you use this you should never modify the timestamp manually /// </summary> /// <param name="newValue"></param> public void UpdateWithTimestampSynchronization(T newValue) { var prop = newValue.GetType().GetProperty("Timestamp"); if (prop == null) { throw new CacheException($"No Timestamp property found on type {typeof(T).Name}"); } if (!prop.CanWrite) { throw new CacheException($"The Timestamp property of type {typeof(T).Name} is not writable"); } var oldTimestamp = prop.GetValue(newValue); var kv = new KeyValue(oldTimestamp, new KeyInfo("Timestamp", 0, IndexType.Dictionary)); var q = new AtomicQuery(_collectionSchema.KeyByName(kv.KeyName), kv); var andQuery = new AndQuery(); andQuery.Elements.Add(q); var orq = new OrQuery(_collectionName); orq.Elements.Add(andQuery); var now = DateTime.Now; var newTimestamp = now.AddTicks(1); // add one to be sure its different prop.SetValue(newValue, newTimestamp); _client.UpdateIf(Pack(newValue), orq); }
public IndexRanking(IReadOnlyIndex index, AtomicQuery resolvedQuery, int ranking) { Index = index; ResolvedQuery = resolvedQuery; Ranking = ranking; }
//TODO add unit test for OR expression with Contains /// <summary> /// OR expression can be present only at root level /// </summary> /// <param name="binaryExpression"></param> /// <param name="rootExpression"></param> private void VisitOrExpression(BinaryExpression binaryExpression, OrQuery rootExpression) { // visit left part if (IsLeafExpression(binaryExpression.Left)) { var andExpression = new AndQuery(); rootExpression.Elements.Add(andExpression); andExpression.Elements.Add(VisitLeafExpression((BinaryExpression)binaryExpression.Left)); } else if (binaryExpression.Left.NodeType == ExpressionType.AndAlso) { var andExpression = new AndQuery(); rootExpression.Elements.Add(andExpression); VisitAndExpression((BinaryExpression)binaryExpression.Left, andExpression); } else if (binaryExpression.Left.NodeType == ExpressionType.Extension) { if (binaryExpression.Left is SubQueryExpression subQuery) { AndQuery andExpression; if (!rootExpression.MultipleWhereClauses) { andExpression = new AndQuery(); rootExpression.Elements.Add(andExpression); } else // multiple where clauses are joined by AND { andExpression = rootExpression.Elements[0]; } var leaf = new AtomicQuery(); andExpression.Elements.Add(leaf); VisitContainsExpression(subQuery, leaf); } } else if (binaryExpression.Left.NodeType == ExpressionType.OrElse) { VisitOrExpression((BinaryExpression)binaryExpression.Left, rootExpression); } else if (binaryExpression.Left.NodeType == ExpressionType.AndAlso) { var andExpression = new AndQuery(); rootExpression.Elements.Add(andExpression); VisitAndExpression((BinaryExpression)binaryExpression.Left, andExpression); } else { throw new NotSupportedException("Query too complex"); } // visit right part if (IsLeafExpression(binaryExpression.Right)) { var andExpression = new AndQuery(); rootExpression.Elements.Add(andExpression); andExpression.Elements.Add(VisitLeafExpression((BinaryExpression)binaryExpression.Right)); } else if (binaryExpression.Right.NodeType == ExpressionType.Extension) { if (binaryExpression.Right is SubQueryExpression subQuery) { var andExpression = new AndQuery(); rootExpression.Elements.Add(andExpression); if (rootExpression.MultipleWhereClauses) { throw new NotSupportedException( "Multiple where clauses can be used only with simple expressions"); } var leaf = new AtomicQuery(); andExpression.Elements.Add(leaf); VisitContainsExpression(subQuery, leaf); } } else if (binaryExpression.Right.NodeType == ExpressionType.OrElse) { VisitOrExpression((BinaryExpression)binaryExpression.Right, rootExpression); } else if (binaryExpression.Right.NodeType == ExpressionType.AndAlso) { var andExpression = new AndQuery(); rootExpression.Elements.Add(andExpression); VisitAndExpression((BinaryExpression)binaryExpression.Right, andExpression); } else { throw new NotSupportedException("Query too complex"); } }
private void VisitContainsExpression(SubQueryExpression subQuery, AtomicQuery leaf) { if (subQuery.QueryModel.ResultOperators.Count != 1) { throw new NotSupportedException("Only Contains extension is supported"); } var contains = subQuery.QueryModel.ResultOperators[0] as ContainsResultOperator; // process collection.Contains(x=>x.Member) if (contains?.Item is MemberExpression item) { var select = subQuery.QueryModel?.SelectClause.Selector as QuerySourceReferenceExpression; if (select?.ReferencedQuerySource is MainFromClause from) { var expression = from.FromExpression as ConstantExpression; if (expression?.Value is IEnumerable values) { leaf.Operator = QueryOperator.In; foreach (var value in values) { var kval = AsKeyValue(item.Member, value); leaf.InValues.Add(kval); } return; } } } // process x=>x.VectorMember.Contains(value) else { var value = contains?.Item; if (value != null) { var select = subQuery.QueryModel?.SelectClause.Selector as QuerySourceReferenceExpression; var from = select?.ReferencedQuerySource as MainFromClause; if (from?.FromExpression is MemberExpression expression) { // the member must not be a scalar type. A string is a vector of chars but still considered a scalar in this context var isVector = typeof(IEnumerable).IsAssignableFrom(expression.Type) && !typeof(string).IsAssignableFrom(expression.Type); if (!isVector) { throw new NotSupportedException("Trying to use Contains extension on a scalar member"); } if (value is ConstantExpression valueExpession) { leaf.Operator = QueryOperator.In; var kval = AsKeyValue(expression.Member, valueExpession.Value); leaf.InValues.Add(kval); return; } } } } throw new NotSupportedException("Only Contains extension is supported"); }