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 static object CollectionFilter <T>(QueryBuffer query, QueryBuffer.TypeBuffer typeBuf, object result) { var typedResult = result as IEnumerable <T>; if (typedResult != null) { if (typeBuf.Skip != null) { typedResult = typedResult.Skip((int)typeBuf.Skip(query.Context)); } if (typeBuf.Top != null) { typedResult = typedResult.Take((int)typeBuf.Top(query.Context)); } return(typedResult.ToList()); } else { return(result); } }
public PreparedQueryPlan PrepareQuery(HarmonyQueryCompilationContext compilationContext) { var rootExpr = RootExpressions[_valueBufferParameter]; var processedOns = new List <object>(); var flatList = new List <Tuple <HarmonyTableExpression, QueryBuffer.TypeBuffer> >(); var typeBuffers = new QueryBuffer.TypeBuffer[] { GetTypeBuffer(rootExpr, flatList) }; var expressionTableMapping = flatList.ToDictionary(kvp => kvp.Item1.RootExpression.ConvertedParameter as Expression, kvp => kvp.Item1 as IHarmonyQueryTable, new ExpressionValueComparer()); var tableList = flatList.Select(tpl => tpl.Item1 as IHarmonyQueryTable).ToList(); //extract all of expressions that might represent a given table and add them to the mapping dictionary foreach (var table in tableList) { foreach (var alias in ((HarmonyTableExpression)table).Aliases) { if (!expressionTableMapping.ContainsKey(alias)) { expressionTableMapping.Add(alias, table); } } } var whereBuilder = new WhereExpressionBuilder(rootExpr.IsCaseSensitive, tableList, expressionTableMapping); var processedWheres = new List <Object>(); var orderBys = new List <Tuple <FileIO.Queryable.FieldReference, bool> >(); foreach (var expr in rootExpr.WhereExpressions) { whereBuilder.VisitForWhere(expr, processedWheres, processedOns); } foreach (var tpl in flatList) { foreach (var expr in tpl.Item1.OnExpressions) { var madeOn = whereBuilder.VisitForOn(expr); if (madeOn != null) { processedOns.Add(madeOn); if (tpl.Item2.JoinOn == null) { tpl.Item2.JoinOn = madeOn; } else { throw new NotImplementedException(); } } } if (tpl.Item1 != rootExpr) { foreach (var expr in tpl.Item1.WhereExpressions) { var madeOn = whereBuilder.VisitForOn(expr); if (madeOn != null) { processedOns.Add(madeOn); if (tpl.Item2.JoinOn != null) { madeOn = new ConnectorPart() { Op = WhereClauseConnector.AndOperator, Left = tpl.Item2.JoinOn, Right = madeOn } } ; tpl.Item2.JoinOn = madeOn; } } } foreach (var expr in tpl.Item1.OrderByExpressions) { var fieldRef = whereBuilder.VisitForOrderBy(expr.Item1); if (fieldRef != null) { orderBys.Add(Tuple.Create(fieldRef, expr.Item2)); } } } var queryBuffer = new QueryBuffer(flatList.Select(tpl => tpl.Item2).ToList()); var fieldReferences = new Dictionary <int, List <FieldDataDefinition> >(); foreach (var queryExpr in flatList) { if (queryExpr.Item1.ReferencedFields.Count > 0) { var bufferIndex = queryBuffer.TypeBuffers.IndexOf(queryExpr.Item2); fieldReferences.Add(bufferIndex, queryExpr.Item1.ReferencedFields); } } var queryPlan = new PreparedQueryPlan(true, processedWheres, fieldReferences, processedOns, orderBys, queryBuffer, ""); return(queryPlan); }