Skip to content

Commit

Permalink
inter alia, make generate_artifacts not care about PathAndContent
Browse files Browse the repository at this point in the history
  • Loading branch information
rbalicki2 committed May 11, 2024
1 parent 391a007 commit e2912ac
Show file tree
Hide file tree
Showing 6 changed files with 287 additions and 297 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use isograph_schema::{
};

use crate::{
eager_reader_artifact_info::generate_client_field_parameter_type,
generate_artifacts::{
generate_client_field_parameter_type,
generate_function_import_statement_for_eager_or_component, generate_output_type,
generate_path, get_output_type_text, nested_client_field_names_to_import_statement,
ClientFieldFunctionImportStatement, ClientFieldOutputType, ClientFieldParameterType,
Expand All @@ -16,13 +16,13 @@ use crate::{
reader_ast::generate_reader_ast,
};

pub(crate) fn generate_component_reader_artifact<'schema>(
schema: &'schema ValidatedSchema,
pub(crate) fn generate_component_reader_artifact(
schema: &ValidatedSchema,
client_field: &ValidatedClientField,
project_root: &PathBuf,
artifact_directory: &PathBuf,
component_name_and_path: (ConstExportName, FilePath),
) -> ComponentReaderArtifactInfo<'schema> {
) -> Vec<PathAndContent> {
if let Some((selection_set, _)) = &client_field.selection_set_and_unwraps {
let parent_type = schema
.server_field_data
Expand Down Expand Up @@ -71,6 +71,7 @@ pub(crate) fn generate_component_reader_artifact<'schema>(
client_field_output_type,
client_field_parameter_type,
}
.path_and_content()
} else {
panic!("Unsupported: client fields not on query with no selection set")
}
Expand Down
252 changes: 17 additions & 235 deletions crates/graphql_artifact_generation/src/eager_reader_artifact_info.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,17 @@
use std::{
collections::{hash_map::Entry, HashMap},
fmt::Display,
path::PathBuf,
};
use std::{collections::HashMap, path::PathBuf};

use common_lang_types::{
ConstExportName, DescriptionValue, FilePath, PathAndContent, SelectableFieldName, WithSpan,
};
use graphql_lang_types::{GraphQLTypeAnnotation, ListTypeAnnotation, NonNullTypeAnnotation};
use intern::Lookup;
use isograph_lang_types::{SelectableServerFieldId, Selection, ServerFieldSelection};
use common_lang_types::{ConstExportName, FilePath, PathAndContent, SelectableFieldName};
use isograph_schema::{
create_merged_selection_set, FieldDefinitionLocation, SchemaObject, ValidatedClientField,
ValidatedSchema, ValidatedSelection,
create_merged_selection_set, SchemaObject, ValidatedClientField, ValidatedSchema,
};

use crate::{
generate_artifacts::{
generate_client_field_parameter_type,
generate_function_import_statement_for_eager_or_component, generate_output_type,
generate_path, get_output_type_text, nested_client_field_names_to_import_statement,
ClientFieldFunctionImportStatement, ClientFieldOutputType, ClientFieldParameterType,
JavaScriptImports, NestedClientFieldImports, ReaderAst, TypeImportName, READER,
READER_OUTPUT_TYPE, READER_PARAM_TYPE,
NestedClientFieldImports, ReaderAst, READER, READER_OUTPUT_TYPE, READER_PARAM_TYPE,
},
reader_ast::generate_reader_ast,
};
Expand All @@ -32,7 +22,7 @@ pub fn generate_eager_reader_artifact<'schema>(
project_root: &PathBuf,
artifact_directory: &PathBuf,
component_name_and_path: (ConstExportName, FilePath),
) -> EagerReaderArtifactInfo<'schema> {
) -> Vec<PathAndContent> {
if let Some((selection_set, _)) = &client_field.selection_set_and_unwraps {
let parent_type = schema
.server_field_data
Expand Down Expand Up @@ -83,24 +73,25 @@ pub fn generate_eager_reader_artifact<'schema>(
client_field_output_type,
client_field_parameter_type,
}
.path_and_content()
} else {
panic!("Unsupported: client fields not on query with no selection set")
}
}

#[derive(Debug)]
pub(crate) struct EagerReaderArtifactInfo<'schema> {
pub parent_type: &'schema SchemaObject,
pub(crate) client_field_name: SelectableFieldName,
pub nested_client_field_artifact_imports: NestedClientFieldImports,
pub client_field_output_type: ClientFieldOutputType,
pub reader_ast: ReaderAst,
pub client_field_parameter_type: ClientFieldParameterType,
pub function_import_statement: ClientFieldFunctionImportStatement,
struct EagerReaderArtifactInfo<'schema> {
parent_type: &'schema SchemaObject,
client_field_name: SelectableFieldName,
nested_client_field_artifact_imports: NestedClientFieldImports,
client_field_output_type: ClientFieldOutputType,
reader_ast: ReaderAst,
client_field_parameter_type: ClientFieldParameterType,
function_import_statement: ClientFieldFunctionImportStatement,
}

impl<'schema> EagerReaderArtifactInfo<'schema> {
pub fn path_and_content(self) -> Vec<PathAndContent> {
fn path_and_content(self) -> Vec<PathAndContent> {
let EagerReaderArtifactInfo {
parent_type,
client_field_name,
Expand All @@ -112,7 +103,7 @@ impl<'schema> EagerReaderArtifactInfo<'schema> {
self.file_contents(&relative_directory)
}

pub(crate) fn file_contents(self, relative_directory: &PathBuf) -> Vec<PathAndContent> {
fn file_contents(self, relative_directory: &PathBuf) -> Vec<PathAndContent> {
let EagerReaderArtifactInfo {
function_import_statement,
client_field_parameter_type,
Expand Down Expand Up @@ -184,212 +175,3 @@ impl<'schema> EagerReaderArtifactInfo<'schema> {
]
}
}

pub(crate) fn generate_client_field_parameter_type(
schema: &ValidatedSchema,
selection_set: &[WithSpan<ValidatedSelection>],
parent_type: &SchemaObject,
nested_client_field_imports: &mut NestedClientFieldImports,
indentation_level: u8,
) -> ClientFieldParameterType {
// TODO use unwraps
let mut client_field_parameter_type = "{\n".to_string();
for selection in selection_set.iter() {
write_query_types_from_selection(
schema,
&mut client_field_parameter_type,
selection,
parent_type,
nested_client_field_imports,
indentation_level + 1,
);
}
client_field_parameter_type.push_str(&format!("{}}}", " ".repeat(indentation_level as usize)));

ClientFieldParameterType(client_field_parameter_type)
}

fn write_query_types_from_selection(
schema: &ValidatedSchema,
query_type_declaration: &mut String,
selection: &WithSpan<ValidatedSelection>,
parent_type: &SchemaObject,
nested_client_field_imports: &mut NestedClientFieldImports,
indentation_level: u8,
) {
match &selection.item {
Selection::ServerField(field) => match field {
ServerFieldSelection::ScalarField(scalar_field) => {
match scalar_field.associated_data.location {
FieldDefinitionLocation::Server(_server_field) => {
query_type_declaration
.push_str(&format!("{}", " ".repeat(indentation_level as usize)));
let parent_field = parent_type
.encountered_fields
.get(&scalar_field.name.item.into())
.expect("parent_field should exist 1")
.as_server_field()
.expect("parent_field should exist and be server field");
let field = schema.server_field(*parent_field);

write_optional_description(
field.description,
query_type_declaration,
indentation_level,
);

let name_or_alias = scalar_field.name_or_alias().item;

// TODO there should be a clever way to print without cloning
let output_type = field.associated_data.clone().map(|output_type_id| {
// TODO not just scalars, enums as well. Both should have a javascript name
let scalar_id =
if let SelectableServerFieldId::Scalar(scalar) = output_type_id {
scalar
} else {
panic!("output_type_id should be a scalar");
};
schema.server_field_data.scalar(scalar_id).javascript_name
});
query_type_declaration.push_str(&format!(
"{}: {},\n",
name_or_alias,
print_type_annotation(&output_type)
));
}
FieldDefinitionLocation::Client(client_field_id) => {
let client_field = schema.client_field(client_field_id);
write_optional_description(
client_field.description,
query_type_declaration,
indentation_level,
);
query_type_declaration
.push_str(&format!("{}", " ".repeat(indentation_level as usize)));

match nested_client_field_imports.entry(client_field.type_and_field) {
Entry::Occupied(mut occupied) => {
occupied.get_mut().types.push(TypeImportName(format!(
"{}__outputType",
client_field.type_and_field.underscore_separated()
)));
}
Entry::Vacant(vacant) => {
vacant.insert(JavaScriptImports {
default_import: false,
types: vec![TypeImportName(format!(
"{}__outputType",
client_field.type_and_field.underscore_separated()
))],
});
}
}

query_type_declaration.push_str(&format!(
"{}: {}__outputType,\n",
scalar_field.name_or_alias().item,
client_field.type_and_field.underscore_separated()
));
}
}
}
ServerFieldSelection::LinkedField(linked_field) => {
let parent_field = parent_type
.encountered_fields
.get(&linked_field.name.item.into())
.expect("parent_field should exist 2")
.as_server_field()
.expect("Parent field should exist and be server field");
let field = schema.server_field(*parent_field);
write_optional_description(
field.description,
query_type_declaration,
indentation_level,
);
query_type_declaration
.push_str(&format!("{}", " ".repeat(indentation_level as usize)));
let name_or_alias = linked_field.name_or_alias().item;
let type_annotation = field.associated_data.clone().map(|output_type_id| {
// TODO Or interface or union type
let object_id = if let SelectableServerFieldId::Object(object) = output_type_id
{
object
} else {
panic!("output_type_id should be a object");
};
let object = schema.server_field_data.object(object_id);
let inner = generate_client_field_parameter_type(
schema,
&linked_field.selection_set,
object.into(),
nested_client_field_imports,
indentation_level,
);
inner
});
query_type_declaration.push_str(&format!(
"{}: {},\n",
name_or_alias,
print_type_annotation(&type_annotation),
));
}
},
}
}

fn write_optional_description(
description: Option<DescriptionValue>,
query_type_declaration: &mut String,
indentation_level: u8,
) {
if let Some(description) = description {
query_type_declaration.push_str(&format!("{}", " ".repeat(indentation_level as usize)));
query_type_declaration.push_str("/**\n");
query_type_declaration.push_str(description.lookup());
query_type_declaration.push_str("\n");
query_type_declaration.push_str(&format!("{}", " ".repeat(indentation_level as usize)));
query_type_declaration.push_str("*/\n");
}
}

fn print_type_annotation<T: Display>(type_annotation: &GraphQLTypeAnnotation<T>) -> String {
let mut s = String::new();
print_type_annotation_impl(type_annotation, &mut s);
s
}

fn print_type_annotation_impl<T: Display>(
type_annotation: &GraphQLTypeAnnotation<T>,
s: &mut String,
) {
match &type_annotation {
GraphQLTypeAnnotation::Named(named) => {
s.push_str("(");
s.push_str(&named.item.to_string());
s.push_str(" | null)");
}
GraphQLTypeAnnotation::List(list) => {
print_list_type_annotation(list, s);
}
GraphQLTypeAnnotation::NonNull(non_null) => {
print_non_null_type_annotation(non_null, s);
}
}
}

fn print_list_type_annotation<T: Display>(list: &ListTypeAnnotation<T>, s: &mut String) {
s.push_str("(");
print_type_annotation_impl(&list.0, s);
s.push_str(")[]");
}

fn print_non_null_type_annotation<T: Display>(non_null: &NonNullTypeAnnotation<T>, s: &mut String) {
match non_null {
NonNullTypeAnnotation::Named(named) => {
s.push_str(&named.item.to_string());
}
NonNullTypeAnnotation::List(list) => {
print_list_type_annotation(list, s);
}
}
}
23 changes: 12 additions & 11 deletions crates/graphql_artifact_generation/src/entrypoint_artifact_info.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,20 @@ use crate::{
};

#[derive(Debug)]
pub(crate) struct EntrypointArtifactInfo<'schema> {
pub(crate) query_name: QueryOperationName,
pub parent_type: &'schema SchemaObject,
pub query_text: QueryText,
pub normalization_ast_text: NormalizationAstText,
pub refetch_query_artifact_import: RefetchQueryArtifactImport,
struct EntrypointArtifactInfo<'schema> {
query_name: QueryOperationName,
parent_type: &'schema SchemaObject,
query_text: QueryText,
normalization_ast_text: NormalizationAstText,
refetch_query_artifact_import: RefetchQueryArtifactImport,
}

pub(crate) fn generate_entrypoint_artifact<'schema>(
schema: &'schema ValidatedSchema,
pub(crate) fn generate_entrypoint_artifact(
schema: &ValidatedSchema,
client_field_id: ClientFieldId,
artifact_queue: &mut Vec<ImperativelyLoadedFieldArtifactInfo>,
encountered_client_field_ids: &mut HashSet<ClientFieldId>,
) -> EntrypointArtifactInfo<'schema> {
) -> PathAndContent {
let fetchable_client_field = schema.client_field(client_field_id);
if let Some((ref selection_set, _)) = fetchable_client_field.selection_set_and_unwraps {
let query_name = fetchable_client_field.name.into();
Expand Down Expand Up @@ -84,6 +84,7 @@ pub(crate) fn generate_entrypoint_artifact<'schema>(
normalization_ast_text,
refetch_query_artifact_import: refetch_query_artifact_imports,
}
.path_and_content()
} else {
// TODO convert to error
todo!("Unsupported: client fields on query with no selection set")
Expand Down Expand Up @@ -118,7 +119,7 @@ fn generate_refetch_query_artifact_imports(
}

impl<'schema> EntrypointArtifactInfo<'schema> {
pub fn path_and_content(self) -> PathAndContent {
fn path_and_content(self) -> PathAndContent {
let EntrypointArtifactInfo {
query_name,
parent_type,
Expand All @@ -134,7 +135,7 @@ impl<'schema> EntrypointArtifactInfo<'schema> {
}
}

pub(crate) fn file_contents(self) -> String {
fn file_contents(self) -> String {
let EntrypointArtifactInfo {
query_text,
normalization_ast_text,
Expand Down

0 comments on commit e2912ac

Please sign in to comment.