refactor IR types and related code (#704)

This is a no-op refactor of IR related types. Introducing a new concrete
`IR` enum with `Mutation` and `Query` variants, where each contains a
map of root fields.

V3_GIT_ORIGIN_REV_ID: 76a197f5cf1efb34a8493c2b3356bea2bc2feb3c
This commit is contained in:
Rakesh Emmadi 2024-06-12 09:57:40 +05:30 committed by hasura-bot
parent 9f3b8370c1
commit 87d6e2a9b6
13 changed files with 116 additions and 141 deletions

View File

@ -1,3 +1,7 @@
use indexmap::IndexMap;
use lang_graphql::ast::common as ast;
use serde::Serialize;
pub mod arguments;
pub mod commands;
pub mod error;
@ -10,3 +14,10 @@ pub mod query_root;
pub mod relationship;
pub mod root_field;
pub mod selection_set;
/// The IR is the intermediate representation of the GraphQL operation.
#[derive(Serialize, Debug)]
pub enum IR<'n, 's> {
Query(IndexMap<ast::Alias, root_field::QueryRootField<'n, 's>>),
Mutation(IndexMap<ast::Alias, root_field::MutationRootField<'n, 's>>),
}

View File

@ -18,7 +18,7 @@ pub fn generate_ir<'n, 's>(
selection_set: &'s gql::normalized_ast::SelectionSet<'s, GDS>,
session_variables: &SessionVariables,
request_headers: &reqwest::header::HeaderMap,
) -> Result<IndexMap<ast::Alias, root_field::RootField<'n, 's>>, error::Error> {
) -> Result<IndexMap<ast::Alias, root_field::MutationRootField<'n, 's>>, error::Error> {
let tracer = tracing_util::global_tracer();
tracer.in_span(
"generate_ir",
@ -80,10 +80,7 @@ pub fn generate_ir<'n, 's>(
}),
},
}?;
root_fields.insert(
alias.clone(),
root_field::RootField::MutationRootField(field_response),
);
root_fields.insert(alias.clone(), field_response);
}
Ok(root_fields)
},

View File

@ -32,7 +32,7 @@ pub fn generate_ir<'n, 's>(
session: &Session,
request_headers: &reqwest::header::HeaderMap,
selection_set: &'s gql::normalized_ast::SelectionSet<'s, GDS>,
) -> Result<IndexMap<ast::Alias, root_field::RootField<'n, 's>>, error::Error> {
) -> Result<IndexMap<ast::Alias, root_field::QueryRootField<'n, 's>>, error::Error> {
let type_name = selection_set
.type_name
.clone()
@ -146,10 +146,7 @@ pub fn generate_ir<'n, 's>(
)),
},
}?;
ir.insert(
alias.clone(),
root_field::RootField::QueryRootField(field_ir),
);
ir.insert(alias.clone(), field_ir);
}
Ok(ir)
}

View File

@ -10,13 +10,6 @@ use super::{
};
use schema::GDS;
/// IR of a root field
#[derive(Serialize, Debug)]
pub enum RootField<'n, 's> {
QueryRootField(QueryRootField<'n, 's>),
MutationRootField(MutationRootField<'n, 's>),
}
/// IR of a query root field
#[derive(Serialize, Debug)]
pub enum QueryRootField<'n, 's> {

View File

@ -8,7 +8,6 @@ mod plan;
mod process_response;
mod remote_joins;
use indexmap::IndexMap;
use thiserror::Error;
use gql::normalized_ast::Operation;
@ -354,7 +353,7 @@ pub(crate) fn build_ir<'n, 's>(
session: &Session,
request_headers: &reqwest::header::HeaderMap,
normalized_request: &'s Operation<'s, GDS>,
) -> Result<IndexMap<ast::Alias, ir::root_field::RootField<'n, 's>>, ir::error::Error> {
) -> Result<ir::IR<'n, 's>, ir::error::Error> {
let tracer = tracing_util::global_tracer();
let ir = tracer.in_span(
"generate_ir",
@ -367,7 +366,7 @@ pub(crate) fn build_ir<'n, 's>(
/// Build a plan to execute the request
pub(crate) fn build_request_plan<'n, 's, 'ir>(
ir: &'ir IndexMap<ast::Alias, ir::root_field::RootField<'n, 's>>,
ir: &'ir ir::IR<'n, 's>,
) -> Result<plan::RequestPlan<'n, 's, 'ir>, plan::error::Error> {
let tracer = tracing_util::global_tracer();
let plan = tracer.in_span(
@ -384,24 +383,29 @@ pub fn generate_ir<'n, 's>(
session: &Session,
request_headers: &reqwest::header::HeaderMap,
normalized_request: &'s Operation<'s, GDS>,
) -> Result<IndexMap<ast::Alias, ir::root_field::RootField<'n, 's>>, ir::error::Error> {
let ir = match &normalized_request.ty {
ast::OperationType::Query => ir::query_root::generate_ir(
schema,
session,
request_headers,
&normalized_request.selection_set,
)?,
ast::OperationType::Mutation => ir::mutation_root::generate_ir(
&normalized_request.selection_set,
&session.variables,
request_headers,
)?,
) -> Result<ir::IR<'n, 's>, ir::error::Error> {
match &normalized_request.ty {
ast::OperationType::Query => {
let query_ir = ir::query_root::generate_ir(
schema,
session,
request_headers,
&normalized_request.selection_set,
)?;
Ok(ir::IR::Query(query_ir))
}
ast::OperationType::Mutation => {
let mutation_ir = ir::mutation_root::generate_ir(
&normalized_request.selection_set,
&session.variables,
request_headers,
)?;
Ok(ir::IR::Mutation(mutation_ir))
}
ast::OperationType::Subscription => {
Err(ir::error::InternalEngineError::SubscriptionsNotSupported)?
}
};
Ok(ir)
}
}
#[cfg(test)]

View File

@ -1,8 +1,7 @@
//! Track the models that were used in query.
use super::ir::root_field::{self, RootField};
use indexmap::IndexMap;
use lang_graphql::ast::common::Alias;
use super::ir;
use super::ir::root_field::{self};
use metadata_resolve::Qualified;
use open_dds::{commands::CommandName, models::ModelName};
use serde::{Deserialize, Serialize};
@ -47,52 +46,58 @@ pub struct ModelCount {
// field. We then merge the models/commands used in each root field into a single map.
// That means, if the same model was used in multiple root fields, we will
// sum up the number of times that model was used.
pub fn get_all_usage_counts_in_query(ir: &IndexMap<Alias, RootField<'_, '_>>) -> UsagesCounts {
pub fn get_all_usage_counts_in_query(ir: &ir::IR<'_, '_>) -> UsagesCounts {
let mut all_usage_counts = UsagesCounts::new();
for ir_field in ir.values() {
match ir_field {
root_field::RootField::QueryRootField(ir) => match ir {
root_field::QueryRootField::TypeName { .. }
| root_field::QueryRootField::SchemaField { .. }
| root_field::QueryRootField::TypeField { .. }
| root_field::QueryRootField::ApolloFederation(
root_field::ApolloFederationRootFields::ServiceField { .. },
) => {}
root_field::QueryRootField::ModelSelectOne { ir, .. } => {
let usage_counts = ir.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
root_field::QueryRootField::ModelSelectMany { ir, .. } => {
let usage_counts = ir.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
root_field::QueryRootField::NodeSelect(ir1) => match ir1 {
None => {}
Some(ir2) => {
let usage_counts = ir2.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
},
root_field::QueryRootField::FunctionBasedCommand { ir, .. } => {
let usage_counts = ir.command_info.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
root_field::QueryRootField::ApolloFederation(
root_field::ApolloFederationRootFields::EntitiesSelect(irs),
) => {
for ir in irs {
match ir {
ir::IR::Query(ir) => {
for ir_field in ir.values() {
match ir_field {
root_field::QueryRootField::TypeName { .. }
| root_field::QueryRootField::SchemaField { .. }
| root_field::QueryRootField::TypeField { .. }
| root_field::QueryRootField::ApolloFederation(
root_field::ApolloFederationRootFields::ServiceField { .. },
) => {}
root_field::QueryRootField::ModelSelectOne { ir, .. } => {
let usage_counts = ir.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
root_field::QueryRootField::ModelSelectMany { ir, .. } => {
let usage_counts = ir.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
root_field::QueryRootField::NodeSelect(ir1) => match ir1 {
None => {}
Some(ir2) => {
let usage_counts = ir2.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
},
root_field::QueryRootField::FunctionBasedCommand { ir, .. } => {
let usage_counts = ir.command_info.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
root_field::QueryRootField::ApolloFederation(
root_field::ApolloFederationRootFields::EntitiesSelect(irs),
) => {
for ir in irs {
let usage_counts = ir.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
}
}
},
root_field::RootField::MutationRootField(rf) => match rf {
root_field::MutationRootField::TypeName { .. } => {}
root_field::MutationRootField::ProcedureBasedCommand { ir, .. } => {
let usage_counts = ir.command_info.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
}
ir::IR::Mutation(ir) => {
for ir_field in ir.values() {
match ir_field {
root_field::MutationRootField::TypeName { .. } => {}
root_field::MutationRootField::ProcedureBasedCommand { ir, .. } => {
let usage_counts = ir.command_info.usage_counts.clone();
extend_usage_count(usage_counts, &mut all_usage_counts);
}
}
},
}
}
}
all_usage_counts

View File

@ -13,6 +13,7 @@ use lang_graphql::ast::common as ast;
use serde_json as json;
use tracing_util::{set_attribute_on_active_span, AttributeVisibility, Traceable};
use super::ir;
use super::ir::model_selection::ModelSelection;
use super::ir::root_field;
use super::ndc;
@ -148,46 +149,23 @@ impl<'ir> ProcessResponseAs<'ir> {
/// plan, but currently can't be both. This may change when we support protocols other than
/// GraphQL.
pub fn generate_request_plan<'n, 's, 'ir>(
ir: &'ir IndexMap<ast::Alias, root_field::RootField<'n, 's>>,
ir: &'ir ir::IR<'n, 's>,
) -> Result<RequestPlan<'n, 's, 'ir>, error::Error> {
let mut request_plan = None;
for (alias, field) in ir {
match field {
root_field::RootField::QueryRootField(field_ir) => {
let mut query_plan = match request_plan {
Some(RequestPlan::MutationPlan(_)) => {
Err(error::InternalError::InternalGeneric {
description:
"Parsed engine request contains mixed mutation/query operations"
.to_string(),
})?
}
Some(RequestPlan::QueryPlan(query_plan)) => query_plan,
None => IndexMap::new(),
};
query_plan.insert(alias.clone(), plan_query(field_ir)?);
request_plan = Some(RequestPlan::QueryPlan(query_plan));
match ir {
ir::IR::Query(ir) => {
let mut query_plan = IndexMap::new();
for (alias, field) in ir {
query_plan.insert(alias.clone(), plan_query(field)?);
}
root_field::RootField::MutationRootField(field_ir) => {
let mut mutation_plan = match request_plan {
Some(RequestPlan::QueryPlan(_)) => {
Err(error::InternalError::InternalGeneric {
description:
"Parsed engine request contains mixed mutation/query operations"
.to_string(),
})?
}
Some(RequestPlan::MutationPlan(mutation_plan)) => mutation_plan,
None => MutationPlan {
nodes: IndexMap::new(),
type_names: IndexMap::new(),
},
};
match field_ir {
Ok(RequestPlan::QueryPlan(query_plan))
}
ir::IR::Mutation(ir) => {
let mut mutation_plan = MutationPlan {
nodes: IndexMap::new(),
type_names: IndexMap::new(),
};
for (alias, field) in ir {
match field {
root_field::MutationRootField::TypeName { type_name } => {
mutation_plan
.type_names
@ -195,7 +173,6 @@ pub fn generate_request_plan<'n, 's, 'ir>(
}
root_field::MutationRootField::ProcedureBasedCommand { selection_set, ir } => {
let plan = plan_mutation(selection_set, ir)?;
mutation_plan
.nodes
.entry(plan.data_connector.clone())
@ -203,17 +180,10 @@ pub fn generate_request_plan<'n, 's, 'ir>(
.insert(alias.clone(), plan);
}
};
request_plan = Some(RequestPlan::MutationPlan(mutation_plan));
}
Ok(RequestPlan::MutationPlan(mutation_plan))
}
}
request_plan.ok_or(error::Error::Internal(
error::InternalError::InternalGeneric {
description: "Parsed an empty request".to_string(),
},
))
}
// Given a singular root field of a mutation, plan the execution of that root field.

View File

@ -1,6 +1,6 @@
{
"ArticleByID": {
"QueryRootField": {
"Query": {
"ArticleByID": {
"ModelSelectOne": {
"selection_set": {
"fields": {

View File

@ -1,6 +1,6 @@
{
"ArticleMany": {
"QueryRootField": {
"Query": {
"ArticleMany": {
"ModelSelectMany": {
"selection_set": {
"fields": {

View File

@ -1,6 +1,6 @@
{
"getLatestArticle": {
"QueryRootField": {
"Query": {
"getLatestArticle": {
"FunctionBasedCommand": {
"selection_set": {
"fields": {

View File

@ -1,6 +1,6 @@
{
"ArticleMany": {
"QueryRootField": {
"Query": {
"ArticleMany": {
"ModelSelectMany": {
"selection_set": {
"fields": {

View File

@ -1,6 +1,6 @@
{
"ArticleMany": {
"QueryRootField": {
"Query": {
"ArticleMany": {
"ModelSelectMany": {
"selection_set": {
"fields": {
@ -174,10 +174,8 @@
}
}
}
}
},
"AuthorMany": {
"QueryRootField": {
},
"AuthorMany": {
"ModelSelectMany": {
"selection_set": {
"fields": {

View File

@ -1,6 +1,6 @@
{
"__typename": {
"QueryRootField": {
"Query": {
"__typename": {
"TypeName": {
"type_name": "Query"
}