mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-14 17:02:49 +03:00
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:
parent
9f3b8370c1
commit
87d6e2a9b6
@ -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>>),
|
||||
}
|
||||
|
@ -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)
|
||||
},
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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> {
|
||||
|
@ -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)]
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ArticleByID": {
|
||||
"QueryRootField": {
|
||||
"Query": {
|
||||
"ArticleByID": {
|
||||
"ModelSelectOne": {
|
||||
"selection_set": {
|
||||
"fields": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ArticleMany": {
|
||||
"QueryRootField": {
|
||||
"Query": {
|
||||
"ArticleMany": {
|
||||
"ModelSelectMany": {
|
||||
"selection_set": {
|
||||
"fields": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"getLatestArticle": {
|
||||
"QueryRootField": {
|
||||
"Query": {
|
||||
"getLatestArticle": {
|
||||
"FunctionBasedCommand": {
|
||||
"selection_set": {
|
||||
"fields": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ArticleMany": {
|
||||
"QueryRootField": {
|
||||
"Query": {
|
||||
"ArticleMany": {
|
||||
"ModelSelectMany": {
|
||||
"selection_set": {
|
||||
"fields": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"ArticleMany": {
|
||||
"QueryRootField": {
|
||||
"Query": {
|
||||
"ArticleMany": {
|
||||
"ModelSelectMany": {
|
||||
"selection_set": {
|
||||
"fields": {
|
||||
@ -174,10 +174,8 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"AuthorMany": {
|
||||
"QueryRootField": {
|
||||
},
|
||||
"AuthorMany": {
|
||||
"ModelSelectMany": {
|
||||
"selection_set": {
|
||||
"fields": {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"__typename": {
|
||||
"QueryRootField": {
|
||||
"Query": {
|
||||
"__typename": {
|
||||
"TypeName": {
|
||||
"type_name": "Query"
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user