public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(EnumerableMethod.Select)) { var sourceExpression = arguments[0]; var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression); var selectorLambda = (LambdaExpression)arguments[1]; var selectorParameter = selectorLambda.Parameters[0]; var selectorParameterSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); var selectorParameterSymbol = context.CreateSymbol(selectorParameter, selectorParameterSerializer); var selectorContext = context.WithSymbol(selectorParameterSymbol); var translatedSelector = ExpressionToAggregationExpressionTranslator.Translate(selectorContext, selectorLambda.Body); var ast = AstExpression.Map( sourceTranslation.Ast, selectorParameterSymbol.Var, translatedSelector.Ast); var serializer = IEnumerableSerializer.Create(translatedSelector.Serializer); return(new AggregationExpression(expression, ast, serializer)); } throw new ExpressionNotSupportedException(expression); }
public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(EnumerableMethod.Zip)) { var firstExpression = arguments[0]; var firstTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, firstExpression); var secondExpression = arguments[1]; var secondTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, secondExpression); var resultSelectorLambda = (LambdaExpression)arguments[2]; var resultSelectorParameters = resultSelectorLambda.Parameters; var resultSelectorParameter1 = resultSelectorParameters[0]; var resultSelectorParameter2 = resultSelectorParameters[1]; var resultSelectorSymbol1 = context.CreateSymbol(resultSelectorParameter1, BsonSerializer.LookupSerializer(resultSelectorParameter1.Type)); var resultSelectorSymbol2 = context.CreateSymbol(resultSelectorParameter2, BsonSerializer.LookupSerializer(resultSelectorParameter2.Type)); var resultSelectorContext = context.WithSymbols(resultSelectorSymbol1, resultSelectorSymbol2); var resultSelectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(resultSelectorContext, resultSelectorLambda.Body); var @as = AstExpression.Var("z__"); var ast = AstExpression.Map( input: AstExpression.Zip(new[] { firstTranslation.Ast, secondTranslation.Ast }), @as: @as, @in: AstExpression.Let( AstExpression.VarBinding(resultSelectorSymbol1.Var, AstExpression.ArrayElemAt(@as, 0)), AstExpression.VarBinding(resultSelectorSymbol2.Var, AstExpression.ArrayElemAt(@as, 1)), @in: resultSelectorTranslation.Ast)); var serializer = IEnumerableSerializer.Create(resultSelectorTranslation.Serializer); return(new AggregationExpression(expression, ast, serializer)); } throw new ExpressionNotSupportedException(expression); }
// public static methods public static AstPipeline Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(QueryableMethod.GroupJoin)) { 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 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 ienumerableInnerSerializer = IEnumerableSerializer.Create(innerSerializer); var innerSymbol = context.CreateSymbol(innerParameter, innerField, ienumerableInnerSerializer); 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, projectStage); return(pipeline); } throw new ExpressionNotSupportedException(expression); }
public static AstFilterField TranslateEnumerable(TranslationContext context, Expression expression) { var field = Translate(context, expression); if (field.Serializer is IWrappedEnumerableSerializer wrappedEnumerableSerializer) { var enumerableSerializer = IEnumerableSerializer.Create(wrappedEnumerableSerializer.EnumerableElementSerializer); field = field.SubField(wrappedEnumerableSerializer.EnumerableFieldName, enumerableSerializer); } return(field); }
public static (AstFilterField, AstFilter) Translate(TranslationContext context, Expression sourceExpression) { if (sourceExpression is MethodCallExpression sourceMethodCallExpression) { var method = sourceMethodCallExpression.Method; var arguments = sourceMethodCallExpression.Arguments; if (method.Is(EnumerableMethod.OfType)) { var ofTypeSourceExpression = arguments[0]; var(sourceField, sourceFilter) = Translate(context, ofTypeSourceExpression); var nominalType = ArraySerializerHelper.GetItemSerializer(sourceField.Serializer).ValueType; var actualType = method.GetGenericArguments()[0]; var discriminatorConvention = BsonSerializer.LookupDiscriminatorConvention(actualType); var discriminatorField = AstFilter.Field(discriminatorConvention.ElementName, BsonValueSerializer.Instance); var discriminatorValue = discriminatorConvention.GetDiscriminator(nominalType, actualType); var ofTypeFilter = AstFilter.Eq(discriminatorField, discriminatorValue); var actualTypeSerializer = context.KnownSerializersRegistry.GetSerializer(sourceExpression); var enumerableActualTypeSerializer = IEnumerableSerializer.Create(actualTypeSerializer); var actualTypeSourceField = AstFilter.Field(sourceField.Path, enumerableActualTypeSerializer); var combinedFilter = AstFilter.Combine(sourceFilter, ofTypeFilter); return(actualTypeSourceField, combinedFilter); } if (method.Is(EnumerableMethod.Where)) { var whereSourceExpression = arguments[0]; var(sourceField, sourceFilter) = Translate(context, whereSourceExpression); var predicateLambda = (LambdaExpression)arguments[1]; var parameterExpression = predicateLambda.Parameters.Single(); var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceField.Serializer); var parameterSymbol = context.CreateSymbol(parameterExpression, "@<elem>", itemSerializer); // @<elem> represents the implied element var predicateContext = context.WithSingleSymbol(parameterSymbol); // @<elem> is the only symbol visible inside an $elemMatch var whereFilter = ExpressionToFilterTranslator.Translate(predicateContext, predicateLambda.Body, exprOk: false); var combinedFilter = AstFilter.Combine(sourceFilter, whereFilter); return(sourceField, combinedFilter); } } var field = ExpressionToFilterFieldTranslator.Translate(context, sourceExpression); return(field, null); }
public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(EnumerableMethod.Reverse)) { var sourceExpression = arguments[0]; var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression); var ast = AstExpression.ReverseArray(sourceTranslation.Ast); var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); var serializer = IEnumerableSerializer.Create(itemSerializer); return(new AggregationExpression(expression, ast, serializer)); } throw new ExpressionNotSupportedException(expression); }
public static AggregationExpression TranslateEnumerable(TranslationContext context, Expression expression) { var aggregateExpression = Translate(context, expression); var serializer = aggregateExpression.Serializer; if (serializer is IWrappedEnumerableSerializer wrappedEnumerableSerializer) { var enumerableFieldName = wrappedEnumerableSerializer.EnumerableFieldName; var enumerableElementSerializer = wrappedEnumerableSerializer.EnumerableElementSerializer; var enumerableSerializer = IEnumerableSerializer.Create(enumerableElementSerializer); var ast = AstExpression.GetField(aggregateExpression.Ast, enumerableFieldName); return(new AggregationExpression(aggregateExpression.Expression, ast, enumerableSerializer)); } return(aggregateExpression); }
// private methods private HashSet <IBsonSerializer> GetPossibleSerializersAtThisLevel(Type type) { if (_knownSerializers.TryGetValue(type, out var knownSerializers)) { return(knownSerializers); } Type itemType = null; if (type.TryGetIEnumerableGenericInterface(out var ienumerableGenericInterface)) { itemType = ienumerableGenericInterface.GetGenericArguments()[0]; } var possibleSerializers = new HashSet <IBsonSerializer>(); foreach (var serializer in _knownSerializers.Values.SelectMany(hashset => hashset)) { var valueType = serializer.ValueType; if (valueType == type || valueType.IsEnum() && Enum.GetUnderlyingType(valueType) == type) { possibleSerializers.Add(serializer); } if (serializer is IBsonArraySerializer arraySerializer && arraySerializer.TryGetItemSerializationInfo(out var itemSerializationInfo)) { var itemSerializer = itemSerializationInfo.Serializer; if (itemSerializer.ValueType == type) { possibleSerializers.Add(itemSerializer); } } if (valueType == itemType) { var ienumerableSerializer = IEnumerableSerializer.Create(serializer); possibleSerializers.Add(ienumerableSerializer); } } return(possibleSerializers); }
private static AstPipeline TranslateResultSelector( TranslationContext context, AstPipeline pipeline, ReadOnlyCollection <Expression> arguments, IBsonSerializer keySerializer, IBsonSerializer elementSerializer) { var resultSelectorLambda = ExpressionHelper.UnquoteLambda(arguments.Last()); var root = AstExpression.Var("ROOT", isCurrent: true); var keyParameter = resultSelectorLambda.Parameters[0]; var keyField = AstExpression.GetField(root, "_id"); var keySymbol = context.CreateSymbol(keyParameter, keyField, keySerializer); var elementsParameter = resultSelectorLambda.Parameters[1]; var elementsField = AstExpression.GetField(root, "_elements"); var elementsSerializer = IEnumerableSerializer.Create(elementSerializer); var elementsSymbol = context.CreateSymbol(elementsParameter, elementsField, elementsSerializer); var resultSelectContext = context.WithSymbols(keySymbol, elementsSymbol); var resultSelectorTranslation = ExpressionToAggregationExpressionTranslator.Translate(resultSelectContext, resultSelectorLambda.Body); var(projectStage, projectionSerializer) = ProjectionHelper.CreateProjectStage(resultSelectorTranslation); return(pipeline.AddStages(projectionSerializer, projectStage)); }
public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(EnumerableMethod.Range)) { var startExpression = arguments[0]; var startTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, startExpression); var(startVar, startAst) = AstExpression.UseVarIfNotSimple("start", startTranslation.Ast); var countExpression = arguments[1]; var countTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, countExpression); var(countVar, countAst) = AstExpression.UseVarIfNotSimple("count", countTranslation.Ast); var ast = AstExpression.Let( startVar, countVar, AstExpression.Range(startAst, end: AstExpression.Add(startAst, countAst))); var serializer = IEnumerableSerializer.Create(new Int32Serializer()); return(new AggregationExpression(expression, ast, serializer)); } throw new ExpressionNotSupportedException(expression); }
public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.Is(EnumerableMethod.Take)) { var sourceExpression = arguments[0]; var countExpression = arguments[1]; Expression skipExpression = null; if (sourceExpression is MethodCallExpression sourceSkipExpression && sourceSkipExpression.Method.Is(EnumerableMethod.Skip)) { sourceExpression = sourceSkipExpression.Arguments[0]; skipExpression = sourceSkipExpression.Arguments[1]; } var sourceTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, sourceExpression); var countTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, countExpression); AstExpression ast; if (skipExpression == null) { ast = AstExpression.Slice(sourceTranslation.Ast, countTranslation.Ast); } else { var skipTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, skipExpression); ast = AstExpression.Slice(sourceTranslation.Ast, skipTranslation.Ast, countTranslation.Ast); } var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); var serializer = IEnumerableSerializer.Create(itemSerializer); return(new AggregationExpression(expression, ast, serializer)); } throw new ExpressionNotSupportedException(expression); }
public static AggregationExpression Translate(TranslationContext context, MethodCallExpression expression) { var method = expression.Method; var arguments = expression.Arguments; if (method.IsOneOf(EnumerableMethod.Where, MongoEnumerableMethod.WhereWithLimit)) { var sourceExpression = arguments[0]; var sourceTranslation = ExpressionToAggregationExpressionTranslator.TranslateEnumerable(context, sourceExpression); var itemSerializer = ArraySerializerHelper.GetItemSerializer(sourceTranslation.Serializer); var predicateLambda = (LambdaExpression)arguments[1]; var predicateParameter = predicateLambda.Parameters[0]; var predicateSymbol = context.CreateSymbol(predicateParameter, itemSerializer); var predicateContext = context.WithSymbol(predicateSymbol); var predicateTranslation = ExpressionToAggregationExpressionTranslator.Translate(predicateContext, predicateLambda.Body); AggregationExpression limitTranslation = null; if (method.Is(MongoEnumerableMethod.WhereWithLimit)) { var limitExpression = arguments[2]; limitTranslation = ExpressionToAggregationExpressionTranslator.Translate(context, limitExpression); } var ast = AstExpression.Filter( sourceTranslation.Ast, predicateTranslation.Ast, predicateParameter.Name, limitTranslation?.Ast); var enumerableSerializer = IEnumerableSerializer.Create(itemSerializer); return(new AggregationExpression(expression, ast, enumerableSerializer)); } throw new ExpressionNotSupportedException(expression); }