예제 #1
0
        public ShuffleTemplate(
            string className,
            Type outerKeyType,
            Type sourceType,
            Type innerKeyType,
            string inlinedHashCodeComputation,
            bool nested, bool powerOf2) : base(className)
        {
            Contract.Requires(className != null);
            Contract.Requires(outerKeyType != null);
            Contract.Requires(sourceType != null);
            Contract.Requires(innerKeyType != null);

            this.inlinedHashCodeComputation = inlinedHashCodeComputation;
            this.isFirstLevelGroup          = !nested;
            this.powerOf2 = powerOf2;

            var tm = new TypeMapper(outerKeyType, sourceType, innerKeyType);

            this.TOuterKey = tm.CSharpNameFor(outerKeyType);
            this.TSource   = tm.CSharpNameFor(sourceType);
            this.TInnerKey = tm.CSharpNameFor(innerKeyType);

            this.genericParameters = tm.GenericTypeVariables(outerKeyType, sourceType, innerKeyType).BracketedCommaSeparatedString();

            this.resultBatchClassType = this.isFirstLevelGroup
                ? Transformer.GetBatchClassName(innerKeyType, sourceType)
                : Transformer.GetBatchClassName(typeof(CompoundGroupKey <,>).MakeGenericType(outerKeyType, innerKeyType), sourceType);
            this.resultBatchGenericParameters = this.genericParameters;

            this.sourceBatchClassType = Transformer.GetBatchClassName(outerKeyType, sourceType);
            this.TOuterKeyTSourceGenericParameters = tm.GenericTypeVariables(outerKeyType, sourceType).BracketedCommaSeparatedString();
        }
예제 #2
0
        protected CommonUnaryTemplate(string className, Type keyType, Type payloadType, Type resultType, bool suppressPayloadBatch = false)
            : base(className)
        {
            this.keyType     = keyType;
            this.payloadType = payloadType;
            this.resultType  = resultType;

            var tm = new TypeMapper(keyType, payloadType, resultType);

            this.TKey     = tm.CSharpNameFor(keyType);
            this.TPayload = tm.CSharpNameFor(payloadType);
            this.TResult  = tm.CSharpNameFor(resultType);

            if (!suppressPayloadBatch)
            {
                this.TKeyTPayloadGenericParameters    = tm.GenericTypeVariables(keyType, payloadType).BracketedCommaSeparatedString();
                this.BatchGeneratedFrom_TKey_TPayload = Transformer.GetBatchClassName(keyType, payloadType);
            }

            this.payloadRepresentation = new ColumnarRepresentation(payloadType);
            this.fields   = this.payloadRepresentation.AllFields;
            this.noFields = this.payloadRepresentation.noFields;

            this.resultRepresentation = new ColumnarRepresentation(resultType);
        }
예제 #3
0
        private TemporalEgressTemplate(Type tKey, Type tPayload, Type tResult, string partitionString, string ingressType, bool isColumnar)
            : base($"GeneratedTemporalEgress_{TemporalEgressSequenceNumber++}")
        {
            var tm = new TypeMapper(tKey, tPayload, tResult);

            this.payloadRepresentation = new ColumnarRepresentation(tPayload);

            this.BatchGeneratedFrom_TKey_TPayload = Transformer.GetBatchClassName(
                tKey == typeof(Empty)
                ? tKey
                : typeof(PartitionKey <>).MakeGenericType(tKey), tPayload);
            this.TKeyTPayloadGenericParameters = tm.GenericTypeVariables(tKey, tPayload).BracketedCommaSeparatedString();

            this.fields = this.payloadRepresentation.AllFields;

            this.TKey     = tm.CSharpNameFor(tKey);
            this.TPayload = tm.CSharpNameFor(tPayload);
            this.TResult  = tm.CSharpNameFor(tResult);

            this.partitionString = partitionString;
            this.ingressType     = ingressType;

            this.partitionKeyArgument = !string.IsNullOrEmpty(partitionString) ? "colkey[i].Key, " : string.Empty;
            this.genericArguments     = string.IsNullOrEmpty(partitionString) ? this.TPayload : this.TKey + ", " + this.TPayload;
            this.egress = (ingressType != "StreamEvent")
                ? this.TResult
                : partitionString + "StreamEvent<" + this.genericArguments + ">";
            this.inputKey   = string.IsNullOrEmpty(partitionString) ? this.TKey : "PartitionKey<" + this.TKey + ">";
            this.isColumnar = isColumnar;
        }
예제 #4
0
        private UngroupTemplate(
            string className,
            bool ungroupingFromCompound,
            Type outerKeyType,
            Type innerKeyType,
            Type innerResultType,
            Type resultType)
        {
            Contract.Requires(className != null);
            Contract.Requires(outerKeyType != null);
            Contract.Requires(innerKeyType != null);
            Contract.Requires(innerResultType != null);
            Contract.Requires(resultType != null);

            this.CLASSNAME              = className;
            this.outerKeyType           = outerKeyType;
            this.innerKeyType           = innerKeyType;
            this.innerResultType        = innerResultType;
            this.resultType             = resultType;
            this.ungroupingToUnit       = outerKeyType == typeof(Empty);
            this.ungroupingFromCompound = ungroupingFromCompound;

            var tm = new TypeMapper(outerKeyType, innerKeyType, innerResultType, resultType);

            this.TOuterKey    = tm.CSharpNameFor(outerKeyType);
            this.TInnerKey    = tm.CSharpNameFor(innerKeyType);
            this.TInnerResult = tm.CSharpNameFor(innerResultType);
            this.TResult      = tm.CSharpNameFor(resultType);

            var gps = tm.GenericTypeVariables(outerKeyType, innerKeyType, innerResultType, resultType);

            this.genericParameters         = gps.BracketedCommaSeparatedString();
            this.numberOfGenericParameters = gps.Count();

            this.inputBatchClassType = ungroupingFromCompound
                ? Transformer.GetBatchClassName(typeof(CompoundGroupKey <,>).MakeGenericType(outerKeyType, innerKeyType), innerResultType)
                : Transformer.GetBatchClassName(innerKeyType, innerResultType);
            this.inputBatchGenericParameters = ungroupingFromCompound
                ? tm.GenericTypeVariables(outerKeyType, innerKeyType, innerResultType).BracketedCommaSeparatedString()
                : tm.GenericTypeVariables(innerKeyType, innerResultType).BracketedCommaSeparatedString();

            this.resultBatchClassType         = Transformer.GetBatchClassName(outerKeyType, resultType);
            this.resultBatchGenericParameters = tm.GenericTypeVariables(outerKeyType, resultType).BracketedCommaSeparatedString();
        }
예제 #5
0
        public static Tuple <Type, string> Generate <TKey, TPayload, TResult>(SelectManyStreamable <TKey, TPayload, TResult> stream)
        {
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(UnaryPipe <TKey, TPayload, TResult>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

            string generatedClassName;
            string expandedCode;
            string errorMessages = null;

            try
            {
                generatedClassName = $"SelectMany_{sequenceNumber++}";
                var keyType     = typeof(TKey);
                var payloadType = typeof(TPayload);
                var resultType  = typeof(TResult);
                var template    = new SelectManyTemplate(generatedClassName, keyType, payloadType, resultType);

                var tm  = new TypeMapper(keyType, payloadType, resultType);
                var gps = tm.GenericTypeVariables(keyType, payloadType, resultType);
                template.genericParameters            = gps.BracketedCommaSeparatedString();
                template.numberOfGenericParameters    = gps.Count();
                template.TKeyTResultGenericParameters = tm.GenericTypeVariables(keyType, resultType).BracketedCommaSeparatedString();
                template.MemoryPoolGenericParameters  = $"<{template.TKey}, {template.TResult}>";
                if (resultType == typeof(int) || resultType == typeof(long) || resultType == typeof(string))
                {
                    template.MemoryPoolGenericParameters = string.Empty;
                }

                var payloadParameterIndex = 0;
                if (stream.HasKey && stream.HasStartEdge)
                {
                    payloadParameterIndex = 2;
                }
                else if (stream.HasKey || stream.HasStartEdge)
                {
                    payloadParameterIndex = 1;
                }

                var selector         = stream.Selector;
                var payloadParameter = selector.Parameters.ElementAt(payloadParameterIndex);

                template.PARAMETER = payloadParameter.Name;

                template.resultPayloadRepresentation = new ColumnarRepresentation(resultType);
                template.resultFields = template.resultPayloadRepresentation.AllFields;

                if (template.numberOfGenericParameters > 0)
                {
                    generatedClassName = generatedClassName + "`" + template.numberOfGenericParameters.ToString(CultureInfo.InvariantCulture);
                }

                expandedCode = string.Empty;

                Expression transformedSelector = selector;

                // No substitutions are made for the start edge parameter or key parameter. Both just remain in the
                // body of the result selector and are set as local variables in the generated code.

                var keyParameterIndex = stream.HasStartEdge ? 1 : 0;

                var tuple = OptimizeSelectMany(selector.Body);
                if (tuple != null)
                {
                    template.enumerableRepeatSelector = true;
                    var resultSelector         = stream.Selector;
                    var sourceMessageType      = StreamMessageManager.GetStreamMessageType <TKey, TPayload>();
                    var pseudoLambdaParameters = new ParameterExpression[stream.HasKey ? 2 : 1];
                    var pseudoLambdaIndex      = 0;
                    if (stream.HasKey)
                    {
                        pseudoLambdaParameters[pseudoLambdaIndex++] = selector.Parameters[keyParameterIndex];
                    }
                    pseudoLambdaParameters[pseudoLambdaIndex] = payloadParameter;
                    var pseudoLambda = Expression.Lambda(tuple.Item1, pseudoLambdaParameters);

                    var parameterSubstitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >
                    {
                        Tuple.Create(payloadParameter, new SelectParameterInformation()
                        {
                            BatchName = "batch", BatchType = sourceMessageType, IndexVariableName = "i", parameterRepresentation = new ColumnarRepresentation(payloadType)
                        })
                    };
                    var projectionResult = SelectTransformer.Transform(pseudoLambda, parameterSubstitutions, template.resultPayloadRepresentation, true, stream.HasStartEdge);
                    template.computedFields = projectionResult.ComputedFields;
                    template.useEnumerator  = false;
                    var loopCounter   = tuple.Item2;
                    var newParameters = new ParameterExpression[stream.HasKey ? 2 : 1];
                    newParameters[0] = payloadParameter;
                    if (stream.HasKey)
                    {
                        newParameters[1] = selector.Parameters[keyParameterIndex];
                    }

                    var loopCounterLambda      = Expression.Lambda(loopCounter, payloadParameter);
                    var transformedLoopCounter = Extensions.TransformFunction <TKey, TPayload>(loopCounterLambda, 0);
                    template.loopCounter = transformedLoopCounter.Body.ExpressionToCSharp();

                    // REVIEW: Alternative: use Inline to replace occurrences of the key parameter
                    // with "batch.key.col[i]".
                    if (stream.HasKey)
                    {
                        template.keyParameterName = selector.Parameters[keyParameterIndex].Name;
                    }
                }
                else
                {
                    transformedSelector = Extensions.TransformFunction <TKey, TPayload>(stream.Selector, payloadParameterIndex).Body;

                    if (transformedSelector == null)
                    {
                        template.useEnumerator = true;
                        template.transformedSelectorAsSource = stream.Selector.ExpressionToCSharp();
                    }
                    else
                    {
                        var tuple2 = OptimizeSelectMany(transformedSelector);
                        if (tuple2 != null)
                        {
                            template.useEnumerator = false;
                            template.loopCounter   = tuple2.Item2.ExpressionToCSharp();
                            template.transformedSelectorAsSource = tuple2.Item1.ExpressionToCSharp();
                        }
                        else
                        {
                            template.useEnumerator = true;
                            template.transformedSelectorAsSource = transformedSelector.ExpressionToCSharp();
                        }
                    }
                }

                template.StartEdgeParameterName = stream.HasStartEdge ? selector.Parameters.ElementAt(0).Name : null;
                template.hasKey = stream.HasKey;
                expandedCode    = template.TransformText();

                var assemblyReferences = Transformer.AssemblyReferencesNeededFor(typeof(TKey), typeof(TPayload), typeof(TResult));
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TPayload>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TResult>());
                assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TKey, TResult>());
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(stream.Selector));

                var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                var t = a.GetType(generatedClassName);
                t = t.InstantiateAsNecessary(typeof(TKey), typeof(TPayload), typeof(TResult));
                return(Tuple.Create(t, errorMessages));
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }
예제 #6
0
        /// <summary>
        /// Generate a batch class definition to be used as a Union pipe.
        /// Compile the definition, dynamically load the assembly containing it, and return the Type representing the
        /// union pipe class.
        /// </summary>
        /// <typeparam name="TKey">The key type for both sides.</typeparam>
        /// <typeparam name="TPayload">The payload type.</typeparam>
        /// <returns>
        /// A type that is defined to be a subtype of BinaryPipe&lt;<typeparamref name="TKey"/>,<typeparamref name="TPayload"/>, <typeparamref name="TPayload"/>, <typeparamref name="TKey"/>, <typeparamref name="TPayload"/>&gt;.
        /// </returns>
        internal static Tuple <Type, string> GenerateUnionPipeClass <TKey, TPayload>(
            UnionStreamable <TKey, TPayload> stream)
        {
            Contract.Requires(stream != null);
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(BinaryPipe <TKey, TPayload, TPayload, TPayload>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

#if CODEGEN_TIMING
            Stopwatch sw = new Stopwatch();
            sw.Start();
#endif
            string errorMessages = null;
            try
            {
                var template = new UnionTemplate();

                var keyType     = template.keyType = typeof(TKey);
                var payloadType = template.payloadType = typeof(TPayload);

                var tm = new TypeMapper(keyType, payloadType);
                template.TKey     = tm.CSharpNameFor(keyType);
                template.TPayload = tm.CSharpNameFor(payloadType);
                var gps = tm.GenericTypeVariables(keyType, payloadType);
                template.genericParameters = gps.BracketedCommaSeparatedString();

                template.className = string.Format("GeneratedUnion_{0}", UnionSequenceNumber++);

                var resultRepresentation = new ColumnarRepresentation(payloadType);

                var batchGeneratedFrom_TKey_TPayload = Transformer.GetBatchClassName(keyType, payloadType);
                var keyAndPayloadGenericParameters   = tm.GenericTypeVariables(keyType, payloadType).BracketedCommaSeparatedString();
                template.GeneratedBatchName = batchGeneratedFrom_TKey_TPayload + keyAndPayloadGenericParameters;

                template.fields = resultRepresentation.AllFields;

                template.staticCtor = Transformer.StaticCtor(template.className);
                var expandedCode = template.TransformText();

                var assemblyReferences = Transformer.AssemblyReferencesNeededFor(typeof(TKey), typeof(TPayload));
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TPayload>());

                var a             = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                var realClassName = template.className.AddNumberOfNecessaryGenericArguments(keyType, payloadType);
                var t             = a.GetType(realClassName);
                if (t.GetTypeInfo().IsGenericType)
                {
                    var list = keyType.GetAnonymousTypes();
                    list.AddRange(payloadType.GetAnonymousTypes());
                    return(Tuple.Create(t.MakeGenericType(list.ToArray()), errorMessages));
                }
                else
                {
                    return(Tuple.Create(t, errorMessages));
                }
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }
예제 #7
0
        public static Tuple <Type, string> Generate <TKey, TPayload, TResult>(SelectStreamable <TKey, TPayload, TResult> stream)
        {
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(UnaryPipe <TKey, TPayload, TResult>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

            string generatedClassName;
            string errorMessages = null;

            try
            {
                var keyType     = typeof(TKey);
                var payloadType = typeof(TPayload);
                var resultType  = typeof(TResult);
                generatedClassName = string.Format("Select_{0}_{1}_{2}_{3}", keyType.GetValidIdentifier(), payloadType.GetValidIdentifier(), resultType.GetValidIdentifier(), sequenceNumber++);
                var template = new SelectTemplate(generatedClassName, keyType, payloadType, resultType);

                var tm  = new TypeMapper(keyType, payloadType, resultType);
                var gps = tm.GenericTypeVariables(keyType, payloadType, resultType);
                template.genericParameters            = gps.BracketedCommaSeparatedString();
                template.numberOfGenericParameters    = gps.Count();
                template.TKeyTResultGenericParameters = tm.GenericTypeVariables(keyType, resultType).BracketedCommaSeparatedString();
                template.MemoryPoolGenericParameters  = $"<{template.TKey}, {template.TResult}>";
                if (resultType == typeof(int) || resultType == typeof(long) || resultType == typeof(string))
                {
                    template.MemoryPoolGenericParameters = string.Empty;
                }

                var payloadParameterIndex = 0;
                if (stream.HasKey && stream.HasStartEdge)
                {
                    payloadParameterIndex = 2;
                }
                else if (stream.HasKey || stream.HasStartEdge)
                {
                    payloadParameterIndex = 1;
                }

                template.PARAMETER = stream.Selector.Parameters[payloadParameterIndex].Name;
                template.resultPayloadRepresentation = new ColumnarRepresentation(resultType);
                template.destinationFields           = template.resultPayloadRepresentation.AllFields;

                if (template.numberOfGenericParameters > 0)
                {
                    generatedClassName = generatedClassName + "`" + template.numberOfGenericParameters.ToString(CultureInfo.InvariantCulture);
                }

                var resultSelector        = stream.Selector;
                var sourceMessageType     = StreamMessageManager.GetStreamMessageType <TKey, TPayload>();
                var parameterSubsitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >();
                // Don't create a parameter substitution for the start edge parameter. That will just remain in the
                // body of the result selector and will be set as a local variable in the generated code.
                if (stream.HasKey)
                {
                    var keyRepresentation = new ColumnarRepresentation(keyType, "key");
                    var keyParameterIndex = stream.HasStartEdge ? 1 : 0;
                    parameterSubsitutions.Add(Tuple.Create(
                                                  resultSelector.Parameters.ElementAt(keyParameterIndex),
                                                  new SelectParameterInformation()
                    {
                        BatchName = "sourceBatch", BatchType = sourceMessageType, IndexVariableName = "i", parameterRepresentation = keyRepresentation,
                    }));
                }
                parameterSubsitutions.Add(Tuple.Create(
                                              resultSelector.Parameters.ElementAt(payloadParameterIndex),
                                              new SelectParameterInformation()
                {
                    BatchName = "sourceBatch", BatchType = sourceMessageType, IndexVariableName = "i", parameterRepresentation = new ColumnarRepresentation(payloadType)
                }));
                var projectionResult = SelectTransformer.Transform(resultSelector, parameterSubsitutions, template.resultPayloadRepresentation, false, stream.HasStartEdge);
                if (projectionResult.Error)
                {
                    if (Config.CodegenOptions.SuperStrictColumnar)
                    {
                        throw new InvalidOperationException("Code Generation couldn't transform a selector!");
                    }
                    return(Tuple.Create((Type)null, errorMessages));
                }
                template.StartEdgeParameterName            = stream.HasStartEdge ? resultSelector.Parameters.ElementAt(0).Name : null;
                template.computedFields                    = projectionResult.ComputedFields;
                template.swingingFields                    = projectionResult.SwingingFields;
                template.unassignedFields                  = projectionResult.UnmentionedFields;
                template.ProjectionReturningResultInstance = projectionResult.ProjectionReturningResultInstance;
                template.multiStringOperations             = projectionResult.MultiStringOperations;
                template.needSourceInstance                = projectionResult.NeedsSourceInstance;

                var d = new Dictionary <MyFieldInfo, int>();
                foreach (var f in template.swingingFields)
                {
                    var target = f.Item1;
                    var source = f.Item2;
                    if (!d.ContainsKey(source))
                    {
                        d.Add(source, 0);
                    }
                    d[source] = d[source] + 1;
                }
                template.swungFieldsCount = d;

                template.nonSwingingFields = template.fields.Where(sf => !template.swingingFields.Any(swingingField => swingingField.Item2.Equals(sf)));
                var expandedCode = template.TransformText();

                var assemblyReferences = Transformer.AssemblyReferencesNeededFor(
                    typeof(TKey), typeof(TPayload), typeof(TResult), typeof(IStreamable <,>));
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TPayload>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TResult>());
                assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TKey, TResult>());
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(stream.Selector));

                var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                var t = a.GetType(generatedClassName);
                t = t.InstantiateAsNecessary(typeof(TKey), typeof(TPayload), typeof(TResult));
                return(Tuple.Create(t, errorMessages));
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }

                return(Tuple.Create((Type)null, errorMessages));
            }
        }
예제 #8
0
        internal static Tuple <Type, string> Generate <TKey, TLeft, TRight, TResult>(
            BinaryStreamable <TKey, TLeft, TRight, TResult> stream,
            Expression <Func <TLeft, TRight, TResult> > selector)
        {
            Contract.Requires(stream != null);
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(BinaryPipe <TKey, TLeft, TRight, TResult>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

            string errorMessages = null;

            try
            {
                var template = new EquiJoinTemplate();

                var keyType    = template.keyType = typeof(TKey);
                var leftType   = template.leftType = typeof(TLeft);
                var rightType  = template.rightType = typeof(TRight);
                var resultType = template.resultType = typeof(TResult);

                var tm = new TypeMapper(keyType, leftType, rightType, resultType);
                template.TKey    = tm.CSharpNameFor(keyType);
                template.TLeft   = tm.CSharpNameFor(leftType);
                template.TRight  = tm.CSharpNameFor(rightType);
                template.TResult = tm.CSharpNameFor(resultType);
                var keyAndLeftGenericParameters  = tm.GenericTypeVariables(keyType, leftType).BracketedCommaSeparatedString();
                var keyAndRightGenericParameters = tm.GenericTypeVariables(keyType, rightType).BracketedCommaSeparatedString();
                template.TKeyTResultGenericParameters = tm.GenericTypeVariables(keyType, resultType).BracketedCommaSeparatedString();
                template.genericParameters            = tm.GenericTypeVariables(keyType, leftType, rightType, resultType).BracketedCommaSeparatedString();

                template.className = string.Format("GeneratedEquiJoin_{0}", EquiJoinSequenceNumber++);

                template.leftMessageRepresentation  = new ColumnarRepresentation(leftType);
                template.rightMessageRepresentation = new ColumnarRepresentation(rightType);
                var resultMessageRepresentation = new ColumnarRepresentation(resultType);

                var batchGeneratedFrom_TKey_TLeft  = Transformer.GetBatchClassName(keyType, leftType);
                var batchGeneratedFrom_TKey_TRight = Transformer.GetBatchClassName(keyType, rightType);
                template.BatchGeneratedFrom_TKey_TResult = Transformer.GetBatchClassName(keyType, resultType);

                template.LeftBatchType  = batchGeneratedFrom_TKey_TLeft + keyAndLeftGenericParameters;
                template.RightBatchType = batchGeneratedFrom_TKey_TRight + keyAndRightGenericParameters;

                template.leftFields   = template.leftMessageRepresentation.AllFields;
                template.rightFields  = template.rightMessageRepresentation.AllFields;
                template.resultFields = resultMessageRepresentation.AllFields;

                template.ActiveEventTypeLeft  = leftType.GetTypeInfo().IsValueType ? template.TLeft : "Active_Event_Left";
                template.ActiveEventTypeRight = rightType.GetTypeInfo().IsValueType ? template.TRight : "Active_Event_Right";

                #region Key Equals
                var keyComparer = stream.Properties.KeyEqualityComparer.GetEqualsExpr();
                template.keyComparerEquals =
                    (left, right) =>
                    keyComparer.Inline(left, right);
                if (keyType.IsAnonymousType())
                {
                    template.keyComparerEquals =
                        (left, right) => string.Format("keyComparerEquals({0}, {1})", left, right);
                }
                #endregion

                #region Left Payload Equals
                {
                    var leftPayloadComparer = stream.Left.Properties.PayloadEqualityComparer.GetEqualsExpr();
                    var newLambda           = Extensions.TransformFunction <TKey, TLeft>(leftPayloadComparer, "leftIndex", 0);
                    template.leftComparerEquals = (left, right) => newLambda.Inline(left, right);
                }
                #endregion

                #region Right Payload Equals
                {
                    var rightPayloadComparer = stream.Right.Properties.PayloadEqualityComparer.GetEqualsExpr();
                    var newLambda            = Extensions.TransformFunction <TKey, TRight>(rightPayloadComparer, "rightIndex", 0);
                    template.rightComparerEquals = (left, right) => newLambda.Inline(left, right);
                }
                #endregion

                #region Result Selector
                {
                    var leftMessageType  = StreamMessageManager.GetStreamMessageType <TKey, TLeft>();
                    var rightMessageType = StreamMessageManager.GetStreamMessageType <TKey, TRight>();

                    if (!ConstantExpressionFinder.IsClosedExpression(selector))
                    {
                        errorMessages = "result selector is not a closed expression";
                        throw new InvalidOperationException();
                    }

                    #region LeftBatchSelector
                    {
                        var parameterSubsitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >()
                        {
                            Tuple.Create(selector.Parameters[0], new SelectParameterInformation()
                            {
                                BatchName = "leftBatch", BatchType = leftMessageType, IndexVariableName = "i", parameterRepresentation = template.leftMessageRepresentation,
                            }),
                        };
                        var projectionResult = SelectTransformer.Transform(selector, parameterSubsitutions, resultMessageRepresentation, true);
                        if (projectionResult.Error)
                        {
                            errorMessages = "error while transforming the result selector";
                            throw new InvalidOperationException();
                        }
                        template.leftBatchSelector = (leftBatch, leftIndex, rightEvent) =>
                        {
                            var d = new Dictionary <ParameterExpression, string>
                            {
                                { Expression.Variable(leftMessageType, "leftBatch"), leftBatch },
                                { Expression.Variable(typeof(int), "i"), leftIndex },
                                { selector.Parameters[1], rightEvent }
                            };
                            var sb = new System.Text.StringBuilder();
                            sb.AppendLine("{");
                            foreach (var kv in projectionResult.ComputedFields)
                            {
                                var f = kv.Key;
                                var e = kv.Value;
                                if (f.OptimizeString())
                                {
                                    sb.AppendFormat(
                                        "output.{0}.AddString({1});\n",
                                        f.Name,
                                        e.ExpressionToCSharpStringWithParameterSubstitution(d));
                                }
                                else
                                {
                                    sb.AppendFormat(
                                        "output.{0}.col[index] = {1};\n",
                                        f.Name,
                                        e.ExpressionToCSharpStringWithParameterSubstitution(d));
                                }
                            }
                            sb.AppendLine("}");
                            return(sb.ToString());
                        };
                    }
                    #endregion
                    #region RightBatchSelector
                    {
                        var parameterSubsitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >()
                        {
                            Tuple.Create(selector.Parameters[1], new SelectParameterInformation()
                            {
                                BatchName = "rightBatch", BatchType = rightMessageType, IndexVariableName = "j", parameterRepresentation = template.rightMessageRepresentation,
                            }),
                        };
                        var projectionResult = SelectTransformer.Transform(selector, parameterSubsitutions, resultMessageRepresentation, true);
                        if (projectionResult.Error)
                        {
                            errorMessages = "error while transforming the result selector";
                            throw new InvalidOperationException();
                        }
                        template.rightBatchSelector = (leftEvent, rightBatch, rightIndex) =>
                        {
                            var d = new Dictionary <ParameterExpression, string>
                            {
                                { selector.Parameters[0], leftEvent },
                                { Expression.Variable(rightMessageType, "rightBatch"), rightBatch },
                                { Expression.Variable(typeof(int), "j"), rightIndex }
                            };
                            var sb = new System.Text.StringBuilder();
                            sb.AppendLine("{");
                            foreach (var kv in projectionResult.ComputedFields)
                            {
                                var f = kv.Key;
                                var e = kv.Value;
                                if (f.OptimizeString())
                                {
                                    sb.AppendFormat(
                                        "output.{0}.AddString({1});\n",
                                        f.Name,
                                        e.ExpressionToCSharpStringWithParameterSubstitution(d));
                                }
                                else
                                {
                                    sb.AppendFormat(
                                        "output.{0}.col[index] = {1};\n",
                                        f.Name,
                                        e.ExpressionToCSharpStringWithParameterSubstitution(d));
                                }
                            }
                            sb.AppendLine("}");
                            return(sb.ToString());
                        };
                    }
                    #endregion
                    #region ActiveSelector
                    {
                        var parameterSubsitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >();
                        var projectionResult      = SelectTransformer.Transform(selector, parameterSubsitutions, resultMessageRepresentation, true);
                        if (projectionResult.Error)
                        {
                            errorMessages = "error while transforming the result selector";
                            throw new InvalidOperationException();
                        }
                        template.activeSelector = (leftEvent, rightEvent) =>
                        {
                            var d = new Dictionary <ParameterExpression, string>
                            {
                                { selector.Parameters[0], leftEvent },
                                { selector.Parameters[1], rightEvent }
                            };
                            var sb = new System.Text.StringBuilder();
                            sb.AppendLine("{");
                            foreach (var kv in projectionResult.ComputedFields)
                            {
                                var f = kv.Key;
                                var e = kv.Value;
                                if (f.OptimizeString())
                                {
                                    sb.AppendFormat(
                                        "output.{0}.AddString({1});\n",
                                        f.Name,
                                        e.ExpressionToCSharpStringWithParameterSubstitution(d));
                                }
                                else
                                {
                                    sb.AppendFormat(
                                        "output.{0}.col[index] = {1};\n",
                                        f.Name,
                                        e.ExpressionToCSharpStringWithParameterSubstitution(d));
                                }
                            }
                            sb.AppendLine("}");
                            return(sb.ToString());
                        };
                    }
                    #endregion
                }
                #endregion

                if (stream.Left.Properties.IsIntervalFree && stream.Right.Properties.IsConstantDuration)
                {
                    template.endPointHeap = "EndPointQueue";
                }
                else if (stream.Right.Properties.IsIntervalFree && stream.Left.Properties.IsConstantDuration)
                {
                    template.endPointHeap = "EndPointQueue";
                }
                else if (stream.Left.Properties.IsConstantDuration && stream.Right.Properties.IsConstantDuration &&
                         stream.Left.Properties.ConstantDurationLength == stream.Right.Properties.ConstantDurationLength)
                {
                    template.endPointHeap = "EndPointQueue";
                }
                else
                {
                    template.endPointHeap = "EndPointHeap";
                }


                template.staticCtor = Transformer.StaticCtor(template.className);
                var expandedCode = template.TransformText();

                var assemblyReferences = Transformer.AssemblyReferencesNeededFor(keyType, leftType, rightType, resultType);
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TLeft>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TRight>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TResult>());

                var a = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                if (keyType.IsAnonymousType())
                {
                    if (errorMessages == null)
                    {
                        errorMessages = string.Empty;
                    }
                    errorMessages += "\nCodegen Warning: The key type for an equi-join is an anonymous type (or contains an anonymous type), preventing the inlining of the key equality and hashcode functions. This may lead to poor performance.\n";
                }
                var realClassName = template.className.AddNumberOfNecessaryGenericArguments(keyType, leftType, rightType, resultType);
                var t             = a.GetType(realClassName);
                if (t.GetTypeInfo().IsGenericType)
                {
                    var list = keyType.GetAnonymousTypes();
                    list.AddRange(leftType.GetAnonymousTypes());
                    list.AddRange(rightType.GetAnonymousTypes());
                    list.AddRange(resultType.GetAnonymousTypes());
                    return(Tuple.Create(t.MakeGenericType(list.ToArray()), errorMessages));
                }
                else
                {
                    return(Tuple.Create(t, errorMessages));
                }
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }
예제 #9
0
        /// <summary>
        /// Generate a batch class definition to be used as a Clip pipe.
        /// Compile the definition, dynamically load the assembly containing it, and return the Type representing the
        /// aggregate class.
        /// </summary>
        /// <typeparam name="TKey">The key type for both sides.</typeparam>
        /// <typeparam name="TLeft">The payload type for the left side.</typeparam>
        /// <typeparam name="TRight">The payload type for the right side.</typeparam>
        /// <returns>
        /// A type that is defined to be a subtype of BinaryPipe&lt;<typeparamref name="TKey"/>,<typeparamref name="TLeft"/>, <typeparamref name="TKey"/>, <typeparamref name="TRight"/>&gt;.
        /// </returns>
        internal static Tuple <Type, string> Generate <TKey, TLeft, TRight>(ClipJoinStreamable <TKey, TLeft, TRight> stream)
        {
            Contract.Requires(stream != null);
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(BinaryPipe <TKey, TLeft, TRight, TLeft>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

            string errorMessages = null;

            try
            {
                var template = new ClipJoinTemplate();

                var keyType   = template.keyType = typeof(TKey);
                var leftType  = template.leftType = typeof(TLeft);
                var rightType = template.rightType = typeof(TRight);

                var tm = new TypeMapper(keyType, leftType, rightType);
                template.TKey   = tm.CSharpNameFor(keyType);
                template.TLeft  = tm.CSharpNameFor(leftType);
                template.TRight = tm.CSharpNameFor(rightType);
                var gps = tm.GenericTypeVariables(keyType, leftType, rightType);
                template.genericParameters = gps.BracketedCommaSeparatedString();

                template.className = string.Format("GeneratedClip_{0}", ClipSequenceNumber++);

                var resultRepresentation = new ColumnarRepresentation(leftType);

                template.ActiveEventType = leftType.GetTypeInfo().IsValueType ? template.TLeft : "Active_Event";

                #region Key Comparer
                var keyComparer = stream.Properties.KeyEqualityComparer.GetEqualsExpr();
                template.keyComparer =
                    (left, right) =>
                    keyComparer.Inline(left, right);
                #endregion

                #region Left Comparer
                var leftComparer = stream.LeftComparer.GetEqualsExpr();
                var newLambda    = Extensions.TransformFunction <TKey, TLeft>(leftComparer, "index_ProcessLeftEvent", 0);
                template.leftComparer = (left, right) => newLambda.Inline(left, right);
                #endregion

                template.BatchGeneratedFrom_TKey_TLeft = Transformer.GetBatchClassName(keyType, leftType);
                template.TKeyTLeftGenericParameters    = tm.GenericTypeVariables(keyType, leftType).BracketedCommaSeparatedString();

                template.BatchGeneratedFrom_TKey_TRight = Transformer.GetBatchClassName(keyType, rightType);
                template.TKeyTRightGenericParameters    = tm.GenericTypeVariables(keyType, rightType).BracketedCommaSeparatedString();

                template.leftFields = resultRepresentation.AllFields;
                template.noFields   = resultRepresentation.noFields;

                template.staticCtor = Transformer.StaticCtor(template.className);
                var expandedCode = template.TransformText();

                var assemblyReferences = Transformer.AssemblyReferencesNeededFor(typeof(TKey), typeof(TLeft), typeof(TRight));
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TLeft>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TRight>());
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(leftComparer));

                var a             = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                var realClassName = template.className.AddNumberOfNecessaryGenericArguments(keyType, leftType, rightType);
                var t             = a.GetType(realClassName);
                if (t.GetTypeInfo().IsGenericType)
                {
                    var list = keyType.GetAnonymousTypes();
                    list.AddRange(leftType.GetAnonymousTypes());
                    list.AddRange(rightType.GetAnonymousTypes());
                    return(Tuple.Create(t.MakeGenericType(list.ToArray()), errorMessages));
                }
                else
                {
                    return(Tuple.Create(t, errorMessages));
                }
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }
        private static Tuple <Type, string> Generate <TKey, TSource, TResult>(
            string ingressType,
            string partitionString,
            Expression <Func <TSource, TKey> > partitionExpression,
            Expression <Func <TSource, long> > startEdgeExpression,
            Expression <Func <TSource, long> > endEdgeExpression,
            string latencyOption,
            string diagnosticOption,
            FuseModule fuseModule)
        {
            var template = new TemporalIngressTemplate(
                $"GeneratedTemporalIngress_{TemporalIngressSequenceNumber++}",
                typeof(TKey), typeof(TSource), fuseModule?.OutputType ?? typeof(TResult));

            var tm  = new TypeMapper(template.keyType, template.payloadType, template.resultType);
            var gps = tm.GenericTypeVariables(template.keyType, template.payloadType);

            template.genericParameters = gps.BracketedCommaSeparatedString();
            template.payloadOrResult   = tm.CSharpNameFor(template.resultRepresentation.RepresentationFor);

            var batchGeneratedFrom_TKey_TPayload = string.IsNullOrEmpty(partitionString)
                ? Transformer.GetBatchClassName(template.keyType, template.resultType)
                : Transformer.GetBatchClassName(typeof(PartitionKey <TKey>), template.resultType);
            var keyAndPayloadGenericParameters = tm.GenericTypeVariables(template.keyType, template.resultType).BracketedCommaSeparatedString();

            template.GeneratedBatchName = batchGeneratedFrom_TKey_TPayload + keyAndPayloadGenericParameters;

            template.keyOrNothing        = string.IsNullOrEmpty(partitionString) ? string.Empty : template.TKey + ", ";
            template.diagnosticOption    = diagnosticOption;
            template.needsStreamEvent    = ingressType == "StreamEvent";
            template.genericArguments    = (string.IsNullOrEmpty(partitionString) ? string.Empty : template.TKey + ", ") + template.TPayload;
            template.adjustedGenericArgs = (string.IsNullOrEmpty(partitionString) ? string.Empty : template.TKey + ", ") + (!fuseModule.IsEmpty && Config.AllowFloatingReorderPolicy ? template.TResult : template.TPayload);
            template.emptyOrPartition    = string.IsNullOrEmpty(partitionString) ? "Microsoft.StreamProcessing.Empty.Default" : "new PartitionKey<" + template.TKey + ">(value.PartitionKey)";
            template.partitionString     = partitionString;
            template.baseStructure       = partitionString + "StreamEvent<" + template.genericArguments + ">";
            template.inheritBase         = (ingressType != "StreamEvent") ? template.TPayload : template.baseStructure;
            template.ingressType         = ingressType;
            template.latencyOption       = latencyOption;

            template.partitionFunction = x => partitionExpression == null ?
                                         string.Empty : partitionExpression.Body.ExpressionToCSharpStringWithParameterSubstitution(
                new Dictionary <ParameterExpression, string>
            {
                { partitionExpression.Parameters.Single(), x }
            });
            template.startEdgeFunction = x => startEdgeExpression == null ?
                                         string.Empty : startEdgeExpression.Body.ExpressionToCSharpStringWithParameterSubstitution(
                new Dictionary <ParameterExpression, string>
            {
                { startEdgeExpression.Parameters.Single(), x }
            });
            template.endEdgeFunction = x => endEdgeExpression == null ?
                                       "StreamEvent.InfinitySyncTime" :
                                       endEdgeExpression.Body.ExpressionToCSharpStringWithParameterSubstitution(
                new Dictionary <ParameterExpression, string>
            {
                { endEdgeExpression.Parameters.Single(), x }
            });

            template.fusionOption = fuseModule.IsEmpty ? "Simple" :
                                    (Config.AllowFloatingReorderPolicy ? "Disordered" : "Fused");
            template.resultMightBeNull = template.resultType.CanContainNull();

            Expression[] expressions = null;
            if (!fuseModule.IsEmpty)
            {
                template.valueString = fuseModule.Coalesce <TSource, TResult, TKey>("value.SyncTime", "value.OtherTime", "value.Payload", template.emptyOrPartition, out template.leadingText, out template.trailingText);
                template.generatedEndTimeVariable = "generatedEndTimeVariable";
                if (Config.AllowFloatingReorderPolicy)
                {
                    template.valueString = "value.Payload";
                    template.generatedEndTimeVariable = "value.OtherTime";
                }

                expressions = fuseModule.GetCodeGenExpressions();
            }

            return(template.Generate <TKey, TSource, TResult>(new Type[] { typeof(IStreamable <,>) }, expressions));
        }
예제 #11
0
        internal static Tuple <Type, string> Generate <TKey, TLeft, TRight, TResult>(
            BinaryStreamable <TKey, TLeft, TRight, TResult> stream,
            Expression <Func <TLeft, TRight, TResult> > selector)
        {
            Contract.Requires(stream != null);
            Contract.Ensures(Contract.Result <Tuple <Type, string> >() == null || typeof(BinaryPipe <TKey, TLeft, TRight, TResult>).GetTypeInfo().IsAssignableFrom(Contract.Result <Tuple <Type, string> >().Item1));

            string errorMessages = null;

            try
            {
                var template = new StartEdgeEquiJoinTemplate();

                var keyType    = template.keyType = typeof(TKey);
                var leftType   = template.leftType = typeof(TLeft);
                var rightType  = template.rightType = typeof(TRight);
                var resultType = template.resultType = typeof(TResult);

                var tm = new TypeMapper(keyType, leftType, rightType, resultType);
                template.TKey    = tm.CSharpNameFor(keyType);
                template.TLeft   = tm.CSharpNameFor(leftType);
                template.TRight  = tm.CSharpNameFor(rightType);
                template.TResult = tm.CSharpNameFor(resultType);
                var gps = tm.GenericTypeVariables(keyType, leftType, rightType, resultType);
                template.genericParameters = gps.BracketedCommaSeparatedString();

                template.className = string.Format("GeneratedStartEdgeEquiJoin_{0}", StartEdgeEquiJoinSequenceNumber++);

                template.leftMessageRepresentation = new ColumnarRepresentation(leftType);
                template.leftFields = template.leftMessageRepresentation.AllFields;
                template.rightMessageRepresentation = new ColumnarRepresentation(rightType);
                template.rightFields = template.rightMessageRepresentation.AllFields;
                var outputMessageRepresentation = new ColumnarRepresentation(resultType);

                var resultRepresentation = outputMessageRepresentation;

                #region Key Comparer
                var keyComparer = stream.Properties.KeyEqualityComparer.GetEqualsExpr();
                template.keyComparer =
                    (left, right) =>
                    keyComparer.Inline(left, right);
                #endregion

                template.BatchGeneratedFrom_TKey_TLeft = Transformer.GetBatchClassName(keyType, leftType);
                template.TKeyTLeftGenericParameters    = tm.GenericTypeVariables(keyType, leftType).BracketedCommaSeparatedString();

                template.BatchGeneratedFrom_TKey_TRight = Transformer.GetBatchClassName(keyType, rightType);
                template.TKeyTRightGenericParameters    = tm.GenericTypeVariables(keyType, rightType).BracketedCommaSeparatedString();

                template.BatchGeneratedFrom_TKey_TResult = Transformer.GetBatchClassName(keyType, resultType);
                template.TKeyTResultGenericParameters    = tm.GenericTypeVariables(keyType, resultType).BracketedCommaSeparatedString();

                template.outputFields = resultRepresentation.AllFields;

                var leftMessageType  = StreamMessageManager.GetStreamMessageType <TKey, TLeft>();
                var rightMessageType = StreamMessageManager.GetStreamMessageType <TKey, TRight>();
                #region LeftBatchSelector
                {
                    var parameterSubsitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >()
                    {
                        Tuple.Create(selector.Parameters[0], new SelectParameterInformation()
                        {
                            BatchName = "leftBatch", BatchType = leftMessageType, IndexVariableName = "i", parameterRepresentation = template.leftMessageRepresentation,
                        }),
                    };
                    var projectionResult = SelectTransformer.Transform(selector, parameterSubsitutions, resultRepresentation, true);
                    if (projectionResult.Error)
                    {
                        errorMessages = "error while transforming the result selector";
                        throw new InvalidOperationException();
                    }
                    template.leftBatchSelector = (leftBatch, leftIndex, rightEvent) =>
                    {
                        var d = new Dictionary <ParameterExpression, string>
                        {
                            { Expression.Variable(leftMessageType, "leftBatch"), leftBatch },
                            { Expression.Variable(typeof(int), "i"), leftIndex },
                            { selector.Parameters[1], rightEvent }
                        };
                        var sb = new System.Text.StringBuilder();
                        sb.AppendLine("{");
                        foreach (var kv in projectionResult.ComputedFields)
                        {
                            var f = kv.Key;
                            var e = kv.Value;
                            if (f.OptimizeString())
                            {
                                sb.AppendFormat(
                                    "output.{0}.AddString({1});\n",
                                    f.Name,
                                    e.ExpressionToCSharpStringWithParameterSubstitution(d));
                            }
                            else
                            {
                                sb.AppendFormat(
                                    "output.{0}.col[index] = {1};\n",
                                    f.Name,
                                    e.ExpressionToCSharpStringWithParameterSubstitution(d));
                            }
                        }
                        sb.AppendLine("}");
                        return(sb.ToString());
                    };
                }
                #endregion
                #region RightBatchSelector
                {
                    var parameterSubsitutions = new List <Tuple <ParameterExpression, SelectParameterInformation> >()
                    {
                        Tuple.Create(selector.Parameters[1], new SelectParameterInformation()
                        {
                            BatchName = "rightBatch", BatchType = rightMessageType, IndexVariableName = "j", parameterRepresentation = template.rightMessageRepresentation,
                        }),
                    };
                    var projectionResult = SelectTransformer.Transform(selector, parameterSubsitutions, resultRepresentation, true);
                    if (projectionResult.Error)
                    {
                        errorMessages = "error while transforming the result selector";
                        throw new InvalidOperationException();
                    }
                    template.rightBatchSelector = (leftEvent, rightBatch, rightIndex) =>
                    {
                        var d = new Dictionary <ParameterExpression, string>
                        {
                            { selector.Parameters[0], leftEvent },
                            { Expression.Variable(rightMessageType, "rightBatch"), rightBatch },
                            { Expression.Variable(typeof(int), "j"), rightIndex }
                        };
                        var sb = new System.Text.StringBuilder();
                        sb.AppendLine("{");
                        foreach (var kv in projectionResult.ComputedFields)
                        {
                            var f = kv.Key;
                            var e = kv.Value;
                            if (f.OptimizeString())
                            {
                                sb.AppendFormat(
                                    "output.{0}.AddString({1});\n",
                                    f.Name,
                                    e.ExpressionToCSharpStringWithParameterSubstitution(d));
                            }
                            else
                            {
                                sb.AppendFormat(
                                    "output.{0}.col[index] = {1};\n",
                                    f.Name,
                                    e.ExpressionToCSharpStringWithParameterSubstitution(d));
                            }
                        }
                        sb.AppendLine("}");
                        return(sb.ToString());
                    };
                }
                #endregion

                template.staticCtor = Transformer.StaticCtor(template.className);
                var expandedCode = template.TransformText();

                var assemblyReferences = Transformer.AssemblyReferencesNeededFor(typeof(TKey), typeof(TLeft), typeof(TRight), typeof(TResult));
                assemblyReferences.Add(typeof(IStreamable <,>).GetTypeInfo().Assembly);
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TLeft>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TRight>());
                assemblyReferences.Add(Transformer.GeneratedStreamMessageAssembly <TKey, TResult>());
                assemblyReferences.Add(Transformer.GeneratedMemoryPoolAssembly <TKey, TResult>());
                assemblyReferences.AddRange(Transformer.AssemblyReferencesNeededFor(selector));

                var a             = Transformer.CompileSourceCode(expandedCode, assemblyReferences, out errorMessages);
                var realClassName = template.className.AddNumberOfNecessaryGenericArguments(keyType, leftType, rightType, resultType);
                var t             = a.GetType(realClassName);
                if (t.GetTypeInfo().IsGenericType)
                {
                    var list = keyType.GetAnonymousTypes();
                    list.AddRange(leftType.GetAnonymousTypes());
                    list.AddRange(rightType.GetAnonymousTypes());
                    list.AddRange(resultType.GetAnonymousTypes());
                    return(Tuple.Create(t.MakeGenericType(list.ToArray()), errorMessages));
                }
                else
                {
                    return(Tuple.Create(t, errorMessages));
                }
            }
            catch
            {
                if (Config.CodegenOptions.DontFallBackToRowBasedExecution)
                {
                    throw new InvalidOperationException("Code Generation failed when it wasn't supposed to!");
                }
                return(Tuple.Create((Type)null, errorMessages));
            }
        }