private void AddGraphQLFields()

in src/Core/Resolvers/Sql Query Structures/SqlQueryStructure.cs [705:830]


        private void AddGraphQLFields(IReadOnlyList<ISelectionNode> selections, RuntimeConfigProvider runtimeConfigProvider)
        {
            foreach (ISelectionNode node in selections)
            {
                if (node.Kind == SyntaxKind.FragmentSpread)
                {
                    if (_ctx == null)
                    {
                        throw new DataApiBuilderException(
                            message: "No GraphQL context exists",
                            statusCode: HttpStatusCode.InternalServerError,
                            subStatusCode: DataApiBuilderException.SubStatusCodes.UnexpectedError);
                    }

                    FragmentSpreadNode fragmentSpread = (FragmentSpreadNode)node;
                    DocumentNode document = _ctx.Document;
                    FragmentDefinitionNode fragmentDocumentNode = document.GetNodes()
                        .Where(n => n.Kind == SyntaxKind.FragmentDefinition)
                        .Cast<FragmentDefinitionNode>()
                        .Where(n => n.Name.Value == fragmentSpread.Name.Value)
                        .First();

                    AddGraphQLFields(fragmentDocumentNode.SelectionSet.Selections, runtimeConfigProvider);
                    return;
                }

                if (node.Kind == SyntaxKind.InlineFragment)
                {
                    InlineFragmentNode inlineFragment = (InlineFragmentNode)node;
                    AddGraphQLFields(inlineFragment.SelectionSet.Selections, runtimeConfigProvider);
                    return;
                }

                if (node.Kind != SyntaxKind.Field)
                {
                    throw new DataApiBuilderException(
                        $"The current node has a SyntaxKind of {node.Kind} which is unsupported.",
                        HttpStatusCode.InternalServerError,
                        DataApiBuilderException.SubStatusCodes.NotSupported);
                }

                FieldNode field = (FieldNode)node;
                string fieldName = field.Name.Value;

                // Do not add reserved introspection fields prefixed with "__" to the SqlQueryStructure because those fields are handled by HotChocolate.
                bool isIntrospectionField = GraphQLNaming.IsIntrospectionField(field.Name.Value);
                if (isIntrospectionField)
                {
                    continue;
                }

                if (field.SelectionSet is null)
                {
                    if (MetadataProvider.TryGetBackingColumn(EntityName, fieldName, out string? name)
                        && !string.IsNullOrWhiteSpace(name))
                    {
                        AddColumn(columnName: name, labelName: fieldName);
                    }
                    else
                    {
                        AddColumn(fieldName);
                    }
                }
                else
                {
                    IObjectField? subschemaField = _underlyingFieldType.Fields[fieldName];

                    if (_ctx == null)
                    {
                        throw new DataApiBuilderException(
                            message: "No GraphQL context exists",
                            statusCode: HttpStatusCode.InternalServerError,
                            subStatusCode: DataApiBuilderException.SubStatusCodes.UnexpectedError);
                    }

                    IDictionary<string, object?> subqueryParams = ExecutionHelper.GetParametersFromSchemaAndQueryFields(subschemaField, field, _ctx.Variables);
                    SqlQueryStructure subquery = new(
                        _ctx,
                        subqueryParams,
                        MetadataProvider,
                        AuthorizationResolver,
                        subschemaField,
                        field,
                        Counter,
                        runtimeConfigProvider,
                        GraphQLFilterParser);

                    if (PaginationMetadata.IsPaginated)
                    {
                        // add the subquery metadata as children of items instead of the pagination metadata
                        // object of this structure which is associated with the pagination query itself
                        PaginationMetadata.Subqueries[QueryBuilder.PAGINATION_FIELD_NAME].Subqueries.Add(fieldName, subquery.PaginationMetadata);
                    }
                    else
                    {
                        PaginationMetadata.Subqueries.Add(fieldName, subquery.PaginationMetadata);
                    }

                    // pass the parameters of the subquery to the current query so upmost query has all the
                    // parameters of the query tree and it can pass them to the database query executor
                    foreach (KeyValuePair<string, DbConnectionParam> parameter in subquery.Parameters)
                    {
                        Parameters.Add(parameter.Key, parameter.Value);
                    }

                    // use the _underlyingType from the subquery which will be overridden appropriately if the query is paginated
                    ObjectType subunderlyingType = subquery._underlyingFieldType;
                    string targetEntityName = MetadataProvider.GetEntityName(subunderlyingType.Name);
                    string subqueryTableAlias = subquery.SourceAlias;
                    EntityRelationshipKey currentEntityRelationshipKey = new(EntityName, relationshipName: fieldName);
                    AddJoinPredicatesForRelationship(
                        fkLookupKey: currentEntityRelationshipKey,
                        targetEntityName,
                        subqueryTargetTableAlias: subqueryTableAlias,
                        subquery);

                    string subqueryAlias = $"{subqueryTableAlias}_subq";
                    JoinQueries.Add(subqueryAlias, subquery);
                    Columns.Add(new LabelledColumn(tableSchema: subquery.DatabaseObject.SchemaName,
                              tableName: subquery.DatabaseObject.Name,
                              columnName: DATA_IDENT,
                              label: fieldName,
                              tableAlias: subqueryAlias));
                }
            }
        }