in compiler/crates/relay-transforms/src/refetchable_fragment/node_query_generator.rs [25:160]
fn build_refetch_operation(
schema: &SDLSchema,
schema_config: &SchemaConfig,
fragment: &Arc<FragmentDefinition>,
query_name: StringKey,
variables_map: &VariableMap,
) -> DiagnosticsResult<Option<RefetchRoot>> {
let id_name = schema_config.node_interface_id_field;
let node_interface_id = schema.get_type(CONSTANTS.node_type_name).and_then(|type_| {
if let Type::Interface(id) = type_ {
Some(id)
} else {
None
}
});
match node_interface_id {
None => Ok(None),
Some(node_interface_id) => {
let eligible = match fragment.type_condition {
Type::Interface(id) => {
id == node_interface_id
|| schema
.interface(id)
.implementing_objects
.iter()
.all(|&object_id| {
schema
.object(object_id)
.interfaces
.iter()
.any(|interface_id| *interface_id == node_interface_id)
})
}
Type::Object(id) => schema
.object(id)
.interfaces
.iter()
.any(|interface_id| *interface_id == node_interface_id),
Type::Union(id) => schema.union(id).members.iter().all(|&object_id| {
schema
.object(object_id)
.interfaces
.iter()
.any(|interface_id| *interface_id == node_interface_id)
}),
_ => false,
};
if !eligible {
return Ok(None);
}
// Check if the fragment type have an `id` field
let should_generate_inline_fragment_on_node = schema
.named_field(fragment.type_condition, id_name)
.is_none();
let query_type = schema.query_type().unwrap();
let (node_field_id, id_arg) =
get_node_field_id_and_id_arg(schema, query_type, fragment)?;
let node_interface = schema.interface(node_interface_id);
let id_field_id = *node_interface
.fields
.iter()
.find(|&&id| schema.field(id).name.item == id_name)
.unwrap_or_else(|| {
panic!("Expected `Node` to contain a field named `{:}`.", id_name)
});
let fragment = Arc::new(FragmentDefinition {
directives: build_fragment_metadata_as_directive(
fragment,
RefetchableMetadata {
operation_name: query_name,
path: vec![CONSTANTS.node_field_name],
identifier_field: Some(id_name),
},
),
used_global_variables: build_used_global_variables(
variables_map,
&fragment.variable_definitions,
)?,
variable_definitions: fragment.variable_definitions.clone(),
selections: enforce_selections_with_id_field(
fragment,
schema,
id_field_id,
schema_config.node_interface_id_field,
if should_generate_inline_fragment_on_node {
Some(node_interface_id)
} else {
None
},
),
..fragment.as_ref().clone()
});
let mut variable_definitions = build_operation_variable_definitions(&fragment);
if let Some(id_argument) = variable_definitions.named(id_name) {
return Err(vec![Diagnostic::error(
ValidationMessage::RefetchableFragmentOnNodeWithExistingID {
fragment_name: fragment.name.item,
},
id_argument.name.location,
)]);
}
variable_definitions.push(VariableDefinition {
name: WithLocation::new(fragment.name.location, id_name),
type_: id_arg.type_.non_null(),
default_value: None,
directives: vec![],
});
Ok(Some(RefetchRoot {
variable_definitions,
selections: vec![Selection::LinkedField(Arc::new(LinkedField {
alias: None,
definition: WithLocation::new(fragment.name.location, node_field_id),
arguments: vec![Argument {
name: WithLocation::new(fragment.name.location, id_arg.name),
value: WithLocation::new(
fragment.name.location,
Value::Variable(Variable {
name: WithLocation::new(fragment.name.location, id_name),
type_: id_arg.type_.non_null(),
}),
),
}],
directives: vec![],
selections: vec![build_fragment_spread(&fragment)],
}))],
fragment,
}))
}
}
}