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));
}
}
}