Skip to content
This repository has been archived by the owner on Oct 25, 2024. It is now read-only.

Commit

Permalink
Push up some WIP work so I can work on it during travel
Browse files Browse the repository at this point in the history
  • Loading branch information
deekerno committed Nov 24, 2023
1 parent 75bd82a commit 920726b
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 99 deletions.
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
schema {
query: Query
}

type Query {
block(id: ID!): Block
blocks(height: u64!): [Block]
}

type Transaction @entity {
id: ID!
hash: Bytes32! @unique
Expand Down
145 changes: 47 additions & 98 deletions packages/fuel-indexer-lib/src/graphql/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use async_graphql_parser::{
};
use fuel_indexer_types::graphql::IndexMetadata;
use sha2::{Digest, Sha256};
use std::collections::{HashMap, HashSet};
use std::collections::HashMap;
use types::IdCol;

/// Maximum amount of foreign key list fields that can exist on a `TypeDefinition`
Expand All @@ -39,89 +39,50 @@ fn inject_native_entities_into_schema(schema: &str) -> String {
}
}

pub(crate) fn inject_query_type(mut ast: ServiceDocument) -> ServiceDocument {
let mut queries: Vec<(&Positioned<Name>, &Positioned<TypeDefinition>)> = vec![];
for ty in ast.definitions.iter() {
if let TypeSystemDefinition::Type(t) = ty {
if let TypeKind::Object(obj) = &t.node.kind {
if !check_for_directive(&t.node.directives, "internal") {
queries.push((&t.node.name, t));
} else if check_for_directive(&t.node.directives, "internal")
&& check_for_directive(&t.node.directives, "connection")
{
}
// if not an internal object, make it a regular query returning one thing
// if an internal connection object, make it a query returning a list
}
}
}
ast
}

/// Inject internal types into the schema. In order to support popular
/// functionality (e.g. cursor-based pagination) and minimize the amount
/// of types that a user needs to create, internal types are injected into
/// the `ServiceDocument`. These types are not used to create database tables/columns
/// or entity structs in handler functions.
pub(crate) fn inject_internal_types_into_document(
mut ast: ServiceDocument,
base_type_names: &HashSet<String>,
) -> ServiceDocument {
let mut pagination_types: Vec<TypeSystemDefinition> = Vec::new();
pagination_types.push(create_page_info_type_def());

// Iterate through all objects in document and create special
// pagination types for each object with a list field.
for ty in ast.definitions.iter_mut() {
for ty in ast.definitions.iter() {
if let TypeSystemDefinition::Type(t) = ty {
if let TypeKind::Object(obj) = &mut t.node.kind {
let mut internal_fields: Vec<Positioned<FieldDefinition>> = Vec::new();

for f in &obj.fields {
if let BaseType::List(inner_type) = &f.node.ty.node.base {
if let BaseType::Named(name) = &inner_type.base {
if base_type_names.contains(&name.to_string()) {
continue;
}
let edge_type = create_edge_type_for_list_field(f);
pagination_types.push(edge_type);

let connection_type =
create_connection_type_def_for_list_entity(name);
pagination_types.push(connection_type);

let connection_field = Positioned::position_node(
f,
FieldDefinition {
description: None,
name: Positioned::position_node(
f,
Name::new(format!(
"{}Connection",
f.node.name.node
)),
),
arguments: vec![],
ty: Positioned::position_node(
f,
Type {
base: BaseType::Named(Name::new(format!(
"{name}Connection"
))),
nullable: false,
},
),
directives: vec![
Positioned::position_node(
f,
ConstDirective {
name: Positioned::position_node(
f,
Name::new("internal"),
),
arguments: vec![],
},
),
Positioned::position_node(
f,
ConstDirective {
name: Positioned::position_node(
f,
Name::new("connection"),
),
arguments: vec![],
},
),
],
},
);
internal_fields.push(connection_field);
}
}
}
if t.node.name.node == "IndexMetadataEntity" {
continue;
}

obj.fields.append(&mut internal_fields);
if matches!(&t.node.kind, TypeKind::Object(_)) {
let edge_type = create_edge_type(t);
pagination_types.push(edge_type);

let connection_type = create_connection_type_def(&t.node.name.node);
pagination_types.push(connection_type);
}
}
}
Expand All @@ -131,46 +92,34 @@ pub(crate) fn inject_internal_types_into_document(
ast
}

fn create_edge_type_for_list_field(
list_field: &Positioned<FieldDefinition>,
) -> TypeSystemDefinition {
let (base_type, name) = if let BaseType::List(t) = &list_field.node.ty.node.base {
if let BaseType::Named(n) = &t.base {
(t, n)
} else {
unreachable!("Edge type creation should not occur for non-list fields")
}
} else {
unreachable!("Edge type creation should not occur for non-list fields")
};

fn create_edge_type(entity_def: &Positioned<TypeDefinition>) -> TypeSystemDefinition {
let edge_obj_type = ObjectType {
implements: vec![],
fields: vec![
Positioned::position_node(
list_field,
entity_def,
FieldDefinition {
description: None,
name: Positioned::position_node(list_field, Name::new("node")),
name: Positioned::position_node(entity_def, Name::new("node")),
arguments: vec![],
ty: Positioned::position_node(
list_field,
entity_def,
Type {
base: base_type.base.clone(),
base: BaseType::Named(entity_def.node.name.node.clone()),
nullable: false,
},
),
directives: vec![],
},
),
Positioned::position_node(
list_field,
entity_def,
FieldDefinition {
description: None,
name: Positioned::position_node(list_field, Name::new("cursor")),
name: Positioned::position_node(entity_def, Name::new("cursor")),
arguments: vec![],
ty: Positioned::position_node(
list_field,
entity_def,
Type {
base: BaseType::Named(Name::new("String")),
nullable: false,
Expand All @@ -183,29 +132,29 @@ fn create_edge_type_for_list_field(
};

TypeSystemDefinition::Type(Positioned::position_node(
list_field,
entity_def,
TypeDefinition {
extend: false,
description: None,
name: Positioned::position_node(
list_field,
Name::new(format!("{}Edge", name)),
entity_def,
Name::new(format!("{}Edge", entity_def.node.name.node.clone())),
),
directives: vec![
Positioned::position_node(
list_field,
entity_def,
ConstDirective {
name: Positioned::position_node(
list_field,
entity_def,
Name::new("internal"),
),
arguments: vec![],
},
),
Positioned::position_node(
list_field,
entity_def,
ConstDirective {
name: Positioned::position_node(list_field, Name::new("edge")),
name: Positioned::position_node(entity_def, Name::new("edge")),
arguments: vec![],
},
),
Expand All @@ -215,8 +164,8 @@ fn create_edge_type_for_list_field(
))
}

/// Generate connection type defintion for a list field on an entity.
fn create_connection_type_def_for_list_entity(name: &Name) -> TypeSystemDefinition {
/// Generate connection type defintion for an entity.
fn create_connection_type_def(name: &Name) -> TypeSystemDefinition {
let dummy_position = Pos {
line: usize::MAX,
column: usize::MAX,
Expand Down
11 changes: 10 additions & 1 deletion packages/fuel-indexer-lib/src/graphql/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,9 @@ pub struct ParsedGraphQLSchema {

/// A mapping of pagination types to the underlying types that they should be used with.
pagination_type_map: HashMap<String, String>,

/// Input types.
input_types: HashMap<String, String>,
}

impl Default for ParsedGraphQLSchema {
Expand Down Expand Up @@ -305,6 +308,7 @@ impl Default for ParsedGraphQLSchema {
version: String::default(),
internal_types: HashMap::new(),
pagination_type_map: HashMap::new(),
input_types: HashMap::new(),
}
}
}
Expand All @@ -328,8 +332,9 @@ impl ParsedGraphQLSchema {
if let Some(schema) = schema {
// Parse _everything_ in the GraphQL schema
let mut ast = parse_schema(schema.schema())?;
println!("{ast:#?}");

ast = inject_internal_types_into_document(ast, &base_type_names);
ast = inject_internal_types_into_document(ast);

decoder.decode_service_document(ast)?;

Expand Down Expand Up @@ -410,6 +415,10 @@ impl ParsedGraphQLSchema {
&self.pagination_type_map
}

pub fn input_types(&self) -> &HashMap<String, String> {
&self.input_types
}

/// Return the base scalar type for a given `FieldDefinition`.
pub fn scalar_type_for(&self, f: &FieldDefinition) -> String {
let typ_name = list_field_type_name(f);
Expand Down

0 comments on commit 920726b

Please sign in to comment.