// Mutation should be null UNLESS adding a mutation at the schema level internal GraphQLFieldBuilder <TContext, TField> AddFieldInternal <TArgs, TField>(string name, Func <TArgs, Expression <Func <TContext, TEntity, TField> > > exprFunc) { var field = GraphQLField.New(_schema, name, exprFunc, typeof(TField), _type); _type.OwnFields.Add(field); return(new GraphQLFieldBuilder <TContext, TField>(field)); }
// Mutation should be null UNLESS adding a mutation at the schema level internal GraphQLFieldBuilder <TContext, TField> AddListMutationInternal <TArgs, TField, TMutReturn>(string name, Func <TArgs, TMutReturn, Expression <Func <TContext, TEntity, IEnumerable <TField> > > > exprFunc, Func <TContext, TArgs, TMutReturn> mutation) { var field = GraphQLField.NewMutation(_schema, name, exprFunc, typeof(IEnumerable <TField>), _type, mutation); _type.OwnFields.Add(field); return(new GraphQLFieldBuilder <TContext, TField>(field)); }
public GraphQLFieldBuilder <TContext, TField> AddPostField <TField>(string name, Func <TField> fieldFunc) { var field = GraphQLField.Post(_schema, name, fieldFunc); _type.OwnFields.Add(field); return(new GraphQLFieldBuilder <TContext, TField>(field)); }
private static Type GetFieldPropertyType(GraphQLField field) { return(field.Type.TypeKind == TypeKind.SCALAR ? (field.IsList ? typeof(IEnumerable <>).MakeGenericType(field.Type.CLRType) : TypeHelpers.MakeNullable(field.Type.CLRType)) : typeof(object)); }
// unsafe generic magic to create a GQLField instance private GraphQLField CreateGenericField(PropertyInfo prop) { // build selector expression, e.g.: (db, p) => p.Id var entityParam = Expression.Parameter(typeof(TEntity), "p"); var memberExpr = Expression.MakeMemberAccess(entityParam, prop); var lambda = Expression.Lambda(memberExpr, GraphQLSchema <TContext> .DbParam, entityParam); // build args func wrapping selector expression, e.g. o => (db, p) => p.Id var objectParam = Expression.Parameter(typeof(object), "o"); var argsExpr = Expression.Lambda(Expression.Quote(lambda), objectParam); var exprFunc = argsExpr.Compile(); return(GraphQLField.New(_schema, prop.Name.ToCamelCase(), (Func <object, LambdaExpression>)exprFunc, prop.PropertyType, _type)); }
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)); } }
internal GraphQLFieldBuilder(GraphQLField field) { _field = field; }