use crate::db::{
GroupedRow, QueryError,
sql::lowering::{
LoweredSqlCommand, LoweredSqlLaneKind, PreparedSqlStatement as CorePreparedSqlStatement,
lower_sql_command_from_prepared_statement, lowered_sql_command_lane, prepare_sql_statement,
},
sql::parser::{SqlExplainTarget, SqlStatement},
};
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum SqlStatementRoute {
Query { entity: String },
Explain { entity: String },
Describe { entity: String },
ShowIndexes { entity: String },
ShowColumns { entity: String },
ShowEntities,
}
#[derive(Debug)]
pub enum SqlDispatchResult {
Projection {
columns: Vec<String>,
rows: Vec<Vec<crate::value::Value>>,
row_count: u32,
},
ProjectionText {
columns: Vec<String>,
rows: Vec<Vec<String>>,
row_count: u32,
},
Grouped {
columns: Vec<String>,
rows: Vec<GroupedRow>,
row_count: u32,
next_cursor: Option<String>,
},
Explain(String),
Describe(crate::db::EntitySchemaDescription),
ShowIndexes(Vec<String>),
ShowColumns(Vec<crate::db::EntityFieldDescription>),
ShowEntities(Vec<String>),
}
#[derive(Clone, Debug)]
pub struct SqlParsedStatement {
pub(in crate::db::session::sql) statement: SqlStatement,
route: SqlStatementRoute,
}
impl SqlParsedStatement {
pub(in crate::db::session::sql) const fn new(
statement: SqlStatement,
route: SqlStatementRoute,
) -> Self {
Self { statement, route }
}
#[must_use]
pub const fn route(&self) -> &SqlStatementRoute {
&self.route
}
pub(in crate::db::session::sql) fn prepare(
&self,
expected_entity: &'static str,
) -> Result<CorePreparedSqlStatement, QueryError> {
prepare_sql_statement(self.statement.clone(), expected_entity)
.map_err(QueryError::from_sql_lowering_error)
}
#[inline(never)]
pub fn lower_query_lane_for_entity(
&self,
expected_entity: &'static str,
primary_key_field: &str,
) -> Result<LoweredSqlCommand, QueryError> {
let lowered = lower_sql_command_from_prepared_statement(
self.prepare(expected_entity)?,
primary_key_field,
)
.map_err(QueryError::from_sql_lowering_error)?;
let lane = lowered_sql_command_lane(&lowered);
match lane {
LoweredSqlLaneKind::Query | LoweredSqlLaneKind::Explain => Ok(lowered),
LoweredSqlLaneKind::Describe
| LoweredSqlLaneKind::ShowIndexes
| LoweredSqlLaneKind::ShowColumns
| LoweredSqlLaneKind::ShowEntities => {
Err(QueryError::unsupported_query_lane_dispatch())
}
}
}
}
impl SqlStatementRoute {
#[must_use]
pub const fn entity(&self) -> &str {
match self {
Self::Query { entity }
| Self::Explain { entity }
| Self::Describe { entity }
| Self::ShowIndexes { entity }
| Self::ShowColumns { entity } => entity.as_str(),
Self::ShowEntities => "",
}
}
#[must_use]
pub const fn is_explain(&self) -> bool {
matches!(self, Self::Explain { .. })
}
#[must_use]
pub const fn is_describe(&self) -> bool {
matches!(self, Self::Describe { .. })
}
#[must_use]
pub const fn is_show_indexes(&self) -> bool {
matches!(self, Self::ShowIndexes { .. })
}
#[must_use]
pub const fn is_show_columns(&self) -> bool {
matches!(self, Self::ShowColumns { .. })
}
#[must_use]
pub const fn is_show_entities(&self) -> bool {
matches!(self, Self::ShowEntities)
}
}
pub(in crate::db::session::sql) fn sql_statement_route_from_statement(
statement: &SqlStatement,
) -> SqlStatementRoute {
match statement {
SqlStatement::Select(select) => SqlStatementRoute::Query {
entity: select.entity.clone(),
},
SqlStatement::Delete(delete) => SqlStatementRoute::Query {
entity: delete.entity.clone(),
},
SqlStatement::Explain(explain) => match &explain.statement {
SqlExplainTarget::Select(select) => SqlStatementRoute::Explain {
entity: select.entity.clone(),
},
SqlExplainTarget::Delete(delete) => SqlStatementRoute::Explain {
entity: delete.entity.clone(),
},
},
SqlStatement::Describe(describe) => SqlStatementRoute::Describe {
entity: describe.entity.clone(),
},
SqlStatement::ShowIndexes(show_indexes) => SqlStatementRoute::ShowIndexes {
entity: show_indexes.entity.clone(),
},
SqlStatement::ShowColumns(show_columns) => SqlStatementRoute::ShowColumns {
entity: show_columns.entity.clone(),
},
SqlStatement::ShowEntities(_) => SqlStatementRoute::ShowEntities,
}
}