private static QueryBuffer.TypeBuffer GetTypeBuffer(HarmonyTableExpression table, List <Tuple <HarmonyTableExpression, QueryBuffer.TypeBuffer> > flatList)
        {
            var queryTables = table.RootExpression.RootExpressions.Values.OfType <HarmonyTableExpression>().Where(qt => qt != table);
            var made        = new QueryBuffer.TypeBuffer
            {
                DataObjectType  = table.ItemType,
                IsCollection    = table.IsCollection,
                ParentFieldName = table.Name,
                Metadata        = DataObjectMetadataBase.LookupType(table.ItemType)
            };

            if (table.Top != null)
            {
                var bakedFunction = Expression.Lambda <Func <QueryContext, long> >(Expression.Convert(table.Top, typeof(long)), QueryCompilationContext.QueryContextParameter).Compile();
                made.Top = (obj) => bakedFunction(obj as QueryContext);
            }

            if (table.Skip != null)
            {
                var bakedFunction = Expression.Lambda <Func <QueryContext, long> >(Expression.Convert(table.Skip, typeof(long)), QueryCompilationContext.QueryContextParameter).Compile();
                made.Skip = (obj) => bakedFunction(obj as QueryContext);
            }

            if (made.Top != null || made.Skip != null)
            {
                made.SelectResult = CollectionFilterMethod.MakeGenericMethod(made.DataObjectType).CreateDelegate(typeof(Func <QueryBuffer, QueryBuffer.TypeBuffer, object, object>), null) as Func <QueryBuffer, QueryBuffer.TypeBuffer, object, object>;
            }

            flatList.Add(Tuple.Create(table, made));
            var joinedBuffers = queryTables.OfType <HarmonyTableExpression>().Where(qt => !qt.Name.Contains(".")).Select(qt => GetTypeBuffer(qt, flatList)).ToList();
            var namedLookup   = joinedBuffers.ToDictionary(tb => tb.ParentFieldName);

            foreach (var nestedTable in queryTables.OfType <HarmonyTableExpression>().Where(qt => qt.Name.Contains(".")).OrderBy(qt => qt.Name.Length))
            {
                var nameParts = nestedTable.Name.Split(".");
                if (namedLookup.TryGetValue(string.Join(".", nameParts.Take(nameParts.Length - 1)), out var foundBuffer))
                {
                    var fullName = nestedTable.Name;
                    nestedTable.Name = nameParts.Last();
                    var madeBuffer = GetTypeBuffer(nestedTable, flatList);
                    foundBuffer.JoinedBuffers.Add(madeBuffer);
                    namedLookup.Add(fullName, madeBuffer);
                }
                else
                {
                    throw new Exception(string.Format("failed to find parent table while processing query {0}", nestedTable.Name));
                }
            }
            made.JoinedBuffers = joinedBuffers;
            return(made);
        }
        public HarmonyQueryExpression(IEntityType entityType)
        {
            Type = typeof(IQueryable <>).MakeGenericType(new Type[] { entityType.ClrType });
            _valueBufferParameter = Parameter(typeof(DataObjectBase), "valueBuffer");
            var rootTable = new HarmonyTableExpression(entityType, "", this);

            RootExpressions = new Dictionary <Expression, HarmonyTableExpression> {
                { CurrentParameter, rootTable }
            };
            ServerQueryExpression = rootTable;
            //var readExpressionMap = new Dictionary<IProperty, Expression>();
            //foreach (var property in entityType.GetAllBaseTypesInclusive().SelectMany(et => et.GetDeclaredProperties()))
            //{
            //    readExpressionMap[property] = CreateReadValueExpression(property.ClrType, property.GetIndex(), property);
            //}

            //foreach (var property in entityType.GetDerivedTypes().SelectMany(et => et.GetDeclaredProperties()))
            //{
            //    readExpressionMap[property] = CreateReadValueExpression(property.ClrType, property.GetIndex(), property);
            //}

            //var entityProjection = new EntityProjectionExpression(entityType, readExpressionMap);
            _projectionMapping[new ProjectionMember()] = ConvertedParameter = Expression.Convert(CurrentParameter, entityType.ClrType);
        }