From 0db936f893ea41b4f3e6cb1617d81ec4d23e5af8 Mon Sep 17 00:00:00 2001 From: Alexander Date: Thu, 9 Nov 2023 13:54:27 -0500 Subject: [PATCH] Remove some of the format!() calls --- packages/fuel-indexer-graphql/src/dynamic.rs | 4 +- packages/fuel-indexer-graphql/src/query.rs | 98 +++++++++++++++----- 2 files changed, 77 insertions(+), 25 deletions(-) diff --git a/packages/fuel-indexer-graphql/src/dynamic.rs b/packages/fuel-indexer-graphql/src/dynamic.rs index 03415d5f6..622c20fa7 100644 --- a/packages/fuel-indexer-graphql/src/dynamic.rs +++ b/packages/fuel-indexer-graphql/src/dynamic.rs @@ -137,7 +137,7 @@ pub async fn execute_query( )?; let query = parsed.prepare(schema.parsed(), &pool.database_type())?; - vec![query] + vec![query.as_sql()] } DocumentOperations::Multiple(op_defs) => { let mut v = vec![]; @@ -149,7 +149,7 @@ pub async fn execute_query( Some(name.to_string()), )?; let s = parsed.prepare(schema.parsed(), &pool.database_type())?; - v.push(s); + v.push(s.as_sql()); } v diff --git a/packages/fuel-indexer-graphql/src/query.rs b/packages/fuel-indexer-graphql/src/query.rs index 24f2776df..ea22c915e 100644 --- a/packages/fuel-indexer-graphql/src/query.rs +++ b/packages/fuel-indexer-graphql/src/query.rs @@ -9,6 +9,7 @@ use async_graphql_parser::{ }; use async_graphql_value::Name; use fuel_indexer_database::DbType; +use fuel_indexer_database_types::SqlFragment; use fuel_indexer_lib::graphql::{parser::InternalType, ParsedGraphQLSchema}; use petgraph::graph::{Graph, NodeIndex}; @@ -34,6 +35,29 @@ pub struct DependencyGraph { pub graph: Graph, } +#[allow(unused)] +pub struct Join { + pub child_table: String, + pub parent_table: String, + pub referring_field: String, + pub fk_field: String, + // TODO: Allow for different join types + pub join_type: String, +} + +impl SqlFragment for Join { + fn create(&self) -> String { + format!( + "INNER JOIN {} ON {}.{} = {}.{}", + self.child_table, + self.parent_table, + self.referring_field, + self.child_table, + self.fk_field + ) + } +} + impl DependencyGraph { /// Add a new node to dependency graph. fn add_node(&mut self, table: String) -> NodeIndex { @@ -59,7 +83,7 @@ impl DependencyGraph { } /// Returns database joins in topologically sorted order. - fn get_sorted_joins(&self) -> GraphqlResult> { + fn get_sorted_joins(&self) -> GraphqlResult> { let toposorted_nodes = if let Ok(sorted) = petgraph::algo::toposort(&self.graph, None) { sorted @@ -69,7 +93,7 @@ impl DependencyGraph { )); }; - let mut joins: Vec = vec![]; + let mut joins: Vec = vec![]; let mut seen = vec![false; self.graph.node_count()]; let mut stack = VecDeque::new(); @@ -95,15 +119,13 @@ impl DependencyGraph { self.graph.node_weight(parent_node), self.graph.node_weight(child_node), ) { - let join = format!( - "INNER JOIN {} ON {}.{} = {}.{}", - child_table, - parent_table, - referring_field, - child_table, - fk_field - ); - joins.push(join); + joins.push(Join { + child_table: child_table.to_owned(), + parent_table: parent_table.to_owned(), + referring_field: referring_field.to_owned(), + fk_field: fk_field.to_owned(), + join_type: "INNER".to_string(), + }); } stack.push_front(child_node); @@ -117,6 +139,39 @@ impl DependencyGraph { } } +pub struct PreparedOperation { + pub selections: Vec, + pub fully_qualified_namespace: String, + pub root_object_name: Name, + pub joins: Vec, + pub query_parameters: QueryParams, + pub db_type: DbType, +} + +impl PreparedOperation { + pub fn as_sql(&self) -> String { + match self.db_type { + DbType::Postgres => { + format!( + "SELECT json_build_object({}) FROM {}.{} {} {} {}", + self.selections.join(""), + self.fully_qualified_namespace, + self.root_object_name, + self.joins + .iter() + .map(|j| j.create()) + .collect::>() + .join(" "), + self.query_parameters + .get_filtering_expression(&DbType::Postgres), + self.query_parameters + .get_ordering_modififer(&DbType::Postgres) + ) + } + } + } +} + impl ParsedOperation { /// Creates a `ParsedOperation` from a user's operation. pub fn generate( @@ -152,7 +207,7 @@ impl ParsedOperation { &self, schema: &ParsedGraphQLSchema, db_type: &DbType, - ) -> GraphqlResult { + ) -> GraphqlResult { match self.ty { OperationType::Query => match db_type { DbType::Postgres => match &self.selections[0] { @@ -176,17 +231,14 @@ impl ParsedOperation { } } - let joins = dep_graph.get_sorted_joins()?; - - Ok(format!( - "SELECT json_build_object({}) FROM {}.{} {} {} {}", - selections.join(""), - schema.fully_qualified_namespace(), - name, - joins.join(" "), - query_parameters.get_filtering_expression(db_type), - query_parameters.get_ordering_modififer(db_type) - )) + Ok(PreparedOperation { + selections, + fully_qualified_namespace: schema.fully_qualified_namespace(), + root_object_name: name.to_owned(), + joins: dep_graph.get_sorted_joins()?, + query_parameters, + db_type: db_type.to_owned(), + }) } _ => Err(GraphqlError::QueryError( "Query must begin with an object".to_string(),