mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-19 15:05:47 +01:00
refactor sql_generation/model/query
This commit is contained in:
@@ -982,6 +982,41 @@ impl std::fmt::Display for QualifiedName {
|
||||
}
|
||||
}
|
||||
|
||||
impl QualifiedName {
|
||||
/// Constructor
|
||||
pub fn single(name: Name) -> Self {
|
||||
Self {
|
||||
db_name: None,
|
||||
name,
|
||||
alias: None,
|
||||
}
|
||||
}
|
||||
/// Constructor
|
||||
pub fn fullname(db_name: Name, name: Name) -> Self {
|
||||
Self {
|
||||
db_name: Some(db_name),
|
||||
name,
|
||||
alias: None,
|
||||
}
|
||||
}
|
||||
/// Constructor
|
||||
pub fn xfullname(db_name: Name, name: Name, alias: Name) -> Self {
|
||||
Self {
|
||||
db_name: Some(db_name),
|
||||
name,
|
||||
alias: Some(alias),
|
||||
}
|
||||
}
|
||||
/// Constructor
|
||||
pub fn alias(name: Name, alias: Name) -> Self {
|
||||
Self {
|
||||
db_name: None,
|
||||
name,
|
||||
alias: Some(alias),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `ALTER TABLE` body
|
||||
// https://sqlite.org/lang_altertable.html
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
|
||||
@@ -2,33 +2,13 @@ use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{
|
||||
generation::Shadow,
|
||||
model::table::{SimValue, Table},
|
||||
runner::env::SimulatorTables,
|
||||
};
|
||||
use crate::model::table::Table;
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub(crate) struct Create {
|
||||
pub(crate) table: Table,
|
||||
}
|
||||
|
||||
impl Shadow for Create {
|
||||
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
|
||||
|
||||
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
|
||||
if !tables.iter().any(|t| t.name == self.table.name) {
|
||||
tables.push(self.table.clone());
|
||||
Ok(vec![])
|
||||
} else {
|
||||
Err(anyhow::anyhow!(
|
||||
"Table {} already exists. CREATE TABLE statement ignored.",
|
||||
self.table.name
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Create {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "CREATE TABLE {} (", self.table.name)?;
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
use crate::{
|
||||
generation::{gen_random_text, pick, pick_n_unique, ArbitraryFrom, Shadow},
|
||||
model::table::SimValue,
|
||||
runner::env::{SimulatorEnv, SimulatorTables},
|
||||
};
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, Hash)]
|
||||
@@ -28,19 +22,6 @@ pub(crate) struct CreateIndex {
|
||||
pub(crate) columns: Vec<(String, SortOrder)>,
|
||||
}
|
||||
|
||||
impl Shadow for CreateIndex {
|
||||
type Result = Vec<Vec<SimValue>>;
|
||||
fn shadow(&self, env: &mut SimulatorTables) -> Vec<Vec<SimValue>> {
|
||||
env.tables
|
||||
.iter_mut()
|
||||
.find(|t| t.name == self.table_name)
|
||||
.unwrap()
|
||||
.indexes
|
||||
.push(self.index_name.clone());
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl std::fmt::Display for CreateIndex {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(
|
||||
@@ -56,51 +37,3 @@ impl std::fmt::Display for CreateIndex {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<&SimulatorEnv> for CreateIndex {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, env: &SimulatorEnv) -> Self {
|
||||
assert!(
|
||||
!env.tables.is_empty(),
|
||||
"Cannot create an index when no tables exist in the environment."
|
||||
);
|
||||
|
||||
let table = pick(&env.tables, rng);
|
||||
|
||||
if table.columns.is_empty() {
|
||||
panic!(
|
||||
"Cannot create an index on table '{}' as it has no columns.",
|
||||
table.name
|
||||
);
|
||||
}
|
||||
|
||||
let num_columns_to_pick = rng.random_range(1..=table.columns.len());
|
||||
let picked_column_indices = pick_n_unique(0..table.columns.len(), num_columns_to_pick, rng);
|
||||
|
||||
let columns = picked_column_indices
|
||||
.into_iter()
|
||||
.map(|i| {
|
||||
let column = &table.columns[i];
|
||||
(
|
||||
column.name.clone(),
|
||||
if rng.random_bool(0.5) {
|
||||
SortOrder::Asc
|
||||
} else {
|
||||
SortOrder::Desc
|
||||
},
|
||||
)
|
||||
})
|
||||
.collect::<Vec<(String, SortOrder)>>();
|
||||
|
||||
let index_name = format!(
|
||||
"idx_{}_{}",
|
||||
table.name,
|
||||
gen_random_text(rng).chars().take(8).collect::<String>()
|
||||
);
|
||||
|
||||
CreateIndex {
|
||||
index_name,
|
||||
table_name: table.name.clone(),
|
||||
columns,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,8 +2,6 @@ use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{generation::Shadow, model::table::SimValue, runner::env::SimulatorTables};
|
||||
|
||||
use super::predicate::Predicate;
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
@@ -12,28 +10,6 @@ pub(crate) struct Delete {
|
||||
pub(crate) predicate: Predicate,
|
||||
}
|
||||
|
||||
impl Shadow for Delete {
|
||||
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
|
||||
|
||||
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
|
||||
let table = tables.tables.iter_mut().find(|t| t.name == self.table);
|
||||
|
||||
if let Some(table) = table {
|
||||
// If the table exists, we can delete from it
|
||||
let t2 = table.clone();
|
||||
table.rows.retain_mut(|r| !self.predicate.test(r, &t2));
|
||||
} else {
|
||||
// If the table does not exist, we return an error
|
||||
return Err(anyhow::anyhow!(
|
||||
"Table {} does not exist. DELETE statement ignored.",
|
||||
self.table
|
||||
));
|
||||
}
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Delete {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "DELETE FROM {} WHERE {}", self.table, self.predicate)
|
||||
|
||||
@@ -2,31 +2,11 @@ use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{generation::Shadow, model::table::SimValue, runner::env::SimulatorTables};
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||
pub(crate) struct Drop {
|
||||
pub(crate) table: String,
|
||||
}
|
||||
|
||||
impl Shadow for Drop {
|
||||
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
|
||||
|
||||
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
|
||||
if !tables.iter().any(|t| t.name == self.table) {
|
||||
// If the table does not exist, we return an error
|
||||
return Err(anyhow::anyhow!(
|
||||
"Table {} does not exist. DROP statement ignored.",
|
||||
self.table
|
||||
));
|
||||
}
|
||||
|
||||
tables.tables.retain(|t| t.name != self.table);
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Drop {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "DROP TABLE {}", self.table)
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{generation::Shadow, model::table::SimValue, runner::env::SimulatorTables};
|
||||
use crate::model::table::SimValue;
|
||||
|
||||
use super::select::Select;
|
||||
|
||||
@@ -18,38 +18,6 @@ pub(crate) enum Insert {
|
||||
},
|
||||
}
|
||||
|
||||
impl Shadow for Insert {
|
||||
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
|
||||
|
||||
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
|
||||
match self {
|
||||
Insert::Values { table, values } => {
|
||||
if let Some(t) = tables.tables.iter_mut().find(|t| &t.name == table) {
|
||||
t.rows.extend(values.clone());
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Table {} does not exist. INSERT statement ignored.",
|
||||
table
|
||||
));
|
||||
}
|
||||
}
|
||||
Insert::Select { table, select } => {
|
||||
let rows = select.shadow(tables)?;
|
||||
if let Some(t) = tables.tables.iter_mut().find(|t| &t.name == table) {
|
||||
t.rows.extend(rows);
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Table {} does not exist. INSERT statement ignored.",
|
||||
table
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl Insert {
|
||||
pub(crate) fn table(&self) -> &str {
|
||||
match self {
|
||||
|
||||
@@ -10,14 +10,7 @@ use serde::{Deserialize, Serialize};
|
||||
use turso_parser::ast::fmt::ToSqlContext;
|
||||
use update::Update;
|
||||
|
||||
use crate::{
|
||||
generation::Shadow,
|
||||
model::{
|
||||
query::transaction::{Begin, Commit, Rollback},
|
||||
table::SimValue,
|
||||
},
|
||||
runner::env::SimulatorTables,
|
||||
};
|
||||
use crate::model::query::transaction::{Begin, Commit, Rollback};
|
||||
|
||||
pub mod create;
|
||||
pub mod create_index;
|
||||
@@ -75,25 +68,6 @@ impl Query {
|
||||
}
|
||||
}
|
||||
|
||||
impl Shadow for Query {
|
||||
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
|
||||
|
||||
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
|
||||
match self {
|
||||
Query::Create(create) => create.shadow(env),
|
||||
Query::Insert(insert) => insert.shadow(env),
|
||||
Query::Delete(delete) => delete.shadow(env),
|
||||
Query::Select(select) => select.shadow(env),
|
||||
Query::Update(update) => update.shadow(env),
|
||||
Query::Drop(drop) => drop.shadow(env),
|
||||
Query::CreateIndex(create_index) => Ok(create_index.shadow(env)),
|
||||
Query::Begin(begin) => Ok(begin.shadow(env)),
|
||||
Query::Commit(commit) => Ok(commit.shadow(env)),
|
||||
Query::Rollback(rollback) => Ok(rollback.shadow(env)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Query {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
|
||||
@@ -1,18 +1,12 @@
|
||||
use std::{collections::HashSet, fmt::Display};
|
||||
|
||||
use anyhow::Context;
|
||||
pub use ast::Distinctness;
|
||||
use itertools::Itertools;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use turso_parser::ast::{self, fmt::ToTokens, SortOrder};
|
||||
|
||||
use crate::{
|
||||
generation::Shadow,
|
||||
model::{
|
||||
query::EmptyContext,
|
||||
table::{JoinTable, JoinType, JoinedTable, SimValue, Table, TableContext},
|
||||
},
|
||||
runner::env::SimulatorTables,
|
||||
use crate::model::{
|
||||
query::EmptyContext,
|
||||
table::{JoinType, JoinedTable},
|
||||
};
|
||||
|
||||
use super::predicate::Predicate;
|
||||
@@ -188,45 +182,30 @@ pub struct FromClause {
|
||||
impl FromClause {
|
||||
fn to_sql_ast(&self) -> ast::FromClause {
|
||||
ast::FromClause {
|
||||
select: Some(Box::new(ast::SelectTable::Table(
|
||||
ast::QualifiedName::single(ast::Name::from_str(&self.table)),
|
||||
select: Box::new(ast::SelectTable::Table(
|
||||
ast::QualifiedName::single(ast::Name::new(&self.table)),
|
||||
None,
|
||||
None,
|
||||
))),
|
||||
joins: if self.joins.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(
|
||||
self.joins
|
||||
.iter()
|
||||
.map(|join| ast::JoinedSelectTable {
|
||||
operator: match join.join_type {
|
||||
JoinType::Inner => {
|
||||
ast::JoinOperator::TypedJoin(Some(ast::JoinType::INNER))
|
||||
}
|
||||
JoinType::Left => {
|
||||
ast::JoinOperator::TypedJoin(Some(ast::JoinType::LEFT))
|
||||
}
|
||||
JoinType::Right => {
|
||||
ast::JoinOperator::TypedJoin(Some(ast::JoinType::RIGHT))
|
||||
}
|
||||
JoinType::Full => {
|
||||
ast::JoinOperator::TypedJoin(Some(ast::JoinType::OUTER))
|
||||
}
|
||||
JoinType::Cross => {
|
||||
ast::JoinOperator::TypedJoin(Some(ast::JoinType::CROSS))
|
||||
}
|
||||
},
|
||||
table: ast::SelectTable::Table(
|
||||
ast::QualifiedName::single(ast::Name::from_str(&join.table)),
|
||||
None,
|
||||
None,
|
||||
),
|
||||
constraint: Some(ast::JoinConstraint::On(join.on.0.clone())),
|
||||
})
|
||||
.collect(),
|
||||
)
|
||||
},
|
||||
)),
|
||||
joins: self
|
||||
.joins
|
||||
.iter()
|
||||
.map(|join| ast::JoinedSelectTable {
|
||||
operator: match join.join_type {
|
||||
JoinType::Inner => ast::JoinOperator::TypedJoin(Some(ast::JoinType::INNER)),
|
||||
JoinType::Left => ast::JoinOperator::TypedJoin(Some(ast::JoinType::LEFT)),
|
||||
JoinType::Right => ast::JoinOperator::TypedJoin(Some(ast::JoinType::RIGHT)),
|
||||
JoinType::Full => ast::JoinOperator::TypedJoin(Some(ast::JoinType::OUTER)),
|
||||
JoinType::Cross => ast::JoinOperator::TypedJoin(Some(ast::JoinType::CROSS)),
|
||||
},
|
||||
table: Box::new(ast::SelectTable::Table(
|
||||
ast::QualifiedName::single(ast::Name::new(&join.table)),
|
||||
None,
|
||||
None,
|
||||
)),
|
||||
constraint: Some(ast::JoinConstraint::On(Box::new(join.on.0.clone()))),
|
||||
})
|
||||
.collect(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -239,166 +218,12 @@ impl FromClause {
|
||||
}
|
||||
}
|
||||
|
||||
impl Shadow for FromClause {
|
||||
type Result = anyhow::Result<JoinTable>;
|
||||
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
|
||||
let tables = &mut env.tables;
|
||||
|
||||
let first_table = tables
|
||||
.iter()
|
||||
.find(|t| t.name == self.table)
|
||||
.context("Table not found")?;
|
||||
|
||||
let mut join_table = JoinTable {
|
||||
tables: vec![first_table.clone()],
|
||||
rows: Vec::new(),
|
||||
};
|
||||
|
||||
for join in &self.joins {
|
||||
let joined_table = tables
|
||||
.iter()
|
||||
.find(|t| t.name == join.table)
|
||||
.context("Joined table not found")?;
|
||||
|
||||
join_table.tables.push(joined_table.clone());
|
||||
|
||||
match join.join_type {
|
||||
JoinType::Inner => {
|
||||
// Implement inner join logic
|
||||
let join_rows = joined_table
|
||||
.rows
|
||||
.iter()
|
||||
.filter(|row| join.on.test(row, joined_table))
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
// take a cartesian product of the rows
|
||||
let all_row_pairs = join_table
|
||||
.rows
|
||||
.clone()
|
||||
.into_iter()
|
||||
.cartesian_product(join_rows.iter());
|
||||
|
||||
for (row1, row2) in all_row_pairs {
|
||||
let row = row1.iter().chain(row2.iter()).cloned().collect::<Vec<_>>();
|
||||
|
||||
let is_in = join.on.test(&row, &join_table);
|
||||
|
||||
if is_in {
|
||||
join_table.rows.push(row);
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
Ok(join_table)
|
||||
}
|
||||
}
|
||||
|
||||
impl Shadow for SelectInner {
|
||||
type Result = anyhow::Result<JoinTable>;
|
||||
|
||||
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
|
||||
if let Some(from) = &self.from {
|
||||
let mut join_table = from.shadow(env)?;
|
||||
let col_count = join_table.columns().count();
|
||||
for row in &mut join_table.rows {
|
||||
assert_eq!(
|
||||
row.len(),
|
||||
col_count,
|
||||
"Row length does not match column length after join"
|
||||
);
|
||||
}
|
||||
let join_clone = join_table.clone();
|
||||
|
||||
join_table
|
||||
.rows
|
||||
.retain(|row| self.where_clause.test(row, &join_clone));
|
||||
|
||||
if self.distinctness == Distinctness::Distinct {
|
||||
join_table.rows.sort_unstable();
|
||||
join_table.rows.dedup();
|
||||
}
|
||||
|
||||
Ok(join_table)
|
||||
} else {
|
||||
assert!(self
|
||||
.columns
|
||||
.iter()
|
||||
.all(|col| matches!(col, ResultColumn::Expr(_))));
|
||||
|
||||
// If `WHERE` is false, just return an empty table
|
||||
if !self.where_clause.test(&[], &Table::anonymous(vec![])) {
|
||||
return Ok(JoinTable {
|
||||
tables: Vec::new(),
|
||||
rows: Vec::new(),
|
||||
});
|
||||
}
|
||||
|
||||
// Compute the results of the column expressions and make a row
|
||||
let mut row = Vec::new();
|
||||
for col in &self.columns {
|
||||
match col {
|
||||
ResultColumn::Expr(expr) => {
|
||||
let value = expr.eval(&[], &Table::anonymous(vec![]));
|
||||
if let Some(value) = value {
|
||||
row.push(value);
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Failed to evaluate expression in free select ({})",
|
||||
expr.0.format_with_context(&EmptyContext {}).unwrap()
|
||||
));
|
||||
}
|
||||
}
|
||||
_ => unreachable!("Only expressions are allowed in free selects"),
|
||||
}
|
||||
}
|
||||
|
||||
Ok(JoinTable {
|
||||
tables: Vec::new(),
|
||||
rows: vec![row],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Shadow for Select {
|
||||
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
|
||||
|
||||
fn shadow(&self, env: &mut SimulatorTables) -> Self::Result {
|
||||
let first_result = self.body.select.shadow(env)?;
|
||||
|
||||
let mut rows = first_result.rows;
|
||||
|
||||
for compound in self.body.compounds.iter() {
|
||||
let compound_results = compound.select.shadow(env)?;
|
||||
|
||||
match compound.operator {
|
||||
CompoundOperator::Union => {
|
||||
// Union means we need to combine the results, removing duplicates
|
||||
let mut new_rows = compound_results.rows;
|
||||
new_rows.extend(rows.clone());
|
||||
new_rows.sort_unstable();
|
||||
new_rows.dedup();
|
||||
rows = new_rows;
|
||||
}
|
||||
CompoundOperator::UnionAll => {
|
||||
// Union all means we just concatenate the results
|
||||
rows.extend(compound_results.rows.into_iter());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(rows)
|
||||
}
|
||||
}
|
||||
|
||||
impl Select {
|
||||
pub fn to_sql_ast(&self) -> ast::Select {
|
||||
ast::Select {
|
||||
with: None,
|
||||
body: ast::SelectBody {
|
||||
select: Box::new(ast::OneSelect::Select(Box::new(ast::SelectInner {
|
||||
select: ast::OneSelect::Select {
|
||||
distinctness: if self.body.select.distinctness == Distinctness::Distinct {
|
||||
Some(ast::Distinctness::Distinct)
|
||||
} else {
|
||||
@@ -411,77 +236,81 @@ impl Select {
|
||||
.iter()
|
||||
.map(|col| match col {
|
||||
ResultColumn::Expr(expr) => {
|
||||
ast::ResultColumn::Expr(expr.0.clone(), None)
|
||||
ast::ResultColumn::Expr(expr.0.clone().into_boxed(), None)
|
||||
}
|
||||
ResultColumn::Star => ast::ResultColumn::Star,
|
||||
ResultColumn::Column(name) => ast::ResultColumn::Expr(
|
||||
ast::Expr::Id(ast::Name::Ident(name.clone())),
|
||||
ast::Expr::Id(ast::Name::Ident(name.clone())).into_boxed(),
|
||||
None,
|
||||
),
|
||||
})
|
||||
.collect(),
|
||||
from: self.body.select.from.as_ref().map(|f| f.to_sql_ast()),
|
||||
where_clause: Some(self.body.select.where_clause.0.clone()),
|
||||
where_clause: Some(self.body.select.where_clause.0.clone().into_boxed()),
|
||||
group_by: None,
|
||||
window_clause: None,
|
||||
}))),
|
||||
compounds: Some(
|
||||
self.body
|
||||
.compounds
|
||||
.iter()
|
||||
.map(|compound| ast::CompoundSelect {
|
||||
operator: match compound.operator {
|
||||
CompoundOperator::Union => ast::CompoundOperator::Union,
|
||||
CompoundOperator::UnionAll => ast::CompoundOperator::UnionAll,
|
||||
},
|
||||
select: Box::new(ast::OneSelect::Select(Box::new(ast::SelectInner {
|
||||
distinctness: Some(compound.select.distinctness),
|
||||
columns: compound
|
||||
.select
|
||||
.columns
|
||||
.iter()
|
||||
.map(|col| match col {
|
||||
ResultColumn::Expr(expr) => {
|
||||
ast::ResultColumn::Expr(expr.0.clone(), None)
|
||||
}
|
||||
ResultColumn::Star => ast::ResultColumn::Star,
|
||||
ResultColumn::Column(name) => ast::ResultColumn::Expr(
|
||||
ast::Expr::Id(ast::Name::Ident(name.clone())),
|
||||
None,
|
||||
),
|
||||
})
|
||||
.collect(),
|
||||
from: compound.select.from.as_ref().map(|f| f.to_sql_ast()),
|
||||
where_clause: Some(compound.select.where_clause.0.clone()),
|
||||
group_by: None,
|
||||
window_clause: None,
|
||||
}))),
|
||||
})
|
||||
.collect(),
|
||||
),
|
||||
},
|
||||
order_by: self.body.select.order_by.as_ref().map(|o| {
|
||||
o.columns
|
||||
window_clause: Vec::new(),
|
||||
},
|
||||
compounds: self
|
||||
.body
|
||||
.compounds
|
||||
.iter()
|
||||
.map(|(name, order)| ast::SortedColumn {
|
||||
expr: ast::Expr::Id(ast::Name::Ident(name.clone())),
|
||||
order: match order {
|
||||
SortOrder::Asc => Some(ast::SortOrder::Asc),
|
||||
SortOrder::Desc => Some(ast::SortOrder::Desc),
|
||||
.map(|compound| ast::CompoundSelect {
|
||||
operator: match compound.operator {
|
||||
CompoundOperator::Union => ast::CompoundOperator::Union,
|
||||
CompoundOperator::UnionAll => ast::CompoundOperator::UnionAll,
|
||||
},
|
||||
select: ast::OneSelect::Select {
|
||||
distinctness: Some(compound.select.distinctness),
|
||||
columns: compound
|
||||
.select
|
||||
.columns
|
||||
.iter()
|
||||
.map(|col| match col {
|
||||
ResultColumn::Expr(expr) => {
|
||||
ast::ResultColumn::Expr(expr.0.clone().into_boxed(), None)
|
||||
}
|
||||
ResultColumn::Star => ast::ResultColumn::Star,
|
||||
ResultColumn::Column(name) => ast::ResultColumn::Expr(
|
||||
ast::Expr::Id(ast::Name::Ident(name.clone())).into_boxed(),
|
||||
None,
|
||||
),
|
||||
})
|
||||
.collect(),
|
||||
from: compound.select.from.as_ref().map(|f| f.to_sql_ast()),
|
||||
where_clause: Some(compound.select.where_clause.0.clone().into_boxed()),
|
||||
group_by: None,
|
||||
window_clause: Vec::new(),
|
||||
},
|
||||
nulls: None,
|
||||
})
|
||||
.collect()
|
||||
}),
|
||||
limit: self.limit.map(|l| {
|
||||
Box::new(ast::Limit {
|
||||
expr: ast::Expr::Literal(ast::Literal::Numeric(l.to_string())),
|
||||
offset: None,
|
||||
.collect(),
|
||||
},
|
||||
order_by: self
|
||||
.body
|
||||
.select
|
||||
.order_by
|
||||
.as_ref()
|
||||
.map(|o| {
|
||||
o.columns
|
||||
.iter()
|
||||
.map(|(name, order)| ast::SortedColumn {
|
||||
expr: ast::Expr::Id(ast::Name::Ident(name.clone())).into_boxed(),
|
||||
order: match order {
|
||||
SortOrder::Asc => Some(ast::SortOrder::Asc),
|
||||
SortOrder::Desc => Some(ast::SortOrder::Desc),
|
||||
},
|
||||
nulls: None,
|
||||
})
|
||||
.collect()
|
||||
})
|
||||
.unwrap_or(Vec::new()),
|
||||
limit: self.limit.map(|l| ast::Limit {
|
||||
expr: ast::Expr::Literal(ast::Literal::Numeric(l.to_string())).into_boxed(),
|
||||
offset: None,
|
||||
}),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Select {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
self.to_sql_ast().to_fmt_with_context(f, &EmptyContext {})
|
||||
|
||||
@@ -2,8 +2,6 @@ use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{generation::Shadow, model::table::SimValue, runner::env::SimulatorTables};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub(crate) struct Begin {
|
||||
pub(crate) immediate: bool,
|
||||
@@ -15,32 +13,6 @@ pub(crate) struct Commit;
|
||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||
pub(crate) struct Rollback;
|
||||
|
||||
impl Shadow for Begin {
|
||||
type Result = Vec<Vec<SimValue>>;
|
||||
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
|
||||
tables.snapshot = Some(tables.tables.clone());
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Shadow for Commit {
|
||||
type Result = Vec<Vec<SimValue>>;
|
||||
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
|
||||
tables.snapshot = None;
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Shadow for Rollback {
|
||||
type Result = Vec<Vec<SimValue>>;
|
||||
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
|
||||
if let Some(tables_) = tables.snapshot.take() {
|
||||
tables.tables = tables_;
|
||||
}
|
||||
vec![]
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Begin {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "BEGIN {}", if self.immediate { "IMMEDIATE" } else { "" })
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::fmt::Display;
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use crate::{generation::Shadow, model::table::SimValue, runner::env::SimulatorTables};
|
||||
use crate::model::table::SimValue;
|
||||
|
||||
use super::predicate::Predicate;
|
||||
|
||||
@@ -19,43 +19,6 @@ impl Update {
|
||||
}
|
||||
}
|
||||
|
||||
impl Shadow for Update {
|
||||
type Result = anyhow::Result<Vec<Vec<SimValue>>>;
|
||||
|
||||
fn shadow(&self, tables: &mut SimulatorTables) -> Self::Result {
|
||||
let table = tables.tables.iter_mut().find(|t| t.name == self.table);
|
||||
|
||||
let table = if let Some(table) = table {
|
||||
table
|
||||
} else {
|
||||
return Err(anyhow::anyhow!(
|
||||
"Table {} does not exist. UPDATE statement ignored.",
|
||||
self.table
|
||||
));
|
||||
};
|
||||
|
||||
let t2 = table.clone();
|
||||
for row in table
|
||||
.rows
|
||||
.iter_mut()
|
||||
.filter(|r| self.predicate.test(r, &t2))
|
||||
{
|
||||
for (column, set_value) in &self.set_values {
|
||||
if let Some((idx, _)) = table
|
||||
.columns
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, c)| &c.name == column)
|
||||
{
|
||||
row[idx] = set_value.clone();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(vec![])
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Update {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "UPDATE {} SET ", self.table)?;
|
||||
|
||||
Reference in New Issue
Block a user