Use counter instead of uuid in remote predicates (#1401)

<!-- The PR description should answer 2 important questions: -->

### What

We need a unique identifier for remote predicates, and used `uuid`.
However this makes snapshot tests of `explain` unstable because the
ordering changes all the time, so we switch it for a counter, threaded
through the planning code.

### How

Make a counter with a private inner value that we pass around, that
provides a fresh `u64` when required.

V3_GIT_ORIGIN_REV_ID: 386c6d47935b8da497e1471a3ca44bd52a12f72a
This commit is contained in:
Daniel Harvey 2024-12-02 09:59:16 +00:00 committed by hasura-bot
parent fb37167680
commit 6b781009f1
15 changed files with 184 additions and 73 deletions

1
v3/Cargo.lock generated
View File

@ -4177,7 +4177,6 @@ dependencies = [
"serde",
"serde_json",
"smol_str",
"uuid",
]
[[package]]

View File

@ -2,6 +2,7 @@ use engine_types::ExposeInternalErrors;
use gql::{ast::common as ast, http::GraphQLError};
use lang_graphql as gql;
use open_dds::relationships::RelationshipName;
use plan_types::RemotePredicateKey;
use reqwest::StatusCode;
use serde_json as json;
use thiserror::Error;
@ -218,7 +219,7 @@ pub enum FilterPredicateError {
TooManyRowsReturned,
#[error("could not find remote predicate result for {0}")]
CouldNotFindRemotePredicate(uuid::Uuid),
CouldNotFindRemotePredicate(RemotePredicateKey),
}
impl TraceableError for FilterPredicateError {

View File

@ -3,7 +3,6 @@
// frontend
use std::sync::Arc;
use uuid::Uuid;
mod ndc_request;
mod remote_joins;
mod remote_predicates;
@ -15,7 +14,7 @@ pub use ndc_request::{make_ndc_mutation_request, make_ndc_query_request};
use plan_types::{
ExecutionTree, JoinLocations, NDCMutationExecution, NDCQueryExecution,
NDCSubscriptionExecution, PredicateQueryTrees, ProcessResponseAs, QueryExecutionPlan,
ResolvedFilterExpression,
RemotePredicateKey, ResolvedFilterExpression,
};
use std::collections::BTreeMap;
@ -53,7 +52,7 @@ async fn execute_remote_predicates(
execution_span_attribute: &'static str,
process_response_as: &ProcessResponseAs,
project_id: Option<&ProjectId>,
) -> Result<BTreeMap<Uuid, ResolvedFilterExpression>, FieldError> {
) -> Result<BTreeMap<RemotePredicateKey, ResolvedFilterExpression>, FieldError> {
// resolve all our filter expressions into here, ready to && them in
// at the appropriate moment
let mut filter_expressions = BTreeMap::new();
@ -109,7 +108,7 @@ async fn execute_execution_tree<'s>(
execution_span_attribute: &'static str,
process_response_as: &ProcessResponseAs,
project_id: Option<&ProjectId>,
child_filter_expressions: &BTreeMap<Uuid, ResolvedFilterExpression>,
child_filter_expressions: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<Vec<ndc_models::RowSet>, FieldError> {
// given an execution tree
// 1) run remote predicates

View File

@ -2,17 +2,16 @@ use crate::error::{FieldError, FieldInternalError, FilterPredicateError};
use indexmap::{IndexMap, IndexSet};
use plan_types::{
Argument, Field, FieldsSelection, NestedArray, NestedField, NestedObject, QueryExecutionPlan,
QueryNodeNew, ResolvedFilterExpression,
QueryNodeNew, RemotePredicateKey, ResolvedFilterExpression,
};
use std::collections::BTreeMap;
use uuid::Uuid;
// replace any placeholders in our predicates with
// `ResolvedFilterExpression`s we have calculated from
// our remote predicate execution
pub fn replace_predicates_in_query_execution_plan(
query_execution_plan: QueryExecutionPlan,
predicates: &BTreeMap<Uuid, ResolvedFilterExpression>,
predicates: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<QueryExecutionPlan, FilterPredicateError> {
Ok(QueryExecutionPlan {
query_node: replace_predicates_in_query_node(query_execution_plan.query_node, predicates)?,
@ -35,7 +34,7 @@ pub fn replace_predicates_in_query_execution_plan(
fn replace_predicates_in_argument(
argument: Argument,
predicates: &BTreeMap<Uuid, ResolvedFilterExpression>,
predicates: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<Argument, FilterPredicateError> {
Ok(match argument {
Argument::BooleanExpression { predicate } => Argument::BooleanExpression {
@ -48,7 +47,7 @@ fn replace_predicates_in_argument(
fn replace_predicates_in_query_node(
query_node: QueryNodeNew,
predicates: &BTreeMap<Uuid, ResolvedFilterExpression>,
predicates: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<QueryNodeNew, FilterPredicateError> {
Ok(QueryNodeNew {
aggregates: query_node.aggregates,
@ -78,7 +77,7 @@ fn replace_predicates_in_query_node(
fn replace_predicates_in_nested_field(
nested_field: NestedField,
predicates: &BTreeMap<Uuid, ResolvedFilterExpression>,
predicates: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<NestedField, FilterPredicateError> {
Ok(match nested_field {
NestedField::Object(nested_object) => NestedField::Object(
@ -92,7 +91,7 @@ fn replace_predicates_in_nested_field(
}
fn replace_predicates_in_nested_array(
nested_array: NestedArray,
predicates: &BTreeMap<Uuid, ResolvedFilterExpression>,
predicates: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<NestedArray, FilterPredicateError> {
let NestedArray { fields } = nested_array;
Ok(NestedArray {
@ -102,7 +101,7 @@ fn replace_predicates_in_nested_array(
fn replace_predicates_in_nested_object(
nested_object: NestedObject,
predicates: &BTreeMap<Uuid, ResolvedFilterExpression>,
predicates: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<NestedObject, FilterPredicateError> {
let NestedObject { fields } = nested_object;
Ok(NestedObject {
@ -120,7 +119,7 @@ fn replace_predicates_in_nested_object(
fn replace_predicates_in_field(
field: Field,
predicates: &BTreeMap<Uuid, ResolvedFilterExpression>,
predicates: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<Field, FilterPredicateError> {
Ok(match field {
Field::Relationship {
@ -164,7 +163,7 @@ fn replace_predicates_in_field(
fn replace_predicates_in_filter_expression(
filter_expression: ResolvedFilterExpression,
predicates: &BTreeMap<Uuid, ResolvedFilterExpression>,
predicates: &BTreeMap<RemotePredicateKey, ResolvedFilterExpression>,
) -> Result<ResolvedFilterExpression, FilterPredicateError> {
Ok(match filter_expression {
ResolvedFilterExpression::RemoteRelationshipComparison {

View File

@ -16,7 +16,7 @@ use indexmap::IndexMap;
use lang_graphql as gql;
use plan_types::{
ExecutionTree, NDCMutationExecution, NDCQueryExecution, NDCSubscriptionExecution,
ProcessResponseAs, QueryExecutionPlan,
ProcessResponseAs, QueryExecutionPlan, UniqueNumber,
};
pub use relationships::process_model_relationship_definition;
pub use types::{
@ -36,11 +36,13 @@ pub use types::{
pub fn generate_request_plan<'n, 's, 'ir>(
ir: &'ir IR<'n, 's>,
) -> Result<RequestPlan<'n, 's, 'ir>, error::Error> {
let mut unique_number = UniqueNumber::new();
match ir {
IR::Query(ir) => {
let mut query_plan = IndexMap::new();
for (alias, field) in ir {
query_plan.insert(alias.clone(), plan_query(field)?);
query_plan.insert(alias.clone(), plan_query(field, &mut unique_number)?);
}
Ok(RequestPlan::QueryPlan(query_plan))
}
@ -57,7 +59,7 @@ pub fn generate_request_plan<'n, 's, 'ir>(
.insert(alias.clone(), type_name.clone());
}
MutationRootField::ProcedureBasedCommand { selection_set, ir } => {
let plan = plan_mutation(selection_set, ir)?;
let plan = plan_mutation(selection_set, ir, &mut unique_number)?;
mutation_plan
.nodes
.entry(plan.mutation_execution.data_connector.clone())
@ -70,7 +72,7 @@ pub fn generate_request_plan<'n, 's, 'ir>(
}
IR::Subscription(alias, ir) => Ok(RequestPlan::SubscriptionPlan(
alias.clone(),
plan_subscription(ir)?,
plan_subscription(ir, &mut unique_number)?,
)),
}
}
@ -79,12 +81,13 @@ pub fn generate_request_plan<'n, 's, 'ir>(
fn plan_mutation<'n, 's>(
selection_set: &'n gql::normalized_ast::SelectionSet<'s, GDS>,
ir: &ProcedureBasedCommand<'s>,
unique_number: &mut UniqueNumber,
) -> Result<MutationSelect<'n, 's>, error::Error> {
let Plan {
inner: ndc_ir,
join_locations,
remote_predicates,
} = commands::plan_mutation_execution(ir.procedure_name, ir)?;
} = commands::plan_mutation_execution(ir.procedure_name, ir, unique_number)?;
// _should not_ happen but let's fail rather than do a query with missing filters
if !remote_predicates.0.is_empty() {
@ -110,6 +113,7 @@ fn plan_mutation<'n, 's>(
fn plan_subscription<'s, 'ir>(
root_field: &'ir SubscriptionRootField<'_, 's>,
unique_number: &mut UniqueNumber,
) -> Result<SubscriptionSelect<'s, 'ir>, error::Error> {
match root_field {
SubscriptionRootField::ModelSelectOne {
@ -117,7 +121,8 @@ fn plan_subscription<'s, 'ir>(
selection_set,
polling_interval_ms,
} => {
let execution_tree = model_selection::plan_query_execution(&ir.model_selection)?;
let execution_tree =
model_selection::plan_query_execution(&ir.model_selection, unique_number)?;
let query_execution_plan = reject_remote_joins(execution_tree)?;
Ok(SubscriptionSelect {
selection_set,
@ -138,7 +143,8 @@ fn plan_subscription<'s, 'ir>(
selection_set,
polling_interval_ms,
} => {
let execution_tree = model_selection::plan_query_execution(&ir.model_selection)?;
let execution_tree =
model_selection::plan_query_execution(&ir.model_selection, unique_number)?;
let query_execution_plan = reject_remote_joins(execution_tree)?;
Ok(SubscriptionSelect {
selection_set,
@ -159,7 +165,8 @@ fn plan_subscription<'s, 'ir>(
selection_set,
polling_interval_ms,
} => {
let execution_tree = model_selection::plan_query_execution(&ir.model_selection)?;
let execution_tree =
model_selection::plan_query_execution(&ir.model_selection, unique_number)?;
let query_execution_plan = reject_remote_joins(execution_tree)?;
Ok(SubscriptionSelect {
selection_set,
@ -185,6 +192,7 @@ fn reject_remote_joins(tree: ExecutionTree) -> Result<QueryExecutionPlan, error:
// Given a singular root field of a query, plan the execution of that root field.
fn plan_query<'n, 's, 'ir>(
ir: &'ir QueryRootField<'n, 's>,
unique_number: &mut UniqueNumber,
) -> Result<NodeQueryPlan<'n, 's, 'ir>, error::Error> {
let query_plan = match ir {
QueryRootField::TypeName { type_name } => NodeQueryPlan::TypeName {
@ -211,7 +219,8 @@ fn plan_query<'n, 's, 'ir>(
schema,
},
QueryRootField::ModelSelectOne { ir, selection_set } => {
let execution_tree = model_selection::plan_query_execution(&ir.model_selection)?;
let execution_tree =
model_selection::plan_query_execution(&ir.model_selection, unique_number)?;
NodeQueryPlan::NDCQueryExecution {
selection_set,
query_execution: NDCQueryExecution {
@ -226,7 +235,8 @@ fn plan_query<'n, 's, 'ir>(
}
QueryRootField::ModelSelectMany { ir, selection_set } => {
let execution_tree = model_selection::plan_query_execution(&ir.model_selection)?;
let execution_tree =
model_selection::plan_query_execution(&ir.model_selection, unique_number)?;
NodeQueryPlan::NDCQueryExecution {
selection_set,
query_execution: NDCQueryExecution {
@ -240,7 +250,8 @@ fn plan_query<'n, 's, 'ir>(
}
}
QueryRootField::ModelSelectAggregate { ir, selection_set } => {
let execution_tree = model_selection::plan_query_execution(&ir.model_selection)?;
let execution_tree =
model_selection::plan_query_execution(&ir.model_selection, unique_number)?;
NodeQueryPlan::NDCQueryExecution {
query_execution: NDCQueryExecution {
execution_tree,
@ -253,7 +264,8 @@ fn plan_query<'n, 's, 'ir>(
}
QueryRootField::NodeSelect(optional_ir) => match optional_ir {
Some(ir) => {
let execution_tree = model_selection::plan_query_execution(&ir.model_selection)?;
let execution_tree =
model_selection::plan_query_execution(&ir.model_selection, unique_number)?;
NodeQueryPlan::RelayNodeSelect(Some((
NDCQueryExecution {
execution_tree,
@ -267,7 +279,7 @@ fn plan_query<'n, 's, 'ir>(
None => NodeQueryPlan::RelayNodeSelect(None),
},
QueryRootField::FunctionBasedCommand { ir, selection_set } => {
let execution_tree = commands::plan_query_execution(ir)?;
let execution_tree = commands::plan_query_execution(ir, unique_number)?;
NodeQueryPlan::NDCQueryExecution {
selection_set,
@ -286,7 +298,8 @@ fn plan_query<'n, 's, 'ir>(
QueryRootField::ApolloFederation(ApolloFederationRootFields::EntitiesSelect(irs)) => {
let mut ndc_query_executions = Vec::new();
for ir in irs {
let execution_tree = model_selection::plan_query_execution(&ir.model_selection)?;
let execution_tree =
model_selection::plan_query_execution(&ir.model_selection, unique_number)?;
ndc_query_executions.push((
NDCQueryExecution {
execution_tree,

View File

@ -5,12 +5,14 @@ use std::collections::BTreeMap;
use super::error as plan_error;
use plan_types::{
Argument, MutationArgument, NdcRelationshipName, PredicateQueryTrees, Relationship,
UniqueNumber,
};
/// Generate the argument plan from IR argument
pub fn plan_argument(
ir_argument: &crate::Argument<'_>,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<(Argument, PredicateQueryTrees), plan_error::Error> {
let mut remote_predicates = PredicateQueryTrees::new();
let argument = match ir_argument {
@ -20,8 +22,12 @@ pub fn plan_argument(
})
}
crate::Argument::BooleanExpression { predicate } => {
let expression =
filter::plan_expression(predicate, relationships, &mut remote_predicates)?;
let expression = filter::plan_expression(
predicate,
relationships,
&mut remote_predicates,
unique_number,
)?;
Ok(Argument::BooleanExpression {
predicate: expression,
@ -37,6 +43,7 @@ pub fn plan_argument(
pub fn plan_mutation_argument(
ir_argument: &crate::Argument<'_>,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<MutationArgument, plan_error::Error> {
let mut remote_predicates = PredicateQueryTrees::new();
@ -47,8 +54,12 @@ pub fn plan_mutation_argument(
})
}
crate::Argument::BooleanExpression { predicate } => {
let expression =
super::filter::plan_expression(predicate, relationships, &mut remote_predicates)?;
let expression = super::filter::plan_expression(
predicate,
relationships,
&mut remote_predicates,
unique_number,
)?;
Ok(MutationArgument::BooleanExpression {
predicate: expression,
@ -62,6 +73,7 @@ pub fn plan_mutation_argument(
pub fn plan_arguments(
arguments: &BTreeMap<DataConnectorArgumentName, crate::Argument<'_>>,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<
(
BTreeMap<DataConnectorArgumentName, Argument>,
@ -73,7 +85,8 @@ pub fn plan_arguments(
let mut remote_predicates = PredicateQueryTrees::new();
for (argument_name, argument_value) in arguments {
let (argument, argument_remote_predicates) = plan_argument(argument_value, relationships)?;
let (argument, argument_remote_predicates) =
plan_argument(argument_value, relationships, unique_number)?;
remote_predicates.0.extend(argument_remote_predicates.0);
@ -86,13 +99,14 @@ pub fn plan_arguments(
pub fn plan_mutation_arguments(
arguments: &BTreeMap<DataConnectorArgumentName, crate::Argument<'_>>,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<BTreeMap<DataConnectorArgumentName, MutationArgument>, plan_error::Error> {
arguments
.iter()
.map(|(name, argument)| {
Ok((
name.clone(),
plan_mutation_argument(argument, relationships)?,
plan_mutation_argument(argument, relationships, unique_number)?,
))
})
.collect::<Result<BTreeMap<_, _>, plan_error::Error>>()

View File

@ -12,12 +12,13 @@ use open_dds::commands::ProcedureName;
use plan_types::{
Argument, ExecutionTree, Field, FieldsSelection, JoinLocations, MutationExecutionPlan,
NdcFieldAlias, NdcRelationshipName, PredicateQueryTrees, QueryExecutionPlan, QueryNodeNew,
Relationship, VariableName, FUNCTION_IR_VALUE_COLUMN_NAME,
Relationship, UniqueNumber, VariableName, FUNCTION_IR_VALUE_COLUMN_NAME,
};
pub(crate) fn plan_query_node(
ir: &CommandInfo<'_>,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<Plan<QueryNodeNew>, error::Error> {
let mut ndc_nested_field = None;
let mut join_locations = JoinLocations::new();
@ -32,6 +33,7 @@ pub(crate) fn plan_query_node(
nested_selection,
ir.data_connector.capabilities.supported_ndc_version,
relationships,
unique_number,
)?;
ndc_nested_field = Some(fields);
join_locations = nested_join_locations;
@ -63,10 +65,14 @@ pub(crate) fn plan_query_node(
pub(crate) fn plan_query_execution(
ir: &FunctionBasedCommand<'_>,
unique_number: &mut UniqueNumber,
) -> Result<ExecutionTree, error::Error> {
let mut collection_relationships = BTreeMap::new();
let (mut arguments, mut remote_predicates) =
arguments::plan_arguments(&ir.command_info.arguments, &mut collection_relationships)?;
let (mut arguments, mut remote_predicates) = arguments::plan_arguments(
&ir.command_info.arguments,
&mut collection_relationships,
unique_number,
)?;
// Add the variable arguments which are used for remote joins
for (variable_name, variable_argument) in &ir.variable_arguments {
@ -82,7 +88,11 @@ pub(crate) fn plan_query_execution(
inner: query_node,
join_locations: remote_join_executions,
remote_predicates: query_remote_predicates,
} = plan_query_node(&ir.command_info, &mut collection_relationships)?;
} = plan_query_node(
&ir.command_info,
&mut collection_relationships,
unique_number,
)?;
remote_predicates.0.extend(query_remote_predicates.0);
@ -104,6 +114,7 @@ pub(crate) fn plan_query_execution(
pub(crate) fn plan_mutation_execution(
procedure_name: &ProcedureName,
ir: &ProcedureBasedCommand<'_>,
unique_number: &mut UniqueNumber,
) -> Result<Plan<MutationExecutionPlan>, error::Error> {
let mut ndc_nested_field = None;
let mut join_locations = JoinLocations::new();
@ -122,6 +133,7 @@ pub(crate) fn plan_mutation_execution(
.capabilities
.supported_ndc_version,
&mut collection_relationships,
unique_number,
)?;
ndc_nested_field = Some(fields);
join_locations = nested_join_locations;
@ -132,6 +144,7 @@ pub(crate) fn plan_mutation_execution(
procedure_arguments: arguments::plan_mutation_arguments(
&ir.command_info.arguments,
&mut collection_relationships,
unique_number,
)?,
procedure_fields: ndc_nested_field,
collection_relationships,

View File

@ -7,7 +7,7 @@ use indexmap::IndexMap;
use plan_types::{
ExecutionTree, Field, FieldsSelection, JoinLocations, NdcFieldAlias, NdcRelationshipName,
PredicateQueryTree, PredicateQueryTrees, QueryExecutionPlan, QueryNodeNew, Relationship,
ResolvedFilterExpression,
ResolvedFilterExpression, UniqueNumber,
};
/// Plan the filter expression IR.
@ -21,6 +21,7 @@ pub(crate) fn plan_filter_expression(
relationship_join_filter,
}: &FilterExpression<'_>,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<(Option<ResolvedFilterExpression>, PredicateQueryTrees), plan_error::Error> {
let mut expressions = Vec::new();
let mut remote_predicates = PredicateQueryTrees::new();
@ -30,6 +31,7 @@ pub(crate) fn plan_filter_expression(
filter,
relationships,
&mut remote_predicates,
unique_number,
)?);
}
@ -38,6 +40,7 @@ pub(crate) fn plan_filter_expression(
filter,
relationships,
&mut remote_predicates,
unique_number,
)?);
}
@ -46,6 +49,7 @@ pub(crate) fn plan_filter_expression(
filter,
relationships,
&mut remote_predicates,
unique_number,
)?);
}
@ -54,6 +58,7 @@ pub(crate) fn plan_filter_expression(
query_where_expression,
relationships,
&mut remote_predicates,
unique_number,
)?;
expressions.push(planned_expression);
}
@ -69,6 +74,7 @@ pub fn plan_expression<'a>(
expression: &'a plan_types::Expression<'_>,
relationships: &'a mut BTreeMap<NdcRelationshipName, Relationship>,
remote_predicates: &'a mut PredicateQueryTrees,
unique_number: &mut UniqueNumber,
) -> Result<ResolvedFilterExpression, plan_error::Error> {
match expression {
plan_types::Expression::And {
@ -76,7 +82,12 @@ pub fn plan_expression<'a>(
} => {
let mut results = Vec::new();
for and_expression in and_expressions {
let result = plan_expression(and_expression, relationships, remote_predicates)?;
let result = plan_expression(
and_expression,
relationships,
remote_predicates,
unique_number,
)?;
results.push(result);
}
Ok(ResolvedFilterExpression::mk_and(results))
@ -86,7 +97,12 @@ pub fn plan_expression<'a>(
} => {
let mut results = Vec::new();
for or_expression in or_expressions {
let result = plan_expression(or_expression, relationships, remote_predicates)?;
let result = plan_expression(
or_expression,
relationships,
remote_predicates,
unique_number,
)?;
results.push(result);
}
Ok(ResolvedFilterExpression::mk_or(results))
@ -94,7 +110,12 @@ pub fn plan_expression<'a>(
plan_types::Expression::Not {
expression: not_expression,
} => {
let result = plan_expression(not_expression, relationships, remote_predicates)?;
let result = plan_expression(
not_expression,
relationships,
remote_predicates,
unique_number,
)?;
Ok(ResolvedFilterExpression::mk_not(result))
}
plan_types::Expression::LocalField(local_field_comparison) => Ok(
@ -105,7 +126,8 @@ pub fn plan_expression<'a>(
field_path,
column,
} => {
let resolved_predicate = plan_expression(predicate, relationships, remote_predicates)?;
let resolved_predicate =
plan_expression(predicate, relationships, remote_predicates, unique_number)?;
Ok(ResolvedFilterExpression::LocalNestedArray {
column: column.clone(),
field_path: field_path.clone(),
@ -117,7 +139,8 @@ pub fn plan_expression<'a>(
predicate,
info,
} => {
let relationship_filter = plan_expression(predicate, relationships, remote_predicates)?;
let relationship_filter =
plan_expression(predicate, relationships, remote_predicates, unique_number)?;
relationships.insert(
relationship.clone(),
process_model_relationship_definition(info)?,
@ -136,7 +159,7 @@ pub fn plan_expression<'a>(
predicate,
} => {
let (remote_query_node, rest_predicate_trees, collection_relationships) =
plan_remote_predicate(ndc_column_mapping, predicate)?;
plan_remote_predicate(ndc_column_mapping, predicate, unique_number)?;
let query_execution_plan: QueryExecutionPlan = QueryExecutionPlan {
query_node: remote_query_node,
@ -157,7 +180,7 @@ pub fn plan_expression<'a>(
children: rest_predicate_trees,
};
let remote_predicate_id = remote_predicates.insert(predicate_query_tree);
let remote_predicate_id = remote_predicates.insert(unique_number, predicate_query_tree);
Ok(ResolvedFilterExpression::RemoteRelationshipComparison {
remote_predicate_id,
@ -170,6 +193,7 @@ pub fn plan_expression<'a>(
pub fn plan_remote_predicate<'a>(
ndc_column_mapping: &'a [plan_types::RelationshipColumnMapping],
predicate: &'a plan_types::Expression<'_>,
unique_number: &mut UniqueNumber,
) -> Result<
(
QueryNodeNew,
@ -180,7 +204,12 @@ pub fn plan_remote_predicate<'a>(
> {
let mut relationships = BTreeMap::new();
let mut remote_predicates = PredicateQueryTrees::new();
let planned_predicate = plan_expression(predicate, &mut relationships, &mut remote_predicates)?;
let planned_predicate = plan_expression(
predicate,
&mut relationships,
&mut remote_predicates,
unique_number,
)?;
let query_node = QueryNodeNew {
limit: None,

View File

@ -9,7 +9,7 @@ use crate::plan::Plan;
use crate::ModelSelection;
use plan_types::{
ExecutionTree, FieldsSelection, JoinLocations, NdcRelationshipName, PredicateQueryTrees,
QueryExecutionPlan, QueryNodeNew, Relationship,
QueryExecutionPlan, QueryNodeNew, Relationship, UniqueNumber,
};
use std::collections::BTreeMap;
@ -18,6 +18,7 @@ use std::collections::BTreeMap;
pub(crate) fn plan_query_node(
ir: &ModelSelection<'_>,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<Plan<QueryNodeNew>, error::Error> {
let mut query_fields = None;
let mut join_locations = JoinLocations::new();
@ -31,6 +32,7 @@ pub(crate) fn plan_query_node(
selection,
ir.data_connector.capabilities.supported_ndc_version,
relationships,
unique_number,
)?;
query_fields = Some(fields);
@ -39,7 +41,7 @@ pub(crate) fn plan_query_node(
}
let (predicate, filter_remote_predicates) =
filter::plan_filter_expression(&ir.filter_clause, relationships)?;
filter::plan_filter_expression(&ir.filter_clause, relationships, unique_number)?;
remote_predicates.0.extend(filter_remote_predicates.0);
@ -60,19 +62,22 @@ pub(crate) fn plan_query_node(
}
/// Generate query execution plan from internal IR (`ModelSelection`)
pub(crate) fn plan_query_execution(ir: &ModelSelection<'_>) -> Result<ExecutionTree, error::Error> {
pub(crate) fn plan_query_execution(
ir: &ModelSelection<'_>,
unique_number: &mut UniqueNumber,
) -> Result<ExecutionTree, error::Error> {
let mut collection_relationships = BTreeMap::new();
let Plan {
inner: query,
join_locations: remote_join_executions,
mut remote_predicates,
} = plan_query_node(ir, &mut collection_relationships)?;
} = plan_query_node(ir, &mut collection_relationships, unique_number)?;
// collection relationships from order_by clause
relationships::collect_relationships_from_order_by(ir, &mut collection_relationships)?;
let (arguments, argument_remote_predicates) =
arguments::plan_arguments(&ir.arguments, &mut collection_relationships)?;
arguments::plan_arguments(&ir.arguments, &mut collection_relationships, unique_number)?;
remote_predicates.0.extend(argument_remote_predicates.0);

View File

@ -15,13 +15,14 @@ use plan_types::{
NestedField, NestedObject, PredicateQueryTrees, RemoteJoin, RemoteJoinType, SourceFieldAlias,
TargetField,
};
use plan_types::{NdcFieldAlias, NdcRelationshipName, Relationship};
use plan_types::{NdcFieldAlias, NdcRelationshipName, Relationship, UniqueNumber};
use std::collections::{BTreeMap, HashMap};
pub(crate) fn plan_nested_selection(
nested_selection: &NestedSelection<'_>,
ndc_version: NdcVersion,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<Plan<NestedField>, error::Error> {
match nested_selection {
NestedSelection::Object(model_selection) => {
@ -29,7 +30,7 @@ pub(crate) fn plan_nested_selection(
inner: fields,
join_locations,
remote_predicates,
} = plan_selection_set(model_selection, ndc_version, relationships)?;
} = plan_selection_set(model_selection, ndc_version, relationships, unique_number)?;
Ok(Plan {
inner: NestedField::Object(NestedObject { fields }),
join_locations,
@ -41,7 +42,7 @@ pub(crate) fn plan_nested_selection(
inner: field,
join_locations,
remote_predicates,
} = plan_nested_selection(nested_selection, ndc_version, relationships)?;
} = plan_nested_selection(nested_selection, ndc_version, relationships, unique_number)?;
Ok(Plan {
inner: NestedField::Array(NestedArray {
fields: Box::new(field),
@ -62,6 +63,7 @@ pub(crate) fn plan_selection_set(
model_selection: &ResultSelectionSet<'_>,
ndc_version: NdcVersion,
relationships: &mut BTreeMap<NdcRelationshipName, Relationship>,
unique_number: &mut UniqueNumber,
) -> Result<Plan<IndexMap<NdcFieldAlias, Field>>, error::Error> {
let mut fields = IndexMap::<NdcFieldAlias, Field>::new();
let mut join_locations = JoinLocations::new();
@ -80,7 +82,12 @@ pub(crate) fn plan_selection_set(
inner: nested_fields,
join_locations: jl,
remote_predicates: nested_remote_predicates,
} = plan_nested_selection(nested_selection, ndc_version, relationships)?;
} = plan_nested_selection(
nested_selection,
ndc_version,
relationships,
unique_number,
)?;
remote_predicates.0.extend(nested_remote_predicates.0);
@ -88,7 +95,7 @@ pub(crate) fn plan_selection_set(
nested_join_locations = jl;
}
let (arguments, argument_remote_predicates) =
arguments::plan_arguments(arguments, relationships)?;
arguments::plan_arguments(arguments, relationships, unique_number)?;
remote_predicates.0.extend(argument_remote_predicates.0);
@ -124,7 +131,7 @@ pub(crate) fn plan_selection_set(
inner: relationship_query,
join_locations: jl,
remote_predicates: relationship_remote_predicates,
} = model_selection::plan_query_node(query, relationships)?;
} = model_selection::plan_query_node(query, relationships, unique_number)?;
remote_predicates.0.extend(relationship_remote_predicates.0);
@ -158,12 +165,16 @@ pub(crate) fn plan_selection_set(
inner: relationship_query,
join_locations: jl,
remote_predicates: command_remote_predicates,
} = commands::plan_query_node(&ir.command_info, relationships)?;
} = commands::plan_query_node(&ir.command_info, relationships, unique_number)?;
remote_predicates.0.extend(command_remote_predicates.0);
let (relationship_arguments, argument_remote_predicates) =
arguments::plan_arguments(&ir.command_info.arguments, relationships)?;
arguments::plan_arguments(
&ir.command_info.arguments,
relationships,
unique_number,
)?;
remote_predicates.0.extend(argument_remote_predicates.0);
@ -209,7 +220,7 @@ pub(crate) fn plan_selection_set(
query_execution_plan: query_execution,
remote_join_executions: sub_join_locations,
remote_predicates: model_remote_predicates,
} = model_selection::plan_query_execution(ir)?;
} = model_selection::plan_query_execution(ir, unique_number)?;
// push any remote predicates to the outer list
remote_predicates.0.extend(model_remote_predicates.0);
@ -255,7 +266,7 @@ pub(crate) fn plan_selection_set(
query_execution_plan: ndc_ir,
remote_join_executions: sub_join_locations,
remote_predicates: command_remote_predicates,
} = commands::plan_query_execution(ir)?;
} = commands::plan_query_execution(ir, unique_number)?;
remote_predicates.0.extend(command_remote_predicates.0);

View File

@ -20,7 +20,6 @@ schemars = { workspace = true }
serde = { workspace = true }
serde_json = { workspace = true }
smol_str = { workspace = true }
uuid = { workspace = true }
[lints]
workspace = true

View File

@ -19,6 +19,7 @@ pub use mutation::MutationExecutionPlan;
pub use order_by::{OrderByDirection, OrderByElement, OrderByTarget};
pub use query::{
FieldsSelection, PredicateQueryTree, PredicateQueryTrees, QueryExecutionPlan, QueryNodeNew,
RemotePredicateKey, UniqueNumber,
};
pub use relationships::{Relationship, RelationshipArgument};
pub use remote_joins::{

View File

@ -1,6 +1,5 @@
use crate::{LocalFieldComparison, NdcRelationshipName};
use crate::{LocalFieldComparison, NdcRelationshipName, RemotePredicateKey};
use open_dds::data_connector::DataConnectorColumnName;
use uuid::Uuid;
/// Filter expression plan to be resolved
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@ -25,7 +24,7 @@ pub enum ResolvedFilterExpression {
predicate: Box<ResolvedFilterExpression>,
},
RemoteRelationshipComparison {
remote_predicate_id: Uuid,
remote_predicate_id: RemotePredicateKey,
},
}

View File

@ -5,7 +5,6 @@ use indexmap::IndexMap;
use open_dds::{data_connector::CollectionName, types::DataConnectorArgumentName};
use std::collections::BTreeMap;
use std::sync::Arc;
use uuid::Uuid;
#[derive(Debug, Clone, PartialEq)]
// this represents an execution plan. all predicates only refer to local comparisons.
@ -34,14 +33,18 @@ pub struct PredicateQueryTree {
}
#[derive(Debug, Clone, PartialEq)]
pub struct PredicateQueryTrees(pub BTreeMap<Uuid, PredicateQueryTree>);
pub struct PredicateQueryTrees(pub BTreeMap<RemotePredicateKey, PredicateQueryTree>);
impl PredicateQueryTrees {
pub fn new() -> Self {
Self(BTreeMap::new())
}
pub fn insert(&mut self, value: PredicateQueryTree) -> Uuid {
let key = Uuid::new_v4();
pub fn insert(
&mut self,
unique_number: &mut UniqueNumber,
value: PredicateQueryTree,
) -> RemotePredicateKey {
let key = RemotePredicateKey(unique_number.fresh());
self.0.insert(key, value);
key
}
@ -53,6 +56,32 @@ impl Default for PredicateQueryTrees {
}
}
#[derive(Debug, PartialEq, Eq, PartialOrd, derive_more::Display, Ord, Hash, Clone, Copy)]
pub struct RemotePredicateKey(pub u64);
// we need to generate unique identifiers for remote predicates
// in a reproducable fashion so we thread this around
pub struct UniqueNumber(u64);
impl UniqueNumber {
pub fn new() -> Self {
UniqueNumber(1)
}
// get the next number, increment internal value
pub fn fresh(&mut self) -> u64 {
let value = self.0;
self.0 += 1;
value
}
}
impl Default for UniqueNumber {
fn default() -> Self {
Self::new()
}
}
/// Query plan for fetching data
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct QueryNodeNew {

View File

@ -14,7 +14,7 @@ pub use execution_plan::{
NestedArray, NestedField, NestedObject, OrderByDirection, OrderByElement, OrderByTarget,
PredicateQueryTree, PredicateQueryTrees, ProcessResponseAs, QueryExecutionPlan, QueryNodeNew,
Relationship, RelationshipArgument, RemoteJoin, RemoteJoinArgument, RemoteJoinType,
ResolvedFilterExpression, SourceFieldAlias, TargetField,
RemotePredicateKey, ResolvedFilterExpression, SourceFieldAlias, TargetField, UniqueNumber,
};
pub use expression::{
ComparisonTarget, ComparisonValue, Expression, LocalFieldComparison, RelationshipColumnMapping,