Skip to content

Commit

Permalink
implement relationships
Browse files Browse the repository at this point in the history
  • Loading branch information
Gil Mizrahi committed Jan 26, 2024
1 parent 7274787 commit 9f0dad7
Show file tree
Hide file tree
Showing 3 changed files with 92 additions and 41 deletions.
101 changes: 67 additions & 34 deletions crates/query-engine/translation/src/translation/mutation/delete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,9 @@ use crate::translation::query::values::translate_json_value;
use ndc_sdk::models;
use query_engine_metadata::metadata;
use query_engine_metadata::metadata::database;
use query_engine_sql::sql;
use query_engine_sql::sql::ast;
use std::collections::BTreeMap;
use std::collections::{BTreeMap, VecDeque};

/// A representation of an auto-generated delete mutation.
///
Expand Down Expand Up @@ -84,31 +85,50 @@ pub fn translate_delete(
by_column,
..
} => {
let predicate_json = arguments
.get("%predicate")
.ok_or(Error::ArgumentNotFound("%predicate".to_string()))?;
// The root table we are going to be deleting from.
let table = ast::TableReference::DBTable {
schema: schema_name.clone(),
table: table_name.clone(),
};

let table_alias = state.make_table_alias(table_name.0.clone());

let table_name_and_reference = TableNameAndReference {
name: collection_name.clone(),
reference: ast::TableReference::AliasedTable(table_alias.clone()),
};

let from = ast::From::Table {
reference: table,
alias: table_alias.clone(),
};

// Build the `UNIQUE_KEY = <value>` boolean expression.
let unique_key = arguments
.get(&by_column.name)
.ok_or(Error::ArgumentNotFound(by_column.name.clone()))?;

let key_value = translate_json_value(state, unique_key, &by_column.r#type).unwrap();

let table = ast::TableReference::DBTable {
schema: schema_name.clone(),
table: table_name.clone(),
let unique_expression = ast::Expression::BinaryOperation {
left: Box::new(ast::Expression::ColumnReference(
ast::ColumnReference::TableColumn {
table: ast::TableReference::AliasedTable(table_alias),
name: ast::ColumnName(by_column.name.clone()),
},
)),
right: Box::new(key_value),
operator: ast::BinaryOperator("=".to_string()),
};

let table_alias = state.make_table_alias(table_name.0.clone());
// Build the `%predicate` argument boolean expression.
let predicate_json = arguments
.get("%predicate")
.ok_or(Error::ArgumentNotFound("%predicate".to_string()))?;

let predicate: models::Expression = serde_json::from_value(predicate_json.clone())
.map_err(|_| Error::ArgumentNotFound("%predicate".to_string()))?;

let table_name_and_reference = TableNameAndReference {
name: collection_name.clone(),
reference: ast::TableReference::AliasedTable(table_alias.clone()),
};

let (predicate_expression, joins) = filtering::translate_expression(
env,
state,
Expand All @@ -119,30 +139,43 @@ pub fn translate_delete(
&predicate,
)?;

let where_expr = ast::Expression::BinaryOperation {
left: Box::new(ast::Expression::ColumnReference(
ast::ColumnReference::TableColumn {
table: ast::TableReference::AliasedTable(table_alias.clone()),
name: ast::ColumnName(by_column.name.clone()),
},
)),
right: Box::new(key_value),
operator: ast::BinaryOperator("=".to_string()),
};
// We build the where clause depending on whether joins are involved in the predicate or not.
let mut joins = VecDeque::from(joins);
let first = joins.pop_front();

let from = ast::From::Table {
reference: table,
alias: table_alias,
};

let where_ = if joins.is_empty() {
ast::Expression::And {
left: Box::new(where_expr),
let where_ = match first {
// If no joins are involved, we just AND the unique expression and the predicate expression.
None => Ok(ast::Expression::And {
left: Box::new(unique_expression),
right: Box::new(predicate_expression),
}),
// If joins are involved, we wrap them in an EXISTS expression over selecting the first
// table in the joins list, joining with the rest of them.
Some(first) => {
let mut select = match first {
ast::Join::LeftOuterJoinLateral(join) => *join.select,
ast::Join::InnerJoinLateral(join) => *join.select,
ast::Join::CrossJoinLateral(join) => *join.select,
ast::Join::CrossJoin(join) => *join.select,
};

select.joins = Vec::from(joins);

// AND between the join key, the unique expression, and the predicate expression.
select.where_ = sql::ast::Where(sql::ast::Expression::And {
left: Box::new(select.where_.0),
right: Box::new(ast::Expression::And {
left: Box::new(unique_expression),
right: Box::new(predicate_expression),
}),
});

// Wrap in EXISTS.
Ok(sql::ast::Expression::Exists {
select: Box::new(select),
})
}
} else {
todo!()
};
}?;

Ok(ast::Delete {
from,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
mod aggregates;
pub mod filtering;
pub mod native_queries;
mod relationships;
pub mod relationships;
pub mod root;
mod sorting;
pub mod values;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,30 @@
"type": "procedure",
"name": "v1_delete_InvoiceLine_by_InvoiceLineId",
"arguments": {
"InvoiceLineId": 91,
"InvoiceLineId": 90,
"%predicate": {
"type": "binary_comparison_operator",
"column": {
"type": "column",
"name": "InvoiceLineId",
"path": []
"name": "TrackId",
"path": [
{
"relationship": "InvoiceLineTrack",
"arguments": {},
"predicate": {
"type": "and",
"expressions": []
}
}
]
},
"operator": {
"type": "other",
"name": "_gt"
"name": "_eq"
},
"value": {
"type": "scalar",
"value": 340
"value": 512
}
}
},
Expand All @@ -34,5 +43,14 @@
}
}
],
"collection_relationships": {}
"collection_relationships": {
"InvoiceLineTrack": {
"column_mapping": {
"TrackId": "TrackId"
},
"relationship_type": "object",
"target_collection": "Track",
"arguments": {}
}
}
}

0 comments on commit 9f0dad7

Please sign in to comment.