/// <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);
            }
        }
 /// <summary>
 /// Build a Select() on the context of the field type
 /// </summary>
 /// <param name="context"></param>
 /// <returns></returns>
 public IGraphQLBaseNode ParseFieldSelect(ExpressionResult expContext, string name, EntityGraphQLParser.ObjectSelectionContext context)
 {
     try
     {
         IGraphQLBaseNode graphQLNode = null;
         if (expContext.Type.IsEnumerableOrArray())
         {
             graphQLNode = BuildDynamicSelectOnCollection(expContext, name, context);
         }
         else
         {
             // Could be a list.First() that we need to turn into a select, or
             // other levels are object selection. e.g. from the top level people query I am selecting all their children { field1, etc. }
             // Can we turn a list.First() into and list.Select().First()
             var listExp = ExpressionUtil.FindIEnumerable(expContext);
             if (listExp.Item1 != null)
             {
                 // yes we can
                 // rebuild the ExpressionResult so we keep any ConstantParameters
                 var item1 = (ExpressionResult)listExp.Item1;
                 item1.AddConstantParameters(expContext.ConstantParameters);
                 item1.AddServices(expContext.Services);
                 graphQLNode = BuildDynamicSelectOnCollection(item1, name, context);
                 graphQLNode.SetCombineExpression(listExp.Item2);
             }
             else
             {
                 graphQLNode = BuildDynamicSelectForObjectGraph(expContext, currentExpressionContext.AsParameter(), name, context);
             }
         }
         return(graphQLNode);
     }
     catch (EntityGraphQLCompilerException ex)
     {
         throw SchemaException.MakeFieldCompileError($"Error 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);
        }
示例#4
0
        /// <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
                bool wrapField = 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);
            }
        }