Skip to content

Commit

Permalink
RMLNQ-28 Implement AsQueryableResultOperator to add AsQueryable to th…
Browse files Browse the repository at this point in the history
…e QueryModel.
  • Loading branch information
MichaelKetting committed Jan 21, 2018
1 parent f078bf9 commit c477aea
Show file tree
Hide file tree
Showing 7 changed files with 154 additions and 5 deletions.
66 changes: 66 additions & 0 deletions Core/Clauses/ResultOperators/AsQueryableResultOperator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
// Copyright (c) rubicon IT GmbH, www.rubicon.eu
//
// See the NOTICE file distributed with this work for additional information
// regarding copyright ownership. rubicon licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
using System;
using System.Linq;
using System.Linq.Expressions;
using Remotion.Linq.Clauses.StreamedData;
using Remotion.Utilities;

namespace Remotion.Linq.Clauses.ResultOperators
{
/// <summary>
/// Represents the transformation of a sequence to a query data source.
/// This is a result operator, operating on the whole result set of a query.
/// </summary>
/// <example>
/// In C#, the "AsQueryable" call in the following example corresponds to a <see cref="AsQueryableResultOperator"/>.
/// <code>
/// var query = (from s in Students
/// select s).AsQueryable();
/// </code>
/// </example>
public sealed class AsQueryableResultOperator : SequenceTypePreservingResultOperatorBase
{
/// <summary>
/// Initializes a new instance of the <see cref="AsQueryableResultOperator"/>.
/// </summary>
public AsQueryableResultOperator ()
{
}

public override ResultOperatorBase Clone (CloneContext cloneContext)
{
return new AsQueryableResultOperator();
}

public override StreamedSequence ExecuteInMemory<T> (StreamedSequence input)
{
var sequence = input.GetTypedSequence<T>();
return new StreamedSequence (sequence.AsQueryable(), GetOutputDataInfo (input.DataInfo));
}

public override void TransformExpressions (Func<Expression, Expression> transformation)
{
//nothing to do here
}

public override string ToString ()
{
return "AsQueryable()";
}
}
}
1 change: 1 addition & 0 deletions Core/Core.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@
<Compile Include="Clauses\Expressions\IVBSpecificExpressionVisitor.cs" />
<Compile Include="Clauses\Expressions\VBStringComparisonExpression.cs" />
<Compile Include="Clauses\IFromClause.cs" />
<Compile Include="Clauses\ResultOperators\AsQueryableResultOperator.cs" />
<Compile Include="Parsing\ExpressionVisitors\TreeEvaluation\EvaluatableExpressionFilterBase.cs" />
<Compile Include="Parsing\ExpressionVisitors\TreeEvaluation\IEvaluatableExpressionFilter.cs" />
<Compile Include="Parsing\ExpressionVisitors\TreeEvaluation\NullEvaluatableExpressionFilter.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
using System.Linq;
using System.Linq.Expressions;
using System.Reflection;
using Remotion.Linq.Clauses;
using Remotion.Linq.Clauses.ResultOperators;
using Remotion.Linq.Utilities;
using Remotion.Utilities;

Expand All @@ -14,15 +16,15 @@ namespace Remotion.Linq.Parsing.Structure.IntermediateModel
/// When this node is used, it will not modify the <see cref="QueryModel"/>, i.e. the call to <see cref="Queryable.AsQueryable{TSource}"/>
/// will be removed given how it is transparent to the process of executing the query.
/// </summary>
public sealed class AsQueryableExpressionNode : MethodCallExpressionNodeBase
public sealed class AsQueryableExpressionNode : ResultOperatorExpressionNodeBase
{
public static IEnumerable<MethodInfo> GetSupportedMethods ()
{
return ReflectionUtility.EnumerableAndQueryableMethods.WhereNameMatches ("AsQueryable");
}

public AsQueryableExpressionNode (MethodCallExpressionParseInfo parseInfo)
: base (parseInfo)
: base (parseInfo, null, null)
{
}

Expand All @@ -35,9 +37,9 @@ public override Expression Resolve (ParameterExpression inputParameter, Expressi
return Source.Resolve (inputParameter, expressionToBeResolved, clauseGenerationContext);
}

protected override void ApplyNodeSpecificSemantics (QueryModel queryModel, ClauseGenerationContext clauseGenerationContext)
protected override ResultOperatorBase CreateResultOperator (ClauseGenerationContext clauseGenerationContext)
{
// don't change query model
return new AsQueryableResultOperator();
}
}
}
59 changes: 59 additions & 0 deletions UnitTests/Clauses/ResultOperators/AsQueryableResultOperatorTest.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
// Copyright (c) rubicon IT GmbH, www.rubicon.eu
//
// See the NOTICE file distributed with this work for additional information
// regarding copyright ownership. rubicon licenses this file to you under
// the Apache License, Version 2.0 (the "License"); you may not use this
// file except in compliance with the License. You may obtain a copy of the
// License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.
//
using System;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;
using NUnit.Framework;
using Remotion.Linq.Clauses;
using Remotion.Linq.Clauses.ResultOperators;
using Remotion.Linq.Clauses.StreamedData;

namespace Remotion.Linq.UnitTests.Clauses.ResultOperators
{
[TestFixture]
public class AsQueryableResultOperatorTest
{
private AsQueryableResultOperator _resultOperator;

[SetUp]
public void SetUp ()
{
_resultOperator = new AsQueryableResultOperator();
}

[Test]
public void Clone ()
{
var clonedClauseMapping = new QuerySourceMapping();
var cloneContext = new CloneContext (clonedClauseMapping);
var clone = _resultOperator.Clone (cloneContext);

Assert.That (clone, Is.InstanceOf (typeof (AsQueryableResultOperator)));
}

[Test]
public void ExecuteInMemory ()
{
IEnumerable items = new[] { 1, 2, 3, 0, 2 };
var input = new StreamedSequence (items, new StreamedSequenceInfo (typeof (int[]), Expression.Constant (0)));
var result = _resultOperator.ExecuteInMemory<int> (input);

Assert.That (result.GetTypedSequence<int>().ToArray(), Is.EqualTo (new[] { 1, 2, 3, 0, 2 }));
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
using System;
using System.Linq;
using NUnit.Framework;
using Remotion.Linq.Clauses.ResultOperators;
using Remotion.Linq.Development.UnitTesting;
using Remotion.Linq.Parsing.Structure.IntermediateModel;
using Remotion.Linq.Utilities;
Expand Down Expand Up @@ -79,7 +80,7 @@ public void Apply ()
var result = _node.Apply (QueryModel, ClauseGenerationContext);
Assert.That (result, Is.SameAs (QueryModel));

Assert.That (QueryModel.ResultOperators, Is.Empty);
Assert.That (QueryModel.ResultOperators[0], Is.InstanceOf<AsQueryableResultOperator>());
Assert.That (QueryModel.BodyClauses, Is.Empty);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -872,5 +872,24 @@ public void Aggregate_Seed_FuncParameterAssignableFromSeedValue ()
Assert.That (resultOperator.Seed.Type, Is.SameAs (typeof (string)));
Assert.That (resultOperator.Func.Parameters[0].Type, Is.SameAs (typeof (IConvertible)));
}

[Test]
public void AsQueryable ()
{
var query =
from s in QuerySource.Where (c => c.Assistants.AsQueryable().Any())
select s;

var queryModel = QueryParser.GetParsedQuery (query.Expression);
Assert.That (queryModel.GetOutputDataInfo ().DataType, Is.SameAs (typeof (IQueryable<Cook>)));

CheckConstantQuerySource (queryModel.MainFromClause.FromExpression, QuerySource);

var whereClause = (WhereClause) queryModel.BodyClauses[0];

var subQueryModel = ((SubQueryExpression) whereClause.Predicate).QueryModel;
Assert.That (subQueryModel.ResultOperators[0], Is.InstanceOf (typeof (AsQueryableResultOperator)));
Assert.That (subQueryModel.ResultOperators[1], Is.InstanceOf (typeof (AnyResultOperator)));
}
}
}
1 change: 1 addition & 0 deletions UnitTests/UnitTests.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@
<Compile Include="Clauses\Expressions\SubQueryExpressionTest.cs" />
<Compile Include="Clauses\Expressions\VBStringComparisonExpressionTest.cs" />
<Compile Include="Clauses\ExpressionVisitors\IntegrationTests\AccessorFindingExpressionTreeVisitorIntegrationTest.cs" />
<Compile Include="Clauses\ResultOperators\AsQueryableResultOperatorTest.cs" />
<Compile Include="Clauses\ResultOperators\ConcatResultOperatorTest.cs" />
<Compile Include="Parsing\ExpressionVisitors\MultiReplacingExpressionVisitorTest.cs" />
<Compile Include="Clauses\Expressions\PartialEvaluationExceptionExpressionTest.cs" />
Expand Down

0 comments on commit c477aea

Please sign in to comment.