diff --git a/packages/fuel-indexer-graphql/src/arguments.rs b/packages/fuel-indexer-graphql/src/arguments.rs index be7ab4a1c..8367a3a2f 100644 --- a/packages/fuel-indexer-graphql/src/arguments.rs +++ b/packages/fuel-indexer-graphql/src/arguments.rs @@ -1,6 +1,6 @@ use super::graphql::GraphqlError; use fuel_indexer_database::DbType; -use fuel_indexer_schema::db::tables::IndexerSchema; +use fuel_indexer_lib::graphql::ParsedGraphQLSchema; use async_graphql_value::{indexmap::IndexMap, Name, Value}; use std::fmt; @@ -12,6 +12,7 @@ pub struct QueryParams { pub sorts: Vec, pub offset: Option, pub limit: Option, + pub cursor: Option, } impl QueryParams { @@ -36,6 +37,7 @@ impl QueryParams { }), ParamType::Offset(n) => self.offset = Some(n), ParamType::Limit(n) => self.limit = Some(n), + ParamType::Cursor(s) => self.cursor = Some(s), } } } @@ -102,6 +104,7 @@ pub enum ParamType { Sort(String, SortOrder), Offset(u64), Limit(u64), + Cursor(String), } #[derive(Debug, Clone, PartialEq, Eq)] @@ -368,7 +371,7 @@ impl FilterType { } } -/// Parse an argument key-value pair into a `Filter`. +/// Parse an argument key-value pair into a `ParamType`. /// /// `parse_arguments` is the entry point for parsing all API query arguments. /// Any new top-level operators should first be added here. @@ -376,7 +379,7 @@ pub fn parse_argument_into_param( entity_type: Option<&String>, arg: &str, value: Value, - schema: &IndexerSchema, + schema: &ParsedGraphQLSchema, ) -> Result { match arg { "filter" => { @@ -399,11 +402,7 @@ pub fn parse_argument_into_param( "order" => { if let Value::Object(obj) = value { if let Some((field, sort_order)) = obj.into_iter().next() { - if schema - .parsed() - .graphql_type(entity_type, field.as_str()) - .is_some() - { + if schema.graphql_type(entity_type, field.as_str()).is_some() { if let Value::Enum(sort_order) = sort_order { match sort_order.as_str() { "asc" => { @@ -458,6 +457,20 @@ pub fn parse_argument_into_param( Err(GraphqlError::UnsupportedValueType(value.to_string())) } } + "before" => { + if let Value::String(s) = value { + Ok(ParamType::Cursor(s)) + } else { + Err(GraphqlError::UnsupportedValueType(value.to_string())) + } + } + "after" => { + if let Value::String(s) = value { + Ok(ParamType::Cursor(s)) + } else { + Err(GraphqlError::UnsupportedValueType(value.to_string())) + } + } _ => { if let Some(entity) = entity_type { Err(GraphqlError::UnrecognizedArgument( @@ -481,7 +494,7 @@ pub fn parse_argument_into_param( fn parse_filter_object( obj: IndexMap, entity_type: Option<&String>, - schema: &IndexerSchema, + schema: &ParsedGraphQLSchema, prior_filter: &mut Option, ) -> Result { let mut iter = obj.into_iter(); @@ -510,7 +523,7 @@ fn parse_arg_pred_pair( key: &str, predicate: Value, entity_type: Option<&String>, - schema: &IndexerSchema, + schema: &ParsedGraphQLSchema, prior_filter: &mut Option, top_level_arg_value_iter: &mut impl Iterator, ) -> Result { @@ -520,11 +533,7 @@ fn parse_arg_pred_pair( let mut column_list = vec![]; for element in elements { if let Value::Enum(column) = element { - if schema - .parsed() - .graphql_type(entity_type, column.as_str()) - .is_some() - { + if schema.graphql_type(entity_type, column.as_str()).is_some() { column_list.push(column.to_string()) } else if let Some(entity) = entity_type { return Err(GraphqlError::UnrecognizedField( @@ -570,7 +579,7 @@ fn parse_arg_pred_pair( } } other => { - if schema.parsed().graphql_type(entity_type, other).is_some() { + if schema.graphql_type(entity_type, other).is_some() { if let Value::Object(inner_obj) = predicate { for (key, predicate) in inner_obj.iter() { match key.as_str() { @@ -668,7 +677,7 @@ fn parse_binary_logical_operator( key: &str, predicate: Value, entity_type: Option<&String>, - schema: &IndexerSchema, + schema: &ParsedGraphQLSchema, top_level_arg_value_iter: &mut impl Iterator, prior_filter: &mut Option, ) -> Result { diff --git a/packages/fuel-indexer-graphql/src/graphql.rs b/packages/fuel-indexer-graphql/src/graphql.rs index 094419787..e07f0d63b 100644 --- a/packages/fuel-indexer-graphql/src/graphql.rs +++ b/packages/fuel-indexer-graphql/src/graphql.rs @@ -120,7 +120,7 @@ impl Selections { Some(subfield_type), &arg.to_string(), value.node.clone(), - schema, + schema.parsed(), ) }) .collect::, GraphqlError>>()?; diff --git a/packages/fuel-indexer-graphql/src/queries.rs b/packages/fuel-indexer-graphql/src/queries.rs index a56eede84..8ec0c78ff 100644 --- a/packages/fuel-indexer-graphql/src/queries.rs +++ b/packages/fuel-indexer-graphql/src/queries.rs @@ -466,6 +466,7 @@ mod tests { sorts: vec![], offset: None, limit: None, + cursor: None, }, alias: None, }; diff --git a/packages/fuel-indexer-graphql/src/query.rs b/packages/fuel-indexer-graphql/src/query.rs index fa385fbdd..005a2e683 100644 --- a/packages/fuel-indexer-graphql/src/query.rs +++ b/packages/fuel-indexer-graphql/src/query.rs @@ -12,7 +12,10 @@ use fuel_indexer_database::DbType; use fuel_indexer_lib::graphql::{parser::InternalType, ParsedGraphQLSchema}; use petgraph::graph::{Graph, NodeIndex}; -use crate::graphql::{GraphqlError, GraphqlResult}; +use crate::{ + arguments::{parse_argument_into_param, ParamType}, + graphql::{GraphqlError, GraphqlResult}, +}; /// Contains information about a successfully-parsed user operation. #[derive(Debug)] @@ -210,6 +213,7 @@ pub enum SelectionNode { alias: Option>, fields: Vec, is_part_of_list: bool, + arguments: Vec, }, List { name: Name, @@ -220,6 +224,7 @@ pub enum SelectionNode { name: Name, alias: Option>, fields: Vec, + arguments: Vec, }, PageInfo { name: Name, @@ -232,6 +237,7 @@ pub enum SelectionNode { alias: Option>, entity: String, fields: Vec, + arguments: Vec, }, Edge { name: Name, @@ -288,6 +294,7 @@ impl SelectionNode { fields, parent_entity, is_part_of_list, + arguments: _, } => { if let Some(fk_map) = schema .foreign_key_mappings() @@ -375,6 +382,7 @@ impl SelectionNode { alias, entity: _, fields, + arguments: _, } => { // Connection types require a special process for resolving // queries. Instead of calling the .prepare() method on the @@ -457,6 +465,20 @@ fn parse_selections( let parsed_selections = selections.iter().try_fold(vec![], |mut v, selection| { Ok(match &selection.node { Selection::Field(f) => { + let field_type = schema.graphql_type(parent_obj, &f.node.name.node); + let arguments = f + .node + .arguments + .iter() + .map(|(arg, value)| { + parse_argument_into_param( + field_type, + &arg.to_string(), + value.node.clone(), + schema, + ) + }) + .collect::>>()?; if let Some(parent) = parent_obj { let has_no_subselections = f.node.selection_set.node.items.is_empty(); let (is_list_field, internal_type) = if let Some(parent) = parent_obj @@ -532,6 +554,7 @@ fn parse_selections( alias: f.node.alias.clone(), entity, fields, + arguments, }, InternalType::Edge => { let (cursor, fields) = if let Some(idx) = @@ -581,6 +604,7 @@ fn parse_selections( fields, parent_entity: parent.to_string(), is_part_of_list: is_list_field, + arguments, } }; @@ -607,6 +631,7 @@ fn parse_selections( name: f.node.name.node.clone(), alias: f.node.alias.clone(), fields, + arguments, }); v }