From 1c4a3b6ccb4763a8806a08c1a6b5348a4de3ca5d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Wa=C5=82ach?= <35966385+PatrykWalach@users.noreply.github.com> Date: Fri, 15 Nov 2024 20:27:43 +0100 Subject: [PATCH 1/8] add magic `__link` field --- .../src/eager_reader_artifact.rs | 2 +- .../src/generate_artifacts.rs | 30 +++++---- .../src/iso_overload_file.rs | 1 + .../src/reader_ast.rs | 52 +++++++++++----- crates/isograph_compiler/src/source_files.rs | 1 + crates/isograph_schema/src/add_link_fields.rs | 61 +++++++++++++++++++ .../src/add_pointers_to_supertypes.rs | 28 ++++++++- .../src/create_merged_selection_set.rs | 28 +++++---- crates/isograph_schema/src/lib.rs | 1 + .../src/process_client_field_declaration.rs | 1 + crates/isograph_schema/src/validate_schema.rs | 1 + .../__isograph/User/asUser/resolver_reader.ts | 6 +- .../AdItem/asAdItem/resolver_reader.ts | 6 +- .../BlogItem/asBlogItem/resolver_reader.ts | 6 +- .../src/core/areEqualWithDeepComparison.ts | 1 + libs/isograph-react/src/core/read.ts | 5 ++ libs/isograph-react/src/core/reader.ts | 9 ++- 17 files changed, 196 insertions(+), 43 deletions(-) create mode 100644 crates/isograph_schema/src/add_link_fields.rs diff --git a/crates/graphql_artifact_generation/src/eager_reader_artifact.rs b/crates/graphql_artifact_generation/src/eager_reader_artifact.rs index 57dcd8982..77a2fa35a 100644 --- a/crates/graphql_artifact_generation/src/eager_reader_artifact.rs +++ b/crates/graphql_artifact_generation/src/eager_reader_artifact.rs @@ -167,7 +167,7 @@ pub(crate) fn generate_eager_reader_condition_artifact( {}{reader_output_type}\n\ > = {{\n\ {}kind: \"EagerReaderArtifact\",\n\ - {}resolver: ({{ data }}) => data.__typename === \"{concrete_type}\",\n\ + {}resolver: ({{ data }}) => data.__typename === \"{concrete_type}\" ? data.__link : null,\n\ {}readerAst,\n\ }};\n\n\ export default artifact;\n", diff --git a/crates/graphql_artifact_generation/src/generate_artifacts.rs b/crates/graphql_artifact_generation/src/generate_artifacts.rs index 9269d83a4..424c87fe0 100644 --- a/crates/graphql_artifact_generation/src/generate_artifacts.rs +++ b/crates/graphql_artifact_generation/src/generate_artifacts.rs @@ -133,6 +133,7 @@ pub fn get_artifact_path_and_content( let encountered_client_field = schema.client_field(*encountered_client_field_id); // Generate reader ASTs for all encountered client fields, which may be reader or refetch reader match &encountered_client_field.variant { + ClientFieldVariant::Link => (), ClientFieldVariant::UserWritten(info) => { path_and_contents.extend(generate_eager_reader_artifacts( schema, @@ -248,6 +249,7 @@ pub fn get_artifact_path_and_content( for user_written_client_field in schema.client_fields.iter().flat_map(|field| match field { ClientType::ClientField(field) => match field.variant { + ClientFieldVariant::Link => None, ClientFieldVariant::UserWritten(_) => Some(field), ClientFieldVariant::ImperativelyLoadedField(_) => None, }, @@ -283,20 +285,25 @@ pub fn get_artifact_path_and_content( for output_type_id in encountered_output_types { let client_field = schema.client_field(output_type_id); - let path_and_content = match client_field.variant { - ClientFieldVariant::UserWritten(info) => generate_eager_reader_output_type_artifact( - schema, - client_field, - project_root, - artifact_directory, - info, - file_extensions, - ), + let artifact_path_and_content = match client_field.variant { + ClientFieldVariant::Link => None, + ClientFieldVariant::UserWritten(info) => { + Some(generate_eager_reader_output_type_artifact( + schema, + client_field, + project_root, + artifact_directory, + info, + file_extensions, + )) + } ClientFieldVariant::ImperativelyLoadedField(_) => { - generate_refetch_output_type_artifact(schema, client_field) + Some(generate_refetch_output_type_artifact(schema, client_field)) } }; - path_and_contents.push(path_and_content); + if let Some(path_and_content) = artifact_path_and_content { + path_and_contents.push(path_and_content); + }; } path_and_contents.push(build_iso_overload_artifact( @@ -403,6 +410,7 @@ pub(crate) fn get_serialized_field_arguments( pub(crate) fn generate_output_type(client_field: &ValidatedClientField) -> ClientFieldOutputType { let variant = &client_field.variant; match variant { + ClientFieldVariant::Link => ClientFieldOutputType("Link".to_string()), ClientFieldVariant::UserWritten(info) => match info.user_written_component_variant { UserWrittenComponentVariant::Eager => { ClientFieldOutputType("ReturnType".to_string()) diff --git a/crates/graphql_artifact_generation/src/iso_overload_file.rs b/crates/graphql_artifact_generation/src/iso_overload_file.rs index 85d347c0c..3a04edb99 100644 --- a/crates/graphql_artifact_generation/src/iso_overload_file.rs +++ b/crates/graphql_artifact_generation/src/iso_overload_file.rs @@ -263,6 +263,7 @@ fn user_written_fields( .iter() .filter_map(|client_field| match client_field { ClientType::ClientField(client_field) => match client_field.variant { + ClientFieldVariant::Link => None, ClientFieldVariant::UserWritten(info) => { Some((client_field, info.user_written_component_variant)) } diff --git a/crates/graphql_artifact_generation/src/reader_ast.rs b/crates/graphql_artifact_generation/src/reader_ast.rs index 789f1c281..3df374ef9 100644 --- a/crates/graphql_artifact_generation/src/reader_ast.rs +++ b/crates/graphql_artifact_generation/src/reader_ast.rs @@ -5,9 +5,9 @@ use isograph_lang_types::{ LoadableDirectiveParameters, RefetchQueryIndex, SelectionType, ServerFieldSelection, }; use isograph_schema::{ - categorize_field_loadability, transform_arguments_with_child_context, FieldType, Loadability, - NameAndArguments, NormalizationKey, ObjectTypeAndFieldName, PathToRefetchField, - RefetchedPathsMap, SchemaServerFieldVariant, ValidatedClientField, + categorize_field_loadability, transform_arguments_with_child_context, ClientFieldVariant, + FieldType, Loadability, NameAndArguments, NormalizationKey, ObjectTypeAndFieldName, + PathToRefetchField, RefetchedPathsMap, SchemaServerFieldVariant, ValidatedClientField, ValidatedIsographSelectionVariant, ValidatedLinkedFieldSelection, ValidatedScalarFieldSelection, ValidatedSchema, ValidatedSelection, VariableContext, }; @@ -204,20 +204,44 @@ fn scalar_client_defined_field_ast_node( indentation_level, scalar_field_selection, ), - None => user_written_variant_ast_node( - scalar_field_selection, - indentation_level, - client_field, - schema, - path, - root_refetched_paths, - reader_imports, - &client_field_variable_context, - parent_variable_context, - ), + None => match client_field.variant { + ClientFieldVariant::Link => { + link_variant_ast_node(scalar_field_selection, indentation_level) + } + ClientFieldVariant::UserWritten(_) | ClientFieldVariant::ImperativelyLoadedField(_) => { + user_written_variant_ast_node( + scalar_field_selection, + indentation_level, + client_field, + schema, + path, + root_refetched_paths, + reader_imports, + &client_field_variable_context, + parent_variable_context, + ) + } + }, } } +#[allow(clippy::too_many_arguments)] +fn link_variant_ast_node( + scalar_field_selection: &ValidatedScalarFieldSelection, + indentation_level: u8, +) -> String { + let alias = scalar_field_selection.name_or_alias().item; + let indent_1 = " ".repeat(indentation_level as usize); + let indent_2 = " ".repeat((indentation_level + 1) as usize); + + format!( + "{indent_1}{{\n\ + {indent_2}kind: \"Link\",\n\ + {indent_2}alias: \"{alias}\",\n\ + {indent_1}}},\n", + ) +} + #[allow(clippy::too_many_arguments)] fn user_written_variant_ast_node( scalar_field_selection: &ValidatedScalarFieldSelection, diff --git a/crates/isograph_compiler/src/source_files.rs b/crates/isograph_compiler/src/source_files.rs index 3447bd4db..1318b0800 100644 --- a/crates/isograph_compiler/src/source_files.rs +++ b/crates/isograph_compiler/src/source_files.rs @@ -67,6 +67,7 @@ impl SourceFiles { process_iso_literals(schema, self.contains_iso)?; process_exposed_fields(schema)?; schema.add_fields_to_subtypes(&outcome.type_refinement_maps.supertype_to_subtype_map)?; + schema.add_link_fields()?; schema .add_pointers_to_supertypes(&outcome.type_refinement_maps.subtype_to_supertype_map)?; add_refetch_fields_to_objects(schema)?; diff --git a/crates/isograph_schema/src/add_link_fields.rs b/crates/isograph_schema/src/add_link_fields.rs new file mode 100644 index 000000000..fbf861b35 --- /dev/null +++ b/crates/isograph_schema/src/add_link_fields.rs @@ -0,0 +1,61 @@ +use common_lang_types::{Location, WithLocation}; +use intern::string_key::Intern; + +use crate::{ + ClientField, ClientFieldVariant, ClientType, FieldType, ObjectTypeAndFieldName, + ProcessTypeDefinitionError, ProcessTypeDefinitionResult, UnvalidatedSchema, +}; + +impl UnvalidatedSchema { + /// For each supertype (e.g. Node), add the fields defined on it (e.g. Node.MyComponent) + /// to subtypes (e.g. creating User.MyComponent). + /// + /// We do not transfer server fields (because that makes no sense in GraphQL, but does + /// it make sense otherwise??) and refetch fields (which are already defined on all valid + /// types.) + /// + /// TODO confirm we don't do this for unions... + pub fn add_link_fields(&mut self) -> ProcessTypeDefinitionResult<()> { + for object in &mut self.server_field_data.server_objects { + let field_name = "__link".intern().into(); + let next_client_field_id = self.client_fields.len().into(); + self.client_fields + .push(ClientType::ClientField(ClientField { + description: Some( + format!("A store Link for the {} type.", object.name) + .intern() + .into(), + ), + id: next_client_field_id, + name: field_name, + parent_object_id: object.id, + variable_definitions: vec![], + reader_selection_set: Some(vec![]), + variant: ClientFieldVariant::Link, + type_and_field: ObjectTypeAndFieldName { + field_name, + type_name: "ID".intern().into(), + }, + refetch_strategy: None, + })); + + if object + .encountered_fields + .insert( + field_name, + FieldType::ClientField(ClientType::ClientField(next_client_field_id)), + ) + .is_some() + { + return Err(WithLocation::new( + ProcessTypeDefinitionError::FieldExistsOnType { + field_name, + parent_type: object.name, + }, + Location::generated(), + )); + } + } + Ok(()) + } +} diff --git a/crates/isograph_schema/src/add_pointers_to_supertypes.rs b/crates/isograph_schema/src/add_pointers_to_supertypes.rs index abe3cdc81..2f054bae0 100644 --- a/crates/isograph_schema/src/add_pointers_to_supertypes.rs +++ b/crates/isograph_schema/src/add_pointers_to_supertypes.rs @@ -4,7 +4,7 @@ use intern::string_key::Intern; use isograph_lang_types::{ScalarFieldSelection, ServerFieldSelection}; use crate::{ - FieldType, ProcessTypeDefinitionError, ProcessTypeDefinitionResult, SchemaObject, + ClientType, FieldType, ProcessTypeDefinitionError, ProcessTypeDefinitionResult, SchemaObject, SchemaServerField, SchemaServerFieldVariant, ServerFieldTypeAssociatedData, ServerFieldTypeAssociatedDataInlineFragment, UnvalidatedSchema, ValidatedIsographSelectionVariant, ValidatedScalarFieldAssociatedData, @@ -56,7 +56,31 @@ impl UnvalidatedSchema { Span::todo_generated(), ); - let condition_selection_set = vec![typename_selection]; + let link_selection = WithSpan::new( + ServerFieldSelection::ScalarField(ScalarFieldSelection { + arguments: vec![], + associated_data: ValidatedScalarFieldAssociatedData { + location: FieldType::ClientField( + match *subtype + .encountered_fields + .get(&"__link".intern().into()) + .expect("Expected __link to exist") + .as_client_field() + .expect("Expected __link to be client field") + { + ClientType::ClientField(client_field_id) => client_field_id, + }, + ), + selection_variant: ValidatedIsographSelectionVariant::Regular, + }, + directives: vec![], + name: WithLocation::new("__link".intern().into(), Location::generated()), + reader_alias: None, + }), + Span::todo_generated(), + ); + + let condition_selection_set = vec![typename_selection, link_selection]; let server_field = SchemaServerField { description: Some( diff --git a/crates/isograph_schema/src/create_merged_selection_set.rs b/crates/isograph_schema/src/create_merged_selection_set.rs index 44bc3b198..35ee4a31b 100644 --- a/crates/isograph_schema/src/create_merged_selection_set.rs +++ b/crates/isograph_schema/src/create_merged_selection_set.rs @@ -18,7 +18,7 @@ use lazy_static::lazy_static; use crate::{ categorize_field_loadability, create_transformed_name_and_arguments, expose_field_directive::RequiresRefinement, transform_arguments_with_child_context, - transform_name_and_arguments_with_child_variable_context, FieldType, + transform_name_and_arguments_with_child_variable_context, ClientFieldVariant, FieldType, ImperativelyLoadedFieldVariant, Loadability, NameAndArguments, PathToRefetchField, RootOperationName, SchemaObject, SchemaServerFieldVariant, UnvalidatedVariableDefinition, ValidatedClientField, ValidatedIsographSelectionVariant, ValidatedScalarFieldSelection, @@ -713,16 +713,22 @@ fn merge_validated_selections_into_selection_map( variant, ); } - None => merge_non_loadable_scalar_client_field( - parent_type, - schema, - parent_map, - merge_traversal_state, - newly_encountered_scalar_client_field, - encountered_client_field_map, - variable_context, - &scalar_field_selection.arguments, - ), + None => match newly_encountered_scalar_client_field.variant { + ClientFieldVariant::Link => {} + ClientFieldVariant::ImperativelyLoadedField(_) + | ClientFieldVariant::UserWritten(_) => { + merge_non_loadable_scalar_client_field( + parent_type, + schema, + parent_map, + merge_traversal_state, + newly_encountered_scalar_client_field, + encountered_client_field_map, + variable_context, + &scalar_field_selection.arguments, + ) + } + }, } merge_traversal_state diff --git a/crates/isograph_schema/src/lib.rs b/crates/isograph_schema/src/lib.rs index 9367d1685..909a25cba 100644 --- a/crates/isograph_schema/src/lib.rs +++ b/crates/isograph_schema/src/lib.rs @@ -1,5 +1,6 @@ mod accessible_client_fields_iterator; mod add_fields_to_subtypes; +mod add_link_fields; mod add_pointers_to_supertypes; mod argument_map; mod create_merged_selection_set; diff --git a/crates/isograph_schema/src/process_client_field_declaration.rs b/crates/isograph_schema/src/process_client_field_declaration.rs index 5eb80815b..f75ed1214 100644 --- a/crates/isograph_schema/src/process_client_field_declaration.rs +++ b/crates/isograph_schema/src/process_client_field_declaration.rs @@ -199,6 +199,7 @@ pub struct UserWrittenClientFieldInfo { pub enum ClientFieldVariant { UserWritten(UserWrittenClientFieldInfo), ImperativelyLoadedField(ImperativelyLoadedFieldVariant), + Link, } lazy_static! { diff --git a/crates/isograph_schema/src/validate_schema.rs b/crates/isograph_schema/src/validate_schema.rs index 3cad920c2..061ce057e 100644 --- a/crates/isograph_schema/src/validate_schema.rs +++ b/crates/isograph_schema/src/validate_schema.rs @@ -331,6 +331,7 @@ pub fn categorize_field_loadability<'a>( selection_variant: &'a ValidatedIsographSelectionVariant, ) -> Option> { match &client_field.variant { + ClientFieldVariant::Link => None, ClientFieldVariant::UserWritten(_) => match selection_variant { ValidatedIsographSelectionVariant::Regular => None, ValidatedIsographSelectionVariant::Loadable((l, _)) => { diff --git a/demos/github-demo/src/isograph-components/__isograph/User/asUser/resolver_reader.ts b/demos/github-demo/src/isograph-components/__isograph/User/asUser/resolver_reader.ts index aa9b966b7..235b7e77d 100644 --- a/demos/github-demo/src/isograph-components/__isograph/User/asUser/resolver_reader.ts +++ b/demos/github-demo/src/isograph-components/__isograph/User/asUser/resolver_reader.ts @@ -7,6 +7,10 @@ const readerAst: ReaderAst<{ data: any, parameters: Record } alias: null, arguments: null, }, + { + kind: "Link", + alias: "__link", + }, ]; const artifact: EagerReaderArtifact< @@ -14,7 +18,7 @@ const artifact: EagerReaderArtifact< boolean > = { kind: "EagerReaderArtifact", - resolver: ({ data }) => data.__typename === "User", + resolver: ({ data }) => data.__typename === "User" ? data.__link : null, readerAst, }; diff --git a/demos/pet-demo/src/components/__isograph/AdItem/asAdItem/resolver_reader.ts b/demos/pet-demo/src/components/__isograph/AdItem/asAdItem/resolver_reader.ts index 2000168ff..6deafd5e8 100644 --- a/demos/pet-demo/src/components/__isograph/AdItem/asAdItem/resolver_reader.ts +++ b/demos/pet-demo/src/components/__isograph/AdItem/asAdItem/resolver_reader.ts @@ -7,6 +7,10 @@ const readerAst: ReaderAst<{ data: any, parameters: Record } alias: null, arguments: null, }, + { + kind: "Link", + alias: "__link", + }, ]; const artifact: EagerReaderArtifact< @@ -14,7 +18,7 @@ const artifact: EagerReaderArtifact< boolean > = { kind: "EagerReaderArtifact", - resolver: ({ data }) => data.__typename === "AdItem", + resolver: ({ data }) => data.__typename === "AdItem" ? data.__link : null, readerAst, }; diff --git a/demos/pet-demo/src/components/__isograph/BlogItem/asBlogItem/resolver_reader.ts b/demos/pet-demo/src/components/__isograph/BlogItem/asBlogItem/resolver_reader.ts index f65548744..4879175ee 100644 --- a/demos/pet-demo/src/components/__isograph/BlogItem/asBlogItem/resolver_reader.ts +++ b/demos/pet-demo/src/components/__isograph/BlogItem/asBlogItem/resolver_reader.ts @@ -7,6 +7,10 @@ const readerAst: ReaderAst<{ data: any, parameters: Record } alias: null, arguments: null, }, + { + kind: "Link", + alias: "__link", + }, ]; const artifact: EagerReaderArtifact< @@ -14,7 +18,7 @@ const artifact: EagerReaderArtifact< boolean > = { kind: "EagerReaderArtifact", - resolver: ({ data }) => data.__typename === "BlogItem", + resolver: ({ data }) => data.__typename === "BlogItem" ? data.__link : null, readerAst, }; diff --git a/libs/isograph-react/src/core/areEqualWithDeepComparison.ts b/libs/isograph-react/src/core/areEqualWithDeepComparison.ts index 2a4bb5570..e4f8c4933 100644 --- a/libs/isograph-react/src/core/areEqualWithDeepComparison.ts +++ b/libs/isograph-react/src/core/areEqualWithDeepComparison.ts @@ -96,6 +96,7 @@ export function mergeObjectsUsingReaderAst( } break; } + case 'Link': case 'ImperativelyLoadedField': case 'LoadablySelectedField': break; diff --git a/libs/isograph-react/src/core/read.ts b/libs/isograph-react/src/core/read.ts index 60643ec71..d558078b1 100644 --- a/libs/isograph-react/src/core/read.ts +++ b/libs/isograph-react/src/core/read.ts @@ -163,6 +163,10 @@ function readData( target[field.alias ?? field.fieldName] = value; break; } + case 'Link': { + target[field.alias] = root; + break; + } case 'Linked': { const storeRecordName = getParentRecordKey(field, variables); const value = storeRecord[storeRecordName]; @@ -605,6 +609,7 @@ function readData( } break; } + default: { // Ensure we have covered all variants let _: never = field; diff --git a/libs/isograph-react/src/core/reader.ts b/libs/isograph-react/src/core/reader.ts index a36e0655f..d59b99565 100644 --- a/libs/isograph-react/src/core/reader.ts +++ b/libs/isograph-react/src/core/reader.ts @@ -79,7 +79,8 @@ export type ReaderAstNode = | ReaderLinkedField | ReaderNonLoadableResolverField | ReaderImperativelyLoadedField - | ReaderLoadableField; + | ReaderLoadableField + | ReaderLinkeField; // @ts-ignore export type ReaderAst = ReadonlyArray; @@ -90,6 +91,12 @@ export type ReaderScalarField = { readonly alias: string | null; readonly arguments: Arguments | null; }; + +export type ReaderLinkeField = { + readonly kind: 'Link'; + readonly alias: string; +}; + export type ReaderLinkedField = { readonly kind: 'Linked'; readonly fieldName: string; From a428142542b0bf44e36254a4d9e87df73f00b5a7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Wa=C5=82ach?= <35966385+PatrykWalach@users.noreply.github.com> Date: Sun, 17 Nov 2024 18:12:46 +0100 Subject: [PATCH 2/8] rename to `link` and import `Link` type --- .../src/eager_reader_artifact.rs | 43 +++++-- .../src/generate_artifacts.rs | 111 +++++++++++------- .../src/import_statements.rs | 1 + .../src/reader_ast.rs | 1 - crates/isograph_schema/src/add_link_fields.rs | 2 +- .../src/add_pointers_to_supertypes.rs | 8 +- .../__isograph/User/asUser/resolver_reader.ts | 8 +- .../AdItem/asAdItem/resolver_reader.ts | 8 +- .../BlogItem/asBlogItem/resolver_reader.ts | 8 +- 9 files changed, 118 insertions(+), 72 deletions(-) diff --git a/crates/graphql_artifact_generation/src/eager_reader_artifact.rs b/crates/graphql_artifact_generation/src/eager_reader_artifact.rs index 77a2fa35a..107727bae 100644 --- a/crates/graphql_artifact_generation/src/eager_reader_artifact.rs +++ b/crates/graphql_artifact_generation/src/eager_reader_artifact.rs @@ -156,10 +156,10 @@ pub(crate) fn generate_eager_reader_condition_artifact( reader_imports_to_import_statement(&reader_imports, file_extensions); let reader_param_type = "{ data: any, parameters: Record }"; - let reader_output_type = "boolean"; + let reader_output_type = "Link | null"; let reader_content = format!( - "import type {{ EagerReaderArtifact, ReaderAst }} from '@isograph/react';\n\ + "import type {{ EagerReaderArtifact, ReaderAst, Link }} from '@isograph/react';\n\ {reader_import_statement}\n\ const readerAst: ReaderAst<{reader_param_type}> = {reader_ast};\n\n\ const artifact: EagerReaderArtifact<\n\ @@ -167,7 +167,7 @@ pub(crate) fn generate_eager_reader_condition_artifact( {}{reader_output_type}\n\ > = {{\n\ {}kind: \"EagerReaderArtifact\",\n\ - {}resolver: ({{ data }}) => data.__typename === \"{concrete_type}\" ? data.__link : null,\n\ + {}resolver: ({{ data }}) => data.__typename === \"{concrete_type}\" ? data.link : null,\n\ {}readerAst,\n\ }};\n\n\ export default artifact;\n", @@ -196,6 +196,7 @@ pub(crate) fn generate_eager_reader_param_type_artifact( let mut param_type_imports = BTreeSet::new(); let mut loadable_fields = BTreeSet::new(); + let mut link_fields = BTreeSet::new(); let client_field_parameter_type = generate_client_field_parameter_type( schema, client_field.selection_set_for_parent_query(), @@ -203,21 +204,45 @@ pub(crate) fn generate_eager_reader_param_type_artifact( &mut param_type_imports, &mut loadable_fields, 1, + &mut link_fields, ); let param_type_import_statement = param_type_imports_to_import_statement(¶m_type_imports, file_extensions); let reader_param_type = format!("{}__{}__param", parent_type.name, client_field.name); + let link_field_imports = if !link_fields.is_empty() { + Some("type Link") + } else { + None + }; + let loadable_field_imports = if !loadable_fields.is_empty() { let param_imports = param_type_imports_to_import_param_statement(&loadable_fields, file_extensions); - format!( - "import {{ type LoadableField, type ExtractParameters }} from '@isograph/react';\n\ - {param_imports}" - ) + + Some(("type LoadableField, type ExtractParameters", param_imports)) } else { - "".to_string() + None + }; + + let isograph_react_imports = match (link_field_imports, loadable_field_imports) { + (None, None) => "".to_string(), + (Some(link_field_import), None) => { + format!("import {{ {link_field_import} }} from '@isograph/react';\n") + } + (None, Some((loadable_field_imports, param_imports))) => { + format!( + "import {{ {loadable_field_imports} }} from '@isograph/react';\n\ + {param_imports}" + ) + } + (Some(link_field_import), Some((loadable_field_imports, param_imports))) => { + format!( + "import {{ {link_field_import}, {loadable_field_imports} }} from '@isograph/react';\n\ + {param_imports}" + ) + } }; let (parameters_import, parameters_type) = if !client_field.variable_definitions.is_empty() { @@ -234,7 +259,7 @@ pub(crate) fn generate_eager_reader_param_type_artifact( let indent = " "; let param_type_content = format!( "{param_type_import_statement}\ - {loadable_field_imports}\ + {isograph_react_imports}\ {parameters_import}\n\ export type {reader_param_type} = {{\n\ {indent}readonly data: {client_field_parameter_type},\n\ diff --git a/crates/graphql_artifact_generation/src/generate_artifacts.rs b/crates/graphql_artifact_generation/src/generate_artifacts.rs index 424c87fe0..dfe7bbe11 100644 --- a/crates/graphql_artifact_generation/src/generate_artifacts.rs +++ b/crates/graphql_artifact_generation/src/generate_artifacts.rs @@ -36,7 +36,7 @@ use crate::{ generate_entrypoint_artifacts_with_client_field_traversal_result, }, format_parameter_type::format_parameter_type, - import_statements::ParamTypeImports, + import_statements::{LinkImports, ParamTypeImports}, iso_overload_file::build_iso_overload_artifact, refetch_reader_artifact::{ generate_refetch_output_type_artifact, generate_refetch_reader_artifact, @@ -446,6 +446,7 @@ pub(crate) fn generate_client_field_parameter_type( nested_client_field_imports: &mut ParamTypeImports, loadable_fields: &mut ParamTypeImports, indentation_level: u8, + link_fields: &mut LinkImports, ) -> ClientFieldParameterType { // TODO use unwraps let mut client_field_parameter_type = "{\n".to_string(); @@ -458,6 +459,7 @@ pub(crate) fn generate_client_field_parameter_type( nested_client_field_imports, loadable_fields, indentation_level + 1, + link_fields, ); } client_field_parameter_type.push_str(&format!("{}}}", " ".repeat(indentation_level as usize))); @@ -465,6 +467,7 @@ pub(crate) fn generate_client_field_parameter_type( ClientFieldParameterType(client_field_parameter_type) } +#[allow(clippy::too_many_arguments)] fn write_param_type_from_selection( schema: &ValidatedSchema, query_type_declaration: &mut String, @@ -473,6 +476,7 @@ fn write_param_type_from_selection( nested_client_field_imports: &mut ParamTypeImports, loadable_fields: &mut ParamTypeImports, indentation_level: u8, + link_fields: &mut LinkImports, ) { match &selection.item { ServerFieldSelection::ScalarField(scalar_field_selection) => { @@ -524,55 +528,71 @@ fn write_param_type_from_selection( query_type_declaration .push_str(&" ".repeat(indentation_level as usize).to_string()); - nested_client_field_imports.insert(client_field.type_and_field); - let inner_output_type = format!( - "{}__output_type", - client_field.type_and_field.underscore_separated() - ); - - let output_type = match scalar_field_selection.associated_data.selection_variant - { - ValidatedIsographSelectionVariant::Regular => inner_output_type, - ValidatedIsographSelectionVariant::Loadable(_) => { - loadable_fields.insert(client_field.type_and_field); - let provided_arguments = get_provided_arguments( - client_field.variable_definitions.iter().map(|x| &x.item), - &scalar_field_selection.arguments, + match client_field.variant { + ClientFieldVariant::Link => { + link_fields.insert(()); + let output_type = "Link"; + query_type_declaration.push_str( + &(format!( + "readonly {}: {},\n", + scalar_field_selection.name_or_alias().item, + output_type + )), + ); + } + ClientFieldVariant::UserWritten(_) + | ClientFieldVariant::ImperativelyLoadedField(_) => { + nested_client_field_imports.insert(client_field.type_and_field); + let inner_output_type = format!( + "{}__output_type", + client_field.type_and_field.underscore_separated() ); + let output_type = match scalar_field_selection + .associated_data + .selection_variant + { + ValidatedIsographSelectionVariant::Regular => inner_output_type, + ValidatedIsographSelectionVariant::Loadable(_) => { + loadable_fields.insert(client_field.type_and_field); + let provided_arguments = get_provided_arguments( + client_field.variable_definitions.iter().map(|x| &x.item), + &scalar_field_selection.arguments, + ); - let indent = " ".repeat((indentation_level + 1) as usize); - let provided_args_type = if provided_arguments.is_empty() { - "".to_string() - } else { - format!( - ",\n{indent}Omit, keyof {}>", - client_field.type_and_field.underscore_separated(), - get_loadable_field_type_from_arguments( - schema, - provided_arguments + let indent = " ".repeat((indentation_level + 1) as usize); + let provided_args_type = if provided_arguments.is_empty() { + "".to_string() + } else { + format!( + ",\n{indent}Omit, keyof {}>", + client_field.type_and_field.underscore_separated(), + get_loadable_field_type_from_arguments( + schema, + provided_arguments + ) + ) + }; + + format!( + "LoadableField<\n\ + {indent}{}__param,\n\ + {indent}{inner_output_type}\ + {provided_args_type}\n\ + {}>", + client_field.type_and_field.underscore_separated(), + " ".repeat(indentation_level as usize), ) - ) + } }; - - format!( - "LoadableField<\n\ - {indent}{}__param,\n\ - {indent}{inner_output_type}\ - {provided_args_type}\n\ - {}>", - client_field.type_and_field.underscore_separated(), - " ".repeat(indentation_level as usize), - ) + query_type_declaration.push_str( + &(format!( + "readonly {}: {},\n", + scalar_field_selection.name_or_alias().item, + output_type + )), + ); } - }; - - query_type_declaration.push_str( - &(format!( - "readonly {}: {},\n", - scalar_field_selection.name_or_alias().item, - output_type - )), - ); + } } } } @@ -611,6 +631,7 @@ fn write_param_type_from_selection( nested_client_field_imports, loadable_fields, indentation_level, + link_fields, ) }), }; diff --git a/crates/graphql_artifact_generation/src/import_statements.rs b/crates/graphql_artifact_generation/src/import_statements.rs index 176feaf8a..d1d53c22f 100644 --- a/crates/graphql_artifact_generation/src/import_statements.rs +++ b/crates/graphql_artifact_generation/src/import_statements.rs @@ -22,6 +22,7 @@ impl ImportedFileCategory { pub(crate) type ReaderImports = BTreeSet<(ObjectTypeAndFieldName, ImportedFileCategory)>; pub(crate) type ParamTypeImports = BTreeSet; +pub(crate) type LinkImports = BTreeSet<()>; pub(crate) fn reader_imports_to_import_statement( reader_imports: &ReaderImports, diff --git a/crates/graphql_artifact_generation/src/reader_ast.rs b/crates/graphql_artifact_generation/src/reader_ast.rs index 3df374ef9..076413a9b 100644 --- a/crates/graphql_artifact_generation/src/reader_ast.rs +++ b/crates/graphql_artifact_generation/src/reader_ast.rs @@ -225,7 +225,6 @@ fn scalar_client_defined_field_ast_node( } } -#[allow(clippy::too_many_arguments)] fn link_variant_ast_node( scalar_field_selection: &ValidatedScalarFieldSelection, indentation_level: u8, diff --git a/crates/isograph_schema/src/add_link_fields.rs b/crates/isograph_schema/src/add_link_fields.rs index fbf861b35..012b22e48 100644 --- a/crates/isograph_schema/src/add_link_fields.rs +++ b/crates/isograph_schema/src/add_link_fields.rs @@ -17,7 +17,7 @@ impl UnvalidatedSchema { /// TODO confirm we don't do this for unions... pub fn add_link_fields(&mut self) -> ProcessTypeDefinitionResult<()> { for object in &mut self.server_field_data.server_objects { - let field_name = "__link".intern().into(); + let field_name = "link".intern().into(); let next_client_field_id = self.client_fields.len().into(); self.client_fields .push(ClientType::ClientField(ClientField { diff --git a/crates/isograph_schema/src/add_pointers_to_supertypes.rs b/crates/isograph_schema/src/add_pointers_to_supertypes.rs index 2f054bae0..b7638d590 100644 --- a/crates/isograph_schema/src/add_pointers_to_supertypes.rs +++ b/crates/isograph_schema/src/add_pointers_to_supertypes.rs @@ -63,10 +63,10 @@ impl UnvalidatedSchema { location: FieldType::ClientField( match *subtype .encountered_fields - .get(&"__link".intern().into()) - .expect("Expected __link to exist") + .get(&"link".intern().into()) + .expect("Expected link to exist") .as_client_field() - .expect("Expected __link to be client field") + .expect("Expected link to be client field") { ClientType::ClientField(client_field_id) => client_field_id, }, @@ -74,7 +74,7 @@ impl UnvalidatedSchema { selection_variant: ValidatedIsographSelectionVariant::Regular, }, directives: vec![], - name: WithLocation::new("__link".intern().into(), Location::generated()), + name: WithLocation::new("link".intern().into(), Location::generated()), reader_alias: None, }), Span::todo_generated(), diff --git a/demos/github-demo/src/isograph-components/__isograph/User/asUser/resolver_reader.ts b/demos/github-demo/src/isograph-components/__isograph/User/asUser/resolver_reader.ts index 235b7e77d..6c7cc03ef 100644 --- a/demos/github-demo/src/isograph-components/__isograph/User/asUser/resolver_reader.ts +++ b/demos/github-demo/src/isograph-components/__isograph/User/asUser/resolver_reader.ts @@ -1,4 +1,4 @@ -import type { EagerReaderArtifact, ReaderAst } from '@isograph/react'; +import type { EagerReaderArtifact, ReaderAst, Link } from '@isograph/react'; const readerAst: ReaderAst<{ data: any, parameters: Record }> = [ { @@ -9,16 +9,16 @@ const readerAst: ReaderAst<{ data: any, parameters: Record } }, { kind: "Link", - alias: "__link", + alias: "link", }, ]; const artifact: EagerReaderArtifact< { data: any, parameters: Record }, - boolean + Link | null > = { kind: "EagerReaderArtifact", - resolver: ({ data }) => data.__typename === "User" ? data.__link : null, + resolver: ({ data }) => data.__typename === "User" ? data.link : null, readerAst, }; diff --git a/demos/pet-demo/src/components/__isograph/AdItem/asAdItem/resolver_reader.ts b/demos/pet-demo/src/components/__isograph/AdItem/asAdItem/resolver_reader.ts index 6deafd5e8..7562bd540 100644 --- a/demos/pet-demo/src/components/__isograph/AdItem/asAdItem/resolver_reader.ts +++ b/demos/pet-demo/src/components/__isograph/AdItem/asAdItem/resolver_reader.ts @@ -1,4 +1,4 @@ -import type { EagerReaderArtifact, ReaderAst } from '@isograph/react'; +import type { EagerReaderArtifact, ReaderAst, Link } from '@isograph/react'; const readerAst: ReaderAst<{ data: any, parameters: Record }> = [ { @@ -9,16 +9,16 @@ const readerAst: ReaderAst<{ data: any, parameters: Record } }, { kind: "Link", - alias: "__link", + alias: "link", }, ]; const artifact: EagerReaderArtifact< { data: any, parameters: Record }, - boolean + Link | null > = { kind: "EagerReaderArtifact", - resolver: ({ data }) => data.__typename === "AdItem" ? data.__link : null, + resolver: ({ data }) => data.__typename === "AdItem" ? data.link : null, readerAst, }; diff --git a/demos/pet-demo/src/components/__isograph/BlogItem/asBlogItem/resolver_reader.ts b/demos/pet-demo/src/components/__isograph/BlogItem/asBlogItem/resolver_reader.ts index 4879175ee..5bb1d6963 100644 --- a/demos/pet-demo/src/components/__isograph/BlogItem/asBlogItem/resolver_reader.ts +++ b/demos/pet-demo/src/components/__isograph/BlogItem/asBlogItem/resolver_reader.ts @@ -1,4 +1,4 @@ -import type { EagerReaderArtifact, ReaderAst } from '@isograph/react'; +import type { EagerReaderArtifact, ReaderAst, Link } from '@isograph/react'; const readerAst: ReaderAst<{ data: any, parameters: Record }> = [ { @@ -9,16 +9,16 @@ const readerAst: ReaderAst<{ data: any, parameters: Record } }, { kind: "Link", - alias: "__link", + alias: "link", }, ]; const artifact: EagerReaderArtifact< { data: any, parameters: Record }, - boolean + Link | null > = { kind: "EagerReaderArtifact", - resolver: ({ data }) => data.__typename === "BlogItem" ? data.__link : null, + resolver: ({ data }) => data.__typename === "BlogItem" ? data.link : null, readerAst, }; From 67637e86004cd3eae0d741e8ecc610aa963b0e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Wa=C5=82ach?= <35966385+PatrykWalach@users.noreply.github.com> Date: Tue, 19 Nov 2024 23:09:42 +0100 Subject: [PATCH 3/8] check `Link` equality --- .../src/core/areEqualWithDeepComparison.ts | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/libs/isograph-react/src/core/areEqualWithDeepComparison.ts b/libs/isograph-react/src/core/areEqualWithDeepComparison.ts index e4f8c4933..8574cbf0e 100644 --- a/libs/isograph-react/src/core/areEqualWithDeepComparison.ts +++ b/libs/isograph-react/src/core/areEqualWithDeepComparison.ts @@ -1,3 +1,4 @@ +import type { Link } from './IsographEnvironment'; import type { ReaderAst, ReaderLinkedField, ReaderScalarField } from './reader'; export function mergeUsingReaderAst( field: ReaderScalarField | ReaderLinkedField, @@ -96,7 +97,24 @@ export function mergeObjectsUsingReaderAst( } break; } - case 'Link': + case 'Link': { + const key = field.alias; + // @ts-expect-error + const oldValue: Link = oldItemObject[key]; + // @ts-expect-error + const newValue: Link = newItemObject[key]; + + if ( + oldValue.__link !== newValue.__link || + oldValue.__typename !== newValue.__typename + ) { + canRecycle = false; + } else { + // @ts-expect-error + newItemObject[key] = oldValue; + } + break; + } case 'ImperativelyLoadedField': case 'LoadablySelectedField': break; From 0b5e64cfd93e065a5ea1480ac86ecc9d4b3e1089 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Wa=C5=82ach?= <35966385+PatrykWalach@users.noreply.github.com> Date: Sat, 23 Nov 2024 19:01:34 +0100 Subject: [PATCH 4/8] remove old comments --- .../graphql_artifact_generation/src/generate_artifacts.rs | 2 +- crates/isograph_schema/src/add_link_fields.rs | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/crates/graphql_artifact_generation/src/generate_artifacts.rs b/crates/graphql_artifact_generation/src/generate_artifacts.rs index dfe7bbe11..829754cb6 100644 --- a/crates/graphql_artifact_generation/src/generate_artifacts.rs +++ b/crates/graphql_artifact_generation/src/generate_artifacts.rs @@ -131,7 +131,7 @@ pub fn get_artifact_path_and_content( } FieldType::ClientField(encountered_client_field_id) => { let encountered_client_field = schema.client_field(*encountered_client_field_id); - // Generate reader ASTs for all encountered client fields, which may be reader or refetch reader + match &encountered_client_field.variant { ClientFieldVariant::Link => (), ClientFieldVariant::UserWritten(info) => { diff --git a/crates/isograph_schema/src/add_link_fields.rs b/crates/isograph_schema/src/add_link_fields.rs index 012b22e48..6c307151b 100644 --- a/crates/isograph_schema/src/add_link_fields.rs +++ b/crates/isograph_schema/src/add_link_fields.rs @@ -7,14 +7,6 @@ use crate::{ }; impl UnvalidatedSchema { - /// For each supertype (e.g. Node), add the fields defined on it (e.g. Node.MyComponent) - /// to subtypes (e.g. creating User.MyComponent). - /// - /// We do not transfer server fields (because that makes no sense in GraphQL, but does - /// it make sense otherwise??) and refetch fields (which are already defined on all valid - /// types.) - /// - /// TODO confirm we don't do this for unions... pub fn add_link_fields(&mut self) -> ProcessTypeDefinitionResult<()> { for object in &mut self.server_field_data.server_objects { let field_name = "link".intern().into(); From ce17fa646c265e715ef0ee1b9680feaa41ff9247 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Wa=C5=82ach?= <35966385+PatrykWalach@users.noreply.github.com> Date: Sat, 23 Nov 2024 19:02:23 +0100 Subject: [PATCH 5/8] fix `type_and_field` `type_name` --- crates/isograph_schema/src/add_link_fields.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/isograph_schema/src/add_link_fields.rs b/crates/isograph_schema/src/add_link_fields.rs index 6c307151b..324070fe3 100644 --- a/crates/isograph_schema/src/add_link_fields.rs +++ b/crates/isograph_schema/src/add_link_fields.rs @@ -26,7 +26,7 @@ impl UnvalidatedSchema { variant: ClientFieldVariant::Link, type_and_field: ObjectTypeAndFieldName { field_name, - type_name: "ID".intern().into(), + type_name: object.name, }, refetch_strategy: None, })); From aa9798bd8a2a40470a3a8e24f81b2dea78847e48 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Wa=C5=82ach?= <35966385+PatrykWalach@users.noreply.github.com> Date: Sat, 23 Nov 2024 19:10:36 +0100 Subject: [PATCH 6/8] split generated `isograph/react` imports --- .../src/eager_reader_artifact.rs | 34 +++++-------------- 1 file changed, 9 insertions(+), 25 deletions(-) diff --git a/crates/graphql_artifact_generation/src/eager_reader_artifact.rs b/crates/graphql_artifact_generation/src/eager_reader_artifact.rs index 107727bae..c86626523 100644 --- a/crates/graphql_artifact_generation/src/eager_reader_artifact.rs +++ b/crates/graphql_artifact_generation/src/eager_reader_artifact.rs @@ -212,37 +212,20 @@ pub(crate) fn generate_eager_reader_param_type_artifact( let reader_param_type = format!("{}__{}__param", parent_type.name, client_field.name); let link_field_imports = if !link_fields.is_empty() { - Some("type Link") + "import type { Link } from '@isograph/react';\n".to_string() } else { - None + "".to_string() }; let loadable_field_imports = if !loadable_fields.is_empty() { let param_imports = param_type_imports_to_import_param_statement(&loadable_fields, file_extensions); - - Some(("type LoadableField, type ExtractParameters", param_imports)) + format!( + "import {{ type LoadableField, type ExtractParameters }} from '@isograph/react';\n\ + {param_imports}" + ) } else { - None - }; - - let isograph_react_imports = match (link_field_imports, loadable_field_imports) { - (None, None) => "".to_string(), - (Some(link_field_import), None) => { - format!("import {{ {link_field_import} }} from '@isograph/react';\n") - } - (None, Some((loadable_field_imports, param_imports))) => { - format!( - "import {{ {loadable_field_imports} }} from '@isograph/react';\n\ - {param_imports}" - ) - } - (Some(link_field_import), Some((loadable_field_imports, param_imports))) => { - format!( - "import {{ {link_field_import}, {loadable_field_imports} }} from '@isograph/react';\n\ - {param_imports}" - ) - } + "".to_string() }; let (parameters_import, parameters_type) = if !client_field.variable_definitions.is_empty() { @@ -259,7 +242,8 @@ pub(crate) fn generate_eager_reader_param_type_artifact( let indent = " "; let param_type_content = format!( "{param_type_import_statement}\ - {isograph_react_imports}\ + {link_field_imports}\ + {loadable_field_imports}\ {parameters_import}\n\ export type {reader_param_type} = {{\n\ {indent}readonly data: {client_field_parameter_type},\n\ From 83c1ecc1c4c6b14509ca1e0af0789f0f9bb4aed2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Wa=C5=82ach?= <35966385+PatrykWalach@users.noreply.github.com> Date: Sat, 23 Nov 2024 19:14:02 +0100 Subject: [PATCH 7/8] use `bool` to track if there's an `link` field --- .../graphql_artifact_generation/src/eager_reader_artifact.rs | 4 ++-- crates/graphql_artifact_generation/src/generate_artifacts.rs | 2 +- crates/graphql_artifact_generation/src/import_statements.rs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/graphql_artifact_generation/src/eager_reader_artifact.rs b/crates/graphql_artifact_generation/src/eager_reader_artifact.rs index c86626523..d7dee8d07 100644 --- a/crates/graphql_artifact_generation/src/eager_reader_artifact.rs +++ b/crates/graphql_artifact_generation/src/eager_reader_artifact.rs @@ -196,7 +196,7 @@ pub(crate) fn generate_eager_reader_param_type_artifact( let mut param_type_imports = BTreeSet::new(); let mut loadable_fields = BTreeSet::new(); - let mut link_fields = BTreeSet::new(); + let mut link_fields = false; let client_field_parameter_type = generate_client_field_parameter_type( schema, client_field.selection_set_for_parent_query(), @@ -211,7 +211,7 @@ pub(crate) fn generate_eager_reader_param_type_artifact( param_type_imports_to_import_statement(¶m_type_imports, file_extensions); let reader_param_type = format!("{}__{}__param", parent_type.name, client_field.name); - let link_field_imports = if !link_fields.is_empty() { + let link_field_imports = if link_fields { "import type { Link } from '@isograph/react';\n".to_string() } else { "".to_string() diff --git a/crates/graphql_artifact_generation/src/generate_artifacts.rs b/crates/graphql_artifact_generation/src/generate_artifacts.rs index 829754cb6..4db9e470f 100644 --- a/crates/graphql_artifact_generation/src/generate_artifacts.rs +++ b/crates/graphql_artifact_generation/src/generate_artifacts.rs @@ -530,7 +530,7 @@ fn write_param_type_from_selection( match client_field.variant { ClientFieldVariant::Link => { - link_fields.insert(()); + *link_fields = true; let output_type = "Link"; query_type_declaration.push_str( &(format!( diff --git a/crates/graphql_artifact_generation/src/import_statements.rs b/crates/graphql_artifact_generation/src/import_statements.rs index d1d53c22f..36c75958b 100644 --- a/crates/graphql_artifact_generation/src/import_statements.rs +++ b/crates/graphql_artifact_generation/src/import_statements.rs @@ -22,7 +22,7 @@ impl ImportedFileCategory { pub(crate) type ReaderImports = BTreeSet<(ObjectTypeAndFieldName, ImportedFileCategory)>; pub(crate) type ParamTypeImports = BTreeSet; -pub(crate) type LinkImports = BTreeSet<()>; +pub(crate) type LinkImports = bool; pub(crate) fn reader_imports_to_import_statement( reader_imports: &ReaderImports, From ee62312df9132235b0bb55a0714020783879b892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Patryk=20Wa=C5=82ach?= <35966385+PatrykWalach@users.noreply.github.com> Date: Thu, 26 Dec 2024 14:16:01 +0100 Subject: [PATCH 8/8] use `lazy_static!` --- crates/isograph_schema/src/add_link_fields.rs | 9 ++++----- crates/isograph_schema/src/add_pointers_to_supertypes.rs | 6 +++--- .../isograph_schema/src/create_merged_selection_set.rs | 1 + 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/crates/isograph_schema/src/add_link_fields.rs b/crates/isograph_schema/src/add_link_fields.rs index 324070fe3..74ba9c445 100644 --- a/crates/isograph_schema/src/add_link_fields.rs +++ b/crates/isograph_schema/src/add_link_fields.rs @@ -1,15 +1,14 @@ -use common_lang_types::{Location, WithLocation}; -use intern::string_key::Intern; - use crate::{ ClientField, ClientFieldVariant, ClientType, FieldType, ObjectTypeAndFieldName, - ProcessTypeDefinitionError, ProcessTypeDefinitionResult, UnvalidatedSchema, + ProcessTypeDefinitionError, ProcessTypeDefinitionResult, UnvalidatedSchema, LINK_FIELD_NAME, }; +use common_lang_types::{Location, WithLocation}; +use intern::string_key::Intern; impl UnvalidatedSchema { pub fn add_link_fields(&mut self) -> ProcessTypeDefinitionResult<()> { for object in &mut self.server_field_data.server_objects { - let field_name = "link".intern().into(); + let field_name = (*LINK_FIELD_NAME).into(); let next_client_field_id = self.client_fields.len().into(); self.client_fields .push(ClientType::ClientField(ClientField { diff --git a/crates/isograph_schema/src/add_pointers_to_supertypes.rs b/crates/isograph_schema/src/add_pointers_to_supertypes.rs index b7638d590..f5a12f9a6 100644 --- a/crates/isograph_schema/src/add_pointers_to_supertypes.rs +++ b/crates/isograph_schema/src/add_pointers_to_supertypes.rs @@ -8,7 +8,7 @@ use crate::{ SchemaServerField, SchemaServerFieldVariant, ServerFieldTypeAssociatedData, ServerFieldTypeAssociatedDataInlineFragment, UnvalidatedSchema, ValidatedIsographSelectionVariant, ValidatedScalarFieldAssociatedData, - ValidatedTypeRefinementMap, + ValidatedTypeRefinementMap, LINK_FIELD_NAME, }; use common_lang_types::Location; impl UnvalidatedSchema { @@ -63,7 +63,7 @@ impl UnvalidatedSchema { location: FieldType::ClientField( match *subtype .encountered_fields - .get(&"link".intern().into()) + .get(&(*LINK_FIELD_NAME).into()) .expect("Expected link to exist") .as_client_field() .expect("Expected link to be client field") @@ -74,7 +74,7 @@ impl UnvalidatedSchema { selection_variant: ValidatedIsographSelectionVariant::Regular, }, directives: vec![], - name: WithLocation::new("link".intern().into(), Location::generated()), + name: WithLocation::new(*LINK_FIELD_NAME, Location::generated()), reader_alias: None, }), Span::todo_generated(), diff --git a/crates/isograph_schema/src/create_merged_selection_set.rs b/crates/isograph_schema/src/create_merged_selection_set.rs index 35ee4a31b..615756e20 100644 --- a/crates/isograph_schema/src/create_merged_selection_set.rs +++ b/crates/isograph_schema/src/create_merged_selection_set.rs @@ -44,6 +44,7 @@ lazy_static! { pub static ref REFETCH_FIELD_NAME: ScalarFieldName = "__refetch".intern().into(); pub static ref NODE_FIELD_NAME: LinkedFieldName = "node".intern().into(); pub static ref TYPENAME_FIELD_NAME: ScalarFieldName = "__typename".intern().into(); + pub static ref LINK_FIELD_NAME: ScalarFieldName = "link".intern().into(); } #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]