-
Notifications
You must be signed in to change notification settings - Fork 3.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
64 changed files
with
3,314 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
18 changes: 18 additions & 0 deletions
18
src/EFCore.InMemory/Query/PipeLine/EntityValuesExpression.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; } | ||
} | ||
|
||
} |
24 changes: 24 additions & 0 deletions
24
src/EFCore.InMemory/Query/PipeLine/InMemoryEntityQueryableExpressionVisitor2.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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)); | ||
} | ||
} | ||
} |
23 changes: 23 additions & 0 deletions
23
src/EFCore.InMemory/Query/PipeLine/InMemoryEntityQueryableExpressionVisitorFactory2.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 InMemoryEntityQueryableExpressionVisitorFactory2 : IEntityQueryableExpressionVisitorFactory2 | ||
{ | ||
private readonly IModel _model; | ||
|
||
public InMemoryEntityQueryableExpressionVisitorFactory2(IModel model) | ||
{ | ||
_model = model; | ||
} | ||
|
||
public EntityQueryableExpressionVisitor2 Create() | ||
{ | ||
return new InMemoryEntityQueryableExpressionVisitor2(_model); | ||
} | ||
} | ||
} |
73 changes: 73 additions & 0 deletions
73
src/EFCore.InMemory/Query/PipeLine/InMemoryLinqOperatorProvider.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
// 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 First = GetMethod(nameof(Enumerable.First)); | ||
public static MethodInfo FirstPredicate = GetMethod(nameof(Enumerable.First), 1); | ||
public static MethodInfo FirstOrDefault = GetMethod(nameof(Enumerable.FirstOrDefault)); | ||
public static MethodInfo FirstOrDefaultPredicate = GetMethod(nameof(Enumerable.FirstOrDefault), 1); | ||
public static MethodInfo Last = GetMethod(nameof(Enumerable.Last)); | ||
public static MethodInfo LastPredicate = GetMethod(nameof(Enumerable.Last), 1); | ||
public static MethodInfo LastOrDefault = GetMethod(nameof(Enumerable.LastOrDefault)); | ||
public static MethodInfo LastOrDefaultPredicate = GetMethod(nameof(Enumerable.LastOrDefault), 1); | ||
public static MethodInfo Single = GetMethod(nameof(Enumerable.Single)); | ||
public static MethodInfo SinglePredicate = GetMethod(nameof(Enumerable.Single), 1); | ||
public static MethodInfo SingleOrDefault = GetMethod(nameof(Enumerable.SingleOrDefault)); | ||
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); | ||
} | ||
} | ||
|
||
} |
71 changes: 71 additions & 0 deletions
71
src/EFCore.InMemory/Query/PipeLine/InMemoryProjectionBindingExpressionVisitor.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// 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 System.Reflection; | ||
using Microsoft.EntityFrameworkCore.Query.PipeLine; | ||
|
||
namespace Microsoft.EntityFrameworkCore.InMemory.Query.PipeLine | ||
{ | ||
public class InMemoryProjectionBindingExpressionVisitor : ExpressionVisitor | ||
{ | ||
private readonly InMemoryQueryExpression _queryExpression; | ||
private readonly Translator _translator; | ||
private readonly IDictionary<ProjectionMember, Expression> _projectionMapping | ||
= new Dictionary<ProjectionMember, Expression>(); | ||
|
||
private readonly Stack<ProjectionMember> _projectionMembers = new Stack<ProjectionMember>(); | ||
|
||
public InMemoryProjectionBindingExpressionVisitor(InMemoryQueryExpression queryExpression) | ||
{ | ||
_queryExpression = queryExpression; | ||
_translator = new Translator(queryExpression); | ||
} | ||
|
||
public Expression Translate(Expression expression) | ||
{ | ||
_projectionMembers.Push(new ProjectionMember()); | ||
|
||
var result = Visit(expression); | ||
|
||
_queryExpression.ApplyProjection(_projectionMapping); | ||
|
||
return result; | ||
} | ||
|
||
public override Expression Visit(Expression expression) | ||
{ | ||
if (expression == null) | ||
{ | ||
return null; | ||
} | ||
|
||
if (!(expression is NewExpression)) | ||
{ | ||
var translation = _translator.Visit(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); | ||
} | ||
} | ||
} |
Oops, something went wrong.