public static object Execute (GraphQLSchema <TContext> schema, TContext context, GraphQLField field, ExecSelection <Info> query) { var mutReturn = field.RunMutation(context, query.Arguments.Values()); var queryableFuncExpr = field.GetExpression(query.Arguments.Values(), mutReturn); var replaced = (LambdaExpression)ParameterReplacer.Replace(queryableFuncExpr, queryableFuncExpr.Parameters[0], GraphQLSchema <TContext> .DbParam); // sniff queryable provider to determine how selector should be built var dummyQuery = replaced.Compile().DynamicInvoke(context, null); var queryType = dummyQuery.GetType(); var expressionOptions = schema.GetOptionsForQueryable(queryType); if (expressionOptions.UseBaseType) { queryType = queryType.BaseType; expressionOptions = schema.GetOptionsForQueryable(queryType); } var queryExecSelections = query.Selections.Values(); var selector = GetSelector(schema, field.Type, queryExecSelections, expressionOptions); if (field.ResolutionType != ResolutionType.Unmodified) { var selectorExpr = Expression.Quote(selector); // TODO: This should be temporary - queryable and enumerable should both work var body = replaced.Body; if (body.NodeType == ExpressionType.Convert) { body = ((UnaryExpression)body).Operand; } var call = Expression.Call(typeof(Queryable), "Select", new[] { field.Type.CLRType, field.Type.QueryType }, body, selectorExpr); var expr = Expression.Lambda(call, GraphQLSchema <TContext> .DbParam); var transformed = expr.Compile().DynamicInvoke(context); object results; switch (field.ResolutionType) { case ResolutionType.Unmodified: throw new Exception("Queries cannot have unmodified resolution. May change in the future."); case ResolutionType.ToList: var list = GenericQueryableCall <IEnumerable <object> >(transformed, q => q.ToList()); results = list.Select(o => MapResults(o, queryExecSelections, schema)).ToList(); break; case ResolutionType.FirstOrDefault: var fod = GenericQueryableCall(transformed, q => q.FirstOrDefault()); results = MapResults(fod, queryExecSelections, schema); break; case ResolutionType.First: var first = GenericQueryableCall(transformed, q => q.FirstOrDefault()); results = MapResults(first, queryExecSelections, schema); break; default: throw new ArgumentOutOfRangeException(); } return(results); } else { var invocation = Expression.Invoke(selector, replaced.Body); var expr = Expression.Lambda(invocation, GraphQLSchema <TContext> .DbParam); var result = expr.Compile().DynamicInvoke(context); return(MapResults(result, queryExecSelections, schema)); } }