use indexmap::IndexMap;
use dibs_sql::{ColumnName, TableName};
#[derive(Debug, Clone)]
pub struct QueryPlan {
pub from_table: TableName,
pub from_alias: String,
pub joins: Vec<JoinClause>,
pub select_columns: Vec<SelectColumn>,
pub count_subqueries: Vec<CountSubquery>,
pub result_mapping: ResultMapping,
alias_counter: usize,
}
impl QueryPlan {
pub fn new(from_table: TableName) -> Self {
Self {
from_table,
from_alias: "t0".to_string(),
joins: Vec::new(),
select_columns: Vec::new(),
count_subqueries: Vec::new(),
result_mapping: ResultMapping::default(),
alias_counter: 1, }
}
pub fn next_alias(&mut self) -> String {
let alias = format!("t{}", self.alias_counter);
self.alias_counter += 1;
alias
}
pub fn add_column(
&mut self,
table_alias: &str,
column: &ColumnName,
result_alias: ColumnName,
path: Vec<ColumnName>,
) {
self.select_columns.push(SelectColumn {
table_alias: table_alias.to_string(),
column: column.clone(),
result_alias: result_alias.clone(),
});
self.result_mapping.columns.insert(result_alias, path);
}
pub fn add_join(&mut self, join: JoinClause) -> String {
let alias = join.alias.clone();
self.joins.push(join);
alias
}
pub fn add_count(&mut self, subquery: CountSubquery, path: Vec<ColumnName>) {
let alias = subquery.result_alias.clone();
self.count_subqueries.push(subquery);
self.result_mapping.columns.insert(alias, path);
}
pub fn add_relation(&mut self, name: ColumnName, mapping: RelationMapping) {
self.result_mapping.relations.insert(name, mapping);
}
}
#[derive(Debug, Clone)]
pub struct JoinClause {
pub join_type: JoinType,
pub table: TableName,
pub alias: String,
pub on_condition: (String, String),
pub extra_conditions: Vec<JoinCondition>,
pub first: bool,
pub select_columns: Vec<ColumnName>,
}
#[derive(Debug, Clone)]
pub struct JoinCondition {
pub column: ColumnName,
pub value: JoinConditionValue,
}
#[derive(Debug, Clone)]
pub enum JoinConditionValue {
Literal(String),
Param(dibs_sql::ParamName),
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum JoinType {
Left,
Inner,
}
#[derive(Debug, Clone)]
pub struct SelectColumn {
pub table_alias: String,
pub column: ColumnName,
pub result_alias: ColumnName,
}
#[derive(Debug, Clone)]
pub struct CountSubquery {
pub result_alias: ColumnName,
pub count_table: TableName,
pub fk_column: ColumnName,
pub parent_alias: String,
pub parent_key: ColumnName,
}
#[derive(Debug, Clone, Default)]
pub struct ResultMapping {
pub columns: IndexMap<ColumnName, Vec<ColumnName>>,
pub relations: IndexMap<ColumnName, RelationMapping>,
}
#[derive(Debug, Clone)]
pub struct RelationMapping {
pub name: ColumnName,
pub first: bool,
pub columns: IndexMap<ColumnName, ColumnName>,
pub parent_key_column: Option<ColumnName>,
pub table_alias: String,
pub nested_relations: IndexMap<ColumnName, RelationMapping>,
}
#[derive(Debug)]
pub enum PlanError {
TableNotFound { table: String },
NoForeignKey { from: String, to: String },
#[allow(dead_code)]
RelationNeedsFrom { relation: String },
}
#[derive(Debug, Clone, Copy, PartialEq)]
pub enum FkDirection {
Forward,
Reverse,
}
#[derive(Debug, Clone)]
pub struct FkResolution {
pub join_clause: JoinClause,
pub _direction: FkDirection,
pub parent_key_column: ColumnName,
}