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); }
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 ); }
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 )); }
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); }