private static AstPipeline TranslateSelectManyWithCollectionSelectorAndNonIdentityResultSelector( TranslationContext context, AstPipeline pipeline, AggregationExpression collectionSelectorTranslation, LambdaExpression resultSelectorLambda) { var sourceSerializer = pipeline.OutputSerializer; var collectionItemSerializer = ArraySerializerHelper.GetItemSerializer(collectionSelectorTranslation.Serializer); var resultSelectorSourceParameterExpression = resultSelectorLambda.Parameters[0]; var resultSelectorSourceAst = AstExpression.Var("ROOT", isCurrent: true); var resultSelectorSourceParameterSymbol = context.CreateSymbol(resultSelectorSourceParameterExpression, resultSelectorSourceAst, sourceSerializer, isCurrent: true); var resultSelectorCollectionItemParameterExpression = resultSelectorLambda.Parameters[1]; var resultSelectorCollectionItemParameterSymbol = context.CreateSymbol(resultSelectorCollectionItemParameterExpression, collectionItemSerializer); var resultSelectorContext = context.WithSymbols(resultSelectorSourceParameterSymbol, resultSelectorCollectionItemParameterSymbol); var resultSelectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(resultSelectorContext, resultSelectorLambda.Body); var resultValueSerializer = resultSelectorTranslation.Serializer; var resultWrappedValueSerializer = WrappedValueSerializer.Create("_v", resultValueSerializer); var resultAst = AstExpression.Map( input: collectionSelectorTranslation.Ast, @as: resultSelectorCollectionItemParameterSymbol.Var, @in: resultSelectorTranslation.Ast); return(pipeline.AddStages( resultWrappedValueSerializer, AstStage.Project( AstProject.Set("_v", resultAst), AstProject.ExcludeId()), AstStage.Unwind("_v"))); }
// public static methods public static AstPipeline Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(QueryableMethod.Join)) { var outerExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, outerExpression); var outerSerializer = pipeline.OutputSerializer; var wrapOuterStage = AstStage.Project( AstProject.Set("_outer", AstExpression.Var("ROOT")), AstProject.ExcludeId()); var wrappedOuterSerializer = WrappedValueSerializer.Create("_outer", outerSerializer); var innerExpression = arguments[1]; var(innerCollectionName, innerSerializer) = innerExpression.GetCollectionInfo(containerExpression: expression); var outerKeySelectorLambda = ExpressionHelper.UnquoteLambda(arguments[2]); var localFieldPath = outerKeySelectorLambda.GetFieldPath(context, wrappedOuterSerializer); var innerKeySelectorLambda = ExpressionHelper.UnquoteLambda(arguments[3]); var foreignFieldPath = innerKeySelectorLambda.GetFieldPath(context, innerSerializer); var lookupStage = AstStage.Lookup( from: innerCollectionName, match: new AstLookupStageEqualityMatch(localFieldPath, foreignFieldPath), @as: "_inner"); var unwindStage = AstStage.Unwind("_inner"); var resultSelectorLambda = ExpressionHelper.UnquoteLambda(arguments[4]); var root = AstExpression.Var("ROOT", isCurrent: true); var outerParameter = resultSelectorLambda.Parameters[0]; var outerField = AstExpression.GetField(root, "_outer"); var outerSymbol = context.CreateSymbol(outerParameter, outerField, outerSerializer); var innerParameter = resultSelectorLambda.Parameters[1]; var innerField = AstExpression.GetField(root, "_inner"); var innerSymbol = context.CreateSymbol(innerParameter, innerField, innerSerializer); var resultSelectorContext = context.WithSymbols(outerSymbol, innerSymbol); var resultSelectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(resultSelectorContext, resultSelectorLambda.Body); var(projectStage, newOutputSerializer) = ProjectionHelper.CreateProjectStage(resultSelectorTranslation); pipeline = pipeline.AddStages( newOutputSerializer, wrapOuterStage, lookupStage, unwindStage, projectStage); return(pipeline); } throw new ExpressionNotSupportedException(expression); }
// public static methods public static ExecutableQuery <TDocument, TOutput> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__averageMethods)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; AstExpression valueExpression; if (method.IsOneOf(__averageWithSelectorMethods)) { var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); valueExpression = selectorTranslation.Ast; } else { Ensure.That(sourceSerializer is IWrappedValueSerializer, "Expected sourceSerializer to be an IWrappedValueSerializer.", nameof(sourceSerializer)); var root = AstExpression.Var("ROOT", isCurrent: true); valueExpression = AstExpression.GetField(root, "_v"); } IBsonSerializer outputValueSerializer = expression.GetResultType() switch { Type t when t == typeof(int) => new Int32Serializer(), Type t when t == typeof(long) => new Int64Serializer(), Type t when t == typeof(float) => new SingleSerializer(), Type t when t == typeof(double) => new DoubleSerializer(), Type t when t == typeof(decimal) => new DecimalSerializer(), Type { IsConstructedGenericType : true } t when t.GetGenericTypeDefinition() == typeof(Nullable <>) => (IBsonSerializer)Activator.CreateInstance(typeof(NullableSerializer <>).MakeGenericType(t.GenericTypeArguments[0])), _ => throw new ExpressionNotSupportedException(expression) }; var outputWrappedValueSerializer = WrappedValueSerializer.Create("_v", outputValueSerializer); pipeline = pipeline.AddStages( outputWrappedValueSerializer, AstStage.Group( id: BsonNull.Value, fields: AstExpression.AccumulatorField("_v", AstAccumulatorOperator.Avg, valueExpression)), AstStage.Project(AstProject.ExcludeId())); return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, __finalizer)); } throw new ExpressionNotSupportedException(expression); } }
private static (AstProjectStage, IBsonSerializer) CreateWrappedValueProjectStage(AggregationExpression expression) { var wrappedValueSerializer = WrappedValueSerializer.Create("_v", expression.Serializer); var projectStage = AstStage.Project( AstProject.Set("_v", expression.Ast), AstProject.ExcludeId()); return(projectStage, wrappedValueSerializer); }
// public static methods public static ExecutableQuery <TDocument, TOutput> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__maxMethods)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; var root = AstExpression.Var("ROOT", isCurrent: true); AstExpression valueAst; IBsonSerializer valueSerializer; if (method.IsOneOf(__maxWithSelectorMethods)) { var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); if (selectorTranslation.Serializer is IBsonDocumentSerializer) { valueAst = selectorTranslation.Ast; valueSerializer = selectorTranslation.Serializer; } else { valueAst = AstExpression.ComputedDocument(new[] { AstExpression.ComputedField("_v", selectorTranslation.Ast) }); valueSerializer = WrappedValueSerializer.Create("_v", selectorTranslation.Serializer); } } else { valueAst = root; valueSerializer = pipeline.OutputSerializer; } pipeline = pipeline.AddStages( valueSerializer, AstStage.Group( id: BsonNull.Value, fields: AstExpression.AccumulatorField("_max", AstAccumulatorOperator.Max, valueAst)), AstStage.ReplaceRoot(AstExpression.GetField(root, "_max"))); return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, __finalizer)); } throw new ExpressionNotSupportedException(expression); }
private static AstPipeline TranslateSelectManyWithCollectionSelectorAndIdentityResultSelector( AstPipeline pipeline, AggregationExpression collectionSelectorTranslation) { var collectionItemSerializer = ArraySerializerHelper.GetItemSerializer(collectionSelectorTranslation.Serializer); var resultValueSerializer = collectionItemSerializer; var resultWrappedValueSerializer = WrappedValueSerializer.Create("_v", resultValueSerializer); return(pipeline.AddStages( resultWrappedValueSerializer, AstStage.Project( AstProject.Set("_v", collectionSelectorTranslation.Ast), AstProject.ExcludeId()), AstStage.Unwind("_v"))); }
// public static methods public static ExecutableQuery <TDocument, bool> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(QueryableMethod.Contains)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); IBsonSerializer valueSerializer; if (pipeline.OutputSerializer is IWrappedValueSerializer wrappedValueSerializer) { valueSerializer = wrappedValueSerializer.ValueSerializer; } else { valueSerializer = pipeline.OutputSerializer; wrappedValueSerializer = WrappedValueSerializer.Create("_v", valueSerializer); pipeline = pipeline.AddStages( wrappedValueSerializer, AstStage.Project( AstProject.ExcludeId(), AstProject.Set("_v", AstExpression.Var("ROOT")))); } var itemExpression = arguments[1]; var itemValue = itemExpression.GetConstantValue <object>(containingExpression: expression); var serializedValue = SerializationHelper.SerializeValue(pipeline.OutputSerializer, itemValue); AstFilter filter = AstFilter.Eq(AstFilter.Field("_v", valueSerializer), serializedValue); pipeline = pipeline.AddStages( __outputSerializer, AstStage.Match(filter), AstStage.Limit(1), AstStage.Project( AstProject.ExcludeId(), AstProject.Set("_v", BsonNull.Value))); return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, __finalizer)); } throw new ExpressionNotSupportedException(expression); }
// public static methods public static ExecutableQuery <TDocument, TOutput> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__standardDeviationMethods)) { var sourceExpression = ConvertHelper.RemoveConvertToMongoQueryable(arguments[0]); var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; var stdDevOperator = method.IsOneOf(__standardDeviationPopulationMethods) ? AstAccumulatorOperator.StdDevPop : AstAccumulatorOperator.StdDevSamp; AstExpression valueAst; if (method.IsOneOf(__standardDeviationWithSelectorMethods)) { var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); valueAst = selectorTranslation.Ast; } else { var root = AstExpression.Var("ROOT", isCurrent: true); valueAst = AstExpression.GetField(root, "_v"); } var outputValueType = expression.GetResultType(); var outputValueSerializer = BsonSerializer.LookupSerializer(outputValueType); var outputWrappedValueSerializer = WrappedValueSerializer.Create("_v", outputValueSerializer); pipeline = pipeline.AddStages( outputWrappedValueSerializer, AstStage.Group( id: BsonNull.Value, AstExpression.AccumulatorField("_v", stdDevOperator, valueAst)), AstStage.Project(AstProject.ExcludeId())); var finalizer = method.IsOneOf(__standardDeviationNullableMethods) ? __singleOrDefaultFinalizer : __singleFinalizer; return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, finalizer)); } throw new ExpressionNotSupportedException(expression); }
// public static methods public static ExecutableQuery <TDocument, TOutput> Translate <TDocument>(MongoQueryProvider <TDocument> provider, TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(__sumMethods)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceSerializer = pipeline.OutputSerializer; AstExpression valueAst; if (method.IsOneOf(__sumWithSelectorMethods)) { var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); valueAst = selectorTranslation.Ast; } else { Ensure.That(sourceSerializer is IWrappedValueSerializer, "Expected sourceSerializer to be an IWrappedValueSerializer.", nameof(sourceSerializer)); var rootVar = AstExpression.Var("ROOT", isCurrent: true); valueAst = AstExpression.GetField(rootVar, "_v"); } var outputValueType = expression.GetResultType(); var outputValueSerializer = BsonSerializer.LookupSerializer(outputValueType); var outputWrappedValueSerializer = WrappedValueSerializer.Create("_v", outputValueSerializer); pipeline = pipeline.AddStages( outputWrappedValueSerializer, AstStage.Group( id: BsonNull.Value, fields: AstExpression.AccumulatorField("_v", AstAccumulatorOperator.Sum, valueAst)), AstStage.Project(AstProject.ExcludeId())); return(ExecutableQuery.Create( provider.Collection, provider.Options, pipeline, __finalizer)); } throw new ExpressionNotSupportedException(expression); }
private static AstPipeline TranslateSelectMany( TranslationContext context, AstPipeline pipeline, ReadOnlyCollection <Expression> arguments) { var sourceSerializer = pipeline.OutputSerializer; var selectorLambda = ExpressionHelper.UnquoteLambda(arguments[1]); var selectorTranslation = ExpressionToAggregationExpressionTranslator.TranslateLambdaBody(context, selectorLambda, sourceSerializer, asRoot: true); var resultValueSerializer = ArraySerializerHelper.GetItemSerializer(selectorTranslation.Serializer); var resultWrappedValueSerializer = WrappedValueSerializer.Create("_v", resultValueSerializer); pipeline = pipeline.AddStages( resultWrappedValueSerializer, AstStage.Project( AstProject.Set("_v", selectorTranslation.Ast), AstProject.ExcludeId()), AstStage.Unwind("_v")); return(pipeline); }
// public static methods public static AstPipeline Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(QueryableMethod.OfType)) { var sourceExpression = arguments[0]; var pipeline = ExpressionToPipelineTranslator.Translate(context, sourceExpression); var sourceType = sourceExpression.Type; var nominalType = sourceType.GetGenericArguments()[0]; var actualType = method.GetGenericArguments()[0]; var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(nominalType); var discriminatorElementName = discriminatorConvention.ElementName; var wrappedValueOutputSerializer = pipeline.OutputSerializer as IWrappedValueSerializer; if (wrappedValueOutputSerializer != null) { discriminatorElementName = wrappedValueOutputSerializer.FieldName + "." + discriminatorElementName; } var discriminatorField = AstFilter.Field(discriminatorElementName, BsonValueSerializer.Instance); var discriminatorValue = discriminatorConvention.GetDiscriminator(nominalType, actualType); var filter = AstFilter.Eq(discriminatorField, discriminatorValue); // note: OfType only works with hierarchical discriminators var actualSerializer = context.KnownSerializersRegistry.GetSerializer(expression); if (wrappedValueOutputSerializer != null) { actualSerializer = WrappedValueSerializer.Create(wrappedValueOutputSerializer.FieldName, actualSerializer); } pipeline = pipeline.AddStages( actualSerializer, AstStage.Match(filter)); return(pipeline); } throw new ExpressionNotSupportedException(expression); }