예제 #1
0
        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;
                    }
                }
            }
        }
예제 #2
0
        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++;
            }
            
        }
예제 #3
0
        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");
        }
예제 #4
0
        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;
        }