Skip to content

Commit

Permalink
generate refetch fields later
Browse files Browse the repository at this point in the history
  • Loading branch information
rbalicki2 committed May 10, 2024
1 parent a698ae9 commit 8171352
Show file tree
Hide file tree
Showing 8 changed files with 98 additions and 73 deletions.
11 changes: 8 additions & 3 deletions crates/isograph_cli/src/batch_compile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ use crate::{
isograph_literals::{
extract_iso_literal_from_file_content, read_files_in_folder, IsoLiteralExtraction,
},
refetch_fields::add_refetch_fields_to_objects,
schema::read_schema_file,
write_artifacts::{write_to_disk, GenerateArtifactsError},
};
Expand Down Expand Up @@ -121,9 +122,8 @@ pub(crate) fn handle_compile_command(
// - process schema and validate
// - process schema extension and validate
// Validation state: all types have been defined
// - add mutation fields
// - add refetch fields
// - process parsed iso field definitions
// - add mutation, refetch fields, etc. and fields to subtypes
// - and client fields defined in iso field literals, but don't validate
// Validation state: all fields have been defined
// - validate fields with selection sets
// Validation state: fully validated
Expand Down Expand Up @@ -163,6 +163,8 @@ pub(crate) fn handle_compile_command(
.supertype_to_subtype_map,
)?;

add_refetch_fields_to_objects(&mut schema)?;

let validated_schema = Schema::validate_and_construct(schema)?;

let paths_and_content = get_artifact_path_and_content(
Expand Down Expand Up @@ -443,6 +445,9 @@ pub(crate) enum BatchCompileError {

#[error("Unable to convert file {path:?} to utf8.\nDetailed reason: {reason}")]
UnableToConvertToString { path: PathBuf, reason: Utf8Error },

#[error("The __refetch field was already defined. Isograph creates it automatically; you cannot create it.")]
DuplicateRefetchField,
}

impl From<Vec<WithLocation<IsographLiteralParseError>>> for BatchCompileError {
Expand Down
1 change: 1 addition & 0 deletions crates/isograph_cli/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ mod opt;
mod schema;
mod watch;
mod write_artifacts;
mod refetch_fields;

use batch_compile::compile_and_print;
use colored::Colorize;
Expand Down
78 changes: 78 additions & 0 deletions crates/isograph_cli/src/refetch_fields.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
use std::collections::hash_map::Entry;

use common_lang_types::{Location, Span, WithLocation, WithSpan};
use intern::string_key::Intern;
use isograph_lang_types::{
IsographSelectionVariant, ScalarFieldSelection, Selection, ServerFieldSelection,
};
use isograph_schema::{
ClientField, ClientFieldVariant, FieldDefinitionLocation, ObjectTypeAndFieldNames,
UnvalidatedClientField, UnvalidatedSchema, UnvalidatedSchemaObject, REFETCH_FIELD_NAME,
};

use crate::batch_compile::BatchCompileError;

pub fn add_refetch_fields_to_objects(
schema: &mut UnvalidatedSchema,
) -> Result<(), BatchCompileError> {
'objects: for object in schema.server_field_data.server_objects.iter_mut() {
if object.id_field.is_none() {
continue 'objects;
}

if let Some(value) = add_refetch_field_to_object(object, &mut schema.client_fields) {
return value;
}
}
Ok(())
}

fn add_refetch_field_to_object(
object: &mut UnvalidatedSchemaObject,
client_fields: &mut Vec<UnvalidatedClientField>,
) -> Option<Result<(), BatchCompileError>> {
match object
.encountered_fields
.entry((*REFETCH_FIELD_NAME).into())
{
Entry::Occupied(_) => return Some(Err(BatchCompileError::DuplicateRefetchField)),
Entry::Vacant(vacant_entry) => {
let next_client_field_id = client_fields.len().into();

vacant_entry.insert(FieldDefinitionLocation::Client(next_client_field_id));

let id_field_selection = WithSpan::new(
Selection::ServerField(ServerFieldSelection::ScalarField(ScalarFieldSelection {
name: WithLocation::new("id".intern().into(), Location::generated()),
reader_alias: None,
normalization_alias: None,
associated_data: IsographSelectionVariant::Regular,
unwraps: vec![],
arguments: vec![],
directives: vec![],
})),
Span::todo_generated(),
);
client_fields.push(ClientField {
description: Some(
format!("A refetch field for the {} type.", object.name)
.intern()
.into(),
),
name: (*REFETCH_FIELD_NAME).into(),
id: next_client_field_id,
selection_set_and_unwraps: Some((vec![id_field_selection], vec![])),
variant: ClientFieldVariant::RefetchField,
variable_definitions: vec![],
type_and_field: ObjectTypeAndFieldNames {
type_name: object.name,
field_name: "__refetch".intern().into(),
},
parent_object_id: object.id,
});

object.client_field_ids.push(next_client_field_id);
}
}
None
}
1 change: 1 addition & 0 deletions crates/isograph_schema/src/isograph_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -481,6 +481,7 @@ pub struct ClientField<
// TODO we should probably model this differently
pub variant: ClientFieldVariant,

// Is this used for anything except for some reason, for refetch fields?
pub variable_definitions:
Vec<WithSpan<VariableDefinition<TClientFieldVariableDefinitionAssociatedData>>>,

Expand Down
74 changes: 7 additions & 67 deletions crates/isograph_schema/src/process_type_definition.rs
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
use std::collections::{hash_map::Entry, HashMap};

use crate::{
ClientField, ClientFieldVariant, EncounteredRootTypes, FieldDefinitionLocation,
IsographObjectTypeDefinition, ObjectTypeAndFieldNames, ProcessedRootTypes, RootOperationName,
RootTypes, Schema, SchemaObject, SchemaScalar, SchemaServerField, UnvalidatedClientField,
UnvalidatedObjectFieldInfo, UnvalidatedSchema, UnvalidatedSchemaField, ID_GRAPHQL_TYPE,
STRING_JAVASCRIPT_TYPE,
EncounteredRootTypes, FieldDefinitionLocation, IsographObjectTypeDefinition,
ProcessedRootTypes, RootOperationName, RootTypes, Schema, SchemaObject, SchemaScalar,
SchemaServerField, UnvalidatedObjectFieldInfo, UnvalidatedSchema, UnvalidatedSchemaField,
ID_GRAPHQL_TYPE, STRING_JAVASCRIPT_TYPE,
};
use common_lang_types::{
GraphQLObjectTypeName, GraphQLScalarTypeName, IsographObjectTypeName, Location,
Expand All @@ -20,8 +19,7 @@ use graphql_lang_types::{
use intern::{string_key::Intern, Lookup};
use isograph_config::ConfigOptions;
use isograph_lang_types::{
ClientFieldId, IsographSelectionVariant, ScalarFieldSelection, SelectableServerFieldId,
Selection, ServerFieldId, ServerFieldSelection, ServerObjectId, ServerStrongIdFieldId,
SelectableServerFieldId, ServerFieldId, ServerObjectId, ServerStrongIdFieldId,
};
use lazy_static::lazy_static;
use serde::Deserialize;
Expand Down Expand Up @@ -384,7 +382,6 @@ impl UnvalidatedSchema {
let &mut Schema {
server_fields: ref mut schema_fields,
server_field_data: ref mut schema_data,
ref mut client_fields,
..
} = self;
let next_object_id = schema_data.server_objects.len().into();
Expand All @@ -409,7 +406,7 @@ impl UnvalidatedSchema {
let FieldObjectIdsEtc {
unvalidated_schema_fields,
server_fields,
mut encountered_fields,
encountered_fields,
id_field,
} = get_field_objects_ids_and_names(
type_def_2.fields,
Expand All @@ -421,20 +418,12 @@ impl UnvalidatedSchema {
options,
)?;

let client_field_ids = get_client_fields_for_schema_object(
&id_field,
&mut encountered_fields,
client_fields,
next_object_id,
&object_type_definition,
);

objects.push(SchemaObject {
description: object_type_definition.description.map(|d| d.item),
name: object_type_definition.name.item,
id: next_object_id,
server_field_ids: server_fields,
client_field_ids,
client_field_ids: vec![],
encountered_fields,
id_field,
directives: object_type_definition.directives,
Expand Down Expand Up @@ -608,55 +597,6 @@ impl FieldMapItem {
}
}

/// Returns the client fields for a schema object that we know up-front (before processing
/// iso literals.) This is either a refetch field (if the object is refetchable), or
/// nothing.
fn get_client_fields_for_schema_object(
id_field_id: &Option<ServerStrongIdFieldId>,
encountered_fields: &mut HashMap<SelectableFieldName, UnvalidatedObjectFieldInfo>,
unvalidated_client_field: &mut Vec<UnvalidatedClientField>,
parent_object_id: ServerObjectId,
type_definition: &IsographObjectTypeDefinition,
) -> Vec<ClientFieldId> {
if let Some(_id_field_id) = id_field_id {
let next_client_field_id = unvalidated_client_field.len().into();
let id_field_selection = WithSpan::new(
Selection::ServerField(ServerFieldSelection::ScalarField(ScalarFieldSelection {
name: WithLocation::new("id".intern().into(), Location::generated()),
reader_alias: None,
normalization_alias: None,
associated_data: IsographSelectionVariant::Regular,
unwraps: vec![],
arguments: vec![],
directives: vec![],
})),
Span::todo_generated(),
);
unvalidated_client_field.push(ClientField {
description: Some("A refetch field for this object.".intern().into()),
name: "__refetch".intern().into(),
id: next_client_field_id,
selection_set_and_unwraps: Some((vec![id_field_selection], vec![])),
variant: ClientFieldVariant::RefetchField,
variable_definitions: vec![],
type_and_field: ObjectTypeAndFieldNames {
type_name: type_definition.name.item,
field_name: "__refetch".intern().into(),
},
// This is extremely likely to be wrong. What id is this? It's probably
// not Query or Mutation
parent_object_id,
});
encountered_fields.insert(
"__refetch".intern().into(),
FieldDefinitionLocation::Client(next_client_field_id),
);
vec![next_client_field_id]
} else {
vec![]
}
}

fn get_typename_type(
string_type_for_typename: GraphQLScalarTypeName,
) -> GraphQLTypeAnnotation<UnvalidatedTypeName> {
Expand Down
2 changes: 1 addition & 1 deletion crates/isograph_schema/src/unvalidated_schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ pub(crate) type UnvalidatedSchemaData =
pub(crate) type UnvalidatedSchemaField =
SchemaServerField<GraphQLTypeAnnotation<UnvalidatedTypeName>>;

pub(crate) type UnvalidatedClientField = ClientField<
pub type UnvalidatedClientField = ClientField<
<UnvalidatedSchemaState as SchemaValidationState>::ClientFieldSelectionScalarFieldAssociatedData,
<UnvalidatedSchemaState as SchemaValidationState>::ClientFieldSelectionLinkedFieldAssociatedData,
<UnvalidatedSchemaState as SchemaValidationState>::ClientFieldVariableDefinitionAssociatedData,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ The user's public profile name.
name: (string | null),
RepositoryList: User__RepositoryList__outputType,
/**
A refetch field for this object.
A refetch field for the User type.
*/
__refetch: User____refetch__outputType,
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export type Pet__PetUpdater__param = {
set_pet_tagline: Pet__set_pet_tagline__outputType,
tagline: string,
/**
A refetch field for this object.
A refetch field for the Pet type.
*/
__refetch: Pet____refetch__outputType,
};

0 comments on commit 8171352

Please sign in to comment.