Release notes for re-motion version 1.13.17

List of Issues

Bugfixes

Improvements

Performance

Details

[COMMONS-1395] ResultOperators that hold expressions should implement TransformExpressions

Component/s: Data.Linq
Issue Type: Bug
Resolution: Fixed
Status: Closed


(no description)

[COMMONS-1157] Subquery in Where clause cannot be parsed when the query's main from clause accesses a variable from the outer query

Component/s: Data.Linq
Issue Type: Bug
Resolution: Fixed
Status: Closed


Implement by leveraging the ContainsResultOperator introduced in COMMONS-1313

[COMMONS-1375] Better ExecuteInMemory

Component/s: Data.Linq
Issue Type: Improvement
Resolution: Fixed
Status: Closed


(no description)

[COMMONS-1380] Implement support for the GroupResultOperator in re-store's QueryExecutor via ExecuteInMemory, write integration test

Component/s: Data.Linq
Issue Type: Sub-task
Resolution: Fixed
Status: Closed


(no description)

[COMMONS-1379] Remove InputDependentExpression, replace GroupResultOperator.... by ordinary (resolved) expressions

Component/s: Data.Linq
Issue Type: Sub-task
Resolution: Fixed
Status: Closed


The new KeySelector/ElementSelector expressions correspond KeySelector.ResolvedExpression and ElementSelector.ResolvedExpression.

[COMMONS-1378] Implement new GroupResultOperator.ExecuteInMemory using AccessorFindingExpressionTreeVisitor

Component/s: Data.Linq
Issue Type: Sub-task
Resolution: Fixed
Status: Closed


  • Use the visitor and the input expression provided via ExecuteInMemoryData to find out to get the required input data from the input object.
    (Maybe implement this code on the ExecuteInMemoryData class.)
  • Construct a LambaExpression from the ElementSelector/KeySelector using the above information.
  • Invoke GroupBy in memory on the input stream using the lambdas constructed above.

[COMMONS-1377] Create AccessorFindingExpressionTreeVisitor

Component/s: Data.Linq
Issue Type: Sub-task
Resolution: Fixed
Status: Closed


Constructs a LambdaExpression that finds how to extract a specific piece of data (QuerySourceReferenceExpression) from a complex expression.

Examples:
AccessorFindingExpressionTreeVisitor.FindAccessor ([s], [s]) -> input => input
AccessorFindingExpressionTreeVisitor.FindAccessor ([s], new {x = [s], y = [sd]}) -> input => input.x
AccessorFindingExpressionTreeVisitor.FindAccessor ([sector], new { x = [s], y = new { a = [sd], b = [sector] } }) -> input => input.y.b

Suggested implementation:

  • hold a stack of members
  • VisitNewExpression/VisitMemberInitExpression (expression):
    foreach (memberbinding)
      {
        push memberbinding.Member; 
        VisitExpression (memberBinding.Expression); 
        pop memberbinding.Member;
      }
  • VisitExpression (expression):
    if (input == searchedExpression)
      {
        return MakeMemberAccessChain (members);
      }
      else if (input.NodeType != New/MemberInit)
        throw ...;
      else
        return base.VisitExpression (expression);

[COMMONS-1376] Add new ExecuteInMemoryData class and new ResultOperator.ExecuteInMemory method that makes use of that class

Component/s: Data.Linq
Issue Type: Sub-task
Resolution: Fixed
Status: Closed


class ExecuteInMemoryData
{
  public object CurrentValue { get; private set; }
  public Expression CurrentExpression  { get; private set; }
}

public abstract ResultOperatorBase
{
  public abstract ExecuteInMemoryData ExecuteInMemory (ExecuteInMemoryData input);
}

Implementation is similar to current ExecuteInMemory method, with the difference that every result operator gets an Expression matching the input data and returns an Expression matching the output data. For example, for Count:

public override ExecuteInMemoryData ExecuteInMemory (ExecuteInMemoryData input)
{
  ArgumentUtility.CheckNotNull ("input", input);
  return InvokeGenericExecuteForEnumerable<int> (input, ExecuteInMemory);
}

public ExecuteInMemoryData ExecuteInMemory<T> (ExecuteInMemoryData input)
{
  ArgumentUtility.CheckNotNull ("input", input);
  
  var enumerableInput = (IEnumerable<T>) input.CurrentValue;
  var result = enumerableInput.Count ():
  var resultExpression = Resolve<IEnumerable<T>, int> (input.CurrentExpression, input => input.Count());

  return new ExecuteInMemoryData (result, resultExpression);
}

protected Expression Resolve<TSource, TResult> (Expression inputExpression, Expression<Func<TSource, TResult>> expressionToBeResolved)
{
  return ReplacingExpressionTreeVisitor.Replace (expressionToBeResolved.Parameters[0], inputExpression, expressionToBeResolved.Body);
}

Implement for all trivial result operators, do not implement for GroupResultOperator.

[COMMONS-1088] Refactor ContainsObjectParser to be as simple as ContainsParser

Component/s: Data.Linq
Issue Type: Improvement
Resolution: Duplicate
Status: Closed


(no description)

[COMMONS-1087] Refactor WhereConditionParsers.MemberExpressionParser to allow for collection expressions (such as "o.OrderItems"); generate SubQueries for those

Component/s: Data.Linq
Issue Type: Improvement
Resolution: Won't Fix yet
Status: Closed


(no description)

[COMMONS-1392] Rewrite ContainsObjectParser to use new parser extensibility facilities

Component/s: Data.Linq
Issue Type: Performance
Resolution: Fixed
Status: Closed


Create a ContainsObjectExpressionNode, which, in its CreateResultOperator method creates a ContainsResultOperator with the argument passed to the ContainsObject method.

Ie.

from o in QueryFactory.CreateLinqQuery<Order>()
where o.OrderItems.ContainsObject (item)
select o

becomes

from o in ... 
where { from gen in o.OrderItems select gen => Contains (item) } 
select o

automatically via the ContainsObjectExpressionNode.

The new parser must be registered in DomainObjectQueryable's ctor.