Skip to content

Commit

Permalink
New Query Pipeline
Browse files Browse the repository at this point in the history
  • Loading branch information
smitpatel committed Mar 11, 2019
1 parent f990fa0 commit 1efef34
Show file tree
Hide file tree
Showing 302 changed files with 11,579 additions and 5,547 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Diagnostics;
using System.Reflection;
using JetBrains.Annotations;
using Microsoft.EntityFrameworkCore.Internal;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@
using Microsoft.EntityFrameworkCore.InMemory.Metadata.Conventions.Internal;
using Microsoft.EntityFrameworkCore.InMemory.Query.ExpressionVisitors.Internal;
using Microsoft.EntityFrameworkCore.InMemory.Query.Internal;
using Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline;
using Microsoft.EntityFrameworkCore.InMemory.Storage.Internal;
using Microsoft.EntityFrameworkCore.InMemory.ValueGeneration.Internal;
using Microsoft.EntityFrameworkCore.Metadata.Conventions.Internal;
using Microsoft.EntityFrameworkCore.Query;
using Microsoft.EntityFrameworkCore.Query.ExpressionVisitors;
using Microsoft.EntityFrameworkCore.Query.Pipeline;
using Microsoft.EntityFrameworkCore.Storage;
using Microsoft.EntityFrameworkCore.Utilities;
using Microsoft.EntityFrameworkCore.ValueGeneration;
Expand Down Expand Up @@ -66,6 +68,13 @@ public static IServiceCollection AddEntityFrameworkInMemoryDatabase([NotNull] th
.TryAdd<IQueryContextFactory, InMemoryQueryContextFactory>()
.TryAdd<IEntityQueryModelVisitorFactory, InMemoryQueryModelVisitorFactory>()
.TryAdd<IEntityQueryableExpressionVisitorFactory, InMemoryEntityQueryableExpressionVisitorFactory>()

// New Query pipeline
.TryAdd<IShapedQueryCompilingExpressionVisitorFactory, InMemoryShapedQueryCompilingExpressionVisitorFactory>()
.TryAdd<IQueryableMethodTranslatingExpressionVisitorFactory, InMemoryQueryableMethodTranslatingExpressionVisitorFactory>()
.TryAdd<IEntityQueryableExpressionVisitorsFactory, InMemoryEntityQueryableExpressionVisitorsFactory>()


.TryAdd<IConventionSetBuilder, InMemoryConventionSetBuilder>()
.TryAdd<ISingletonOptions, IInMemorySingletonOptions>(p => p.GetService<IInMemorySingletonOptions>())
.TryAdd<ITypeMappingSource, InMemoryTypeMappingSource>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ var concreteEntityTypes
return Expression.Lambda<Func<IEntityType, MaterializationContext, object>>(
_entityMaterializerSource
.CreateMaterializeExpression(
concreteEntityTypes[0], materializationContextParameter),
concreteEntityTypes[0], "instance", materializationContextParameter),
entityTypeParameter,
materializationContextParameter);
}
Expand All @@ -71,7 +71,7 @@ var blockExpressions
returnLabelTarget,
_entityMaterializerSource
.CreateMaterializeExpression(
concreteEntityTypes[0], materializationContextParameter))),
concreteEntityTypes[0], "instance", materializationContextParameter))),
Expression.Label(
returnLabelTarget,
Expression.Default(returnLabelTarget.Type))
Expand All @@ -87,7 +87,7 @@ var blockExpressions
Expression.Return(
returnLabelTarget,
_entityMaterializerSource
.CreateMaterializeExpression(concreteEntityType, materializationContextParameter)),
.CreateMaterializeExpression(concreteEntityType, "instance", materializationContextParameter)),
blockExpressions[0]);
}

Expand Down
18 changes: 18 additions & 0 deletions src/EFCore.InMemory/Query/PipeLine/EntityValuesExpression.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Linq.Expressions;

namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline
{
public class EntityValuesExpression : Expression
{
public EntityValuesExpression(int startIndex)
{
StartIndex = startIndex;
}

public int StartIndex { get; }
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query.Pipeline;

namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline
{
public class InMemoryEntityQueryableExpressionVisitor2 : EntityQueryableExpressionVisitor2
{
private readonly IModel _model;

public InMemoryEntityQueryableExpressionVisitor2(IModel model)
{
_model = model;
}

protected override ShapedQueryExpression CreateShapedQueryExpression(Type elementType)
{
return new InMemoryShapedQueryExpression(_model.FindEntityType(elementType));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query.Pipeline;

namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline
{
public class InMemoryEntityQueryableExpressionVisitorsFactory : EntityQueryableExpressionVisitorsFactory
{
private readonly IModel _model;

public InMemoryEntityQueryableExpressionVisitorsFactory(IModel model)
{
_model = model;
}

public override EntityQueryableExpressionVisitors Create(QueryCompilationContext2 queryCompilationContext)
{
return new InMemoryEntityQueryableExpressionVisitors(_model);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Query.Pipeline;

namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline
{
public class InMemoryEntityQueryableExpressionVisitors : EntityQueryableExpressionVisitors
{
private readonly IModel _model;

public InMemoryEntityQueryableExpressionVisitors(IModel model)
{
_model = model;
}

public override IEnumerable<ExpressionVisitor> GetVisitors()
{
yield return new InMemoryEntityQueryableExpressionVisitor2(_model);
}
}
}
67 changes: 67 additions & 0 deletions src/EFCore.InMemory/Query/PipeLine/InMemoryLinqOperatorProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.EntityFrameworkCore.Utilities;

namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline
{
public static class InMemoryLinqOperatorProvider
{
private static MethodInfo GetMethod(string name, int parameterCount = 0)
=> GetMethods(name, parameterCount).Single();

private static IEnumerable<MethodInfo> GetMethods(string name, int parameterCount = 0)
=> typeof(Enumerable).GetTypeInfo().GetDeclaredMethods(name)
.Where(mi => mi.GetParameters().Length == parameterCount + 1);

public static MethodInfo Where = GetMethods(nameof(Enumerable.Where), 1)
.Single(mi => mi.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);
public static MethodInfo Select = GetMethods(nameof(Enumerable.Select), 1)
.Single(mi => mi.GetParameters()[1].ParameterType.GetGenericArguments().Length == 2);

public static MethodInfo Join = GetMethod(nameof(Enumerable.Join), 4);
public static MethodInfo Contains = GetMethod(nameof(Enumerable.Contains), 1);

public static MethodInfo OrderBy = GetMethod(nameof(Enumerable.OrderBy), 1);
public static MethodInfo OrderByDescending = GetMethod(nameof(Enumerable.OrderByDescending), 1);
public static MethodInfo ThenBy = GetMethod(nameof(Enumerable.ThenBy), 1);
public static MethodInfo ThenByDescending = GetMethod(nameof(Enumerable.ThenByDescending), 1);
public static MethodInfo All = GetMethod(nameof(Enumerable.All), 1);
public static MethodInfo Any = GetMethod(nameof(Enumerable.Any));
public static MethodInfo AnyPredicate = GetMethod(nameof(Enumerable.Any), 1);
public static MethodInfo Count = GetMethod(nameof(Enumerable.Count));
public static MethodInfo LongCount = GetMethod(nameof(Enumerable.LongCount));
public static MethodInfo CountPredicate = GetMethod(nameof(Enumerable.Count), 1);
public static MethodInfo LongCountPredicate = GetMethod(nameof(Enumerable.LongCount), 1);
public static MethodInfo Distinct = GetMethod(nameof(Enumerable.Distinct));
public static MethodInfo Take = GetMethod(nameof(Enumerable.Take), 1);
public static MethodInfo Skip = GetMethod(nameof(Enumerable.Skip), 1);

public static MethodInfo FirstPredicate = GetMethod(nameof(Enumerable.First), 1);
public static MethodInfo FirstOrDefaultPredicate = GetMethod(nameof(Enumerable.FirstOrDefault), 1);
public static MethodInfo LastPredicate = GetMethod(nameof(Enumerable.Last), 1);
public static MethodInfo LastOrDefaultPredicate = GetMethod(nameof(Enumerable.LastOrDefault), 1);
public static MethodInfo SinglePredicate = GetMethod(nameof(Enumerable.Single), 1);
public static MethodInfo SingleOrDefaultPredicate = GetMethod(nameof(Enumerable.SingleOrDefault), 1);

public static MethodInfo GetAggregateMethod(string methodName, Type elementType, int parameterCount = 0)
{
Check.NotEmpty(methodName, nameof(methodName));
Check.NotNull(elementType, nameof(elementType));

var aggregateMethods = GetMethods(methodName, parameterCount).ToList();

return
aggregateMethods
.Single(
mi => mi.GetParameters().Last().ParameterType.GetGenericArguments().Last() == elementType);
//?? aggregateMethods.Single(mi => mi.IsGenericMethod)
// .MakeGenericMethod(elementType);
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System.Collections.Generic;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore.Query.Pipeline;

namespace Microsoft.EntityFrameworkCore.InMemory.Query.Pipeline
{
public class InMemoryProjectionBindingExpressionVisitor : ExpressionVisitor
{
private InMemoryQueryExpression _queryExpression;
private readonly IDictionary<ProjectionMember, Expression> _projectionMapping
= new Dictionary<ProjectionMember, Expression>();

private readonly Stack<ProjectionMember> _projectionMembers = new Stack<ProjectionMember>();
private readonly InMemoryExpressionTranslatingExpressionVisitor _expressionTranslatingExpressionVisitor;

public InMemoryProjectionBindingExpressionVisitor(
InMemoryExpressionTranslatingExpressionVisitor expressionTranslatingExpressionVisitor)
{
_expressionTranslatingExpressionVisitor = expressionTranslatingExpressionVisitor;
}

public Expression Translate(InMemoryQueryExpression queryExpression, Expression expression)
{
_queryExpression = queryExpression;

_projectionMembers.Push(new ProjectionMember());

var result = Visit(expression);

_queryExpression.ApplyProjection(_projectionMapping);

_queryExpression = null;
_projectionMapping.Clear();
_projectionMembers.Clear();

return result;
}

public override Expression Visit(Expression expression)
{
if (expression == null)
{
return null;
}

if (!(expression is NewExpression))
{
var translation = _expressionTranslatingExpressionVisitor.Translate(_queryExpression, expression);

_projectionMapping[_projectionMembers.Peek()] = translation;

return new ProjectionBindingExpression(_queryExpression, _projectionMembers.Peek(), expression.Type);
}

return base.Visit(expression);
}

protected override Expression VisitNew(NewExpression newExpression)
{
var newArguments = new Expression[newExpression.Arguments.Count];
for (var i = 0; i < newExpression.Arguments.Count; i++)
{
// TODO: Members can be null????
var projectionMember = _projectionMembers.Peek().AddMember(newExpression.Members[i]);
_projectionMembers.Push(projectionMember);

newArguments[i] = Visit(newExpression.Arguments[i]);
}

return newExpression.Update(newArguments);
}
}
}
Loading

0 comments on commit 1efef34

Please sign in to comment.