/// <summary> /// This is one of our top level node. /// mutation MyMutation {...} /// </summary> /// <param name="context"></param> /// <returns></returns> public override IGraphQLBaseNode VisitMutationQuery(EntityGraphQLParser.MutationQueryContext context) { //== JT: set the Operation Type schemaProvider.OperationType = OperationType.Mutation; //== var operation = GetOperation(context.operationName()); foreach (var item in operation.Arguments.Where(a => a.DefaultValue != null)) { variables[item.ArgName] = Expression.Lambda(item.DefaultValue.Expression).Compile().DynamicInvoke(); } this.currentExpressionContext = (ExpressionResult)Expression.Parameter(schemaProvider.ContextType, $"ctx"); var mutateFields = new List <IGraphQLBaseNode>(); foreach (var c in context.objectSelection().children) { var n = Visit(c); if (n != null) { mutateFields.Add(n); } } var mutation = new GraphQLQueryNode(schemaProvider, fragments, operation.Name, null, null, mutateFields, null); return(mutation); }
/// <summary> /// This is one of our top level node. /// query MyQuery { /// entityQuery { fields [, field] }, /// entityQuery { fields [, field] }, /// ... /// } /// </summary> /// <param name="context"></param> /// <returns></returns> public override IGraphQLBaseNode VisitDataQuery(EntityGraphQLParser.DataQueryContext context) { //== JT: set the Operation Type schemaProvider.OperationType = OperationType.Query; //== var operation = GetOperation(context.operationName()); foreach (var item in operation.Arguments.Where(a => a.DefaultValue != null)) { variables[item.ArgName] = Expression.Lambda(item.DefaultValue.Expression).Compile().DynamicInvoke(); } this.currentExpressionContext = (ExpressionResult)Expression.Parameter(schemaProvider.ContextType, $"ctx"); var rootFields = new List <GraphQLQueryNode>(); // Just visit each child node. All top level will be entityQueries foreach (var c in context.objectSelection().children) { var n = Visit(c); if (n != null) { rootFields.Add((GraphQLQueryNode)n); } } var query = new GraphQLQueryNode(schemaProvider, fragments, operation.Name, currentExpressionContext, (ParameterExpression)currentExpressionContext, rootFields, null); return(query); }
public override IGraphQLBaseNode VisitField(EntityGraphQLParser.FieldContext context) { var fieldName = context.fieldDef.GetText(); string schemaTypeName = schemaProvider.GetSchemaTypeNameForDotnetType(currentExpressionContext.Type); var actualFieldName = schemaProvider.GetActualFieldName(schemaTypeName, fieldName, claims); var args = context.argsCall != null?ParseGqlCall(actualFieldName, context.argsCall) : null; var alias = context.alias?.name.GetText(); //== JT: add Operation Type check if (schemaProvider.HasMutation(actualFieldName) && schemaProvider.OperationType == OperationType.Mutation) { var mutationType = schemaProvider.GetMutations().First(m => m.Name == actualFieldName); if (context.select != null) { var expContext = (ExpressionResult)Expression.Parameter(mutationType.ReturnType.SchemaType.ContextType, $"mut_{actualFieldName}"); var oldContext = currentExpressionContext; currentExpressionContext = expContext; var select = ParseFieldSelect(expContext, actualFieldName, context.select); currentExpressionContext = oldContext; return(new GraphQLMutationNode(mutationType, args, (GraphQLQueryNode)select)); } else { var resultName = alias ?? actualFieldName; return(new GraphQLMutationNode(mutationType, args, null)); } } else { if (!schemaProvider.TypeHasField(schemaTypeName, actualFieldName, args != null ? args.Select(d => d.Key) : new string[0], claims)) { throw new EntityGraphQLCompilerException($"Field {actualFieldName} not found on type {schemaTypeName}"); } var result = schemaProvider.GetExpressionForField(currentExpressionContext, schemaTypeName, actualFieldName, args, claims); IGraphQLBaseNode fieldResult; var resultName = alias ?? actualFieldName; if (context.select != null) { fieldResult = ParseFieldSelect(result, resultName, context.select); } else { fieldResult = new GraphQLQueryNode(schemaProvider, fragments, resultName, result, currentExpressionContext.AsParameter(), null, null); } if (context.directive != null) { return(ProcessFieldDirective((GraphQLQueryNode)fieldResult, context.directive)); } return(fieldResult); } }
private IGraphQLBaseNode ProcessFieldDirective(GraphQLQueryNode fieldResult, EntityGraphQLParser.DirectiveCallContext directive) { var processor = schemaProvider.GetDirective(directive.name.GetText()); var argList = directive.directiveArgs.children.Where(c => c.GetType() == typeof(EntityGraphQLParser.GqlargContext)).Cast <EntityGraphQLParser.GqlargContext>(); var args = argList.ToDictionary(a => a.gqlfield.GetText(), a => ParseGqlarg(null, a)); var argType = processor.GetArgumentsType(); var argObj = Activator.CreateInstance(argType); foreach (var arg in args) { var prop = argType.GetProperty(arg.Key); prop.SetValue(argObj, Expression.Lambda(arg.Value.Expression).Compile().DynamicInvoke()); } var result = processor.ProcessQueryInternal(fieldResult, argObj); return(result); }
/// <summary> /// Given a syntax of { fields, to, selection, from, object } with a context /// it will build the correct select statement /// </summary> /// <param name="name"></param> /// <param name="context"></param> /// <param name="selectContext"></param> /// <returns></returns> private IGraphQLBaseNode BuildDynamicSelectForObjectGraph(ExpressionResult selectFromExp, ParameterExpression selectFromParam, string name, EntityGraphQLParser.ObjectSelectionContext context) { try { // visit child fields. Will be field or entityQueries again // These expression will be built on the element type var oldContext = currentExpressionContext; currentExpressionContext = selectFromExp; var fieldExpressions = context.children.Select(c => Visit(c)).Where(n => n != null).ToList(); currentExpressionContext = oldContext; var graphQLNode = new GraphQLQueryNode(schemaProvider, fragments, name, selectFromExp, selectFromParam, fieldExpressions, selectFromExp); return(graphQLNode); } catch (EntityGraphQLCompilerException ex) { throw SchemaException.MakeFieldCompileError($"Failed compiling field {name}", ex.Message); } }
/// Given a syntax of someCollection { fields, to, selection, from, object } /// it will build a select assuming 'someCollection' is an IEnumerables private IGraphQLBaseNode BuildDynamicSelectOnCollection(ExpressionResult queryResult, string resultName, EntityGraphQLParser.ObjectSelectionContext context) { var elementType = queryResult.Type.GetEnumerableOrArrayType(); var contextParameter = Expression.Parameter(elementType, $"p_{elementType.Name}"); var exp = queryResult; var oldContext = currentExpressionContext; currentExpressionContext = (ExpressionResult)contextParameter; // visit child fields. Will be more fields var fieldExpressions = context.children.Select(c => Visit(c)).Where(n => n != null).ToList(); var gqlNode = new GraphQLQueryNode(schemaProvider, fragments, resultName, exp, oldContext.AsParameter(), fieldExpressions, (ExpressionResult)contextParameter); currentExpressionContext = oldContext; return(gqlNode); }
/// <summary> /// Given a syntax of { fields, to, selection, from, object } with a context /// it will build the correct select statement /// </summary> /// <param name="name"></param> /// <param name="context"></param> /// <param name="selectContext"></param> /// <returns></returns> private IGraphQLBaseNode BuildDynamicSelectForObjectGraph(ExpressionResult selectFromExp, ParameterExpression selectFromParam, string name, EntityGraphQLParser.ObjectSelectionContext context) { try { // visit child fields. Will be field or entityQueries again // These expression will be built on the element type var oldContext = currentExpressionContext; currentExpressionContext = selectFromExp; ParameterExpression replacementParameter = null; // we might be using a service i.e. ctx => WithService((T r) => r.DoSomething(ctx.Entities.Select(f => f.Id).ToList())) // if we can we want to avoid calling that multiple times with a expression like // r.DoSomething(ctx.Entities.Select(f => f.Id).ToList()) == null ? null : new { // Field = r.DoSomething(ctx.Entities.Select(f => f.Id).ToList()).Blah // } // by wrapping the whole thing in a method that does the null check once. // This means we build the fieldExpressions on a parameter of the result type // We can only do that if it doesn't use the oldContext unless the oldContext is the root context // i.e we can't do this on a field on a type because we don't have that value as it might be a selection from an ORM bool wrapField = (oldContext.Type == schemaProvider.ContextType || oldContext.NodeType == ExpressionType.Parameter) && currentExpressionContext.Services.Any(); if (wrapField) { // replace with a parameter. The expression is compiled at execution time once replacementParameter = Expression.Parameter(selectFromExp.Type, "null_wrap"); currentExpressionContext = (ExpressionResult)replacementParameter; } var fieldExpressions = context.children.Select(c => Visit(c)).Where(n => n != null).ToList(); currentExpressionContext = oldContext; var graphQLNode = new GraphQLQueryNode(schemaProvider, fragments, name, selectFromExp, selectFromParam, fieldExpressions, selectFromExp) { IsWrapped = wrapField }; return(graphQLNode); } catch (EntityGraphQLCompilerException ex) { throw SchemaException.MakeFieldCompileError($"Failed compiling field {name}", ex.Message); } }