示例#1
0
        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}");
                }
            }
        }
示例#2
0
        /// <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);
        }
示例#3
0
 protected internal virtual void VisitAggregate(TContext context, AggregateElement element)
 {
     if (element.Source != null)
     {
         element.Source.Accept(context, this);
     }
 }
示例#4
0
        /// <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;
        }
示例#5
0
        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();
            }
        }
示例#7
0
 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();
        }
示例#9
0
        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();
        }
示例#10
0
        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);
        }
示例#11
0
        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);
            }
        }
示例#12
0
        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);
            }
        }
示例#13
0
        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);
            }
        }
示例#14
0
        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();
        }
示例#16
0
        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();
        }
示例#17
0
        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();
        }
示例#18
0
        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();
        }
示例#19
0
        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);
        }
示例#20
0
        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();
        }
示例#21
0
        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}");
            }
        }
示例#22
0
        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;
            }
        }
示例#23
0
        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();
        }
示例#24
0
        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}");
            }
        }
示例#25
0
        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);
        }
示例#26
0
 protected override void VisitAggregate(ReteBuilderContext context, AggregateElement element)
 {
     BuildSubnet(context, element.Source);
     BuildAggregateNode(context, element.AggregateType);
 }
示例#27
0
        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);
        }
示例#28
0
        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);
        }
示例#29
0
 protected override void VisitAggregate(ReteBuilderContext context, AggregateElement element)
 {
     VisitSource(context, element, element.Source);
     BuildAggregateNode(context, element);
 }
示例#30
0
        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);
        }