Open
Show file tree
Hide file tree
Changes from all commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Failed to load files.
Original file line numberDiff line numberDiff line change
Expand Up@@ -36,20 +36,32 @@ public static object Evaluate(this Expression expression)
}
}

public static (string CollectionName, IBsonSerializer DocumentSerializer) GetCollectionInfo(this Expression innerExpression, Expression containerExpression)
public static (IMongoQueryProviderInternal QueryProvider, bool IsRawCollectionExpression) FindMongoQueryProvider(this Expression innerExpression, Expression containerExpression)
{
if (innerExpression is ConstantExpression constantExpression &&
constantExpression.Value is IQueryable queryable &&
queryable.Provider is IMongoQueryProviderInternal mongoQueryProvider &&
mongoQueryProvider.CollectionNamespace != null)
var mongoQueryProvider = ExtractQueryProviderFromExpression(innerExpression);
if (mongoQueryProvider.QueryProvider is not null)
{
return (mongoQueryProvider.CollectionNamespace.CollectionName, mongoQueryProvider.PipelineInputSerializer);
return mongoQueryProvider;
}

var message = $"inner expression must be a MongoDB IQueryable against a collection";
var message = "inner expression must be a MongoDB IQueryable against a collection";
throw new ExpressionNotSupportedException(innerExpression, containerExpression, because: message);
}

private static (IMongoQueryProviderInternal QueryProvider, bool IsRawCollectionExpression) ExtractQueryProviderFromExpression(Expression expression, int depth = 0)
{
return expression switch
{
MethodCallExpression methodCallExpression => ExtractQueryProviderFromExpression(methodCallExpression.Arguments.FirstOrDefault(), depth + 1),
ConstantExpression constantExpression => constantExpression.Value switch
{
IQueryable { Provider: IMongoQueryProviderInternal queryProvider } => (queryProvider, depth == 0),
_ => default
},
_ => default
};
}

public static TValue GetConstantValue<TValue>(this Expression expression, Expression containingExpression)
{
if (expression is ConstantExpression constantExpression)
Expand Down
Original file line numberDiff line numberDiff line change
Expand Up@@ -13,6 +13,8 @@
* limitations under the License.
*/

using System.Linq;
using System;
using System.Linq.Expressions;
using MongoDB.Bson.Serialization;
using MongoDB.Driver.Linq.Linq3Implementation.Ast;
Expand DownExpand Up@@ -63,15 +65,31 @@ public static AstPipeline Translate(TranslationContext context, MethodCallExpres
AstProject.Exclude("_id"));
var wrappedOuterSerializer = WrappedValueSerializer.Create("_outer", outerSerializer);

var (innerCollectionName, innerSerializer) = innerExpression.GetCollectionInfo(containerExpression: expression);
var (queryProvider, isRawCollectionExpression) = innerExpression.FindMongoQueryProvider(containerExpression: expression);
var localField = outerKeySelectorLambda.TranslateToDottedFieldName(context, wrappedOuterSerializer);
var foreignField = innerKeySelectorLambda.TranslateToDottedFieldName(context, innerSerializer);
var foreignField = innerKeySelectorLambda.TranslateToDottedFieldName(context, queryProvider.PipelineInputSerializer);

var lookupStage = AstStage.Lookup(
from: innerCollectionName,
localField,
foreignField,
@as: "_inner");
AstStage lookupStage;

if (isRawCollectionExpression)
{
lookupStage = AstStage.Lookup(
from: queryProvider.CollectionNamespace.CollectionName,
localField,
foreignField,
@as: "_inner");
}
else
{
var lookupPipeline = ExpressionToPipelineTranslator.Translate(context, innerExpression);
lookupStage = AstStage.Lookup(
from: queryProvider.CollectionNamespace.CollectionName,
localField,
foreignField,
Array.Empty<AstComputedField>(),
lookupPipeline,
@as: "_inner");
}

var unwindStage = AstStage.Unwind("_inner");

Expand All@@ -80,7 +98,7 @@ public static AstPipeline Translate(TranslationContext context, MethodCallExpres
var outerSymbol = context.CreateSymbol(outerParameter, outerField, outerSerializer);
var innerParameter = resultSelectorLambda.Parameters[1];
var innerField = AstExpression.GetField(AstExpression.RootVar, "_inner");
var innerSymbol = context.CreateSymbol(innerParameter, innerField, innerSerializer);
var innerSymbol = context.CreateSymbol(innerParameter, innerField, queryProvider.PipelineInputSerializer);
var resultSelectorContext = context.WithSymbols(outerSymbol, innerSymbol);
var resultSelectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(resultSelectorContext, resultSelectorLambda.Body);
var (projectStage, projectSerializer) = ProjectionHelper.CreateProjectStage(resultSelectorTranslation);
Expand Down