Skip to content

Commit

Permalink
Add new execution plan types to plan-types crate (#1363)
Browse files Browse the repository at this point in the history
<!-- The PR description should answer 2 important questions: -->

### What

Adds the types required for the new execution planning to the
`plan-types` crate. Some of these lived in `graphql-ir`, so have been
removed from there. Functional no-op.

V3_GIT_ORIGIN_REV_ID: 0e39aca2d35a7fe69382363b2cef8a028e9be86e
  • Loading branch information
danieljharvey authored and hasura-bot committed Nov 20, 2024
1 parent b810b99 commit e6f56f8
Show file tree
Hide file tree
Showing 23 changed files with 428 additions and 100 deletions.
5 changes: 3 additions & 2 deletions v3/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

27 changes: 13 additions & 14 deletions v3/crates/execute/src/plan/ndc_request/v01.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@ use super::super::mutation;
use super::super::query;
use super::super::relationships;
use crate::error::{FieldError, FieldInternalError};
use plan_types::VariableName;
use plan_types::{
AggregateFieldSelection, AggregateSelectionSet, OrderByDirection, OrderByElement,
OrderByTarget, VariableName,
};

pub fn make_query_request(
query_execution_plan: query::ResolvedQueryExecutionPlan,
Expand Down Expand Up @@ -444,28 +447,24 @@ fn make_relationship(relationship: relationships::Relationship) -> ndc_models_v0
}
}

fn make_order_by(order_by_elements: Vec<graphql_ir::OrderByElement>) -> ndc_models_v01::OrderBy {
fn make_order_by(order_by_elements: Vec<OrderByElement>) -> ndc_models_v01::OrderBy {
ndc_models_v01::OrderBy {
elements: order_by_elements
.into_iter()
.map(|element| ndc_models_v01::OrderByElement {
order_direction: match element.order_direction {
graphql_schema::ModelOrderByDirection::Asc => {
ndc_models_v01::OrderDirection::Asc
}
graphql_schema::ModelOrderByDirection::Desc => {
ndc_models_v01::OrderDirection::Desc
}
OrderByDirection::Asc => ndc_models_v01::OrderDirection::Asc,
OrderByDirection::Desc => ndc_models_v01::OrderDirection::Desc,
},
target: make_order_by_target(element.target),
})
.collect(),
}
}

fn make_order_by_target(target: graphql_ir::OrderByTarget) -> ndc_models_v01::OrderByTarget {
fn make_order_by_target(target: OrderByTarget) -> ndc_models_v01::OrderByTarget {
match target {
graphql_ir::OrderByTarget::Column {
OrderByTarget::Column {
name,
field_path,
relationship_path,
Expand Down Expand Up @@ -521,20 +520,20 @@ fn make_order_by_target(target: graphql_ir::OrderByTarget) -> ndc_models_v01::Or

/// Translates the internal IR 'AggregateSelectionSet' into an NDC query aggregates selection
fn make_aggregates(
aggregate_selection_set: graphql_ir::AggregateSelectionSet,
aggregate_selection_set: AggregateSelectionSet,
) -> IndexMap<ndc_models_v01::FieldName, ndc_models_v01::Aggregate> {
aggregate_selection_set
.fields
.into_iter()
.map(|(field_name, aggregate_selection)| {
let aggregate = match aggregate_selection {
graphql_ir::AggregateFieldSelection::Count { column_path, .. } => {
AggregateFieldSelection::Count { column_path, .. } => {
make_count_aggregate(column_path, false)
}
graphql_ir::AggregateFieldSelection::CountDistinct { column_path, .. } => {
AggregateFieldSelection::CountDistinct { column_path, .. } => {
make_count_aggregate(column_path, true)
}
graphql_ir::AggregateFieldSelection::AggregationFunction {
AggregateFieldSelection::AggregationFunction {
function_name,
column_path,
} => {
Expand Down
27 changes: 13 additions & 14 deletions v3/crates/execute/src/plan/ndc_request/v02.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use super::super::mutation;
use super::super::query;
use super::super::relationships;
use crate::error::{FieldError, FieldInternalError};
use plan_types::VariableName;
use plan_types::{
AggregateFieldSelection, AggregateSelectionSet, OrderByDirection, OrderByElement,
OrderByTarget, VariableName,
};

pub fn make_query_request(
query_execution_plan: query::ResolvedQueryExecutionPlan,
Expand Down Expand Up @@ -453,28 +456,24 @@ fn make_relationship(relationship: relationships::Relationship) -> ndc_models_v0
}
}

fn make_order_by(order_by_elements: Vec<graphql_ir::OrderByElement>) -> ndc_models_v02::OrderBy {
fn make_order_by(order_by_elements: Vec<OrderByElement>) -> ndc_models_v02::OrderBy {
ndc_models_v02::OrderBy {
elements: order_by_elements
.into_iter()
.map(|element| ndc_models_v02::OrderByElement {
order_direction: match element.order_direction {
graphql_schema::ModelOrderByDirection::Asc => {
ndc_models_v02::OrderDirection::Asc
}
graphql_schema::ModelOrderByDirection::Desc => {
ndc_models_v02::OrderDirection::Desc
}
OrderByDirection::Asc => ndc_models_v02::OrderDirection::Asc,
OrderByDirection::Desc => ndc_models_v02::OrderDirection::Desc,
},
target: make_order_by_target(element.target),
})
.collect(),
}
}

fn make_order_by_target(target: graphql_ir::OrderByTarget) -> ndc_models_v02::OrderByTarget {
fn make_order_by_target(target: OrderByTarget) -> ndc_models_v02::OrderByTarget {
match target {
graphql_ir::OrderByTarget::Column {
OrderByTarget::Column {
name,
field_path,
relationship_path,
Expand Down Expand Up @@ -532,20 +531,20 @@ fn make_order_by_target(target: graphql_ir::OrderByTarget) -> ndc_models_v02::Or

/// Translates the internal IR 'AggregateSelectionSet' into an NDC query aggregates selection
fn make_aggregates(
aggregate_selection_set: graphql_ir::AggregateSelectionSet,
aggregate_selection_set: AggregateSelectionSet,
) -> IndexMap<ndc_models_v02::FieldName, ndc_models_v02::Aggregate> {
aggregate_selection_set
.fields
.into_iter()
.map(|(field_name, aggregate_selection)| {
let aggregate = match aggregate_selection {
graphql_ir::AggregateFieldSelection::Count { column_path, .. } => {
AggregateFieldSelection::Count { column_path, .. } => {
make_count_aggregate(column_path, false)
}
graphql_ir::AggregateFieldSelection::CountDistinct { column_path, .. } => {
AggregateFieldSelection::CountDistinct { column_path, .. } => {
make_count_aggregate(column_path, true)
}
graphql_ir::AggregateFieldSelection::AggregationFunction {
AggregateFieldSelection::AggregationFunction {
function_name,
column_path,
} => {
Expand Down
5 changes: 3 additions & 2 deletions v3/crates/execute/src/plan/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ use std::sync::Arc;

use crate::error;
use async_recursion::async_recursion;
use graphql_ir::{AggregateSelectionSet, OrderByElement};
use indexmap::IndexMap;
use open_dds::{data_connector::CollectionName, types::DataConnectorArgumentName};
use plan_types::{NdcFieldAlias, NdcRelationshipName, VariableName};
use plan_types::{
AggregateSelectionSet, NdcFieldAlias, NdcRelationshipName, OrderByElement, VariableName,
};
use std::collections::BTreeMap;

use super::arguments;
Expand Down
29 changes: 2 additions & 27 deletions v3/crates/graphql/ir/src/aggregates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,38 +7,13 @@ use indexmap::IndexMap;
use lang_graphql::{ast::common::Alias, normalized_ast};
use metadata_resolve::{Qualified, QualifiedTypeName, TypeMapping};
use open_dds::{
aggregates::DataConnectorAggregationFunctionName,
data_connector::{DataConnectorColumnName, DataConnectorName},
data_connector::DataConnectorName,
types::{CustomTypeName, FieldName},
};
use serde::Serialize;

use crate::error;

use plan_types::NdcFieldAlias;

/// IR that represents the selected fields of an output type.
#[derive(Debug, Serialize, Default, PartialEq, Clone)]
pub struct AggregateSelectionSet {
// The fields in the selection set. They are stored in the form that would
// be converted and sent over the wire. Serialized the map as ordered to
// produce deterministic golden files.
pub fields: IndexMap<NdcFieldAlias, AggregateFieldSelection>,
}

#[derive(Debug, Serialize, PartialEq, Clone)]
pub enum AggregateFieldSelection {
Count {
column_path: Vec<DataConnectorColumnName>,
},
CountDistinct {
column_path: Vec<DataConnectorColumnName>,
},
AggregationFunction {
function_name: DataConnectorAggregationFunctionName,
column_path: nonempty::NonEmpty<DataConnectorColumnName>,
},
}
use plan_types::{AggregateFieldSelection, AggregateSelectionSet, NdcFieldAlias};

pub fn generate_aggregate_selection_set_ir<'s>(
selection_set: &normalized_ast::SelectionSet<'s, GDS>,
Expand Down
6 changes: 2 additions & 4 deletions v3/crates/graphql/ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,15 @@ mod subscription_root;

pub use error::{Error, InternalDeveloperError, InternalEngineError};

pub use aggregates::{
mk_alias_from_graphql_field_path, AggregateFieldSelection, AggregateSelectionSet,
};
pub use aggregates::mk_alias_from_graphql_field_path;
pub use arguments::{process_argument_presets, process_connector_link_presets, Argument};
pub use commands::{CommandInfo, FunctionBasedCommand, ProcedureBasedCommand};
pub use filter::FilterExpression;
pub use global_id::{global_id_col_format, GLOBAL_ID_VERSION};
pub use model_selection::ModelSelection;
pub use model_tracking::get_all_usage_counts_in_query;
pub use mutation_root::generate_ir as generate_mutation_ir;
pub use order_by::{OrderByElement, OrderByTarget, ResolvedOrderBy};
pub use order_by::ResolvedOrderBy;
pub use permissions::process_model_predicate;
pub use query_root::generate_ir as generate_query_ir;
pub use relationship::{
Expand Down
2 changes: 1 addition & 1 deletion v3/crates/graphql/ir/src/model_selection.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ pub struct ModelSelection<'s> {
pub selection: Option<selection_set::ResultSelectionSet<'s>>,

// Aggregates requested of the model
pub aggregate_selection: Option<aggregates::AggregateSelectionSet>,
pub aggregate_selection: Option<plan_types::AggregateSelectionSet>,
}

struct ModelSelectAggregateArguments<'s> {
Expand Down
25 changes: 8 additions & 17 deletions v3/crates/graphql/ir/src/order_by.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ use graphql_schema::OrderByRelationshipAnnotation;
use graphql_schema::{Annotation, InputAnnotation, ModelInputAnnotation};
use lang_graphql::normalized_ast::{self as normalized_ast, InputField};
use open_dds::data_connector::DataConnectorColumnName;
use plan_types::{LocalModelRelationshipInfo, NdcRelationshipName, UsagesCounts};
use plan_types::{
LocalModelRelationshipInfo, NdcRelationshipName, OrderByDirection, OrderByElement,
OrderByTarget, UsagesCounts,
};
use serde::Serialize;

use crate::error;
Expand All @@ -19,21 +22,6 @@ pub struct ResolvedOrderBy<'s> {
pub relationships: BTreeMap<NdcRelationshipName, LocalModelRelationshipInfo<'s>>,
}

#[derive(Debug, Serialize, Clone, PartialEq)]
pub struct OrderByElement {
pub order_direction: graphql_schema::ModelOrderByDirection,
pub target: OrderByTarget,
}

#[derive(Debug, Serialize, Clone, PartialEq)]
pub enum OrderByTarget {
Column {
name: DataConnectorColumnName,
field_path: Option<Vec<DataConnectorColumnName>>,
relationship_path: Vec<NdcRelationshipName>,
},
}

pub fn build_ndc_order_by<'s>(
args_field: &InputField<'s, GDS>,
usage_counts: &mut UsagesCounts,
Expand Down Expand Up @@ -149,7 +137,10 @@ pub fn build_ndc_order_by_element<'s>(
};

let order_element = OrderByElement {
order_direction: order_direction.clone(),
order_direction: match order_direction {
graphql_schema::ModelOrderByDirection::Asc => OrderByDirection::Asc,
graphql_schema::ModelOrderByDirection::Desc => OrderByDirection::Desc,
},
// TODO(naveen): When aggregates are supported, extend this to support other ndc_models::OrderByTarget
target: OrderByTarget::Column {
name,
Expand Down
3 changes: 3 additions & 0 deletions v3/crates/plan-types/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,13 @@ open-dds = { path = "../open-dds" }
metadata-resolve = { path = "../metadata-resolve" }

derive_more = { workspace = true }
indexmap = { workspace = true }
nonempty = { workspace = true }
schemars = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
smol_str = { workspace = true }
uuid = { workspace = true }

[lints]
workspace = true
12 changes: 12 additions & 0 deletions v3/crates/plan-types/src/execution_plan.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//! new execution plan types, entirely separate from `execute` crate
mod aggregates;
mod arguments;
mod field;
mod filter;
mod order_by;
mod query;
mod relationships;

pub use aggregates::{AggregateFieldSelection, AggregateSelectionSet};
pub use order_by::{OrderByDirection, OrderByElement, OrderByTarget};
pub use query::QueryExecutionPlan;
43 changes: 43 additions & 0 deletions v3/crates/plan-types/src/execution_plan/aggregates.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
use crate::NdcFieldAlias;
use indexmap::IndexMap;
use nonempty::NonEmpty;
use open_dds::{
aggregates::DataConnectorAggregationFunctionName, data_connector::DataConnectorColumnName,
};
use serde::Serialize;
use std::hash::Hash;

/// IR that represents the selected fields of an output type.
#[derive(Debug, Serialize, Default, PartialEq, Clone, Eq)]
pub struct AggregateSelectionSet {
// The fields in the selection set. They are stored in the form that would
// be converted and sent over the wire. Serialized the map as ordered to
// produce deterministic golden files.
pub fields: IndexMap<NdcFieldAlias, AggregateFieldSelection>,
}

// FIXME: remove this; this is probably inaccurate.
// https://github.com/indexmap-rs/indexmap/issues/155
// Probably use ordermap (ref: https://github.com/indexmap-rs/indexmap/issues/67#issuecomment-2189801441)
impl Hash for AggregateSelectionSet {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
for (k, v) in &self.fields {
k.hash(state);
v.hash(state);
}
}
}

#[derive(Debug, Serialize, PartialEq, Clone, Eq, Hash)]
pub enum AggregateFieldSelection {
Count {
column_path: Vec<DataConnectorColumnName>,
},
CountDistinct {
column_path: Vec<DataConnectorColumnName>,
},
AggregationFunction {
function_name: DataConnectorAggregationFunctionName,
column_path: NonEmpty<DataConnectorColumnName>,
},
}
19 changes: 19 additions & 0 deletions v3/crates/plan-types/src/execution_plan/arguments.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use super::filter::ResolvedFilterExpression;

use crate::VariableName;

/// Argument plan to express various kinds of arguments
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Argument {
/// The argument is provided as a literal value
Literal {
value: serde_json::Value,
},
/// The argument is provided by reference to a variable
Variable {
name: VariableName,
},
BooleanExpression {
predicate: ResolvedFilterExpression,
},
}
Loading

0 comments on commit e6f56f8

Please sign in to comment.