Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support defer/stream spec proposal #3121

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
85 changes: 60 additions & 25 deletions compiler/crates/relay-codegen/src/build_ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,15 @@ use graphql_ir::{
use graphql_syntax::OperationKind;
use intern::string_key::{Intern, StringKey};
use md5::{Digest, Md5};
use relay_config::DeferStreamInterface;
use relay_transforms::{
extract_connection_metadata_from_directive, extract_handle_field_directives,
extract_values_from_handle_field_directive, generate_abstract_type_refinement_key,
remove_directive, ClientEdgeMetadata, ConnectionConstants, ConnectionMetadata, DeferDirective,
InlineDirectiveMetadata, ModuleMetadata, RefetchableMetadata, RelayDirective,
RelayResolverSpreadMetadata, RequiredMetadataDirective, StreamDirective,
CLIENT_EXTENSION_DIRECTIVE_NAME, DEFER_STREAM_CONSTANTS, DIRECTIVE_SPLIT_OPERATION,
INLINE_DIRECTIVE_NAME, INTERNAL_METADATA_DIRECTIVE, NO_INLINE_DIRECTIVE_NAME,
CLIENT_EXTENSION_DIRECTIVE_NAME, DIRECTIVE_SPLIT_OPERATION, INLINE_DIRECTIVE_NAME,
INTERNAL_METADATA_DIRECTIVE, NO_INLINE_DIRECTIVE_NAME,
REACT_FLIGHT_SCALAR_FLIGHT_FIELD_METADATA_KEY, RELAY_ACTOR_CHANGE_DIRECTIVE_FOR_CODEGEN,
RELAY_CLIENT_COMPONENT_MODULE_ID_ARGUMENT_NAME, RELAY_CLIENT_COMPONENT_SERVER_DIRECTIVE_NAME,
TYPE_DISCRIMINATOR_DIRECTIVE_NAME,
Expand All @@ -40,19 +41,29 @@ pub fn build_request_params_ast_key(
ast_builder: &mut AstBuilder,
operation: &OperationDefinition,
top_level_statements: &TopLevelStatements,
defer_stream_interface: &DeferStreamInterface,
) -> AstKey {
let mut operation_builder =
CodegenBuilder::new(schema, CodegenVariant::Normalization, ast_builder);
let mut operation_builder = CodegenBuilder::new(
schema,
CodegenVariant::Normalization,
ast_builder,
defer_stream_interface,
);
operation_builder.build_request_parameters(operation, request_parameters, top_level_statements)
}

pub fn build_provided_variables(
schema: &SDLSchema,
ast_builder: &mut AstBuilder,
operation: &OperationDefinition,
defer_stream_interface: &DeferStreamInterface,
) -> Option<AstKey> {
let mut operation_builder =
CodegenBuilder::new(schema, CodegenVariant::Normalization, ast_builder);
let mut operation_builder = CodegenBuilder::new(
schema,
CodegenVariant::Normalization,
ast_builder,
defer_stream_interface,
);

operation_builder.build_operation_provided_variables(&operation.variable_definitions)
}
Expand All @@ -63,11 +74,21 @@ pub fn build_request(
operation: &OperationDefinition,
fragment: &FragmentDefinition,
request_parameters: AstKey,
defer_stream_interface: &DeferStreamInterface,
) -> AstKey {
let mut operation_builder =
CodegenBuilder::new(schema, CodegenVariant::Normalization, ast_builder);
let mut operation_builder = CodegenBuilder::new(
schema,
CodegenVariant::Normalization,
ast_builder,
defer_stream_interface,
);
let operation = Primitive::Key(operation_builder.build_operation(operation));
let mut fragment_builder = CodegenBuilder::new(schema, CodegenVariant::Reader, ast_builder);
let mut fragment_builder = CodegenBuilder::new(
schema,
CodegenVariant::Reader,
ast_builder,
defer_stream_interface,
);
let fragment = Primitive::Key(fragment_builder.build_fragment(fragment, true));

ast_builder.intern(Ast::Object(object! {
Expand All @@ -92,22 +113,35 @@ pub fn build_operation(
schema: &SDLSchema,
ast_builder: &mut AstBuilder,
operation: &OperationDefinition,
defer_stream_interface: &DeferStreamInterface,
) -> AstKey {
let mut builder = CodegenBuilder::new(schema, CodegenVariant::Normalization, ast_builder);
let mut builder = CodegenBuilder::new(
schema,
CodegenVariant::Normalization,
ast_builder,
defer_stream_interface,
);
builder.build_operation(operation)
}

pub fn build_fragment(
schema: &SDLSchema,
ast_builder: &mut AstBuilder,
fragment: &FragmentDefinition,
defer_stream_interface: &DeferStreamInterface,
) -> AstKey {
let mut builder = CodegenBuilder::new(schema, CodegenVariant::Reader, ast_builder);
let mut builder = CodegenBuilder::new(
schema,
CodegenVariant::Reader,
ast_builder,
defer_stream_interface,
);
builder.build_fragment(fragment, false)
}

pub struct CodegenBuilder<'schema, 'builder> {
pub struct CodegenBuilder<'schema, 'builder, 'dsi> {
connection_constants: ConnectionConstants,
defer_stream_interface: &'dsi DeferStreamInterface,
schema: &'schema SDLSchema,
variant: CodegenVariant,
ast_builder: &'builder mut AstBuilder,
Expand All @@ -119,15 +153,17 @@ pub enum CodegenVariant {
Normalization,
}

impl<'schema, 'builder> CodegenBuilder<'schema, 'builder> {
impl<'schema, 'builder, 'dsi> CodegenBuilder<'schema, 'builder, 'dsi> {
pub fn new(
schema: &'schema SDLSchema,
variant: CodegenVariant,
ast_builder: &'builder mut AstBuilder,
defer_stream_interface: &'dsi DeferStreamInterface,
) -> Self {
Self {
connection_constants: Default::default(),
schema,
defer_stream_interface,
variant,
ast_builder,
}
Expand Down Expand Up @@ -334,7 +370,7 @@ impl<'schema, 'builder> CodegenBuilder<'schema, 'builder> {
};
if metadata.is_stream_connection {
object.push(ObjectEntry {
key: DEFER_STREAM_CONSTANTS.stream_name,
key: self.defer_stream_interface.stream_name,
value: Primitive::Bool(true),
})
}
Expand Down Expand Up @@ -374,20 +410,16 @@ impl<'schema, 'builder> CodegenBuilder<'schema, 'builder> {
Selection::InlineFragment(inline_fragment) => {
let defer = inline_fragment
.directives
.named(DEFER_STREAM_CONSTANTS.defer_name);
.named(self.defer_stream_interface.defer_name);
if let Some(defer) = defer {
vec![self.build_defer(inline_fragment, defer)]
} else if let Some(inline_data_directive) =
InlineDirectiveMetadata::find(&inline_fragment.directives)
{
// If inline fragment has @__inline directive (created by inline_data_fragment transform)
// we will return selection wrapped with InlineDataFragmentSpread
vec![
self.build_inline_data_fragment_spread(
inline_fragment,
inline_data_directive,
),
]
vec![self
.build_inline_data_fragment_spread(inline_fragment, inline_data_directive)]
} else if let Some(module_metadata) =
ModuleMetadata::find(&inline_fragment.directives)
{
Expand All @@ -403,7 +435,9 @@ impl<'schema, 'builder> CodegenBuilder<'schema, 'builder> {
}
}
Selection::LinkedField(field) => {
let stream = field.directives.named(DEFER_STREAM_CONSTANTS.stream_name);
let stream = field
.directives
.named(self.defer_stream_interface.stream_name);

match stream {
Some(stream) => vec![self.build_stream(field, stream)],
Expand Down Expand Up @@ -806,7 +840,8 @@ impl<'schema, 'builder> CodegenBuilder<'schema, 'builder> {
defer: &Directive,
) -> Primitive {
let next_selections = self.build_selections(inline_fragment.selections.iter());
let DeferDirective { if_arg, label_arg } = DeferDirective::from(defer);
let DeferDirective { if_arg, label_arg } =
DeferDirective::from(defer, self.defer_stream_interface);
let if_variable_name = if_arg.and_then(|arg| match &arg.value.item {
// `true` is the default, remove as the AST is typed just as a variable name string
// `false` constant values should've been transformed away in skip_unreachable_node
Expand All @@ -828,7 +863,7 @@ impl<'schema, 'builder> CodegenBuilder<'schema, 'builder> {
let next_selections = self.build_linked_field_and_handles(&LinkedField {
directives: remove_directive(
&linked_field.directives,
DEFER_STREAM_CONSTANTS.stream_name,
self.defer_stream_interface.stream_name,
),
..linked_field.to_owned()
});
Expand All @@ -844,7 +879,7 @@ impl<'schema, 'builder> CodegenBuilder<'schema, 'builder> {
label_arg,
use_customized_batch_arg: _,
initial_count_arg: _,
} = StreamDirective::from(stream);
} = StreamDirective::from(stream, self.defer_stream_interface);
let if_variable_name = if_arg.and_then(|arg| match &arg.value.item {
// `true` is the default, remove as the AST is typed just as a variable name string
// `false` constant values should've been transformed away in skip_unreachable_node
Expand Down
45 changes: 40 additions & 5 deletions compiler/crates/relay-codegen/src/printer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,12 @@ pub fn print_operation(
project_config: &ProjectConfig,
top_level_statements: &mut TopLevelStatements,
) -> String {
Printer::without_dedupe(project_config).print_operation(schema, operation, top_level_statements)
Printer::without_dedupe(project_config).print_operation(
schema,
operation,
top_level_statements,
project_config,
)
}

pub fn print_fragment(
Expand All @@ -40,7 +45,12 @@ pub fn print_fragment(
project_config: &ProjectConfig,
top_level_statements: &mut TopLevelStatements,
) -> String {
Printer::without_dedupe(project_config).print_fragment(schema, fragment, top_level_statements)
Printer::without_dedupe(project_config).print_fragment(
schema,
fragment,
top_level_statements,
project_config,
)
}

pub fn print_request(
Expand All @@ -57,6 +67,7 @@ pub fn print_request(
fragment,
request_parameters,
top_level_statements,
project_config,
)
}

Expand All @@ -77,6 +88,7 @@ pub fn print_request_params(
&mut builder,
operation,
top_level_statements,
&project_config.schema_config.defer_stream_interface,
);
let printer = JSONPrinter::new(&builder, project_config, top_level_statements);
printer.print(request_parameters_ast_key, false)
Expand Down Expand Up @@ -110,8 +122,14 @@ impl<'p> Printer<'p> {
schema: &SDLSchema,
operation: &OperationDefinition,
top_level_statements: &mut TopLevelStatements,
project_config: &ProjectConfig,
) -> Option<String> {
let key = build_provided_variables(schema, &mut self.builder, operation)?;
let key = build_provided_variables(
schema,
&mut self.builder,
operation,
&project_config.schema_config.defer_stream_interface,
)?;
let printer = JSONPrinter::new(&self.builder, self.project_config, top_level_statements);
Some(printer.print(key, self.dedupe))
}
Expand All @@ -123,20 +141,23 @@ impl<'p> Printer<'p> {
fragment: &FragmentDefinition,
request_parameters: RequestParameters<'_>,
top_level_statements: &mut TopLevelStatements,
project_config: &ProjectConfig,
) -> String {
let request_parameters = build_request_params_ast_key(
schema,
request_parameters,
&mut self.builder,
operation,
top_level_statements,
&project_config.schema_config.defer_stream_interface,
);
let key = build_request(
schema,
&mut self.builder,
operation,
fragment,
request_parameters,
&project_config.schema_config.defer_stream_interface,
);
let printer = JSONPrinter::new(&self.builder, self.project_config, top_level_statements);
printer.print(key, self.dedupe)
Expand All @@ -147,8 +168,14 @@ impl<'p> Printer<'p> {
schema: &SDLSchema,
operation: &OperationDefinition,
top_level_statements: &mut TopLevelStatements,
project_config: &ProjectConfig,
) -> String {
let key = build_operation(schema, &mut self.builder, operation);
let key = build_operation(
schema,
&mut self.builder,
operation,
&project_config.schema_config.defer_stream_interface,
);
let printer = JSONPrinter::new(&self.builder, self.project_config, top_level_statements);
printer.print(key, self.dedupe)
}
Expand All @@ -158,8 +185,14 @@ impl<'p> Printer<'p> {
schema: &SDLSchema,
fragment: &FragmentDefinition,
top_level_statements: &mut TopLevelStatements,
project_config: &ProjectConfig,
) -> String {
let key = build_fragment(schema, &mut self.builder, fragment);
let key = build_fragment(
schema,
&mut self.builder,
fragment,
&project_config.schema_config.defer_stream_interface,
);
let printer = JSONPrinter::new(&self.builder, self.project_config, top_level_statements);
printer.print(key, self.dedupe)
}
Expand All @@ -170,13 +203,15 @@ impl<'p> Printer<'p> {
request_parameters: RequestParameters<'_>,
operation: &OperationDefinition,
top_level_statements: &mut TopLevelStatements,
project_config: &ProjectConfig,
) -> String {
let key = build_request_params_ast_key(
schema,
request_parameters,
&mut self.builder,
operation,
top_level_statements,
&project_config.schema_config.defer_stream_interface,
);
let printer = JSONPrinter::new(&self.builder, self.project_config, top_level_statements);
printer.print(key, self.dedupe)
Expand Down
5 changes: 3 additions & 2 deletions compiler/crates/relay-codegen/tests/connections/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result<String, String> {
validate_connections(&program, &connection_interface)
.map_err(|diagnostics| diagnostics_to_sorted_string(fixture.content, &diagnostics))?;

let next_program = transform_connections(&program, &connection_interface);
let next_program = transform_connections(&program, &project_config.schema_config);

let mut printed = next_program
.operations()
Expand All @@ -58,13 +58,14 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result<String, String> {
&operation_fragment,
request_parameters,
&mut import_statements,
&project_config,
);
format!("{}{}", import_statements, request)
})
.collect::<Vec<_>>();
let mut import_statements = Default::default();
for def in next_program.fragments() {
printed.push(printer.print_fragment(&schema, def, &mut import_statements));
printed.push(printer.print_fragment(&schema, def, &mut import_statements, &project_config));
}
if !import_statements.is_empty() {
printed.push(import_statements.to_string())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,18 @@ pub fn transform_fixture(fixture: &Fixture<'_>) -> Result<String, String> {
&TEST_SCHEMA,
operation,
&mut import_statements,
&project_config,
);
format!("Operation:\n{}{}\n", import_statements, operation,)
}
graphql_ir::ExecutableDefinition::Fragment(fragment) => {
let mut import_statements = Default::default();
let fragment =
printer.print_fragment(&TEST_SCHEMA, fragment, &mut import_statements);
let fragment = printer.print_fragment(
&TEST_SCHEMA,
fragment,
&mut import_statements,
&project_config,
);
format!("Fragment:\n{}{}\n", import_statements, fragment)
}
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ query QueryWithFragmentWithStream($id: ID!) {

fragment FeedbackFragment on Feedback {
id
actors @stream(initial_count: 1) {
actors @stream(initialCount: 1) {
name
}
}
Expand Down
Loading