Beispiel #1
0
        /// <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);
        }
Beispiel #2
0
        /// <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);
        }
Beispiel #3
0
        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);
            }
        }