Skip to content

Commit cf0fb39

Browse files
voideanvaluefacebook-github-bot
authored andcommitted
incremental build compatible ResolversSchemaModule
Reviewed By: alunyov Differential Revision: D51495491 fbshipit-source-id: 44e55c4ae397605a847fb55489092381e2843504
1 parent cf30bf4 commit cf0fb39

File tree

7 files changed

+102
-66
lines changed

7 files changed

+102
-66
lines changed

compiler/crates/relay-compiler/src/artifact_map.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ pub struct ArtifactMap(pub DashMap<ArtifactSourceKey, Vec<ArtifactRecord>>);
3131

3232
#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash)]
3333
pub enum ArtifactSourceKey {
34+
/// Derieved from a GraphQL Executable Definition
3435
ExecutableDefinition(ExecutableDefinitionName),
36+
/// Derieved from a RelayResolver docblock
3537
ResolverHash(ResolverSourceHash),
38+
/// Derived from GraphQL Schema
39+
Schema(),
3640
}
3741

3842
impl From<ArtifactSourceKeyData> for ArtifactSourceKey {

compiler/crates/relay-compiler/src/build_project/build_ir.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ use graphql_syntax::ExecutableDefinition;
1515
use graphql_text_printer::print_executable_definition_ast;
1616
use md5::Digest;
1717
use md5::Md5;
18+
use relay_transforms::annotate_resolver_root_fragments;
1819
use schema::SDLSchema;
1920

2021
use super::ProjectAsts;
@@ -56,7 +57,10 @@ pub fn build_ir(
5657
) -> Result<BuildIRResult, Vec<Diagnostic>> {
5758
let asts = project_asts.definitions;
5859
let source_hashes = SourceHashes::from_definitions(&asts);
59-
let ir = graphql_ir::build_ir_in_relay_mode(schema, &asts, &project_config.feature_flags)?;
60+
let mut ir = graphql_ir::build_ir_in_relay_mode(schema, &asts, &project_config.feature_flags)?;
61+
if project_config.resolvers_schema_module.is_some() {
62+
ir = annotate_resolver_root_fragments(schema, ir);
63+
}
6064
if is_incremental_build {
6165
let affected_ir = get_reachable_ir(
6266
ir,

compiler/crates/relay-compiler/src/build_project/resolvers_schema_module.rs

Lines changed: 3 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ use common::NamedItem;
1515
use common::SourceLocationKey;
1616
use intern::Lookup;
1717
use relay_codegen::printer::get_module_path;
18-
use relay_transforms::generate_relay_resolvers_model_fragments::get_resolver_source_hash;
1918
use relay_transforms::get_fragment_filename;
2019
use relay_transforms::get_resolver_fragment_dependency_name;
2120
use relay_transforms::relay_resolvers::get_resolver_info;
@@ -42,16 +41,10 @@ pub fn generate_resolvers_schema_module(
4241
schema: &SDLSchema,
4342
output_path: PathBuf,
4443
) -> Result<Artifact, Error> {
45-
let mut artifact_source_keys = vec![];
46-
let content = generate_resolvers_schema_module_content(
47-
config,
48-
project_config,
49-
schema,
50-
&output_path,
51-
&mut artifact_source_keys,
52-
)?;
44+
let content =
45+
generate_resolvers_schema_module_content(config, project_config, schema, &output_path)?;
5346
Ok(Artifact {
54-
artifact_source_keys,
47+
artifact_source_keys: vec![ArtifactSourceKey::Schema()],
5548
path: output_path,
5649
content: ArtifactContent::Generic {
5750
content: sign_file(&content).into_bytes(),
@@ -65,7 +58,6 @@ fn generate_resolvers_schema_module_content(
6558
project_config: &ProjectConfig,
6659
schema: &SDLSchema,
6760
artifact_path: &PathBuf,
68-
artifact_source_keys: &mut Vec<ArtifactSourceKey>,
6961
) -> Result<String, Error> {
7062
let mut content = String::new();
7163

@@ -124,9 +116,6 @@ fn generate_resolvers_schema_module_content(
124116
object_name = object.name.item
125117
)?;
126118
}
127-
if let Some(source_hash) = get_resolver_source_hash(field) {
128-
artifact_source_keys.push(ArtifactSourceKey::ResolverHash(source_hash));
129-
}
130119

131120
let js_import_path = project_config.js_module_import_identifier(
132121
artifact_path,

compiler/crates/relay-compiler/src/graphql_asts.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,9 +65,11 @@ impl GraphQLAsts {
6565
ArtifactSourceKey::ExecutableDefinition(def_name) => {
6666
Some(def_name)
6767
}
68-
// Dirty resolvers artifacts are handled separately
69-
// and should not affect the list of affected document defintions
70-
ArtifactSourceKey::ResolverHash(_) => None,
68+
ArtifactSourceKey::Schema()
69+
| ArtifactSourceKey::ResolverHash(_) => {
70+
// We're only concerned with collecting ExecutableDefinitionNames
71+
None
72+
}
7173
})
7274
.collect()
7375
}),

compiler/crates/relay-lsp/src/server/lsp_state_resources.rs

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -433,12 +433,10 @@ impl<TPerfLogger: PerfLogger + 'static, TSchemaDocumentation: SchemaDocumentatio
433433
.iter()
434434
.filter_map(|artifact_source| match artifact_source {
435435
ArtifactSourceKey::ExecutableDefinition(name) => Some(*name),
436-
// For the resolver case, we don't really need to track removed resolver definitions
437-
// here, as the documents for resolves are not accessible for the user
438-
// in the LSP program. We only care about unused fragments/operations
439-
// that are editable by the user.
440-
// We also don't write artifacts from LSP so it is safe to skip these here.
441-
ArtifactSourceKey::ResolverHash(_) => None,
436+
ArtifactSourceKey::Schema() | ArtifactSourceKey::ResolverHash(_) => {
437+
// In the LSP program, we only care about tracking user-editable ExecutableDefinitions
438+
None
439+
}
442440
})
443441
.collect::<Vec<_>>()
444442
});

compiler/crates/relay-transforms/src/generate_relay_resolvers_root_fragment_split_operation.rs

Lines changed: 80 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -10,23 +10,70 @@ use std::sync::Arc;
1010
use common::DiagnosticsResult;
1111
use common::NamedItem;
1212
use docblock_shared::RELAY_RESOLVER_DIRECTIVE_NAME;
13+
use graphql_ir::associated_data_impl;
14+
use graphql_ir::ExecutableDefinition;
15+
use graphql_ir::FragmentDefinition;
16+
use graphql_ir::FragmentDefinitionName;
1317
use graphql_ir::OperationDefinition;
1418
use graphql_ir::OperationDefinitionName;
1519
use graphql_ir::Program;
1620
use graphql_syntax::OperationKind;
1721
use intern::string_key::Intern;
22+
use rustc_hash::FxHashSet;
23+
use schema::SDLSchema;
1824

19-
use crate::generate_relay_resolvers_model_fragments::directives_with_artifact_source;
2025
use crate::get_normalization_operation_name;
2126
use crate::get_resolver_fragment_dependency_name;
2227
use crate::SplitOperationMetadata;
2328
use crate::RESOLVER_BELONGS_TO_BASE_SCHEMA_DIRECTIVE;
2429

30+
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
31+
struct IsResolverRootFragment();
32+
associated_data_impl!(IsResolverRootFragment);
33+
2534
pub fn generate_relay_resolvers_root_fragment_split_operation(
2635
program: &Program,
2736
) -> DiagnosticsResult<Program> {
2837
let mut operations = vec![];
29-
for field in program.schema.get_fields() {
38+
for fragment in program.fragments() {
39+
if IsResolverRootFragment::find(&fragment.directives).is_some() {
40+
operations.push(Arc::new(OperationDefinition {
41+
name: fragment.name.map(|name| {
42+
OperationDefinitionName(get_normalization_operation_name(name.0).intern())
43+
}),
44+
type_: fragment.type_condition,
45+
variable_definitions: fragment.variable_definitions.clone(),
46+
directives: vec![
47+
SplitOperationMetadata {
48+
location: fragment.name.location,
49+
parent_documents: FxHashSet::from_iter([fragment.name.item.into()]),
50+
derived_from: Some(fragment.name.item),
51+
raw_response_type_generation_mode: None,
52+
}
53+
.into(),
54+
],
55+
selections: fragment.selections.clone(),
56+
kind: OperationKind::Query,
57+
}));
58+
}
59+
}
60+
61+
if operations.is_empty() {
62+
Ok(program.clone())
63+
} else {
64+
let mut next_program = program.clone();
65+
66+
for operation in operations {
67+
next_program.insert_operation(operation)
68+
}
69+
70+
Ok(next_program)
71+
}
72+
}
73+
74+
fn get_resolver_root_fragment_names(schema: &SDLSchema) -> FxHashSet<FragmentDefinitionName> {
75+
let mut names = FxHashSet::default();
76+
for field in schema.get_fields() {
3077
if !field.is_extension
3178
|| field
3279
.directives
@@ -40,47 +87,38 @@ pub fn generate_relay_resolvers_root_fragment_split_operation(
4087
continue;
4188
}
4289

43-
let root_fragment_name = get_resolver_fragment_dependency_name(field);
44-
if root_fragment_name.is_none() {
45-
continue;
90+
if let Some(root_fragment_name) = get_resolver_fragment_dependency_name(field) {
91+
names.insert(root_fragment_name);
4692
}
47-
48-
let root_fragment = program.fragment(root_fragment_name.unwrap()).unwrap();
49-
let operation_name = root_fragment
50-
.name
51-
.map(|name| OperationDefinitionName(get_normalization_operation_name(name.0).intern()));
52-
53-
let mut directives = directives_with_artifact_source(field);
54-
directives.push(
55-
SplitOperationMetadata {
56-
location: root_fragment.name.location,
57-
parent_documents: Default::default(),
58-
derived_from: Some(root_fragment.name.item),
59-
raw_response_type_generation_mode: None,
60-
}
61-
.into(),
62-
);
63-
let operation = OperationDefinition {
64-
name: operation_name,
65-
type_: root_fragment.type_condition,
66-
variable_definitions: root_fragment.variable_definitions.clone(),
67-
directives,
68-
selections: root_fragment.selections.clone(),
69-
kind: OperationKind::Query,
70-
};
71-
72-
operations.push(Arc::new(operation))
7393
}
94+
names
95+
}
7496

75-
if operations.is_empty() {
76-
Ok(program.clone())
77-
} else {
78-
let mut next_program = program.clone();
79-
80-
for operation in operations {
81-
next_program.insert_operation(operation)
82-
}
83-
84-
Ok(next_program)
85-
}
97+
/// Adds a directive on all `FragmentDefinition`s in IR that are marked as a `@rootFragment`
98+
/// for any resolver backed field in the schema (but not base schema)
99+
pub fn annotate_resolver_root_fragments(
100+
schema: &SDLSchema,
101+
ir: Vec<ExecutableDefinition>,
102+
) -> Vec<ExecutableDefinition> {
103+
let resolver_root_fragment_names = get_resolver_root_fragment_names(schema);
104+
ir.into_iter()
105+
.map(|def| {
106+
if let ExecutableDefinition::Fragment(ref fragment) = def {
107+
return if resolver_root_fragment_names.contains(&fragment.name.item) {
108+
ExecutableDefinition::Fragment(FragmentDefinition {
109+
directives: fragment
110+
.directives
111+
.iter()
112+
.cloned()
113+
.chain(vec![IsResolverRootFragment().into()])
114+
.collect(),
115+
..fragment.clone()
116+
})
117+
} else {
118+
def
119+
};
120+
}
121+
def
122+
})
123+
.collect()
86124
}

compiler/crates/relay-transforms/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ pub use generate_id_field::generate_id_field;
130130
pub use generate_live_query_metadata::generate_live_query_metadata;
131131
pub use generate_relay_resolvers_model_fragments::ArtifactSourceKeyData;
132132
pub use generate_relay_resolvers_operations_for_nested_objects::generate_relay_resolvers_operations_for_nested_objects;
133+
pub use generate_relay_resolvers_root_fragment_split_operation::annotate_resolver_root_fragments;
133134
pub use generate_relay_resolvers_root_fragment_split_operation::generate_relay_resolvers_root_fragment_split_operation;
134135
pub use generate_typename::generate_typename;
135136
pub use generate_typename::TYPE_DISCRIMINATOR_DIRECTIVE_NAME;

0 commit comments

Comments
 (0)