in src/RequestLoader.cpp [1009:1121]
void RequestLoader::SelectionVisitor::visitField(const peg::ast_node& field)
{
std::string_view name;
peg::on_first_child<peg::field_name>(field, [&name](const peg::ast_node& child) {
name = child.string_view();
});
std::string_view alias;
peg::on_first_child<peg::alias_name>(field, [&alias](const peg::ast_node& child) {
alias = child.string_view();
});
if (alias.empty())
{
alias = name;
}
if (!_names.emplace(alias).second)
{
// Skip fields which map to the same response name as a field we've already visited.
// Validation should handle merging multiple references to the same field or to
// compatible fields.
return;
}
ResponseField responseField;
responseField.name = alias;
responseField.cppName = SchemaLoader::getSafeCppName(alias);
responseField.position = field.begin();
// Special case to handle __typename on any ResponseType
if (name == R"gql(__typename)gql"sv)
{
responseField.type = _schema->LookupType("String"sv);
_fields.push_back(std::move(responseField));
return;
}
if (_schema->supportsIntrospection() && _type == _schema->queryType())
{
if (name == R"gql(__schema)gql"sv)
{
responseField.type = _schema->LookupType("__Schema"sv);
}
else if (name == R"gql(__type)gql"sv)
{
responseField.type = _schema->LookupType("__Type"sv);
responseField.modifiers = { service::TypeModifier::Nullable };
}
}
if (!responseField.type)
{
const auto& typeFields = _type->fields();
const auto itr = std::find_if(typeFields.begin(),
typeFields.end(),
[name](const std::shared_ptr<const schema::Field>& typeField) noexcept {
return typeField->name() == name;
});
if (itr == typeFields.end())
{
// Skip fields that are not found on the current type.
return;
}
responseField.type = (*itr)->type().lock();
}
std::tie(responseField.type, responseField.modifiers) =
unwrapSchemaType(std::move(responseField.type));
const peg::ast_node* selection = nullptr;
peg::on_first_child<peg::selection_set>(field, [&selection](const peg::ast_node& child) {
selection = &child;
});
if (selection)
{
switch (responseField.type->kind())
{
case introspection::TypeKind::OBJECT:
case introspection::TypeKind::INTERFACE:
case introspection::TypeKind::UNION:
{
SelectionVisitor selectionVisitor { _schemaLoader,
_fragments,
_schema,
responseField.type };
selectionVisitor.visit(*selection);
auto selectionFields = selectionVisitor.getFields();
if (!selectionFields.empty())
{
responseField.children = std::move(selectionFields);
}
break;
}
default:
break;
}
}
_fields.push_back(std::move(responseField));
}