Skip to content

Commit

Permalink
incremental build compatible ResolversSchemaModule
Browse files Browse the repository at this point in the history
Reviewed By: alunyov

Differential Revision: D51495491

fbshipit-source-id: 44e55c4ae397605a847fb55489092381e2843504
  • Loading branch information
voideanvalue authored and facebook-github-bot committed Nov 29, 2023
1 parent cf30bf4 commit cf0fb39
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 66 deletions.
4 changes: 4 additions & 0 deletions compiler/crates/relay-compiler/src/artifact_map.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,12 @@ pub struct ArtifactMap(pub DashMap<ArtifactSourceKey, Vec<ArtifactRecord>>);

#[derive(Serialize, Deserialize, Debug, Clone, Eq, PartialEq, Hash)]
pub enum ArtifactSourceKey {
/// Derieved from a GraphQL Executable Definition
ExecutableDefinition(ExecutableDefinitionName),
/// Derieved from a RelayResolver docblock
ResolverHash(ResolverSourceHash),
/// Derived from GraphQL Schema
Schema(),
}

impl From<ArtifactSourceKeyData> for ArtifactSourceKey {
Expand Down
6 changes: 5 additions & 1 deletion compiler/crates/relay-compiler/src/build_project/build_ir.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use graphql_syntax::ExecutableDefinition;
use graphql_text_printer::print_executable_definition_ast;
use md5::Digest;
use md5::Md5;
use relay_transforms::annotate_resolver_root_fragments;
use schema::SDLSchema;

use super::ProjectAsts;
Expand Down Expand Up @@ -56,7 +57,10 @@ pub fn build_ir(
) -> Result<BuildIRResult, Vec<Diagnostic>> {
let asts = project_asts.definitions;
let source_hashes = SourceHashes::from_definitions(&asts);
let ir = graphql_ir::build_ir_in_relay_mode(schema, &asts, &project_config.feature_flags)?;
let mut ir = graphql_ir::build_ir_in_relay_mode(schema, &asts, &project_config.feature_flags)?;
if project_config.resolvers_schema_module.is_some() {
ir = annotate_resolver_root_fragments(schema, ir);
}
if is_incremental_build {
let affected_ir = get_reachable_ir(
ir,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use common::NamedItem;
use common::SourceLocationKey;
use intern::Lookup;
use relay_codegen::printer::get_module_path;
use relay_transforms::generate_relay_resolvers_model_fragments::get_resolver_source_hash;
use relay_transforms::get_fragment_filename;
use relay_transforms::get_resolver_fragment_dependency_name;
use relay_transforms::relay_resolvers::get_resolver_info;
Expand All @@ -42,16 +41,10 @@ pub fn generate_resolvers_schema_module(
schema: &SDLSchema,
output_path: PathBuf,
) -> Result<Artifact, Error> {
let mut artifact_source_keys = vec![];
let content = generate_resolvers_schema_module_content(
config,
project_config,
schema,
&output_path,
&mut artifact_source_keys,
)?;
let content =
generate_resolvers_schema_module_content(config, project_config, schema, &output_path)?;
Ok(Artifact {
artifact_source_keys,
artifact_source_keys: vec![ArtifactSourceKey::Schema()],
path: output_path,
content: ArtifactContent::Generic {
content: sign_file(&content).into_bytes(),
Expand All @@ -65,7 +58,6 @@ fn generate_resolvers_schema_module_content(
project_config: &ProjectConfig,
schema: &SDLSchema,
artifact_path: &PathBuf,
artifact_source_keys: &mut Vec<ArtifactSourceKey>,
) -> Result<String, Error> {
let mut content = String::new();

Expand Down Expand Up @@ -124,9 +116,6 @@ fn generate_resolvers_schema_module_content(
object_name = object.name.item
)?;
}
if let Some(source_hash) = get_resolver_source_hash(field) {
artifact_source_keys.push(ArtifactSourceKey::ResolverHash(source_hash));
}

let js_import_path = project_config.js_module_import_identifier(
artifact_path,
Expand Down
8 changes: 5 additions & 3 deletions compiler/crates/relay-compiler/src/graphql_asts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,9 +65,11 @@ impl GraphQLAsts {
ArtifactSourceKey::ExecutableDefinition(def_name) => {
Some(def_name)
}
// Dirty resolvers artifacts are handled separately
// and should not affect the list of affected document defintions
ArtifactSourceKey::ResolverHash(_) => None,
ArtifactSourceKey::Schema()
| ArtifactSourceKey::ResolverHash(_) => {
// We're only concerned with collecting ExecutableDefinitionNames
None
}
})
.collect()
}),
Expand Down
10 changes: 4 additions & 6 deletions compiler/crates/relay-lsp/src/server/lsp_state_resources.rs
Original file line number Diff line number Diff line change
Expand Up @@ -433,12 +433,10 @@ impl<TPerfLogger: PerfLogger + 'static, TSchemaDocumentation: SchemaDocumentatio
.iter()
.filter_map(|artifact_source| match artifact_source {
ArtifactSourceKey::ExecutableDefinition(name) => Some(*name),
// For the resolver case, we don't really need to track removed resolver definitions
// here, as the documents for resolves are not accessible for the user
// in the LSP program. We only care about unused fragments/operations
// that are editable by the user.
// We also don't write artifacts from LSP so it is safe to skip these here.
ArtifactSourceKey::ResolverHash(_) => None,
ArtifactSourceKey::Schema() | ArtifactSourceKey::ResolverHash(_) => {
// In the LSP program, we only care about tracking user-editable ExecutableDefinitions
None
}
})
.collect::<Vec<_>>()
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,23 +10,70 @@ use std::sync::Arc;
use common::DiagnosticsResult;
use common::NamedItem;
use docblock_shared::RELAY_RESOLVER_DIRECTIVE_NAME;
use graphql_ir::associated_data_impl;
use graphql_ir::ExecutableDefinition;
use graphql_ir::FragmentDefinition;
use graphql_ir::FragmentDefinitionName;
use graphql_ir::OperationDefinition;
use graphql_ir::OperationDefinitionName;
use graphql_ir::Program;
use graphql_syntax::OperationKind;
use intern::string_key::Intern;
use rustc_hash::FxHashSet;
use schema::SDLSchema;

use crate::generate_relay_resolvers_model_fragments::directives_with_artifact_source;
use crate::get_normalization_operation_name;
use crate::get_resolver_fragment_dependency_name;
use crate::SplitOperationMetadata;
use crate::RESOLVER_BELONGS_TO_BASE_SCHEMA_DIRECTIVE;

#[derive(Clone, Debug, PartialEq, Eq, Hash)]
struct IsResolverRootFragment();
associated_data_impl!(IsResolverRootFragment);

pub fn generate_relay_resolvers_root_fragment_split_operation(
program: &Program,
) -> DiagnosticsResult<Program> {
let mut operations = vec![];
for field in program.schema.get_fields() {
for fragment in program.fragments() {
if IsResolverRootFragment::find(&fragment.directives).is_some() {
operations.push(Arc::new(OperationDefinition {
name: fragment.name.map(|name| {
OperationDefinitionName(get_normalization_operation_name(name.0).intern())
}),
type_: fragment.type_condition,
variable_definitions: fragment.variable_definitions.clone(),
directives: vec![
SplitOperationMetadata {
location: fragment.name.location,
parent_documents: FxHashSet::from_iter([fragment.name.item.into()]),
derived_from: Some(fragment.name.item),
raw_response_type_generation_mode: None,
}
.into(),
],
selections: fragment.selections.clone(),
kind: OperationKind::Query,
}));
}
}

if operations.is_empty() {
Ok(program.clone())
} else {
let mut next_program = program.clone();

for operation in operations {
next_program.insert_operation(operation)
}

Ok(next_program)
}
}

fn get_resolver_root_fragment_names(schema: &SDLSchema) -> FxHashSet<FragmentDefinitionName> {
let mut names = FxHashSet::default();
for field in schema.get_fields() {
if !field.is_extension
|| field
.directives
Expand All @@ -40,47 +87,38 @@ pub fn generate_relay_resolvers_root_fragment_split_operation(
continue;
}

let root_fragment_name = get_resolver_fragment_dependency_name(field);
if root_fragment_name.is_none() {
continue;
if let Some(root_fragment_name) = get_resolver_fragment_dependency_name(field) {
names.insert(root_fragment_name);
}

let root_fragment = program.fragment(root_fragment_name.unwrap()).unwrap();
let operation_name = root_fragment
.name
.map(|name| OperationDefinitionName(get_normalization_operation_name(name.0).intern()));

let mut directives = directives_with_artifact_source(field);
directives.push(
SplitOperationMetadata {
location: root_fragment.name.location,
parent_documents: Default::default(),
derived_from: Some(root_fragment.name.item),
raw_response_type_generation_mode: None,
}
.into(),
);
let operation = OperationDefinition {
name: operation_name,
type_: root_fragment.type_condition,
variable_definitions: root_fragment.variable_definitions.clone(),
directives,
selections: root_fragment.selections.clone(),
kind: OperationKind::Query,
};

operations.push(Arc::new(operation))
}
names
}

if operations.is_empty() {
Ok(program.clone())
} else {
let mut next_program = program.clone();

for operation in operations {
next_program.insert_operation(operation)
}

Ok(next_program)
}
/// Adds a directive on all `FragmentDefinition`s in IR that are marked as a `@rootFragment`
/// for any resolver backed field in the schema (but not base schema)
pub fn annotate_resolver_root_fragments(
schema: &SDLSchema,
ir: Vec<ExecutableDefinition>,
) -> Vec<ExecutableDefinition> {
let resolver_root_fragment_names = get_resolver_root_fragment_names(schema);
ir.into_iter()
.map(|def| {
if let ExecutableDefinition::Fragment(ref fragment) = def {
return if resolver_root_fragment_names.contains(&fragment.name.item) {
ExecutableDefinition::Fragment(FragmentDefinition {
directives: fragment
.directives
.iter()
.cloned()
.chain(vec![IsResolverRootFragment().into()])
.collect(),
..fragment.clone()
})
} else {
def
};
}
def
})
.collect()
}
1 change: 1 addition & 0 deletions compiler/crates/relay-transforms/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ pub use generate_id_field::generate_id_field;
pub use generate_live_query_metadata::generate_live_query_metadata;
pub use generate_relay_resolvers_model_fragments::ArtifactSourceKeyData;
pub use generate_relay_resolvers_operations_for_nested_objects::generate_relay_resolvers_operations_for_nested_objects;
pub use generate_relay_resolvers_root_fragment_split_operation::annotate_resolver_root_fragments;
pub use generate_relay_resolvers_root_fragment_split_operation::generate_relay_resolvers_root_fragment_split_operation;
pub use generate_typename::generate_typename;
pub use generate_typename::TYPE_DISCRIMINATOR_DIRECTIVE_NAME;
Expand Down

0 comments on commit cf0fb39

Please sign in to comment.