protected virtual Expression BindGroupBy(Expression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
        {
            var projection = VisitSequence(source);

            _map[keySelector.Parameters[0]] = projection.Projector;
            var keyExpression = Visit(keySelector.Body);

            var elementExpression = projection.Projector;
            if (elementSelector != null)
            {
                _map[elementSelector.Parameters[0]] = projection.Projector;
                elementExpression = Visit(elementSelector.Body);
            }

            var subqueryBasis = VisitSequence(source);
            _map[keySelector.Parameters[0]] = subqueryBasis.Projector;
            var subqueryKeyExpression = Visit(keySelector.Body);

            var subqueryCorrelation = Expression.Equal(keyExpression, subqueryKeyExpression);

            var subqueryElementExpression = subqueryBasis.Projector;
            if (elementSelector != null)
            {
                _map[elementSelector.Parameters[0]] = subqueryBasis.Projector;
                subqueryElementExpression = Visit(elementSelector.Body);
            }

            var elementAlias = new Alias();
            var elementProjection = _projector.ProjectFields(subqueryElementExpression, elementAlias, subqueryBasis.Source.Alias);
            var elementSubquery =
                new ProjectionExpression(
                    new SelectExpression(elementAlias, elementProjection.Fields, subqueryBasis.Source, subqueryCorrelation),
                    elementProjection.Projector);

            var alias = new Alias();

            var info = new GroupByInfo(alias, elementExpression);
            _groupByMap[elementSubquery] = info;

            Expression resultExpression;
            if (resultSelector != null)
            {
                var saveGroupElement = _currentGroupElement;
                _currentGroupElement = elementSubquery;

                _map[resultSelector.Parameters[0]] = keyExpression;
                _map[resultSelector.Parameters[1]] = elementSubquery;
                resultExpression = Visit(resultSelector.Body);
                _currentGroupElement = saveGroupElement;
            }
            else
            {
                resultExpression = Expression.New(
                    typeof(Grouping<,>).MakeGenericType(keyExpression.Type, subqueryElementExpression.Type).GetConstructors()[0],
                    new[] { keyExpression, elementSubquery });
            }

            var fieldProjection = _projector.ProjectFields(resultExpression, alias, projection.Source.Alias);

            var projectedElementSubquery = ((NewExpression)fieldProjection.Projector).Arguments[1];
            _groupByMap[projectedElementSubquery] = info;

            return new ProjectionExpression(
                new SelectExpression(alias, new FieldDeclaration[0], projection.Source, null, null, keyExpression, false, null, null),
                fieldProjection.Projector);
        }
Example #2
0
			public bool Equals(GroupByInfo other)
			{
				if (ReferenceEquals(null, other)) return false;
				if (ReferenceEquals(this, other)) return true;
				return Equals(other.Prev, Prev) && Equals(other.Field, Field);
			}
        protected virtual Expression BindGroupBy(Expression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
        {
            ProjectionExpression projection = this.VisitSequence(source);

            this.map[keySelector.Parameters[0]] = projection.Projector;
            Expression keyExpr = this.Visit(keySelector.Body);

            Expression elemExpr = projection.Projector;
            if (elementSelector != null)
            {
                this.map[elementSelector.Parameters[0]] = projection.Projector;
                elemExpr = this.Visit(elementSelector.Body);
            }

            // Use ProjectColumns to get group-by expressions from key expression
            ProjectedColumns keyProjection = this.ProjectColumns(keyExpr, projection.Select.Alias, projection.Select.Alias);
            var groupExprs = keyProjection.Columns.Select(c => c.Expression).ToArray();

            // make duplicate of source query as basis of element subquery by visiting the source again
            ProjectionExpression subqueryBasis = this.VisitSequence(source);

            // recompute key columns for group expressions relative to subquery (need these for doing the correlation predicate)
            this.map[keySelector.Parameters[0]] = subqueryBasis.Projector;
            Expression subqueryKey = this.Visit(keySelector.Body);

            // use same projection trick to get group-by expressions based on subquery
            ProjectedColumns subqueryKeyPC = this.ProjectColumns(subqueryKey, subqueryBasis.Select.Alias, subqueryBasis.Select.Alias);
            var subqueryGroupExprs = subqueryKeyPC.Columns.Select(c => c.Expression).ToArray();
            Expression subqueryCorrelation = this.BuildPredicateWithNullsEqual(subqueryGroupExprs, groupExprs);

            // compute element based on duplicated subquery
            Expression subqueryElemExpr = subqueryBasis.Projector;
            if (elementSelector != null)
            {
                this.map[elementSelector.Parameters[0]] = subqueryBasis.Projector;
                subqueryElemExpr = this.Visit(elementSelector.Body);
            }

            // build subquery that projects the desired element
            var elementAlias = this.GetNextAlias();
            ProjectedColumns elementPC = this.ProjectColumns(subqueryElemExpr, elementAlias, subqueryBasis.Select.Alias);
            ProjectionExpression elementSubquery =
                new ProjectionExpression(
                    new SelectExpression(elementAlias, elementPC.Columns, subqueryBasis.Select, subqueryCorrelation),
                    elementPC.Projector
                    );

            var alias = this.GetNextAlias();

            // make it possible to tie aggregates back to this group-by
            GroupByInfo info = new GroupByInfo(alias, elemExpr);
            this.groupByMap.Add(elementSubquery, info);

            Expression resultExpr;
            if (resultSelector != null)
            {
                Expression saveGroupElement = this.currentGroupElement;
                this.currentGroupElement = elementSubquery;
                // compute result expression based on key & element-subquery
                this.map[resultSelector.Parameters[0]] = keyProjection.Projector;
                this.map[resultSelector.Parameters[1]] = elementSubquery;
                resultExpr = this.Visit(resultSelector.Body);
                this.currentGroupElement = saveGroupElement;
            }
            else
            {
                // result must be IGrouping<K,E>
                resultExpr =
                    Expression.New(
                        typeof(Grouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type).GetConstructors()[0],
                        new Expression[] { keyExpr, elementSubquery }
                        );

                resultExpr = Expression.Convert(resultExpr, typeof(IGrouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type));
            }

            ProjectedColumns pc = this.ProjectColumns(resultExpr, alias, projection.Select.Alias);

            // make it possible to tie aggregates back to this group-by
            NewExpression newResult = this.GetNewExpression(pc.Projector);
            if (newResult != null && newResult.Type.IsGenericType && newResult.Type.GetGenericTypeDefinition() == typeof(Grouping<,>))
            {
                Expression projectedElementSubquery = newResult.Arguments[1];
                this.groupByMap.Add(projectedElementSubquery, info);
            }

            return new ProjectionExpression(
                new SelectExpression(alias, pc.Columns, projection.Select, null, null, groupExprs),
                pc.Projector
                );
        }
Example #4
0
        protected virtual Expression BindGroupBy(Expression source, LambdaExpression keySelector,
                                                 LambdaExpression elementSelector, LambdaExpression resultSelector)
        {
            ProjectionExpression projection = VisitSequence(source);

            map[keySelector.Parameters[0]] = projection.Projector;
            Expression keyExpr = Visit(keySelector.Body);

            Expression elemExpr = projection.Projector;

            if (elementSelector != null)
            {
                map[elementSelector.Parameters[0]] = projection.Projector;
                elemExpr = Visit(elementSelector.Body);
            }

            // Use ProjectColumns to get group-by expressions from key expression
            ProjectedColumns         keyProjection = ProjectColumns(keyExpr, projection.Source.Alias, projection.Source.Alias);
            IEnumerable <Expression> groupExprs    = keyProjection.Columns.Select(c => c.Expression);

            // make duplicate of source query as basis of element subquery by visiting the source again
            ProjectionExpression subqueryBasis = VisitSequence(source);

            // recompute key columns for group expressions relative to subquery (need these for doing the correlation predicate)
            map[keySelector.Parameters[0]] = subqueryBasis.Projector;
            Expression subqueryKey = Visit(keySelector.Body);

            // use same projection trick to get group-by expressions based on subquery
            ProjectedColumns subqueryKeyPC = ProjectColumns(subqueryKey, subqueryBasis.Source.Alias,
                                                            subqueryBasis.Source.Alias);
            IEnumerable <Expression> subqueryGroupExprs = subqueryKeyPC.Columns.Select(c => c.Expression);
            Expression subqueryCorrelation = BuildPredicateWithNullsEqual(subqueryGroupExprs, groupExprs);

            // compute element based on duplicated subquery
            Expression subqueryElemExpr = subqueryBasis.Projector;

            if (elementSelector != null)
            {
                map[elementSelector.Parameters[0]] = subqueryBasis.Projector;
                subqueryElemExpr = Visit(elementSelector.Body);
            }

            // build subquery that projects the desired element
            var elementAlias = GetNextAlias();
            ProjectedColumns     elementPC       = ProjectColumns(subqueryElemExpr, elementAlias, subqueryBasis.Source.Alias);
            ProjectionExpression elementSubquery =
                new ProjectionExpression(
                    new SelectExpression(elementAlias, elementPC.Columns, subqueryBasis.Source, subqueryCorrelation),
                    elementPC.Projector
                    );

            var alias = GetNextAlias();

            // make it possible to tie aggregates back to this group-by
            GroupByInfo info = new GroupByInfo(alias, elemExpr);

            groupByMap.Add(elementSubquery, info);

            Expression resultExpr;

            if (resultSelector != null)
            {
                Expression saveGroupElement = currentGroupElement;
                currentGroupElement = elementSubquery;
                // compute result expression based on key and element-subquery
                map[resultSelector.Parameters[0]] = keyProjection.Projector;
                map[resultSelector.Parameters[1]] = elementSubquery;
                resultExpr          = Visit(resultSelector.Body);
                currentGroupElement = saveGroupElement;
            }
            else
            {
                // result must be IGrouping<K,E>
                resultExpr =
                    Expression.New(
                        typeof(Grouping <,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type).GetConstructors()[0],
                        new[] { keyExpr, elementSubquery }
                        );
            }

            ProjectedColumns pc = ProjectColumns(resultExpr, alias, projection.Source.Alias);

            // make it possible to tie aggregates back to this group-by
            Expression projectedElementSubquery = ((NewExpression)pc.Projector).Arguments[1];

            groupByMap.Add(projectedElementSubquery, info);

            return(new ProjectionExpression(
                       new SelectExpression(alias, pc.Columns, projection.Source, null, null, groupExprs),
                       pc.Projector
                       ));
        }
Example #5
0
        protected virtual Expression BindGroupBy(Expression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
        {
            var projection = VisitSequence(source);

            _map[keySelector.Parameters[0]] = projection.Projector;
            var keyExpression = Visit(keySelector.Body);

            var elementExpression = projection.Projector;

            if (elementSelector != null)
            {
                _map[elementSelector.Parameters[0]] = projection.Projector;
                elementExpression = Visit(elementSelector.Body);
            }

            var subqueryBasis = VisitSequence(source);

            _map[keySelector.Parameters[0]] = subqueryBasis.Projector;
            var subqueryKeyExpression = Visit(keySelector.Body);

            var subqueryCorrelation = Expression.Equal(keyExpression, subqueryKeyExpression);

            var subqueryElementExpression = subqueryBasis.Projector;

            if (elementSelector != null)
            {
                _map[elementSelector.Parameters[0]] = subqueryBasis.Projector;
                subqueryElementExpression           = Visit(elementSelector.Body);
            }

            var elementAlias      = new Alias();
            var elementProjection = _projector.ProjectFields(subqueryElementExpression, elementAlias, subqueryBasis.Source.Alias);
            var elementSubquery   =
                new ProjectionExpression(
                    new SelectExpression(elementAlias, elementProjection.Fields, subqueryBasis.Source, subqueryCorrelation),
                    elementProjection.Projector);

            var alias = new Alias();

            var info = new GroupByInfo(alias, elementExpression);

            _groupByMap[elementSubquery] = info;

            Expression resultExpression;

            if (resultSelector != null)
            {
                var saveGroupElement = _currentGroupElement;
                _currentGroupElement = elementSubquery;

                _map[resultSelector.Parameters[0]] = keyExpression;
                _map[resultSelector.Parameters[1]] = elementSubquery;
                resultExpression     = Visit(resultSelector.Body);
                _currentGroupElement = saveGroupElement;
            }
            else
            {
                resultExpression = Expression.New(
                    typeof(Grouping <,>).MakeGenericType(keyExpression.Type, subqueryElementExpression.Type).GetConstructors()[0],
                    new[] { keyExpression, elementSubquery });
            }

            var fieldProjection = _projector.ProjectFields(resultExpression, alias, projection.Source.Alias);

            var projectedElementSubquery = ((NewExpression)fieldProjection.Projector).Arguments[1];

            _groupByMap[projectedElementSubquery] = info;

            return(new ProjectionExpression(
                       new SelectExpression(alias, new FieldDeclaration[0], projection.Source, null, null, keyExpression, false, null, null),
                       fieldProjection.Projector));
        }
        internal Configuration BuildXmlConfiguration(IEnumerable <Type> cmdletTypeList, IList <string> warnings)
        {
            var viewList = new List <View>();

            foreach (var cmdletType in cmdletTypeList)
            {
                var attributes = cmdletType.GetCustomAttributes(
                    typeof(OutputTypeAttribute),
                    false);

                if (attributes.Length == 0)
                {
                    continue;
                }

                foreach (var attribute in attributes)
                {
                    var outputTypeAttrubute = (OutputTypeAttribute)attribute;
                    var psTypeNames         = outputTypeAttrubute.Type;

                    foreach (var psTypeName in psTypeNames)
                    {
                        if (_usedTypes.Contains(psTypeName.Name))
                        {
                            continue;
                        }
                        _usedTypes.Add(psTypeName.Name);

                        var psType = psTypeName.Type;

                        var         tableHeaders     = new List <TableColumnHeader>();
                        var         tableColumnItems = new List <TableColumnItem>();
                        var         listItems        = new List <ListItem>();
                        GroupByInfo groupByInfo      = null;

                        HandleMemberInfo(psType.GetProperties(), tableHeaders, tableColumnItems, listItems, ref groupByInfo, warnings);
                        HandleMemberInfo(psType.GetFields(), tableHeaders, tableColumnItems, listItems, ref groupByInfo, warnings);

                        if (tableHeaders.Count != 0)
                        {
                            var view = new View
                            {
                                Name           = psTypeName.Name,
                                ViewSelectedBy = new ViewSelectedBy
                                {
                                    TypeName = psTypeName.Name
                                },
                                TableControl = new TableControl
                                {
                                    TableHeaders    = tableHeaders.ToArray(),
                                    TableRowEntries = new[] {
                                        new TableRowEntry {
                                            TableColumnItems = tableColumnItems.ToArray()
                                        }
                                    }
                                }
                            };

                            if (groupByInfo != null && (groupByInfo.TargetView & ViewControl.Table) != ViewControl.None)
                            {
                                view.GroupBy = new GroupBy
                                {
                                    Label = groupByInfo.Label
                                };
                                if (groupByInfo.ScriptBlock != null)
                                {
                                    view.GroupBy.ScriptBlock = groupByInfo.ScriptBlock;
                                }
                                else
                                {
                                    view.GroupBy.PropertyName = groupByInfo.PropertyName;
                                }
                            }

                            viewList.Add(view);
                        }

                        if (listItems.Count != 0)
                        {
                            var view = new View
                            {
                                Name           = psTypeName.Name,
                                ViewSelectedBy = new ViewSelectedBy
                                {
                                    TypeName = psTypeName.Name
                                },
                                ListControl = new ListControl
                                {
                                    ListEntries = new[]
                                    {
                                        new ListEntry
                                        {
                                            ListItems = listItems.ToArray()
                                        }
                                    }
                                }
                            };

                            if (groupByInfo != null && (groupByInfo.TargetView & ViewControl.List) != ViewControl.None)
                            {
                                view.GroupBy = new GroupBy
                                {
                                    Label = groupByInfo.Label
                                };
                                if (groupByInfo.ScriptBlock != null)
                                {
                                    view.GroupBy.ScriptBlock = groupByInfo.ScriptBlock;
                                }
                                else
                                {
                                    view.GroupBy.PropertyName = groupByInfo.PropertyName;
                                }
                            }

                            viewList.Add(view);
                        }
                    }
                }
            }

            var configuration = new Configuration
            {
                ViewDefinitions = new ViewDefinitions
                {
                    Views = viewList.ToArray()
                }
            };

            return(configuration);
        }
        internal void HandleMemberInfo <T>(
            IEnumerable <T> memberInfoList,
            IList <TableColumnHeader> tableHeaders,
            IList <TableColumnItem> tableColumnItems,
            IList <ListItem> listItems,
            ref GroupByInfo groupByInfo,
            IList <string> warnings)
            where T : MemberInfo
        {
            var memeber = typeof(T) == typeof(PropertyInfo)
                ? "property"
                : "field";

            var memberInfoListFiltered = memberInfoList
                                         .Where(p => {
                if (!_onlyMarkedProperties)
                {
                    return(true);
                }
                var ps1XmlAttributes = Attribute.GetCustomAttributes(p, typeof(Ps1XmlAttribute));
                return(ps1XmlAttributes.Length > 0);
            })
                                         .ToList();

            if (memberInfoListFiltered.Count == 0)
            {
                return;
            }

            var columnHeadersWithPosition = new List <Tuple <TableColumnHeader, uint> >();
            var columnItemsWithPosition   = new List <Tuple <TableColumnItem, uint> >();
            var listItemsWithPosition     = new List <Tuple <ListItem, uint> >();

            // Tuple type assignment: output type name, base type name, property name
            // We track the base type to get a proper warning in case when duplication occurs in a base and derived classes.
            var dupTrackerGroupBy = new List <Tuple <string, string, string> >();

            // tuple type assignment: output type name, base type name, property name, position property value
            var dupTrackerPosition = new List <Tuple <string, string, string, uint> >();

            foreach (var memberInfo in memberInfoListFiltered)
            {
                if (_onlyMarkedProperties)
                {
                    var ps1XmlAttributes = Attribute.GetCustomAttributes(memberInfo, typeof(Ps1XmlAttribute));
                    foreach (var attribute in ps1XmlAttributes)
                    {
                        var ps1XmlAttribute = (Ps1XmlAttribute)attribute;
                        if (ps1XmlAttribute.GroupByThis)
                        {
                            dupTrackerGroupBy.Add(Tuple.Create(memberInfo.DeclaringType?.Name, memberInfo.DeclaringType?.BaseType?.Name, memberInfo.Name));

                            if (groupByInfo == null)
                            {
                                groupByInfo = new GroupByInfo
                                {
                                    Label        = ps1XmlAttribute.Label,
                                    ScriptBlock  = ps1XmlAttribute.ScriptBlock,
                                    PropertyName = memberInfo.Name,
                                    TargetView   = ps1XmlAttribute.Target,
                                };

                                continue;
                            }
                        }

                        var position = ps1XmlAttribute.Position;

                        if ((ps1XmlAttribute.Target & ViewControl.Table) != ViewControl.None)
                        {
                            uint?width             = ps1XmlAttribute.TableColumnWidth;
                            var  tableColumnHeader = new TableColumnHeader
                            {
                                Label = ps1XmlAttribute.Label ?? memberInfo.Name,
                                Width = width > 0 ? width : null,
                            };

                            var tableColumnItem = ps1XmlAttribute.ScriptBlock != null
                                ? new TableColumnItem
                            {
                                Alignment   = Alignment.Left,
                                ScriptBlock = ps1XmlAttribute.ScriptBlock,
                            }
                                : new TableColumnItem
                            {
                                Alignment    = Alignment.Left,
                                PropertyName = memberInfo.Name,
                            };

                            if (position == Ps1XmlConstants.DefaultPosition)
                            {
                                tableHeaders.Add(tableColumnHeader);
                                tableColumnItems.Add(tableColumnItem);
                            }
                            else
                            {
                                columnHeadersWithPosition.Add(Tuple.Create(tableColumnHeader, position));
                                columnItemsWithPosition.Add(Tuple.Create(tableColumnItem, position));
                                dupTrackerPosition.Add(Tuple.Create(memberInfo.DeclaringType?.Name, memberInfo.DeclaringType?.BaseType?.Name, memberInfo.Name, position));
                            }
                        }

                        if ((ps1XmlAttribute.Target & ViewControl.List) == ViewControl.None)
                        {
                            continue;
                        }

                        var listItem = (ps1XmlAttribute.ScriptBlock != null)
                            ? new ListItem
                        {
                            ScriptBlock = ps1XmlAttribute.ScriptBlock,
                        }
                            : new ListItem
                        {
                            PropertyName = memberInfo.Name
                        };

                        if (ps1XmlAttribute.Label != null)
                        {
                            listItem.Label = ps1XmlAttribute.Label;
                        }

                        if (position == Ps1XmlConstants.DefaultPosition)
                        {
                            listItems.Add(listItem);
                        }
                        else
                        {
                            listItemsWithPosition.Add(Tuple.Create(listItem, position));
                        }
                    }
                }
                else
                {
                    tableHeaders.Add(new TableColumnHeader
                    {
                        Label = memberInfo.Name
                    });

                    tableColumnItems.Add(new TableColumnItem
                    {
                        Alignment    = Alignment.Left,
                        PropertyName = memberInfo.Name
                    });

                    listItems.Add(new ListItem
                    {
                        PropertyName = memberInfo.Name
                    });
                }
            }

            // track duplicate
            if (dupTrackerGroupBy.Count > 1)
            {
                var warning = "Found a duplicate. GroupByThis is true for the following properties: ";

                foreach (var tuple in dupTrackerGroupBy)
                {
                    var outputTypeName = tuple.Item1;
                    var baseTypeName   = tuple.Item2;
                    var propName       = tuple.Item3;
                    warning = warning + "'" + propName + "' in the class " + outputTypeName + " : " + baseTypeName + "; ";
                }

                warnings.Add(warning);
            }

            var duplicates = dupTrackerPosition
                             .GroupBy(p => p.Item4)
                             .Where(g => g.Count() > 1)
                             .ToList();

            if (duplicates.Count > 0)
            {
                var warning = "Found a duplicate. ";
                foreach (var duplicate in duplicates)
                {
                    warning += $"Position value of {duplicate.Key} specified: ";
                    foreach (var tuple in duplicate)
                    {
                        var outputTypeName = tuple.Item1;
                        var baseTypeName   = tuple.Item2;
                        var propName       = tuple.Item3;
                        warning = warning + "'" + propName + "' in the class " + outputTypeName + " : " + baseTypeName + "; ";
                    }
                }

                warnings.Add(warning);
            }

            Merge(tableHeaders, columnHeadersWithPosition);
            Merge(tableColumnItems, columnItemsWithPosition);
            Merge(listItems, listItemsWithPosition);
        }