private static string GetTargetPath(DimensionExpression g) { if (string.IsNullOrWhiteSpace(g.Target)) { if (g.Child != null) { var childAsSelector = g.Child as SelectorExpression; if (childAsSelector != null) { var childTargePath = GetTargetPath(childAsSelector); return(childTargePath); } else { throw new Exception("Child does not provide an alias"); } } else { if (g.Source != null) { return(g.Source); } if (g.Function != null) { return("_" + g.Function); } } } return(g.Target); }
private static Type GetTargetTypeForGroupByDimension(Type itemType, DimensionExpression g) { Type memberType = null; if (g.Source != null) { var member = GetMember(itemType, g.Source); memberType = GetMemberType(member); if (memberType == typeof(DateTime)) { memberType = typeof(long); } if (IsCollectionType(memberType)) { memberType = GetTypeOfEnumerable(memberType); } } else if (g.IsFunctionCall) { var methodInfo = typeof(UtilityExtensions).GetMethods().Where(x => string.Equals(x.Name, g.Function, StringComparison.InvariantCultureIgnoreCase)).FirstOrDefault(); memberType = methodInfo.ReturnType; } else if (g.Child != null) { var childExpr = g.Child.CreateExpression(null); memberType = childExpr.Type; } else { throw new Exception("Not able to infer the return type of " + g); } return(memberType); }
public void RemoveArgument(DimensionExpression dim) { if (Dimensions.Contains(dim)) { Dimensions.Remove(dim); } }
internal void CopyFrom(DimensionExpression s) { this.Function = s.Function; this.Target = s.Target; this.SetChild(s.Child); this.AddArguments(s.Arguments); }
private static Expression MakeWhereExpression(Expression filter, Expression collectionParameter, DimensionExpression[] groupBy, Type itemType) { List<Expression> filters = new List<Expression>(); var elementType = GetTypeOfEnumerable(collectionParameter.Type); var genericWhereInfo = typeof(Enumerable).GetMethods().FirstOrDefault(x => x.Name == "Where" && x.IsGenericMethod && x.GetParameters().Length == 2); var whereInfo = genericWhereInfo.MakeGenericMethod(elementType); var mentionParameter = Expression.Parameter(type: elementType, name: GenerateParamName(elementType)); if (groupBy != null) { var collectionFields = groupBy.Where(x => x.Source != null).Select(x => new { x.Source, Member = GetMember(itemType, x.Source) }); collectionFields = collectionFields.Where(x => TypeImplements(GetMemberType(x.Member), typeof(IEnumerable<>))); var count = collectionFields.Count(); if (count == 0 && filter == null) return collectionParameter; filters.AddRange(collectionFields.Select ( x => Expression.ReferenceNotEqual ( left: Expression.MakeMemberAccess(mentionParameter, x.Member), right: Expression.Constant(null) ) ).Cast<Expression>()); } if (filter != null) filters.Add(ParameterRebinder.ReplaceParameters(filter, "x", mentionParameter)); if (!filters.Any()) return collectionParameter; Expression sourceCollection = collectionParameter; sourceCollection = AppendAsParallel(typeof(ParallelEnumerable), collectionParameter); var whereBody = ChainAndExpressionCollection(filters); var result = Expression.Call ( method: whereInfo, arguments: new Expression[] { sourceCollection, Expression.Lambda ( delegateType: typeof(Func<,>).MakeGenericType(elementType, typeof(bool)), parameters: mentionParameter, body: whereBody ) } ); //collectionParameter = Expression.Parameter(type: result.Type, name: "c"); return result; }
private static void LinkDimensions(DimensionExpression[] groupBy, DimensionExpression[] selects) { if (groupBy == null || selects == null) return; foreach (var select in selects.Where(x => !x.IsStar && !string.Equals(x.Function, CountAggregateString, StringComparison.InvariantCultureIgnoreCase))) { string targetPath = GetTargetPath(select); var matchingGroupByFieldReverse = groupBy.FirstOrDefault(x => string.Equals(targetPath, GetSourcePath(x), StringComparison.InvariantCultureIgnoreCase)); if (matchingGroupByFieldReverse != null) { matchingGroupByFieldReverse.Target = select.Target; matchingGroupByFieldReverse.Source = select.Source; select.IsBasedOnGrouping = true; matchingGroupByFieldReverse.IsAutoSelect = true; matchingGroupByFieldReverse.LinkedSelect = select; select.LinkedGroupBy = matchingGroupByFieldReverse; select.IsLinkReversed = true; matchingGroupByFieldReverse.IsLinkReversed = true; continue; } if (select.Source != null) { //find a matching field in the grouping parameters var matchingGroupByField = groupBy.FirstOrDefault(x => string.Equals(GetTargetPath(x), select.Source, StringComparison.InvariantCultureIgnoreCase)); if (matchingGroupByField != null) { matchingGroupByField.IsAutoSelect = true; matchingGroupByField.LinkedSelect = select; select.LinkedGroupBy = matchingGroupByField; select.IsBasedOnGrouping = true; continue; } } } foreach (var select in selects) { if (select.IsStar) { foreach (var g in groupBy) { g.IsAutoSelect = true; } } } }
private static Expression MakeConvertExpression(DimensionExpression currentDimension, Type itemType, ParameterExpression keySelectorParameter, string targetType = null) { if (currentDimension.Arguments.Count != 2 && targetType == null) { throw new BermudaExpressionGenerationException("Convert function requires 2 arguments"); } if (currentDimension.Arguments.Count != 1 && targetType != null) { throw new BermudaExpressionGenerationException("Cast function requires 1 argument"); } string lowerType; if (targetType == null) { targetType = currentDimension.Arguments[1].ToString(); lowerType = targetType.ToLower(); } else { lowerType = targetType.ToLower(); } var firstArg = currentDimension.Arguments.FirstOrDefault(); Expression firstArgExpr = MakeDimensionExpression(itemType, keySelectorParameter, firstArg); Type conversionTargetType = null; switch (lowerType) { case "sql_bigint": conversionTargetType = typeof(long); break; case "integer": conversionTargetType = typeof(int); break; case "date": conversionTargetType = typeof(DateTime); break; default: throw new BermudaExpressionGenerationException("Unknown target type: " + targetType); } if (conversionTargetType == firstArgExpr.Type) { return(firstArgExpr); } var convexpr = Expression.Convert(firstArgExpr, conversionTargetType); return(convexpr); //throw new BermudaExpressionGenerationException("Invalid cast arguments: " + firstArg + " to " + targetType); }
private static string GetSourcePath(DimensionExpression x) { var dimensionChild = x.Child as SelectorExpression; if(dimensionChild != null) { var dimChild = dimensionChild.Child as DimensionExpression; if (dimChild != null) { var result = GetSourcePath(dimChild); return result; } } return x.Source; }
internal void RemoveSelect(DimensionExpression selLol) { if (selLol == null) { return; } else if (_selects.Contains(selLol)) { _selects.Remove(selLol); } else { throw new Exception("Could not remove select from clause"); } }
private static string GetSourcePath(DimensionExpression x) { var dimensionChild = x.Child as SelectorExpression; if (dimensionChild != null) { var dimChild = dimensionChild.Child as DimensionExpression; if (dimChild != null) { var result = GetSourcePath(dimChild); return(result); } } return(x.Source); }
public static Expression AppendCropping(Expression source, DimensionExpression[] selects, DimensionExpression[] groupBy, Type elementType) { //listlol.GroupBy(x => x.OccurredOn).Take(5).SelectMany(x => x).GroupBy(x => x.Name).Take(5).SelectMany(x => x); var genericGroupByInfos = typeof(ParallelEnumerable).GetMethods().Where(x => x.Name == "GroupBy" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericGroupByInfo = genericGroupByInfos.FirstOrDefault(); var groupByInfo = genericGroupByInfo.MakeGenericMethod(elementType, elementType); var genericTakeInfos = typeof(ParallelEnumerable).GetMethods().Where(x => x.Name == "Take" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericTakeInfo = genericTakeInfos.FirstOrDefault(); var takeInfo = genericTakeInfo.MakeGenericMethod(elementType, elementType); List<MemberBinding> memberBindings = new List<MemberBinding>(); var fields = elementType.GetFields(); //var valueField = fields.FirstOrDefault(x => !groupBy.Any(g => string.Equals(GetTargetPath(g), x.Name, StringComparison.InvariantCultureIgnoreCase))); foreach (var g in groupBy) { if (g.Take.HasValue) { var targetPath = GetTargetPath(g); var targetMember = GetMember(elementType, targetPath); var iParam = Expression.Parameter( elementType, "i" ); var memberAccess = Expression.MakeMemberAccess(iParam, targetMember); var lambda = Expression.Lambda(memberAccess, iParam); var groupByCall = Expression.Call ( method: groupByInfo, arg0: source, arg1: lambda ); } } return null; }
public static Type InferClrType(DimensionExpression[] selects, DimensionExpression[] groupBy, Type itemType) { if (selects == null || !selects.Any()) return itemType; var containsAggregates = selects.Any(x => x.IsAggregate); Dictionary<string, Type> requiredFields = null; if (groupBy != null || containsAggregates) { requiredFields = InferReduceType(selects, groupBy, itemType); } else { requiredFields = InferSelectType(selects, itemType); } var type = LinqRuntimeTypeBuilder.GetDynamicType(requiredFields); return type; }
public static Expression GetMapreduceExpression(Expression filter, DimensionExpression[] selects, DimensionExpression[] groupBy, Type itemType, GetExpression get, Expression source, string paramname) { var hash = (filter == null ? 0 : filter.ToString().GetHashCode()) + "|" + (selects == null ? "" : string.Join(",", selects.Select(x => x.GetChecksum()))) + "|" + (groupBy == null ? "" : string.Join(",", groupBy.Select(x => x.GetChecksum()))) + "|" + (get == null ? null : get.Take); Expression expr; var containsAggregates = selects != null && selects.Any(x => x.IsAggregate); LinkDimensions(groupBy, selects); var resultType = InferClrType(selects, groupBy, itemType); if (expressionCache.TryGetValue(hash, out expr)) { return(expr); } //a flat select transformation if (selects != null && groupBy == null && !containsAggregates) { expr = MakeSelectExpression(filter, selects, itemType, resultType, get, source, paramname); } else { //a non-grouping aggregate like "SELECT COUNT(*) FROM table" if (groupBy == null || !groupBy.Any()) { groupBy = new DimensionExpression[] { new DimensionExpression { Source = null, Function = null } } } ; expr = MakeMapreduceExpression(filter, selects, groupBy, itemType, resultType, get, source, paramname); } expressionCache[hash] = expr; return(expr); }
internal void RemoveSelect(DimensionExpression selLol) { if(selLol == null) return; else if (_selects.Contains(selLol)) _selects.Remove(selLol); else throw new Exception("Could not remove select from clause"); }
private static Expression MakeGroupByExpressionEx(Expression collectionParameter, DimensionExpression[] groupBy, DimensionExpression[] selects, int depth, Type itemType, Type metadataType, Type groupingType, Type resultType) { var linqExtensionClassType = !groupBy.Any(x => x.ParallelizedLinq) ? PLinqExtensionClassType : LinqExtensionClassType; var linqEnumType = linqExtensionClassType == PLinqExtensionClassType ? PLinqEnumType : LinqEnumType; var remDepth = groupBy.Skip(depth).Count(); var currentDimension = groupBy.ElementAt(depth); var currentGroupBy = currentDimension.Source; var currentFunction = currentDimension.Function; var currentChild = currentDimension.Child; if (currentDimension.LinkedSelect != null) { currentFunction = currentDimension.LinkedSelect.Function; } if (currentGroupBy == null && currentFunction == null && currentChild == null) { if (remDepth > 1) { var newCollectionParameter = Expression.Parameter(type: typeof(EnumMetadata <>).MakeGenericType(linqEnumType.MakeGenericType(itemType)), name: MakeNumericName("gmd", depth + 1)); groupBy.ElementAt(depth + 1).GroupingEnumParameter = newCollectionParameter; return(MakeGroupByExpressionEx(collectionParameter, groupBy, selects, depth + 1, itemType, metadataType, groupingType, resultType)); } } var sourceCollection = collectionParameter.Type.GetGenericTypeDefinition() == typeof(EnumMetadata <>) ? Expression.MakeMemberAccess(collectionParameter, collectionParameter.Type.GetField("Enum")) : collectionParameter; if (linqEnumType == PLinqEnumType && !TypeImplements(GetTypeOfEnumerable(sourceCollection.Type), PLinqEnumType)) { //.AsParallel() var res = AppendAsParallel(linqExtensionClassType, sourceCollection); groupBy.ElementAt(depth).ParallelizedLinq = true; sourceCollection = res; } var elementType = GetTypeOfEnumerable(sourceCollection.Type); var selectType = resultType; Expression groupByExpr = null; DimensionExpression sortValueType = null; MemberInfo groupByMember; Expression currentChildExpression = null; if (currentChild != null) { currentChildExpression = currentChild.CreateExpression(null); } if (currentGroupBy == null && currentFunction == null && currentChild == null) { groupByExpr = Expression.NewArrayInit(sourceCollection.Type, sourceCollection); } else if ((groupByMember = GetMember(itemType, currentGroupBy)) != null && TypeImplements(GetMemberType(groupByMember), typeof(IEnumerable <>)) || (currentChildExpression != null && TypeImplements(currentChildExpression.Type, typeof(IEnumerable <>)))) { //.SelectMany(m => m.Ngrams, (m, t) => new MentionMetadata { Mention = m, Id = t }) var genericSelectManyInfos = linqExtensionClassType.GetMethods().Where(x => x.Name == "SelectMany" && x.IsGenericMethod && x.GetParameters().Length == 3); var extensionIndex = (linqExtensionClassType == typeof(ParallelEnumerable)) ? 0 : 1; var genericSelectManyInfo = genericSelectManyInfos.Skip(extensionIndex).FirstOrDefault(); var collectionSelectorParameter = Expression.Parameter(type: elementType, name: GenerateParamName(elementType, depth)); var sourcePath = GetSourcePath(currentDimension); var collectionGroupingMemberAccess = Expression.MakeMemberAccess(collectionSelectorParameter, GetField(collectionSelectorParameter.Type, sourcePath)); var collectionSelector = Expression.Lambda ( delegateType: typeof(Func <,>).MakeGenericType(elementType, collectionGroupingMemberAccess.Type), parameters: collectionSelectorParameter, body: collectionGroupingMemberAccess ); var keyType = GetTypeOfEnumerable(collectionGroupingMemberAccess.Type); var selectManyInfo = genericSelectManyInfo.MakeGenericMethod(elementType, keyType, metadataType); var resultSelectorParameters = new ParameterExpression[] { Expression.Parameter(type: elementType, name: GenerateParamName(elementType, depth)), Expression.Parameter(type: keyType, name: GenerateParamName(keyType, depth)) }; var memberBindings = new List <MemberBinding> { Expression.Bind ( member: metadataType.GetField("Item"), expression: resultSelectorParameters[0] ) }; string groupByTargetPath = GetTargetPath(keyType); var targetField = GetField(metadataType, groupByTargetPath); Expression sourceExpression = resultSelectorParameters[1]; if (IsTupleType(sourceExpression.Type)) { var sourceItemInfo = sourceExpression.Type.GetProperty("Item2"); sourceExpression = Expression.MakeMemberAccess ( expression: sourceExpression, member: sourceItemInfo ); } memberBindings.Add(Expression.Bind ( member: targetField, expression: sourceExpression )); var resultSelector = Expression.Lambda ( delegateType: typeof(Func <, ,>).MakeGenericType(elementType, keyType, metadataType), parameters: resultSelectorParameters, body: Expression.MemberInit ( newExpression: Expression.New(type: metadataType), bindings: memberBindings ) ); var selectManyExpr = Expression.Call ( method: selectManyInfo, arguments: new Expression[] { sourceCollection, collectionSelector, resultSelector } ); //.GroupBy(md => md.Id, md => md.Mention) var keySelectorParameter = Expression.Parameter(type: metadataType, name: "md"); var resultSelectorParameter = Expression.Parameter(type: metadataType, name: "md"); var keySelectorBody = Expression.MakeMemberAccess(expression: keySelectorParameter, member: GetField(metadataType, groupByTargetPath)); var resultSelectorBody = Expression.MakeMemberAccess(expression: resultSelectorParameter, member: metadataType.GetField("Item")); var genericGroupByInfos = linqExtensionClassType.GetMethods().Where(x => x.Name == "GroupBy" && x.IsGenericMethod && x.GetParameters().Length == 3); var genericGroupByInfo = genericGroupByInfos.ElementAt(1); var groupByInfo = genericGroupByInfo.MakeGenericMethod(metadataType, keySelectorBody.Type, resultSelectorBody.Type); var keySelectorLambda = Expression.Lambda ( delegateType: typeof(Func <,>).MakeGenericType(metadataType, keySelectorBody.Type), parameters: keySelectorParameter, body: keySelectorBody ); var resultSelectorLambda = Expression.Lambda ( delegateType: typeof(Func <,>).MakeGenericType(metadataType, resultSelectorBody.Type), parameters: resultSelectorParameter, body: resultSelectorBody ); groupByExpr = Expression.Call ( method: groupByInfo, arguments: new Expression[] { selectManyExpr, keySelectorLambda, resultSelectorLambda } ); } else { //.GroupBy(m => m.OccurredOn.Ticks - 28189283) var keySelectorParameter = Expression.Parameter(type: itemType, name: "m"); Expression keySelectorBody = null; if (currentFunction != null) { keySelectorBody = MakeFunctionCallExpression(currentDimension, itemType, keySelectorParameter); } else if (currentGroupBy != null) { var sourcePath = GetSourcePath(currentDimension); var targetMember = GetMember(itemType, sourcePath); keySelectorBody = Expression.MakeMemberAccess(expression: keySelectorParameter, member: targetMember); } else if (currentChild != null) { keySelectorBody = currentChild.CreateExpression(null); } else { throw new BermudaExpressionGenerationException("Don't know how to handle for group by:" + currentDimension); } var genericGroupByInfos = linqExtensionClassType.GetMethods().Where(x => x.Name == "GroupBy" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericGroupByInfo = genericGroupByInfos.FirstOrDefault(); var groupByInfo = genericGroupByInfo.MakeGenericMethod(elementType, keySelectorBody.Type); keySelectorBody = ParameterRebinder.ReplaceParameters(keySelectorBody, "x", keySelectorParameter); var groupByLambda = Expression.Lambda ( delegateType: typeof(Func <,>).MakeGenericType(elementType, keySelectorBody.Type), parameters: keySelectorParameter, body: keySelectorBody ); groupByExpr = Expression.Call ( method: groupByInfo, arguments: new Expression[] { sourceCollection, groupByLambda } ); } var inferredParameterType = typeof(EnumMetadata <>).MakeGenericType(GetTypeOfEnumerable(groupByExpr.Type)); var groupingParameter = Expression.Parameter(type: inferredParameterType, name: MakeNumericName("gmd", depth)); if (groupBy.Length > depth) { groupBy.ElementAt(depth).GroupingEnumParameter = groupingParameter; } //var loldas = temp == groupBy.ElementAt(depth); var enumType = GetTypeOfEnumerable(groupByExpr.Type); var enumMetadataType = typeof(EnumMetadata <>).MakeGenericType(enumType); //.AsParallel() //var genericAsParallelInfo = typeof(ParallelEnumerable).GetMethods().FirstOrDefault(x => x.Name == "AsParallel" && x.IsGenericMethod && x.GetParameters().Length == 1); //var asParallelInfo0 = genericAsParallelInfo.MakeGenericMethod(enumType); //groupByExpr = Expression.Call(method: asParallelInfo0, arg0: groupByExpr); //.Select(g => new GroupMetadata { Group = g, Value = g.Whatever() }) var selectLinqClass = groupByExpr.Type.IsArray ? LinqExtensionClassType : linqExtensionClassType; var genericSelectInfos = selectLinqClass.GetMethods().Where(x => x.Name == "Select" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericSelectInfo = genericSelectInfos.FirstOrDefault(); var selectInfo0 = genericSelectInfo.MakeGenericMethod(enumType, enumMetadataType); var selectGroupParam = Expression.Parameter(type: enumType, name: "g"); var selectGroupMemberBindings = new List <MemberBinding>(); //Group = g, Value selectGroupMemberBindings.Add(Expression.Bind(member: enumMetadataType.GetField("Enum"), expression: selectGroupParam)); //Value = g.Whatever() if (currentDimension != null && currentDimension.Ordering != null && currentDimension.Ordering.Function != null) { sortValueType = currentDimension.Ordering; if (sortValueType != null) { selectGroupMemberBindings.Add(MakeAggregateFunctionCallExpression(selectGroupParam, sortValueType, null, 0, enumMetadataType, "Value")); } } // = new GroupMetadata{} var selectInit = Expression.MemberInit ( newExpression: Expression.New(type: enumMetadataType), bindings: selectGroupMemberBindings ); var selectMetadataLambda = Expression.Lambda ( parameters: selectGroupParam, body: selectInit ); //.Select(...) var selectExpr = Expression.Call ( method: selectInfo0, arg0: groupByExpr, arg1: selectMetadataLambda ); Expression selectSourceExpression = selectExpr; //.OrderByDescending(g => g.Value) if (currentDimension != null && currentDimension.Ordering != null && (currentDimension.Ordering.Function != null || currentDimension.Ordering.Source != null)) { var orderFuncName = currentDimension.OrderDescending ? "OrderByDescending" : "OrderBy"; var genericOrderByInfo = linqExtensionClassType.GetMethods().FirstOrDefault(x => x.Name == orderFuncName && x.IsGenericMethod && x.GetParameters().Length == 2); var orderByInfo = genericOrderByInfo.MakeGenericMethod(enumMetadataType, typeof(long)); var groupOrderParam = Expression.Parameter(type: enumMetadataType, name: "gg"); var orderByExpr = Expression.Call ( method: orderByInfo, arg0: selectExpr, arg1: Expression.Lambda(parameters: groupOrderParam, body: Expression.MakeMemberAccess(expression: groupOrderParam, member: enumMetadataType.GetField("Value"))) ); selectSourceExpression = orderByExpr; } //.Take(5) if (currentDimension.Take.HasValue) { selectSourceExpression = AppendTake(linqExtensionClassType, enumMetadataType, selectSourceExpression, currentDimension.Take.Value); } if (remDepth <= 1) { //if (currentGroupBy == GroupByTypes.None) return collectionParameter; //.Select(gmd2 => new InferredType { Id = gmd.Group.Key, Id2 = gmd2.Group.Key, TargetPath = gmd2.SourcePath }) var selectParameterType = GetTypeOfEnumerable(selectSourceExpression.Type); var selectInfo = genericSelectInfo.MakeGenericMethod(selectParameterType, resultType); var selectMemberBindings = new List <MemberAssignment>(); //gmd2 var parentGroupBy = groupBy.ElementAt(depth); var parentGroupParameter = parentGroupBy.GroupingEnumParameter; //gmd.Group var actualGroupAccess = Expression.MakeMemberAccess(parentGroupParameter, parentGroupParameter.Type.GetField("Enum")); //gmd.Value var groupValueAccess = Expression.MakeMemberAccess(parentGroupParameter, parentGroupParameter.Type.GetField("Value")); var lastGroupBy = groupBy.LastOrDefault(); var computedValueForGroup = lastGroupBy.Ordering; // lastGroupBy.IsDateTime ? null : lastGroupBy.OrderBy; var countSelect = selects.FirstOrDefault(x => string.Equals(x.Function, CountAggregateString, StringComparison.InvariantCultureIgnoreCase)); if (countSelect != null) { //CountAlias = var countBinding = MakeAggregateFunctionCallExpression(actualGroupAccess, new DimensionExpression { Function = CountAggregateString, Target = GetTargetPath(countSelect) }, computedValueForGroup != null && computedValueForGroup.Function == CountAggregateString ? groupValueAccess : null, 0, resultType, null); selectMemberBindings.Add(countBinding); } else if (selects.Any(x => IsCountRequiredForAggregate(x.Function))) { //_Count = var countBinding = MakeAggregateFunctionCallExpression(actualGroupAccess, new DimensionExpression { Function = CountAggregateString, Target = CountTargetPath }, computedValueForGroup != null && computedValueForGroup.Function == CountAggregateString ? groupValueAccess : null, 0, resultType, null); selectMemberBindings.Add(countBinding); } //Value = foreach (var select in selects.Where(x => !x.IsStar && !string.Equals(x.Function, CountAggregateString, StringComparison.InvariantCultureIgnoreCase))) { if (select.IsBasedOnGrouping) { continue; } if (select.IsFunctionCall) { var otherBinding = MakeAggregateFunctionCallExpression(actualGroupAccess, select, computedValueForGroup != null && computedValueForGroup.Equals(select) ? groupValueAccess : null, 0, resultType, null); //it's not an aggregate... that's a problem if (otherBinding == null) { throw new BermudaExpressionGenerationException("Non aggregate function call in an aggregate query not allowed: " + select); } selectMemberBindings.Add(otherBinding); } else { var targetPath = GetTargetPath(select); //var sourceField = GetMember(itemType, select.Source, false); var targetFieldInfo = GetField(resultType, targetPath); var actualValue = Convert.ChangeType(select.Source, select.SourceType); selectMemberBindings.Add(Expression.Bind ( targetFieldInfo, Expression.Constant(actualValue) )); } } //Id = gmd.Group.Key, Id2 = gmd2.Group.Key AddStarSelectColumns(groupBy, selects, resultType, selectMemberBindings); //gmd => new Datapoint{...} var selectLambda = Expression.Lambda ( parameters: parentGroupParameter, body: Expression.MemberInit ( newExpression: Expression.New(type: resultType), bindings: selectMemberBindings ) ); //.Select(...) var result = Expression.Call ( method: selectInfo, arg0: selectSourceExpression, arg1: selectLambda ); return(result); } else if (remDepth >= 2) { //var newCollectionParameter = Expression.Parameter(type: enumMetadataType, name: MakeNumericName("gmd", depth + 1)); //groupBy.ElementAt(depth).GroupingEnumParameter = newCollectionParameter; var currentParameter = groupBy.ElementAt(depth).GroupingEnumParameter; var nestedExpression = MakeGroupByExpressionEx(currentParameter, groupBy, selects, depth + 1, itemType, metadataType, groupingType, resultType); var nestedExpressionLambda = Expression.Lambda ( parameters: currentParameter, body: nestedExpression ); //.SelectMany(gmd => Recurse()) var sourceElementType = GetTypeOfEnumerable(selectSourceExpression.Type); var genericSelectManyInfos = linqExtensionClassType.GetMethods().Where(x => x.Name == "SelectMany" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericSelectManyInfo = genericSelectManyInfos.Skip(0).FirstOrDefault(); var selectManyInfo = genericSelectManyInfo.MakeGenericMethod(sourceElementType, selectType); var selectManyRecursiveExpr = Expression.Call ( method: selectManyInfo, arg0: selectSourceExpression, arg1: nestedExpressionLambda ); return(selectManyRecursiveExpr); } throw new Exception("not supposed to happen"); }
private static Expression MakeDimensionExpression(Type itemType, ParameterExpression keySelectorParameter, DimensionExpression firstArg) { Expression firstArgExpr; bool dontNegate = false; if (firstArg.Child != null) { dontNegate = true; firstArgExpr = firstArg.CreateExpression(null); } else if (firstArg.Function != null) { firstArgExpr = MakeFunctionCallExpression(firstArg, itemType, keySelectorParameter); } else { var sourcePath = firstArg.Source; var member = GetMember(itemType, sourcePath, false); if (member == null) { var stringVersion = firstArg.Source; long num; double num2; if (long.TryParse(stringVersion, out num)) return Expression.Constant( num ); if (double.TryParse(stringVersion, out num2)) return Expression.Constant(num2); firstArgExpr = Expression.Constant(stringVersion); } else { firstArgExpr = Expression.MakeMemberAccess(keySelectorParameter, member); } } if (!dontNegate) { if (firstArg.IsNegated) { firstArgExpr = Expression.Negate(firstArgExpr); } else if (firstArg.IsNotted) { firstArgExpr = Expression.Not(firstArgExpr); } } return firstArgExpr; }
public static Expression MakeFunctionCallExpression(DimensionExpression currentDimension, Type itemType, ParameterExpression keySelectorParameter) { //var functionName = currentDimension.Function ?? currentDimension.LinkedSelect.Function; if (currentDimension.Function == null && currentDimension.LinkedSelect != null) currentDimension = currentDimension.LinkedSelect; if ( string.Equals(currentDimension.Function, "convert", StringComparison.InvariantCultureIgnoreCase) ) { if (currentDimension.Arguments.Count != 2) throw new BermudaExpressionGenerationException("Convert requires 2 arguments"); Expression conv = MakeConvertExpression(currentDimension, itemType, keySelectorParameter); if (currentDimension.IsNegated) conv = Expression.Negate(conv); if (currentDimension.IsNotted) conv = Expression.Not(conv); return conv; } if (string.Equals(currentDimension.Function, "cast", StringComparison.InvariantCultureIgnoreCase)) { if (currentDimension.Arguments.Count != 1) throw new BermudaExpressionGenerationException("Cast requires 1 argument"); Expression conv = MakeConvertExpression(currentDimension, itemType, keySelectorParameter, currentDimension.Arguments.First().Target); if (currentDimension.IsNegated) conv = Expression.Negate(conv); if (currentDimension.IsNotted) conv = Expression.Not(conv); return conv; } Expression keySelectorBody; currentDimension.IsDateTime = true; var functionInfo = typeof(UtilityExtensions).GetMethods().Where(x => string.Equals(x.Name, currentDimension.Function, StringComparison.InvariantCultureIgnoreCase) && currentDimension.Arguments.Count == x.GetParameters().Length).FirstOrDefault(); //keySelectorBody = Expression.MakeMemberAccess(expression: keySelectorBody, member: typeof(DateTime).GetProperty("Ticks")); if (functionInfo == null) throw new BermudaExpressionGenerationException("Function " + currentDimension.Function + "(" + string.Join(",", Enumerable.Range(0, currentDimension.Arguments.Count).Select(n => "arg" + n)) + ") not supported."); var functionArguments = new List<Expression>(); var methodParams = functionInfo.GetParameters(); if (currentDimension.Arguments.Count != methodParams.Length) throw new BermudaExpressionGenerationException("Number of arguments does not match the number of parameters for function " + currentDimension.Function); for (int i = 0; i < methodParams.Length; i++) { var actualArg = currentDimension.Arguments[i]; var parameterType = methodParams[i].ParameterType; if (actualArg.IsFunctionCall) { Expression functionCall = MakeFunctionCallExpression(actualArg, itemType, keySelectorParameter); if (functionCall.Type != parameterType) functionCall = Expression.Convert(functionCall, parameterType); functionArguments.Add(functionCall); } else if (actualArg.Source != null) { if (actualArg.IsQuoted) { functionArguments.Add(Expression.Constant(actualArg.Source)); continue; } //see if the provided string is a column name var targetMember = GetMember(itemType, actualArg.Source, false); if (targetMember != null) { keySelectorBody = Expression.MakeMemberAccess(expression: keySelectorParameter, member: targetMember); functionArguments.Add(keySelectorBody); } else { var actualValue = parameterType == typeof(string) ? actualArg.Source : Convert.ChangeType(actualArg.Source, parameterType); functionArguments.Add(Expression.Constant(actualValue)); } } else if (actualArg.Child != null) { var childExpr = actualArg.Child.CreateExpression(null); if (childExpr.Type != parameterType) childExpr = Expression.Convert(childExpr, parameterType); functionArguments.Add(childExpr); } } keySelectorBody = Expression.Call ( method: functionInfo, arguments: functionArguments ); if (currentDimension.IsNegated) keySelectorBody = Expression.Negate(keySelectorBody); if (currentDimension.IsNotted) keySelectorBody = Expression.Not(keySelectorBody); return keySelectorBody; }
private static Expression MakeGroupByExpressionEx(Expression collectionParameter, DimensionExpression[] groupBy, DimensionExpression[] selects, int depth, Type itemType, Type metadataType, Type groupingType, Type resultType) { var linqExtensionClassType = !groupBy.Any(x => x.ParallelizedLinq) ? PLinqExtensionClassType : LinqExtensionClassType; var linqEnumType = linqExtensionClassType == PLinqExtensionClassType ? PLinqEnumType : LinqEnumType; var remDepth = groupBy.Skip(depth).Count(); var currentDimension = groupBy.ElementAt(depth); var currentGroupBy = currentDimension.Source; var currentFunction = currentDimension.Function; var currentChild = currentDimension.Child; if (currentDimension.LinkedSelect != null) { currentFunction = currentDimension.LinkedSelect.Function; } if (currentGroupBy == null && currentFunction == null && currentChild == null) { if (remDepth > 1) { var newCollectionParameter = Expression.Parameter(type: typeof(EnumMetadata<>).MakeGenericType(linqEnumType.MakeGenericType(itemType)), name: MakeNumericName("gmd", depth + 1)); groupBy.ElementAt(depth + 1).GroupingEnumParameter = newCollectionParameter; return MakeGroupByExpressionEx(collectionParameter, groupBy, selects, depth + 1, itemType, metadataType, groupingType, resultType); } } var sourceCollection = collectionParameter.Type.GetGenericTypeDefinition() == typeof(EnumMetadata<>) ? Expression.MakeMemberAccess(collectionParameter, collectionParameter.Type.GetField("Enum")) : collectionParameter; if (linqEnumType == PLinqEnumType && !TypeImplements(GetTypeOfEnumerable(sourceCollection.Type), PLinqEnumType)) { //.AsParallel() var res = AppendAsParallel(linqExtensionClassType, sourceCollection); groupBy.ElementAt(depth).ParallelizedLinq = true; sourceCollection = res; } var elementType = GetTypeOfEnumerable(sourceCollection.Type); var selectType = resultType; Expression groupByExpr = null; DimensionExpression sortValueType = null; MemberInfo groupByMember; Expression currentChildExpression = null; if (currentChild != null) { currentChildExpression = currentChild.CreateExpression(null); } if (currentGroupBy == null && currentFunction == null && currentChild == null) { groupByExpr = Expression.NewArrayInit(sourceCollection.Type, sourceCollection); } else if ((groupByMember = GetMember(itemType, currentGroupBy)) != null && TypeImplements(GetMemberType(groupByMember), typeof(IEnumerable<>)) || (currentChildExpression != null && TypeImplements(currentChildExpression.Type, typeof(IEnumerable<>)))) { //.SelectMany(m => m.Ngrams, (m, t) => new MentionMetadata { Mention = m, Id = t }) var genericSelectManyInfos = linqExtensionClassType.GetMethods().Where(x => x.Name == "SelectMany" && x.IsGenericMethod && x.GetParameters().Length == 3); var extensionIndex = (linqExtensionClassType == typeof(ParallelEnumerable)) ? 0 : 1; var genericSelectManyInfo = genericSelectManyInfos.Skip(extensionIndex).FirstOrDefault(); var collectionSelectorParameter = Expression.Parameter(type: elementType, name: GenerateParamName(elementType, depth)); var sourcePath = GetSourcePath(currentDimension); var collectionGroupingMemberAccess = Expression.MakeMemberAccess(collectionSelectorParameter, GetField(collectionSelectorParameter.Type, sourcePath)); var collectionSelector = Expression.Lambda ( delegateType: typeof(Func<,>).MakeGenericType(elementType, collectionGroupingMemberAccess.Type), parameters: collectionSelectorParameter, body: collectionGroupingMemberAccess ); var keyType = GetTypeOfEnumerable(collectionGroupingMemberAccess.Type); var selectManyInfo = genericSelectManyInfo.MakeGenericMethod(elementType, keyType, metadataType); var resultSelectorParameters = new ParameterExpression[] { Expression.Parameter(type: elementType, name: GenerateParamName(elementType, depth) ), Expression.Parameter(type: keyType, name: GenerateParamName(keyType, depth) ) }; var memberBindings = new List<MemberBinding> { Expression.Bind ( member: metadataType.GetField("Item"), expression: resultSelectorParameters[0] ) }; string groupByTargetPath = GetTargetPath(keyType); var targetField = GetField(metadataType, groupByTargetPath); Expression sourceExpression = resultSelectorParameters[1]; if (IsTupleType(sourceExpression.Type)) { var sourceItemInfo = sourceExpression.Type.GetProperty("Item2"); sourceExpression = Expression.MakeMemberAccess ( expression: sourceExpression, member :sourceItemInfo ); } memberBindings.Add(Expression.Bind ( member: targetField, expression: sourceExpression )); var resultSelector = Expression.Lambda ( delegateType: typeof(Func<,,>).MakeGenericType(elementType, keyType, metadataType), parameters: resultSelectorParameters, body: Expression.MemberInit ( newExpression: Expression.New(type: metadataType), bindings: memberBindings ) ); var selectManyExpr = Expression.Call ( method: selectManyInfo, arguments: new Expression[] { sourceCollection, collectionSelector, resultSelector } ); //.GroupBy(md => md.Id, md => md.Mention) var keySelectorParameter = Expression.Parameter(type: metadataType, name: "md"); var resultSelectorParameter = Expression.Parameter(type: metadataType, name: "md"); var keySelectorBody = Expression.MakeMemberAccess(expression: keySelectorParameter, member: GetField(metadataType, groupByTargetPath)); var resultSelectorBody = Expression.MakeMemberAccess(expression: resultSelectorParameter, member: metadataType.GetField("Item")); var genericGroupByInfos = linqExtensionClassType.GetMethods().Where(x => x.Name == "GroupBy" && x.IsGenericMethod && x.GetParameters().Length == 3); var genericGroupByInfo = genericGroupByInfos.ElementAt(1); var groupByInfo = genericGroupByInfo.MakeGenericMethod(metadataType, keySelectorBody.Type, resultSelectorBody.Type); var keySelectorLambda = Expression.Lambda ( delegateType: typeof(Func<,>).MakeGenericType(metadataType, keySelectorBody.Type), parameters: keySelectorParameter, body: keySelectorBody ); var resultSelectorLambda = Expression.Lambda ( delegateType: typeof(Func<,>).MakeGenericType(metadataType, resultSelectorBody.Type), parameters: resultSelectorParameter, body: resultSelectorBody ); groupByExpr = Expression.Call ( method: groupByInfo, arguments: new Expression[] { selectManyExpr, keySelectorLambda, resultSelectorLambda } ); } else { //.GroupBy(m => m.OccurredOn.Ticks - 28189283) var keySelectorParameter = Expression.Parameter(type: itemType, name: "m"); Expression keySelectorBody = null; if (currentFunction != null) { keySelectorBody = MakeFunctionCallExpression(currentDimension, itemType, keySelectorParameter); } else if(currentGroupBy != null) { var sourcePath = GetSourcePath(currentDimension); var targetMember = GetMember(itemType, sourcePath); keySelectorBody = Expression.MakeMemberAccess(expression: keySelectorParameter, member: targetMember); } else if (currentChild != null) { keySelectorBody = currentChild.CreateExpression(null); } else { throw new BermudaExpressionGenerationException("Don't know how to handle for group by:" + currentDimension); } var genericGroupByInfos = linqExtensionClassType.GetMethods().Where(x => x.Name == "GroupBy" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericGroupByInfo = genericGroupByInfos.FirstOrDefault(); var groupByInfo = genericGroupByInfo.MakeGenericMethod(elementType, keySelectorBody.Type); keySelectorBody = ParameterRebinder.ReplaceParameters(keySelectorBody, "x", keySelectorParameter); var groupByLambda = Expression.Lambda ( delegateType: typeof(Func<,>).MakeGenericType(elementType, keySelectorBody.Type), parameters: keySelectorParameter, body: keySelectorBody ); groupByExpr = Expression.Call ( method: groupByInfo, arguments: new Expression[] { sourceCollection, groupByLambda } ); } var inferredParameterType = typeof(EnumMetadata<>).MakeGenericType(GetTypeOfEnumerable(groupByExpr.Type)); var groupingParameter = Expression.Parameter(type: inferredParameterType, name: MakeNumericName("gmd", depth)); if (groupBy.Length > depth) { groupBy.ElementAt(depth).GroupingEnumParameter = groupingParameter; } //var loldas = temp == groupBy.ElementAt(depth); var enumType = GetTypeOfEnumerable(groupByExpr.Type); var enumMetadataType = typeof(EnumMetadata<>).MakeGenericType(enumType); //.AsParallel() //var genericAsParallelInfo = typeof(ParallelEnumerable).GetMethods().FirstOrDefault(x => x.Name == "AsParallel" && x.IsGenericMethod && x.GetParameters().Length == 1); //var asParallelInfo0 = genericAsParallelInfo.MakeGenericMethod(enumType); //groupByExpr = Expression.Call(method: asParallelInfo0, arg0: groupByExpr); //.Select(g => new GroupMetadata { Group = g, Value = g.Whatever() }) var selectLinqClass = groupByExpr.Type.IsArray ? LinqExtensionClassType : linqExtensionClassType; var genericSelectInfos = selectLinqClass.GetMethods().Where(x => x.Name == "Select" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericSelectInfo = genericSelectInfos.FirstOrDefault(); var selectInfo0 = genericSelectInfo.MakeGenericMethod(enumType, enumMetadataType); var selectGroupParam = Expression.Parameter(type: enumType, name: "g"); var selectGroupMemberBindings = new List<MemberBinding>(); //Group = g, Value selectGroupMemberBindings.Add(Expression.Bind(member: enumMetadataType.GetField("Enum"), expression: selectGroupParam)); //Value = g.Whatever() if (currentDimension != null && currentDimension.Ordering != null && currentDimension.Ordering.Function != null) { sortValueType = currentDimension.Ordering; if (sortValueType != null) { selectGroupMemberBindings.Add(MakeAggregateFunctionCallExpression(selectGroupParam, sortValueType, null, 0, enumMetadataType, "Value")); } } // = new GroupMetadata{} var selectInit = Expression.MemberInit ( newExpression: Expression.New(type: enumMetadataType), bindings: selectGroupMemberBindings ); var selectMetadataLambda = Expression.Lambda ( parameters: selectGroupParam, body: selectInit ); //.Select(...) var selectExpr = Expression.Call ( method: selectInfo0, arg0: groupByExpr, arg1: selectMetadataLambda ); Expression selectSourceExpression = selectExpr; //.OrderByDescending(g => g.Value) if (currentDimension != null && currentDimension.Ordering != null && (currentDimension.Ordering.Function != null || currentDimension.Ordering.Source != null)) { var orderFuncName = currentDimension.OrderDescending ? "OrderByDescending" : "OrderBy"; var genericOrderByInfo = linqExtensionClassType.GetMethods().FirstOrDefault(x => x.Name == orderFuncName && x.IsGenericMethod && x.GetParameters().Length == 2); var orderByInfo = genericOrderByInfo.MakeGenericMethod(enumMetadataType, typeof(long)); var groupOrderParam = Expression.Parameter(type: enumMetadataType, name: "gg"); var orderByExpr = Expression.Call ( method: orderByInfo, arg0: selectExpr, arg1: Expression.Lambda(parameters: groupOrderParam, body: Expression.MakeMemberAccess(expression: groupOrderParam, member: enumMetadataType.GetField("Value"))) ); selectSourceExpression = orderByExpr; } //.Take(5) if (currentDimension.Take.HasValue) { selectSourceExpression = AppendTake(linqExtensionClassType, enumMetadataType, selectSourceExpression, currentDimension.Take.Value); } if (remDepth <= 1) { //if (currentGroupBy == GroupByTypes.None) return collectionParameter; //.Select(gmd2 => new InferredType { Id = gmd.Group.Key, Id2 = gmd2.Group.Key, TargetPath = gmd2.SourcePath }) var selectParameterType = GetTypeOfEnumerable(selectSourceExpression.Type); var selectInfo = genericSelectInfo.MakeGenericMethod(selectParameterType, resultType); var selectMemberBindings = new List<MemberAssignment>(); //gmd2 var parentGroupBy = groupBy.ElementAt(depth); var parentGroupParameter = parentGroupBy.GroupingEnumParameter; //gmd.Group var actualGroupAccess = Expression.MakeMemberAccess(parentGroupParameter, parentGroupParameter.Type.GetField("Enum")); //gmd.Value var groupValueAccess = Expression.MakeMemberAccess(parentGroupParameter, parentGroupParameter.Type.GetField("Value")); var lastGroupBy = groupBy.LastOrDefault(); var computedValueForGroup = lastGroupBy.Ordering; // lastGroupBy.IsDateTime ? null : lastGroupBy.OrderBy; var countSelect = selects.FirstOrDefault(x => string.Equals(x.Function, CountAggregateString, StringComparison.InvariantCultureIgnoreCase)); if (countSelect != null) { //CountAlias = var countBinding = MakeAggregateFunctionCallExpression(actualGroupAccess, new DimensionExpression { Function = CountAggregateString, Target = GetTargetPath(countSelect) }, computedValueForGroup != null && computedValueForGroup.Function == CountAggregateString ? groupValueAccess : null, 0, resultType, null); selectMemberBindings.Add(countBinding); } else if (selects.Any(x => IsCountRequiredForAggregate(x.Function))) { //_Count = var countBinding = MakeAggregateFunctionCallExpression(actualGroupAccess, new DimensionExpression { Function = CountAggregateString, Target = CountTargetPath }, computedValueForGroup != null && computedValueForGroup.Function == CountAggregateString ? groupValueAccess : null, 0, resultType, null); selectMemberBindings.Add(countBinding); } //Value = foreach (var select in selects.Where(x => !x.IsStar && !string.Equals(x.Function, CountAggregateString, StringComparison.InvariantCultureIgnoreCase))) { if (select.IsBasedOnGrouping) continue; if (select.IsFunctionCall) { var otherBinding = MakeAggregateFunctionCallExpression(actualGroupAccess, select, computedValueForGroup != null && computedValueForGroup.Equals(select) ? groupValueAccess : null, 0, resultType, null); //it's not an aggregate... that's a problem if (otherBinding == null) throw new BermudaExpressionGenerationException("Non aggregate function call in an aggregate query not allowed: " + select); selectMemberBindings.Add(otherBinding); } else { var targetPath = GetTargetPath(select); //var sourceField = GetMember(itemType, select.Source, false); var targetFieldInfo = GetField(resultType, targetPath); var actualValue = Convert.ChangeType(select.Source, select.SourceType); selectMemberBindings.Add(Expression.Bind ( targetFieldInfo, Expression.Constant(actualValue) )); } } //Id = gmd.Group.Key, Id2 = gmd2.Group.Key AddStarSelectColumns(groupBy, selects, resultType, selectMemberBindings); //gmd => new Datapoint{...} var selectLambda = Expression.Lambda ( parameters: parentGroupParameter, body: Expression.MemberInit ( newExpression: Expression.New(type: resultType), bindings: selectMemberBindings ) ); //.Select(...) var result = Expression.Call ( method: selectInfo, arg0: selectSourceExpression, arg1: selectLambda ); return result; } else if (remDepth >= 2) { //var newCollectionParameter = Expression.Parameter(type: enumMetadataType, name: MakeNumericName("gmd", depth + 1)); //groupBy.ElementAt(depth).GroupingEnumParameter = newCollectionParameter; var currentParameter = groupBy.ElementAt(depth).GroupingEnumParameter; var nestedExpression = MakeGroupByExpressionEx(currentParameter, groupBy, selects, depth + 1, itemType, metadataType, groupingType, resultType); var nestedExpressionLambda = Expression.Lambda ( parameters: currentParameter, body: nestedExpression ); //.SelectMany(gmd => Recurse()) var sourceElementType = GetTypeOfEnumerable(selectSourceExpression.Type); var genericSelectManyInfos = linqExtensionClassType.GetMethods().Where(x => x.Name == "SelectMany" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericSelectManyInfo = genericSelectManyInfos.Skip(0).FirstOrDefault(); var selectManyInfo = genericSelectManyInfo.MakeGenericMethod(sourceElementType, selectType); var selectManyRecursiveExpr = Expression.Call ( method: selectManyInfo, arg0: selectSourceExpression, arg1: nestedExpressionLambda ); return selectManyRecursiveExpr; } throw new Exception("not supposed to happen"); }
void Condition(SingleNodeTree parent, SelectorExpression parentSelector, bool? isAsOptional) { SelectorTypes selectorType = SelectorTypes.Unspecified; ModifierTypes modifierType; DimensionExpression dim; ModifierTypes modifierResult; SelectorExpression selector = new SelectorExpression(); MultiAdd(parent, selector); if(parentSelector != null) { selector.SetNodeType(parentSelector.NodeType); selector.SetModifierType(parentSelector.Modifier); selector.SetLeft(parentSelector.Left); } if (la.kind == 7) { ComplexCondition(parent, selector, false); } else if (StartOf(8)) { dim = new DimensionExpression(); selector.SetRight(dim); Primary(dim, false); } else if (StartOf(9)) { ExpressionTreeBase expr = null; LiteralExpression(ref expr); selector.SetRight(expr); } else SynErr(48); if (StartOf(10)) { Modifier(out modifierResult); selector.SetLeft(selector.Right); selector.SetRight(null); modifierType = modifierResult; selector.SetModifierType(modifierType); selector.SetNodeType(SelectorTypes.Unknown); if (la.kind == 7) { ComplexCondition(parent, selector, false); } else if (StartOf(8)) { dim = new DimensionExpression(); selector.SetRight(dim); Primary(dim, false); } else if (StartOf(9)) { ExpressionTreeBase expr = null; LiteralExpression(ref expr); selector.SetRight(expr); } else SynErr(49); } if(isAsOptional == true){ if (la.kind == 3 || la.kind == 4 || la.kind == 28) { if (la.kind == 28) { Get(); } string alias = null; AliasClause(ref alias); selector.Target = alias; } }else if(isAsOptional == false){ if (la.kind == 28) { Get(); string alias = null; AliasClause(ref alias); selector.Target = alias; } } }
void SelectField(ArgumentListExpression expression, DimensionExpression dimensionToUse = null) { var selLol = dimensionToUse ?? new DimensionExpression(); if(expression != null) { selLol.SetParent(expression); expression.AddArgument(selLol); } if (la.kind == 6 || la.kind == 36) { if (la.kind == 6) { Get(); selLol.IsNotted = true; } else { Get(); selLol.IsNegated = true; } if (la.kind == 17) { Get(); } } Condition(selLol, null, true); var selectorChild = selLol.Child as SelectorExpression; if (expression != null && selectorChild != null) { var selectorChildRightDimension = selectorChild.Right as DimensionExpression; if (selectorChildRightDimension != null && selectorChild.Left == null) { selectorChildRightDimension.Target = selectorChild.Target; selectorChildRightDimension.IsNegated = selLol.IsNegated; selectorChildRightDimension.IsNotted = selLol.IsNotted; expression.AddArgument(selectorChildRightDimension); expression.RemoveArgument(selLol); } } }
private static Dictionary<string, Type> InferReduceType(DimensionExpression[] selects, DimensionExpression[] groupBy, Type itemType) { var requiredFields = new Dictionary<string, Type>(); int i = 0; // if( groupBy != null && selects != null && selects.Any(x => x.IsStar)) if (groupBy != null) foreach (var g in groupBy) { //if( g.GroupBy == null ) continue; if (g.LinkedSelect != null) continue; var nameBase = GetTargetPath(g); //if( g. Type memberType = GetTargetTypeForGroupByDimension(itemType, g); if (IsCollectionType(memberType)) memberType = GetTypeOfEnumerable(memberType); if (IsTupleType(memberType)) memberType = memberType.GetGenericArguments().Last(); requiredFields[nameBase] = memberType; //if (memberType == typeof(string)) //{ // requiredFields[nameBase + "_Hash"] = typeof(long); //} i++; } bool isCountSelected = false; bool isCountRequired = false; if (selects != null) foreach (var select in selects.Where(x => !x.IsStar)) { var isCountSel = string.Equals(select.Function, "Count", StringComparison.InvariantCultureIgnoreCase); var isCountReq = IsCountRequiredForAggregate(select.Function); isCountSelected = isCountSelected || isCountSel; isCountRequired = isCountRequired || isCountReq; var targetPath = GetTargetPath(select); if (targetPath != null) { if (isCountSel) { requiredFields[targetPath] = typeof(long); } else if (select.Function != null) { var firstArg = select.Arguments.FirstOrDefault(); Type argType = null; if (firstArg != null) { var paramLol = Expression.Parameter(itemType, "param"); var firstArgExpression = MakeDimensionExpression(itemType, paramLol, firstArg); argType = firstArgExpression.Type; } var aggregateMethodInfo = GetAggregateFunction(select.Function, itemType, argType); if (aggregateMethodInfo != null) { requiredFields[targetPath] = aggregateMethodInfo.ReturnType; } else { var methodInfo = GetFunctionInfo(select.Function); if (methodInfo != null) { requiredFields[targetPath] = methodInfo.ReturnType; } else { throw new BermudaExpressionGenerationException("Unknown function:" + select.Function); } } } else { if (select.Child != null) { var expr = select.CreateExpression(null); requiredFields[targetPath] = expr.Type; } else { //try to retrieve the source MemberInfo from the original type var member = GetMember(itemType, select.Source, false); //set the inferred member to the retrieved type if (member != null) { if (select.LinkedGroupBy == null) throw new Exception("Invalid Column Name: " + select.Source); requiredFields[targetPath] = GetMemberType(member); } else { //try to fall back to a groupby dimension var matchingGroupBy = groupBy.FirstOrDefault(x => string.Equals(x.Target, select.Source)); if (matchingGroupBy != null) { var targetType = GetTargetTypeForGroupByDimension(itemType, matchingGroupBy); requiredFields[targetPath] = targetType; } else { //if source path can't be found just use the column name as a literal value requiredFields[targetPath] = select.SourceType; } } } } } } if (!isCountSelected && isCountRequired) { requiredFields[CountTargetPath] = typeof(long); } return requiredFields; }
private static Dictionary<string, Type> InferSelectType(DimensionExpression[] selects, Type itemType) { var requiredFields = new Dictionary<string, Type>(); var itemParam = Expression.Parameter(itemType, "p"); foreach (var select in selects) { if (select.Function == null) { //var sourceField = GetField(itemType, select.Source); var sourceExpression = MakeDimensionExpression(itemType, itemParam, select); if (!select.IsStar) { var targetPath = GetTargetPath(select); if (targetPath == null) throw new BermudaExpressionGenerationException("No alias provided for the select field: " + select); requiredFields[targetPath] = sourceExpression.Type; } else { foreach (var field in itemType.GetFields().Where(x => !IsCollectionType(x.FieldType) )) { requiredFields[field.Name] = field.FieldType; } } } else { if (select.Target == null) throw new BermudaExpressionGenerationException("Alias not provided for function call: " + select); //var methodInfo = GetFunctionInfo(select.Function); if (IsAggregateFunction(select.Function)) throw new Exception("Cannot use an aggregate function without grouping or while having a non-aggregate select"); var functionCallExpr = MakeFunctionCallExpression(select, itemType, Expression.Parameter(itemType, "x")); var targetPath = GetTargetPath(select); requiredFields[targetPath] = functionCallExpr.Type; } } return requiredFields; }
public static Expression GetMapreduceExpression(Expression filter, DimensionExpression[] selects, DimensionExpression[] groupBy, Type itemType, GetExpression get, Expression source, string paramname) { var hash = (filter == null ? 0 : filter.ToString().GetHashCode()) + "|" + (selects == null ? "" : string.Join(",", selects.Select(x => x.GetChecksum()))) + "|" + (groupBy == null ? "" : string.Join(",", groupBy.Select(x => x.GetChecksum()))) + "|" + (get == null ? null : get.Take); Expression expr; var containsAggregates = selects != null && selects.Any(x => x.IsAggregate); LinkDimensions(groupBy, selects); var resultType = InferClrType(selects, groupBy, itemType); if (expressionCache.TryGetValue(hash, out expr)) { return expr; } //a flat select transformation if (selects != null && groupBy == null && !containsAggregates) { expr = MakeSelectExpression(filter, selects, itemType, resultType, get, source, paramname); } else { //a non-grouping aggregate like "SELECT COUNT(*) FROM table" if (groupBy == null || !groupBy.Any()) groupBy = new DimensionExpression[] { new DimensionExpression { Source = null, Function = null } }; expr = MakeMapreduceExpression(filter, selects, groupBy, itemType, resultType, get, source, paramname); } expressionCache[hash] = expr; return expr; }
private static MemberAssignment MakeAggregateFunctionCallExpression(Expression enumParameter, DimensionExpression select, Expression sourceExpression, int metadataDepth, Type resultType, string targetPathOverride) { var elementType = GetTypeOfEnumerable(enumParameter.Type); if (select.Function == "Count") { var targetPath = targetPathOverride ?? GetTargetPath(select); var genericCountInfo = typeof(Enumerable).GetMethods().FirstOrDefault(x => x.Name == "LongCount" && x.IsGenericMethod && x.GetParameters().Length == 1); var countInfo = genericCountInfo.MakeGenericMethod(elementType); var memberInfo = GetMember(resultType, targetPath); if (memberInfo == null) { throw new Exception("Unknown target path for " + resultType + ": " + targetPath); } var actualExpression = sourceExpression ?? Expression.Call(method: countInfo, arguments: enumParameter); var targetType = GetMemberType(memberInfo); return(Expression.Bind ( member: memberInfo, expression: actualExpression.Type != targetType ? Expression.Convert(type: targetType, expression: actualExpression) : actualExpression )); } else { var targetPath = targetPathOverride ?? GetTargetPath(select); if (targetPath == null) { throw new Exception("Both target and source path required for aggregate: " + select.Function); } var mentionParameter = Expression.Parameter(type: elementType, name: GenerateParamName(elementType, metadataDepth)); var firstArgument = select.Arguments.FirstOrDefault(); //if (firstArgument.Function == null) //{ Expression memberAccessBody = null; if (firstArgument.Function != null) { var targetFieldInfo0 = GetField(resultType, targetPath); var functionCall = MakeFunctionCallExpression(firstArgument, elementType, mentionParameter); memberAccessBody = functionCall; } else { string fieldName = firstArgument.Source; memberAccessBody = GetMemberAccessRecursively(mentionParameter, fieldName, select.SourceType, metadataDepth, metadataDepth); } var targetFieldInfo = GetField(resultType, targetPath); var targetType = targetFieldInfo.FieldType; var averageInfo = GetAggregateFunction(select.Function, elementType, memberAccessBody.Type); if (averageInfo == null) { return(null); } Expression functionCallBody = null; var averageLambda = Expression.Lambda ( delegateType: typeof(Func <,>).MakeGenericType(elementType, memberAccessBody.Type), body: functionCallBody ?? memberAccessBody, parameters: new ParameterExpression[] { mentionParameter } ); var actualExpression = sourceExpression ?? Expression.Call(method: averageInfo, arguments: new Expression[] { enumParameter, averageLambda }); var bindingres = Expression.Bind ( member: targetFieldInfo, expression: actualExpression.Type != targetType ? Expression.Convert(type: targetType, expression: actualExpression) : actualExpression ); return(bindingres); } throw new Exception("Unknown Select"); }
public void AddDimension(DimensionExpression dim) { _dimensions.Add(dim); }
void OrderClause(GetExpression expression) { Expect(19); Expect(20); var ordering = new DimensionExpression(); expression.Ordering = ordering; Primary(ordering, true); if (la.kind == 21) { Get(); expression.OrderDescending = true; } if (la.kind == 22) { Get(); Expect(1); expression.Take = Int32.Parse(t.val); if (la.kind == 18) { Get(); Expect(1); expression.Skip = expression.Take; expression.Take = Int32.Parse(t.val); } } }
void Primary(DimensionExpression sel, bool? isAsOptional) { if (la.kind == 3 || la.kind == 4 || la.kind == 31) { var identifier = new IdentifierExpression(); Identifier(identifier); sel.Source = identifier.LastPart; sel.SourceType = typeof(string); sel.IsQuoted = identifier.IsQuoted; if (la.kind == 7) { sel.Function = sel.Source; sel.Source = null; Get(); if (StartOf(4)) { var argList = new ArgumentListExpression(); argList.SetParent(sel); sel.IsFunctionCall = true; SelectField(argList); while (la.kind == 18) { Get(); SelectField(argList); } sel.AddArguments(argList.GetChildren()); } Expect(8); } } else if (la.kind == 9) { Get(); Expect(11); Primary(sel, null); Expect(10); } else if (la.kind == 1) { Get(); sel.Source = t.val; sel.SourceType = typeof(long); } else if (la.kind == 2) { Get(); sel.Source = t.val; sel.SourceType = typeof(double); } else if (la.kind == 4) { Get(); sel.Source = t.val.Substring(1, t.val.Length - 2); sel.SourceType = typeof(string); sel.IsQuoted = true; } else SynErr(47); }
internal void AddArgument(DimensionExpression dim) { dim.SetParent(this); Arguments.Add(dim); }
void GroupByClause(GetExpression expression) { Expect(30); Expect(20); var groupByDimension = new DimensionExpression(); expression.AddDimension(groupByDimension); GroupByField(groupByDimension); while (la.kind == 18) { Get(); var groupByDimension2 = new DimensionExpression(); expression.AddDimension(groupByDimension2); GroupByField(groupByDimension2); } if (la.kind == 33) { HavingClause(expression); } }
private static Expression GetMergeExpression(Type elementType, ParameterExpression selectGroupParam, DimensionExpression[] selects, DimensionExpression[] groupBy) { //if (select.Aggregate == "First") //{ // var genericFirstOrDefaultInfos = typeof(Enumerable).GetMethods().Where(x => x.Name == "FirstOrDefault" && x.IsGenericMethod && x.GetParameters().Length == 1); // var genericFirstOrDefaultInfo = genericFirstOrDefaultInfos.FirstOrDefault(); // var firstOrDefaultInfo = genericFirstOrDefaultInfo.MakeGenericMethod(elementType); // var mergeExpr = Expression.Call(method: firstOrDefaultInfo, arg0: selectGroupParam); // return mergeExpr; //} //if ((groupBy == null || !groupBy.Any()) && !selects.All(x => ReduceExpressionGeneration.IsAggregateFunction(x.Function) || x.IsStar)) return null; var memberBindigs = new List<MemberAssignment>(); /* //group by all the non-select fields foreach (var x in elementType.GetFields()) { if (selects.Any(s => string.Equals(x.Name, GetTargetPath(s), StringComparison.InvariantCultureIgnoreCase))) continue; var keyAccess = Expression.MakeMemberAccess ( member: selectGroupParam.Type.GetProperty("Key"), expression: selectGroupParam ); var memberAccess = Expression.Bind ( member: x, expression: Expression.MakeMemberAccess ( member: x, expression: keyAccess ) ); memberBindigs.Add(memberAccess); }*/ var fields = elementType.GetFields(); foreach (var sel in fields) { //if (sel.IsStar) continue; //var tar = GetTargetPath(sel); //if (fields.Any(x => string.Equals(x.Name, tar, StringComparison.InvariantCultureIgnoreCase))) continue; if (selects.Any(x => string.Equals(GetTargetPath(x), sel.Name, StringComparison.InvariantCultureIgnoreCase))) continue; if (string.Equals(sel.Name, CountTargetPath, StringComparison.InvariantCultureIgnoreCase)) continue; //var targetMember = fields.FirstOrDefault(x => string.Equals(x.Name, tar)); var targetMember = sel; var keyAccess = Expression.MakeMemberAccess ( member: selectGroupParam.Type.GetProperty("Key"), expression: selectGroupParam ); var memberAccess = Expression.Bind ( member: targetMember, expression: Expression.MakeMemberAccess ( member: targetMember, expression: keyAccess ) ); memberBindigs.Add(memberAccess); } var actualSelects = selects.ToList(); if (!actualSelects.Any(x => string.Equals(x.Function, CountAggregateString, StringComparison.InvariantCultureIgnoreCase)) && actualSelects.Any(x => IsCountRequiredForAggregate(x.Function) )) { actualSelects.Add(new DimensionExpression { Function = CountAggregateString, Target = CountTargetPath } ); } foreach(var g in groupBy) { if (g.IsAutoSelect && g.LinkedSelect == null) { var groupByTargetPath = GetTargetPath(g); var selectTargetPath = g.LinkedSelect == null ? null : GetTargetPath(g.LinkedSelect); actualSelects.Add(new DimensionExpression { Source = groupByTargetPath, Target = selectTargetPath ?? groupByTargetPath, IsBasedOnGrouping = true }); } //else //{ // var groupByTargetPath = GetTargetPath(g); // if( g.LinkedSelect. != null ) groupByTargetPath = GetTargetPath(g.LinkedSelect); // var matchingField = fields.FirstOrDefault(x => string.Equals(x.Name, groupByTargetPath, StringComparison.InvariantCultureIgnoreCase)); //} } foreach (var sel in actualSelects) { if (sel.IsStar) continue; var targetPath = GetTargetPath(sel); var targetField = GetField(elementType, targetPath); if (sel.IsBasedOnGrouping) { var keyPropertyInfo = selectGroupParam.Type.GetProperty("Key"); var keyMemberAccess = Expression.MakeMemberAccess(selectGroupParam, keyPropertyInfo); var keyPropertyAccess = Expression.MakeMemberAccess(keyMemberAccess, targetField); memberBindigs.Add(Expression.Bind ( member: targetField, expression: keyPropertyAccess )); } else { //if( targetField.FieldType != ty var genericSumInfos = typeof(Enumerable).GetMethods().Where(x => x.Name == "Sum" && x.IsGenericMethod && x.GetParameters().Length == 2 && x.ReturnType == targetField.FieldType); var genericSumInfo = genericSumInfos.FirstOrDefault(); var sumInfo = genericSumInfo.MakeGenericMethod(elementType); var genericSumInfos2 = typeof(Enumerable).GetMethods().Where(x => x.Name == "Sum" && x.IsGenericMethod && x.GetParameters().Length == 2 && x.ReturnType == typeof(long)); var genericSumInfo2 = genericSumInfos2.FirstOrDefault(); var sumInfo2 = genericSumInfo2.MakeGenericMethod(elementType); ////TargetField = g.Sum(p => p.TargetField * p._Count) / g.Sum(p => p._Count) if ( string.Equals(sel.Function, "Average", StringComparison.InvariantCultureIgnoreCase) ) { var actualCountTargetPath = CountTargetPath; var countSelect = actualSelects.FirstOrDefault(x => string.Equals(x.Function, CountAggregateString, StringComparison.InvariantCultureIgnoreCase)); if (countSelect == null) throw new Exception("The provided type has no required count field"); actualCountTargetPath = GetTargetPath(countSelect); var pointParameter = Expression.Parameter(elementType, "p1"); var countAccess = Expression.MakeMemberAccess(pointParameter, GetField(elementType, actualCountTargetPath)); var targetPathAccess = Expression.MakeMemberAccess(pointParameter, GetField(elementType, targetPath)); var sumBody = Expression.Multiply ( left: (countAccess.Type == targetPathAccess.Type) ? (Expression)countAccess : Expression.Convert(countAccess, targetPathAccess.Type), right: targetPathAccess ); var pointParameter2 = Expression.Parameter(elementType, "p2"); var sumBody2 = Expression.MakeMemberAccess(pointParameter2, GetField(elementType, actualCountTargetPath)); Expression sumOfProducts = Expression.Call(method: sumInfo, arg0: selectGroupParam, arg1: Expression.Lambda(parameters: pointParameter, body: sumBody)); Expression sumOfCounts = Expression.Call(method: sumInfo2, arg0: selectGroupParam, arg1: Expression.Lambda(parameters: pointParameter2, body: sumBody2)); var division = Expression.Divide ( left: sumOfProducts, right: sumOfProducts.Type != sumOfCounts.Type ? Expression.Convert(sumOfCounts, sumOfProducts.Type) : sumOfCounts ); memberBindigs.Add(Expression.Bind ( member: targetField, expression: division )); } //TargetField = g.Sum(p => p.TargetField) else// (string.Equals(sel.Function, CountAggregateString, StringComparison.InvariantCultureIgnoreCase) || string.Equals(sel.Function, "Sum", StringComparison.InvariantCultureIgnoreCase)) { var pointParameter = Expression.Parameter(elementType, "p0"); var sumBody = Expression.MakeMemberAccess(pointParameter, GetField(elementType, targetPath)); memberBindigs.Add(Expression.Bind ( member: targetField, expression: Expression.Call(method: sumInfo, arg0: selectGroupParam, arg1: Expression.Lambda(parameters: pointParameter, body: sumBody))) ); } } } var result = Expression.MemberInit ( newExpression: Expression.New(elementType), bindings: memberBindigs ); return result; }
void GroupByField(DimensionExpression expression) { if (la.kind == 24 || la.kind == 26) { if (la.kind == 24) { Get(); expression.OrderDescending = true; } else { Get(); expression.OrderDescending = false; } Expect(1); expression.Take = Int32.Parse(t.val); } SelectField(null, expression); if (la.kind == 25) { var inClause = new InExpression(); expression.InClause = inClause; InClause(inClause); } if (la.kind == 27) { Get(); var dim = new DimensionExpression(); Primary(dim, false); expression.Ordering = dim; } }
private static void AddStarSelectColumns(DimensionExpression[] groupBy, DimensionExpression[] selects, Type resultType, List<MemberAssignment> selectMemberBindings) { var starSelect = selects.FirstOrDefault(x => x.IsStar); int i = 0; foreach (var g in groupBy) { if (!(starSelect != null || g.IsAutoSelect)) continue; //if (g.Child != null) //{ //} //else if (g.Source != null || g.Function != null || g.LinkedSelect != null || g.IsAutoSelect) { var actualEnumAccess = Expression.MakeMemberAccess ( expression: g.GroupingEnumParameter, member: g.GroupingEnumParameter.Type.GetField("Enum") ); var keyPropertyInfo = actualEnumAccess.Type.GetProperty("Key"); var keyAccess = Expression.MakeMemberAccess ( expression: actualEnumAccess, member: keyPropertyInfo ); //var groupByTargetPath = GetTargetPath(keyPropertyInfo.PropertyType); //var targetMemberName = MakeNumericName(groupByTargetPath, i); var targetMemberName = GetTargetPath(g); if (g.LinkedSelect != null) { targetMemberName = GetTargetPath(g.LinkedSelect); } //var isNumeric = keyPropertyInfo.PropertyType == typeof(long); var field = GetField(resultType, targetMemberName); var resultMemberAssignment = Expression.Bind ( member: field, expression: keyAccess ); selectMemberBindings.Add(resultMemberAssignment); //if (!isNumeric) //{ // var getHashCall = Expression.Call(instance: keyAccess, method: keyAccess.Type.GetMethod("GetHashCode")); // var setIdForStringGrouping = Expression.Bind // ( // member: resultType.GetField( GetTargetPath(g) + "_Hash" ), // expression: Expression.Convert( type:typeof(long), expression: getHashCall ) // ); // selectMemberBindings.Add(setIdForStringGrouping); //} } i++; } }
private static Expression MakeConvertExpression(DimensionExpression currentDimension, Type itemType, ParameterExpression keySelectorParameter, string targetType = null) { if (currentDimension.Arguments.Count != 2 && targetType == null) throw new BermudaExpressionGenerationException("Convert function requires 2 arguments"); if (currentDimension.Arguments.Count != 1 && targetType != null) throw new BermudaExpressionGenerationException("Cast function requires 1 argument"); string lowerType; if (targetType == null) { targetType = currentDimension.Arguments[1].ToString(); lowerType = targetType.ToLower(); } else { lowerType = targetType.ToLower(); } var firstArg = currentDimension.Arguments.FirstOrDefault(); Expression firstArgExpr = MakeDimensionExpression(itemType, keySelectorParameter, firstArg); Type conversionTargetType = null; switch (lowerType) { case "sql_bigint": conversionTargetType = typeof(long); break; case "integer": conversionTargetType = typeof(int); break; case "date": conversionTargetType = typeof(DateTime); break; default: throw new BermudaExpressionGenerationException("Unknown target type: " + targetType); } if (conversionTargetType == firstArgExpr.Type) return firstArgExpr; var convexpr = Expression.Convert(firstArgExpr, conversionTargetType); return convexpr; //throw new BermudaExpressionGenerationException("Invalid cast arguments: " + firstArg + " to " + targetType); }
private static Expression MakeDimensionExpression(Type itemType, ParameterExpression keySelectorParameter, DimensionExpression firstArg) { Expression firstArgExpr; bool dontNegate = false; if (firstArg.Child != null) { dontNegate = true; firstArgExpr = firstArg.CreateExpression(null); } else if (firstArg.Function != null) { firstArgExpr = MakeFunctionCallExpression(firstArg, itemType, keySelectorParameter); } else { var sourcePath = firstArg.Source; var member = GetMember(itemType, sourcePath, false); if (member == null) { var stringVersion = firstArg.Source; long num; double num2; if (long.TryParse(stringVersion, out num)) { return(Expression.Constant(num)); } if (double.TryParse(stringVersion, out num2)) { return(Expression.Constant(num2)); } firstArgExpr = Expression.Constant(stringVersion); } else { firstArgExpr = Expression.MakeMemberAccess(keySelectorParameter, member); } } if (!dontNegate) { if (firstArg.IsNegated) { firstArgExpr = Expression.Negate(firstArgExpr); } else if (firstArg.IsNotted) { firstArgExpr = Expression.Not(firstArgExpr); } } return(firstArgExpr); }
public static Expression MakeFunctionCallExpression(DimensionExpression currentDimension, Type itemType, ParameterExpression keySelectorParameter) { //var functionName = currentDimension.Function ?? currentDimension.LinkedSelect.Function; if (currentDimension.Function == null && currentDimension.LinkedSelect != null) { currentDimension = currentDimension.LinkedSelect; } if (string.Equals(currentDimension.Function, "convert", StringComparison.InvariantCultureIgnoreCase)) { if (currentDimension.Arguments.Count != 2) { throw new BermudaExpressionGenerationException("Convert requires 2 arguments"); } Expression conv = MakeConvertExpression(currentDimension, itemType, keySelectorParameter); if (currentDimension.IsNegated) { conv = Expression.Negate(conv); } if (currentDimension.IsNotted) { conv = Expression.Not(conv); } return(conv); } if (string.Equals(currentDimension.Function, "cast", StringComparison.InvariantCultureIgnoreCase)) { if (currentDimension.Arguments.Count != 1) { throw new BermudaExpressionGenerationException("Cast requires 1 argument"); } Expression conv = MakeConvertExpression(currentDimension, itemType, keySelectorParameter, currentDimension.Arguments.First().Target); if (currentDimension.IsNegated) { conv = Expression.Negate(conv); } if (currentDimension.IsNotted) { conv = Expression.Not(conv); } return(conv); } Expression keySelectorBody; currentDimension.IsDateTime = true; var functionInfo = typeof(UtilityExtensions).GetMethods().Where(x => string.Equals(x.Name, currentDimension.Function, StringComparison.InvariantCultureIgnoreCase) && currentDimension.Arguments.Count == x.GetParameters().Length).FirstOrDefault(); //keySelectorBody = Expression.MakeMemberAccess(expression: keySelectorBody, member: typeof(DateTime).GetProperty("Ticks")); if (functionInfo == null) { throw new BermudaExpressionGenerationException("Function " + currentDimension.Function + "(" + string.Join(",", Enumerable.Range(0, currentDimension.Arguments.Count).Select(n => "arg" + n)) + ") not supported."); } var functionArguments = new List <Expression>(); var methodParams = functionInfo.GetParameters(); if (currentDimension.Arguments.Count != methodParams.Length) { throw new BermudaExpressionGenerationException("Number of arguments does not match the number of parameters for function " + currentDimension.Function); } for (int i = 0; i < methodParams.Length; i++) { var actualArg = currentDimension.Arguments[i]; var parameterType = methodParams[i].ParameterType; if (actualArg.IsFunctionCall) { Expression functionCall = MakeFunctionCallExpression(actualArg, itemType, keySelectorParameter); if (functionCall.Type != parameterType) { functionCall = Expression.Convert(functionCall, parameterType); } functionArguments.Add(functionCall); } else if (actualArg.Source != null) { if (actualArg.IsQuoted) { functionArguments.Add(Expression.Constant(actualArg.Source)); continue; } //see if the provided string is a column name var targetMember = GetMember(itemType, actualArg.Source, false); if (targetMember != null) { keySelectorBody = Expression.MakeMemberAccess(expression: keySelectorParameter, member: targetMember); functionArguments.Add(keySelectorBody); } else { var actualValue = parameterType == typeof(string) ? actualArg.Source : Convert.ChangeType(actualArg.Source, parameterType); functionArguments.Add(Expression.Constant(actualValue)); } } else if (actualArg.Child != null) { var childExpr = actualArg.Child.CreateExpression(null); if (childExpr.Type != parameterType) { childExpr = Expression.Convert(childExpr, parameterType); } functionArguments.Add(childExpr); } } keySelectorBody = Expression.Call ( method: functionInfo, arguments: functionArguments ); if (currentDimension.IsNegated) { keySelectorBody = Expression.Negate(keySelectorBody); } if (currentDimension.IsNotted) { keySelectorBody = Expression.Not(keySelectorBody); } return(keySelectorBody); }
public static Expression GetMergeInvocationExpression(DimensionExpression[] selects, DimensionExpression[] groupBy, Type elementType) { if ((groupBy == null || !groupBy.Any()) && !selects.All(x => x.IsAggregate)) return null; //var elementType = ReduceExpressionGeneration.GetTypeOfEnumerable( collectionType ); LinkDimensions(groupBy, selects); var collectionType = typeof(IEnumerable<>).MakeGenericType(elementType); var collectionParameter = Expression.Parameter(collectionType, "col"); var genericGroupByInfos = typeof(Enumerable).GetMethods().Where(x => x.Name == "GroupBy" && x.IsGenericMethod && x.GetParameters().Length == 2); var genericGroupByInfo = genericGroupByInfos.FirstOrDefault(); var groupByInfo = genericGroupByInfo.MakeGenericMethod(elementType, elementType); var lambdaParam = Expression.Parameter(elementType, "x"); var groupingDimensionBindings = new List<MemberAssignment>(); var fields = elementType.GetFields(); foreach (var g in groupBy) { var tar = GetTargetPath(g); var tar2 = g.LinkedSelect == null ? null : GetTargetPath(g.LinkedSelect); //fields.Any(x => string.Equals(x.Name, tar, StringComparison.InvariantCultureIgnoreCase)) //if( !sel.IsBasedOnGrouping ) continue; //if (string.Equals(GetTargetPath(sel), CountTargetPath)) continue; var targetField = fields.FirstOrDefault ( x => g.LinkedSelect == null ? string.Equals(x.Name, tar, StringComparison.InvariantCultureIgnoreCase) : string.Equals(x.Name, tar2, StringComparison.InvariantCultureIgnoreCase )); var binding = Expression.Bind(targetField, Expression.MakeMemberAccess(lambdaParam, targetField)); groupingDimensionBindings.Add(binding); } /* foreach (var x in elementType.GetFields()) { if (selects.Any(s => !s.IsBasedOnGrouping && string.Equals(x.Name, GetTargetPath(s), StringComparison.InvariantCultureIgnoreCase))) continue; var binding = Expression.Bind(x, Expression.MakeMemberAccess(lambdaParam, GetField(elementType, x.Name))); groupingDimensionBindings.Add(binding); }*/ var groupByLambda = Expression.Lambda ( parameters: lambdaParam, body: Expression.MemberInit ( Expression.New(elementType), groupingDimensionBindings ) ); var pointGroups = Expression.Call(method: groupByInfo, arg0: collectionParameter, arg1: groupByLambda); var enumType = pointGroups.Type; var groupingType = GetTypeOfEnumerable(enumType); var genericSelectInfo = typeof(Enumerable).GetMethods().FirstOrDefault(x => x.Name == "Select" && x.IsGenericMethod && x.GetParameters().Length == 2); var selectInfo0 = genericSelectInfo.MakeGenericMethod(groupingType, elementType); var selectGroupParam = Expression.Parameter(type: groupingType, name: "g"); //var selectBody = Expression.Invoke(mergeExpr, selectGroupParam); var mergeExpr = GetMergeExpression(elementType, selectGroupParam, selects, groupBy ); var selectLambda = Expression.Lambda(parameters: selectGroupParam, body: mergeExpr); var selectExpr = Expression.Call(method: selectInfo0, arg0: pointGroups, arg1: selectLambda); //selectExpr = AppendToArray(elementType, selectExpr); var finalLambda = Expression.Lambda(selectExpr, collectionParameter); return finalLambda; }
public void RemoveArgument(DimensionExpression dim) { if(Dimensions.Contains(dim)) Dimensions.Remove(dim); }