public static void ValidateCollectAggregate(AggregateElement element) { var sourceType = element.Source.ValueType; var resultType = element.ResultType; var expectedResultType = typeof(IEnumerable <>).MakeGenericType(sourceType); if (!expectedResultType.GetTypeInfo().IsAssignableFrom(resultType.GetTypeInfo())) { throw new ArgumentException( $"Collect result must be a collection of source elements. ElementType={sourceType}, ResultType={resultType}"); } var keySelectorsAscending = element.Expressions.Find(AggregateElement.KeySelectorAscendingName); var keySelectorsDescending = element.Expressions.Find(AggregateElement.KeySelectorDescendingName); foreach (var sortKeySelector in keySelectorsAscending.Concat(keySelectorsDescending).Select(x => x.Expression)) { if (sortKeySelector.Parameters.Count == 0) { throw new ArgumentException( $"Sort key selector must have at least one parameter. KeySelector={sortKeySelector}"); } if (sortKeySelector.Parameters[0].Type != sourceType) { throw new ArgumentException( "Sort key selector must have a parameter type that matches the aggregate source. " + $"KeySelector={sortKeySelector}, ExpectedType={sourceType}, ActualType={sortKeySelector.Parameters[0].Type}"); } } }
/// <summary> /// Creates an element that represents an aggregation of facts. /// </summary> /// <param name="resultType">Type of the aggregate result.</param> /// <param name="name">Aggregate name.</param> /// <param name="expressions">Expressions used to construct aggregates from individual facts.</param> /// <param name="source">Pattern that matches facts for aggregation.</param> /// <param name="customFactoryType">Factory type used construct aggregators for this aggregation.</param> /// <returns>Created element.</returns> public static AggregateElement Aggregate(Type resultType, string name, IEnumerable <NamedExpressionElement> expressions, PatternElement source, Type customFactoryType) { if (resultType == null) { throw new ArgumentNullException(nameof(resultType), "Aggregate result type not provided"); } if (string.IsNullOrEmpty(name)) { throw new ArgumentNullException(nameof(name), "Aggregate name not provided"); } if (expressions == null) { throw new ArgumentNullException(nameof(expressions), "Aggregate expressions not provided"); } if (source == null) { throw new ArgumentNullException(nameof(source), "Aggregate source pattern not provided"); } var expressionCollection = new ExpressionCollection(expressions); var element = new AggregateElement(resultType, name, expressionCollection, source, customFactoryType); ElementValidator.ValidateAggregate(element); return(element); }
protected internal virtual void VisitAggregate(TContext context, AggregateElement element) { if (element.Source != null) { element.Source.Accept(context, this); } }
/// <summary> /// Sets an aggregate element as the source of the pattern element. /// </summary> /// <param name="element">Element to set as the source.</param> public void Aggregate(AggregateElement element) { AssertSingleSource(); var builder = BuilderAdapter.Create(element); _sourceBuilder = builder; }
public static void ValidateFlattenAggregate(AggregateElement element) { var sourceType = element.Source.ValueType; var resultType = element.ResultType; var selector = element.Expressions[AggregateElement.SelectorName].Expression; if (selector.Parameters.Count != 1) { throw new ArgumentException( $"Flattening selector must have a single parameter. Selector={selector}"); } if (selector.Parameters[0].Type != sourceType) { throw new ArgumentException( "Flattening selector must have a parameter type that matches the aggregate source. " + $"Selector={selector}, ExpectedType={sourceType}, ActualType={selector.Parameters[0].Type}"); } var resultCollectionType = typeof(IEnumerable <>).MakeGenericType(resultType); if (!resultCollectionType.GetTypeInfo().IsAssignableFrom(selector.ReturnType.GetTypeInfo())) { throw new ArgumentException( "Flattening selector must produce a collection of values that are assignable to the aggregation result. " + $"Selector={selector}, ResultType={resultType}, SelectorReturnType={selector.ReturnType}"); } }
public void Compile(AggregateElement element, IEnumerable <IAggregateExpression> compiledExpressions) { var sourceType = element.Source.ValueType; var sortConditions = compiledExpressions .Where(x => x.Name == AggregateElement.KeySelectorAscendingName || x.Name == AggregateElement.KeySelectorDescendingName) .Select(x => new SortCondition(x.Name, GetSortDirection(x.Name), x)).ToArray(); if (sortConditions.Any()) { if (sortConditions.Length == 1) { var sortCondition = sortConditions[0]; var selectorElement = element.Expressions.FindSingleOrDefault(sortCondition.Name); _factory = CreateSingleKeySortedAggregatorFactory(sourceType, sortCondition.Direction, selectorElement, sortCondition.KeySelector); } else { _factory = CreateMultiKeySortedAggregatorFactory(sourceType, sortConditions); } } else { var aggregatorType = typeof(CollectionAggregator <>).MakeGenericType(sourceType); var factoryExpression = Expression.Lambda <Func <IAggregator> >( Expression.New(aggregatorType)); _factory = factoryExpression.Compile(); } }
protected internal virtual void VisitAggregate(TContext context, AggregateElement element) { foreach (var expression in element.ExpressionMap) { expression.Accept(context, this); } element.Source?.Accept(context, this); }
public void Compile(AggregateElement element, IDictionary <string, IAggregateExpression> compiledExpressions) { var sourceType = element.Source.ValueType; var aggregatorType = typeof(MimicCollectAggregator <>).MakeGenericType(sourceType); var factoryExpression = Expression.Lambda <Func <IAggregator> >(Expression.New(aggregatorType)); _factory = factoryExpression.Compile(); }
public void Compile(AggregateElement element, IEnumerable <IAggregateExpression> compiledExpressions) { var elementType = element.ResultType; var aggregatorType = typeof(CustomFirstAggregator <>).MakeGenericType(elementType); var factoryExpression = Expression.Lambda <Func <IAggregator> >(Expression.New(aggregatorType)); _factory = factoryExpression.Compile(); }
private static IAggregatorFactory GetCustomFactory(AggregateElement element) { if (element.CustomFactoryType == null) { throw new ArgumentException($"Custom aggregator does not have a factory. Name={element.Name}"); } var factory = (IAggregatorFactory)Activator.CreateInstance(element.CustomFactoryType); return(factory); }
protected internal override void VisitAggregate(Context context, AggregateElement element) { var source = Transform <PatternElement>(context, element.Source); if (context.IsModified) { var newElement = Element.Aggregate(element.ResultType, element.Name, element.Expressions, source, element.CustomFactoryType); Result(context, newElement); } }
protected internal override void VisitAggregate(Context context, AggregateElement element) { var source = Transform <PatternElement>(context, element.Source); if (context.IsModified) { var newElement = new AggregateElement(element.Declarations, element.ResultType, element.AggregateType, source); Result(context, newElement); } }
protected internal override void VisitAggregate(Context context, AggregateElement element) { var source = Transform <PatternElement>(context, element.Source); if (context.IsModified) { var aggregateExpressions = element.Expressions.Select(x => new KeyValuePair <string, LambdaExpression>(x.Name, x.Expression)); var newElement = Element.Aggregate(element.ResultType, element.Name, aggregateExpressions, source, element.CustomFactoryType); Result(context, newElement); } }
protected override void VisitAggregate(ReteBuilderContext context, AggregateElement element) { BuildSubnet(context, element.Source); var betaNode = new AggregateNode(context.BetaSource, context.AlphaSource, element.AggregateType); if (context.HasSubnet) { betaNode.Conditions.Add(new SubnetCondition()); } context.BetaSource = BuildBetaMemoryNode(context, betaNode); context.ResetAlphaSource(); }
public void Compile(AggregateElement element, IEnumerable <IAggregateExpression> compiledExpressions) { var sourceType = element.Source.ValueType; //Flatten selector is Source -> IEnumerable<Result> var resultType = element.ResultType; Type aggregatorType = typeof(FlatteningAggregator <,>).MakeGenericType(sourceType, resultType); var compiledSelector = compiledExpressions.FindSingle(AggregateElement.SelectorName); var ctor = aggregatorType.GetTypeInfo().DeclaredConstructors.Single(); var factoryExpression = Expression.Lambda <Func <IAggregator> >( Expression.New(ctor, Expression.Constant(compiledSelector))); _factory = factoryExpression.Compile(); }
public void Compile(AggregateElement element, IEnumerable <IAggregateExpression> compiledExpressions) { var selector = element.Expressions["Selector"]; var sourceType = element.Source.ValueType; var resultType = selector.Expression.ReturnType; var aggregatorType = typeof(CustomSelectAggregator <,>).MakeGenericType(sourceType, resultType); var compiledSelector = compiledExpressions.FindSingle("Selector"); var ctor = aggregatorType.GetConstructors().Single(); var factoryExpression = Expression.Lambda <Func <IAggregator> >( Expression.New(ctor, Expression.Constant(compiledSelector))); _factory = factoryExpression.Compile(); }
public void Compile(AggregateElement element, IDictionary <string, IAggregateExpression> compiledExpressions) { var selector = element.ExpressionMap["Selector"]; var sourceType = element.Source.ValueType; var resultType = selector.Expression.ReturnType; var aggregatorType = typeof(CustomSelectAggregator <,>).MakeGenericType(sourceType, resultType); var compiledSelector = compiledExpressions["Selector"]; var ctor = aggregatorType.GetTypeInfo().DeclaredConstructors.Single(); var factoryExpression = Expression.Lambda <Func <IAggregator> >( Expression.New(ctor, Expression.Constant(compiledSelector))); _factory = factoryExpression.Compile(); }
public void Compile(AggregateElement element, IEnumerable <IAggregateExpression> compiledExpressions) { var keySelector = element.Expressions[AggregateElement.KeySelectorName]; var elementSelector = element.Expressions[AggregateElement.ElementSelectorName]; var sourceType = element.Source.ValueType; var keyType = keySelector.Expression.ReturnType; var elementType = elementSelector.Expression.ReturnType; Type aggregatorType = typeof(GroupByAggregator <, ,>).MakeGenericType(sourceType, keyType, elementType); var compiledKeySelector = compiledExpressions.FindSingle(AggregateElement.KeySelectorName); var compiledElementSelector = compiledExpressions.FindSingle(AggregateElement.ElementSelectorName); var ctor = aggregatorType.GetTypeInfo().DeclaredConstructors.Single(); var factoryExpression = Expression.Lambda <Func <IAggregator> >( Expression.New(ctor, Expression.Constant(compiledKeySelector), Expression.Constant(compiledElementSelector))); _factory = factoryExpression.Compile(); }
private IAggregatorFactory GetCustomFactory(AggregateElement element) { Type factoryType = element.CustomFactoryType; if (factoryType == null) { factoryType = _aggregatorRegistry[element.Name]; } if (factoryType == null) { throw new ArgumentException($"Custom aggregator does not have a factory registered. Name={element.Name}"); } var factory = (IAggregatorFactory)Activator.CreateInstance(factoryType); return(factory); }
private void BuildAggregateNode(ReteBuilderContext context, AggregateElement element) { var node = context.AlphaSource .Sinks.OfType <AggregateNode>() .FirstOrDefault(x => x.RightSource == context.AlphaSource && x.LeftSource == context.BetaSource && x.Name == element.Name && ExpressionElementComparer.AreEqual(x.Expressions, element.Expressions)); if (node == null) { var aggregatorFactory = BuildAggregatorFactory(context, element); node = new AggregateNode(context.BetaSource, context.AlphaSource, element.Name, element.Expressions, aggregatorFactory, context.HasSubnet); } node.NodeInfo.Add(context.Rule, element); BuildBetaMemoryNode(context, node); context.ResetAlphaSource(); }
public static void ValidateGroupByAggregate(AggregateElement element) { var sourceType = element.Source.ValueType; var resultType = element.ResultType; var keySelector = element.Expressions[AggregateElement.KeySelectorName].Expression; if (keySelector.Parameters.Count == 0) { throw new ArgumentException( $"GroupBy key selector must have at least one parameter. KeySelector={keySelector}"); } if (keySelector.Parameters[0].Type != sourceType) { throw new ArgumentException( "GroupBy key selector must have a parameter type that matches the aggregate source. " + $"KeySelector={keySelector}, ExpectedType={sourceType}, ActualType={keySelector.Parameters[0].Type}"); } var elementSelector = element.Expressions[AggregateElement.ElementSelectorName].Expression; if (elementSelector.Parameters.Count == 0) { throw new ArgumentException( $"GroupBy element selector must have at least one parameter. ElementSelector={elementSelector}"); } if (elementSelector.Parameters[0].Type != sourceType) { throw new ArgumentException( "GroupBy element selector must have a parameter type that matches the aggregate source. " + $"ElementSelector={elementSelector}, ExpectedType={sourceType}, ActualType={elementSelector.Parameters[0].Type}"); } var groupType = typeof(IGrouping <,>).MakeGenericType(keySelector.ReturnType, elementSelector.ReturnType); if (!resultType.GetTypeInfo().IsAssignableFrom(groupType.GetTypeInfo())) { throw new ArgumentException( "GroupBy key/element selectors must produce a grouping assignable to the aggregation result. " + $"ElementSelector={elementSelector}, ResultType={resultType}, GroupingType={groupType}"); } }
public static void ValidateAggregate(AggregateElement element) { switch (element.Name) { case AggregateElement.CollectName: ValidateCollectAggregate(element); break; case AggregateElement.GroupByName: ValidateGroupByAggregate(element); break; case AggregateElement.ProjectName: ValidateProjectAggregate(element); break; case AggregateElement.FlattenName: ValidateFlattenAggregate(element); break; } }
private void BuildAggregateNode(ReteBuilderContext context, AggregateElement element) { var node = context.AlphaSource .Sinks.OfType <AggregateNode>() .FirstOrDefault(x => x.RightSource == context.AlphaSource && x.LeftSource == context.BetaSource && x.Name == element.Name && ExpressionMapComparer.AreEqual(x.ExpressionMap, element.ExpressionMap)); if (node == null) { node = new AggregateNode(context.BetaSource, context.AlphaSource, element.Name, element.ExpressionMap, element.AggregatorFactory); if (context.HasSubnet) { node.Conditions.Insert(0, new SubnetCondition()); } } BuildBetaMemoryNode(context, node); context.ResetAlphaSource(); }
public static void ValidateProjectAggregate(AggregateElement element) { var sourceType = element.Source.ValueType; var resultType = element.ResultType; var selector = element.Expressions[AggregateElement.SelectorName].Expression; if (selector.Parameters.Count == 0) { throw new ArgumentException( $"Projection selector must have at least one parameter. Selector={selector}"); } if (selector.Parameters[0].Type != sourceType) { throw new ArgumentException( "Projection selector must have its first parameter type that matches the aggregate source. " + $"Selector={selector}, ExpectedType={sourceType}, ActualType={selector.Parameters[0].Type}"); } if (!resultType.GetTypeInfo().IsAssignableFrom(selector.ReturnType.GetTypeInfo())) { throw new ArgumentException( "Projection selector must produce a value assignable to the aggregation result. " + $"Selector={selector}, ResultType={resultType}, SelectorReturnType={selector.ReturnType}"); } }
private IAggregatorFactory BuildAggregatorFactory(ReteBuilderContext context, AggregateElement element) { IAggregatorFactory factory; switch (element.Name) { case AggregateElement.CollectName: factory = new CollectionAggregatorFactory(); break; case AggregateElement.GroupByName: factory = new GroupByAggregatorFactory(); break; case AggregateElement.ProjectName: factory = new ProjectionAggregatorFactory(); break; case AggregateElement.FlattenName: factory = new FlatteningAggregatorFactory(); break; default: throw new ArgumentException( $"Unrecognized aggregate element. Name={element.Name}"); } var compiledExpressions = CompileExpressions(context, element); factory.Compile(element, compiledExpressions); return(factory); }
protected override void VisitAggregate(ReteBuilderContext context, AggregateElement element) { BuildSubnet(context, element.Source); BuildAggregateNode(context, element.AggregateType); }
private static Dictionary <string, IAggregateExpression> CompileExpressions(ReteBuilderContext context, AggregateElement element) { var declarations = context.Declarations.Concat(element.Source.Declaration).ToList(); var result = new Dictionary <string, IAggregateExpression>(); foreach (var expression in element.ExpressionMap) { var aggregateExpression = ExpressionCompiler.CompileAggregateExpression(expression, declarations); result[expression.Name] = aggregateExpression; } return(result); }
private IAggregatorFactory BuildAggregatorFactory(ReteBuilderContext context, AggregateElement element) { IAggregatorFactory factory; switch (element.Name) { case AggregateElement.CollectName: factory = new CollectionAggregatorFactory(); break; case AggregateElement.GroupByName: factory = new GroupByAggregatorFactory(); break; case AggregateElement.ProjectName: factory = new ProjectionAggregatorFactory(); break; case AggregateElement.FlattenName: factory = new FlatteningAggregatorFactory(); break; default: factory = GetCustomFactory(element); break; } var compiledExpressions = CompileExpressions(context, element); factory.Compile(element, compiledExpressions); return(factory); }
protected override void VisitAggregate(ReteBuilderContext context, AggregateElement element) { VisitSource(context, element, element.Source); BuildAggregateNode(context, element); }
private static IEnumerable <IAggregateExpression> CompileExpressions(ReteBuilderContext context, AggregateElement element) { var declarations = context.Declarations.Concat(element.Source.Declaration).ToList(); var result = new List <IAggregateExpression>(element.Expressions.Count); foreach (var expression in element.Expressions) { var aggregateExpression = ExpressionCompiler.CompileAggregateExpression(expression, declarations); result.Add(aggregateExpression); } return(result); }