in compiler/crates/relay-transforms/src/transform_connections.rs [57:269]
fn transform_connection_selections(
&mut self,
connection_field: &LinkedField,
connection_metadata: &ConnectionMetadata,
connection_directive: &Directive,
) -> Vec<Selection> {
let is_stream_connection = connection_directive.name.item
== self.connection_constants.stream_connection_directive_name;
let schema = &self.program.schema;
let transformed_selections = self
.transform_selections(&connection_field.selections)
.replace_or_else(|| connection_field.selections.clone());
let ((edges_ix, edges_field), page_info_selection) = assert_connection_selections(
schema,
&transformed_selections,
self.connection_interface,
);
let connection_field_type = schema.field(connection_field.definition.item).type_.inner();
// Construct edges selection
let edges_schema_field_id = schema
.named_field(connection_field_type, self.connection_interface.edges)
.expect("Expected presence of edges field to have been previously validated.");
let edges_schema_field = schema.field(edges_schema_field_id);
let edges_field_name = edges_schema_field.name.item;
let edge_type = edges_schema_field.type_.inner();
let mut is_aliased_edges = false;
let mut transformed_edges_field = if let Some(alias) = edges_field.alias {
is_aliased_edges = true;
// The edges selection has to be generated as non-aliased field (since product
// code may be accessing the non-aliased response keys).
if alias.item != edges_field_name {
// If an alias is present, and it is different from the field name,
// we need to build a new edges_selection
LinkedField {
alias: None,
definition: WithLocation::generated(edges_schema_field_id),
arguments: Vec::new(),
directives: Vec::new(),
selections: Vec::new(),
}
} else {
// Otherwise reuse the existing edges field
edges_field.clone()
}
} else {
// If there is no alias present, we can reuse the existing edges field
edges_field.clone()
};
transformed_edges_field
.selections
.push(build_edge_selections(
schema,
edge_type,
self.connection_interface,
));
if is_stream_connection {
let mut arguments = vec![];
for arg in &connection_directive.arguments {
if arg.name.item == DEFER_STREAM_CONSTANTS.if_arg
|| arg.name.item == DEFER_STREAM_CONSTANTS.initial_count_arg
|| arg.name.item == DEFER_STREAM_CONSTANTS.use_customized_batch_arg
{
arguments.push(arg.clone());
} else if arg.name.item == *KEY_ARG_NAME {
arguments.push(Argument {
name: WithLocation::new(
arg.name.location,
DEFER_STREAM_CONSTANTS.label_arg,
),
value: arg.value.clone(),
});
}
}
transformed_edges_field.directives.push(Directive {
name: WithLocation::new(
connection_directive.name.location,
DEFER_STREAM_CONSTANTS.stream_name,
),
arguments,
data: None,
});
}
// Construct page_info selection
let page_info_schema_field_id = schema
.named_field(connection_field_type, self.connection_interface.page_info)
.expect("Expected presence of page_info field to have been previously validated.");
let page_info_schema_field = schema.field(page_info_schema_field_id);
let page_info_field_name = page_info_schema_field.name.item;
let page_info_type = page_info_schema_field.type_.inner();
let mut page_info_ix = None;
let mut is_aliased_page_info = false;
let mut transformed_page_info_field = match page_info_selection {
Some((ix, page_info_field)) => {
page_info_ix = Some(ix);
if let Some(alias) = page_info_field.alias {
// The page_info selection has to be generated as non-aliased field (since product
// code may be accessing the non-aliased response keys).
if alias.item != page_info_field_name {
is_aliased_page_info = true;
// If an alias is present, and it is different from the field name,
// we need to build a new page_info field
LinkedField {
alias: None,
definition: WithLocation::generated(page_info_schema_field_id),
arguments: Vec::new(),
directives: Vec::new(),
selections: Vec::new(),
}
} else {
// Otherwise reuse the existing edges field
page_info_field.clone()
}
} else {
// If there is no alias present, we can reuse the existing edges field
page_info_field.clone()
}
}
None => LinkedField {
alias: None,
definition: WithLocation::generated(page_info_schema_field_id),
arguments: Vec::new(),
directives: Vec::new(),
selections: Vec::new(),
},
};
transformed_page_info_field
.selections
.push(build_page_info_selections(
schema,
page_info_type,
connection_metadata,
self.connection_constants,
self.connection_interface,
));
let transformed_page_info_field_selection = if is_stream_connection {
let mut arguments = vec![];
let connection_args = &connection_directive.arguments;
if let Some(key_arg) = connection_args.named(*KEY_ARG_NAME) {
let key = key_arg.value.item.expect_string_literal();
arguments.push(Argument {
name: WithLocation::new(
key_arg.name.location,
DEFER_STREAM_CONSTANTS.label_arg,
),
value: WithLocation::new(
key_arg.value.location,
Value::Constant(ConstantValue::String(
format!(
"{}$defer${}${}",
self.current_document_name,
key.lookup(),
self.connection_interface.page_info
)
.intern(),
)),
),
});
}
if let Some(if_arg) = connection_args.named(DEFER_STREAM_CONSTANTS.if_arg) {
arguments.push(if_arg.clone());
}
Selection::InlineFragment(Arc::new(InlineFragment {
type_condition: None,
selections: vec![Selection::LinkedField(From::from(
transformed_page_info_field,
))],
directives: vec![Directive {
name: WithLocation::new(
connection_directive.name.location,
DEFER_STREAM_CONSTANTS.defer_name,
),
arguments,
data: None,
}],
}))
} else {
Selection::LinkedField(From::from(transformed_page_info_field))
};
// Copy the original selections, replacing edges/pageInfo (if present)
// with the generated locations. This is to maintain the original field
// ordering.
let mut next_selections = transformed_selections
.iter()
.enumerate()
.map(|(ix, selection)| {
if ix == edges_ix {
if !is_aliased_edges {
return Selection::LinkedField(From::from(transformed_edges_field.clone()));
}
} else if let Some(page_info_ix) = page_info_ix {
if ix == page_info_ix && !is_aliased_page_info {
return transformed_page_info_field_selection.clone();
}
}
selection.clone()
})
.collect::<Vec<_>>();
// If a page_info selection didn't exist, or the selections are aliased,
// append the generated version instead.
if is_aliased_edges {
next_selections.push(Selection::LinkedField(From::from(transformed_edges_field)));
}
if page_info_selection.is_none() || is_aliased_page_info {
next_selections.push(transformed_page_info_field_selection);
}
next_selections
}