mirror of
https://github.com/aljazceru/turso.git
synced 2026-01-09 03:04:20 +01:00
test for create trigger + fixes
This commit is contained in:
@@ -246,7 +246,7 @@ impl ToSqlString for Expr {
|
||||
ret.push_str(&name1.0);
|
||||
}
|
||||
Expr::Raise(resolve_type, expr) => {
|
||||
ret.push_str("RAISE (");
|
||||
ret.push_str("RAISE(");
|
||||
ret.push_str(&resolve_type.to_sql_string(context));
|
||||
if let Some(expr) = expr {
|
||||
ret.push_str(", ");
|
||||
|
||||
@@ -65,7 +65,7 @@ impl ToSqlString for ast::ColumnConstraint {
|
||||
clause,
|
||||
deref_clause,
|
||||
} => format!(
|
||||
"FOREIGN KEY {}{}",
|
||||
"{}{}",
|
||||
clause.to_sql_string(context),
|
||||
if let Some(deref) = deref_clause {
|
||||
deref.to_sql_string(context)
|
||||
@@ -214,71 +214,71 @@ mod tests {
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_rename,
|
||||
"ALTER TABLE t RENAME TO new_table_name"
|
||||
"ALTER TABLE t RENAME TO new_table_name;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column,
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER"
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_with_default,
|
||||
"ALTER TABLE t ADD COLUMN c TEXT DEFAULT 'value'"
|
||||
"ALTER TABLE t ADD COLUMN c TEXT DEFAULT 'value';"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_not_null_default,
|
||||
"ALTER TABLE t ADD COLUMN c REAL NOT NULL DEFAULT 0.0"
|
||||
"ALTER TABLE t ADD COLUMN c REAL NOT NULL DEFAULT 0.0;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_unique,
|
||||
"ALTER TABLE t ADD COLUMN c TEXT UNIQUE",
|
||||
ignore = "ParserError = Cannot add a UNIQUE column"
|
||||
ignore = "ParserError = Cannot add a UNIQUE column;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_rename_column,
|
||||
"ALTER TABLE t RENAME COLUMN old_name TO new_name"
|
||||
"ALTER TABLE t RENAME COLUMN old_name TO new_name;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(test_alter_table_drop_column, "ALTER TABLE t DROP COLUMN c");
|
||||
to_sql_string_test!(test_alter_table_drop_column, "ALTER TABLE t DROP COLUMN c;");
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_check,
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER CHECK (c > 0)"
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER CHECK (c > 0);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_foreign_key,
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER REFERENCES t2(id) ON DELETE CASCADE"
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER REFERENCES t2(id) ON DELETE CASCADE;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_collate,
|
||||
"ALTER TABLE t ADD COLUMN c TEXT COLLATE NOCASE"
|
||||
"ALTER TABLE t ADD COLUMN c TEXT COLLATE NOCASE;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_primary_key,
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER PRIMARY KEY",
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER PRIMARY KEY;",
|
||||
ignore = "ParserError = Cannot add a PRIMARY KEY column"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_primary_key_autoincrement,
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER PRIMARY KEY AUTOINCREMENT",
|
||||
"ALTER TABLE t ADD COLUMN c INTEGER PRIMARY KEY AUTOINCREMENT;",
|
||||
ignore = "ParserError = Cannot add a PRIMARY KEY column"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_generated_column,
|
||||
"ALTER TABLE t ADD COLUMN c_generated AS (a + b) STORED"
|
||||
"ALTER TABLE t ADD COLUMN c_generated AS (a + b) STORED;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_alter_table_add_column_schema,
|
||||
"ALTER TABLE schema_name.t ADD COLUMN c INTEGER"
|
||||
"ALTER TABLE schema_name.t ADD COLUMN c INTEGER;"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -124,118 +124,118 @@ mod tests {
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_simple,
|
||||
"CREATE TABLE t (a INTEGER, b TEXT)"
|
||||
"CREATE TABLE t (a INTEGER, b TEXT);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_primary_key,
|
||||
"CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT)"
|
||||
"CREATE TABLE t (id INTEGER PRIMARY KEY, name TEXT);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_multi_primary_key,
|
||||
"CREATE TABLE t (a INTEGER, b TEXT, PRIMARY KEY (a, b))"
|
||||
"CREATE TABLE t (a INTEGER, b TEXT, PRIMARY KEY (a, b));"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_data_types,
|
||||
"CREATE TABLE t (a INTEGER, b TEXT, c REAL, d BLOB, e NUMERIC)"
|
||||
"CREATE TABLE t (a INTEGER, b TEXT, c REAL, d BLOB, e NUMERIC);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_foreign_key,
|
||||
"CREATE TABLE t2 (id INTEGER PRIMARY KEY, t_id INTEGER, FOREIGN KEY (t_id) REFERENCES t(id))"
|
||||
"CREATE TABLE t2 (id INTEGER PRIMARY KEY, t_id INTEGER, FOREIGN KEY (t_id) REFERENCES t(id));"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_foreign_key_cascade,
|
||||
"CREATE TABLE t2 (id INTEGER PRIMARY KEY, t_id INTEGER, FOREIGN KEY (t_id) REFERENCES t(id) ON DELETE CASCADE)"
|
||||
"CREATE TABLE t2 (id INTEGER PRIMARY KEY, t_id INTEGER, FOREIGN KEY (t_id) REFERENCES t(id) ON DELETE CASCADE);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_unique,
|
||||
"CREATE TABLE t (a INTEGER UNIQUE, b TEXT)"
|
||||
"CREATE TABLE t (a INTEGER UNIQUE, b TEXT);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_not_null,
|
||||
"CREATE TABLE t (a INTEGER NOT NULL, b TEXT)"
|
||||
"CREATE TABLE t (a INTEGER NOT NULL, b TEXT);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_check,
|
||||
"CREATE TABLE t (a INTEGER CHECK (a > 0), b TEXT)"
|
||||
"CREATE TABLE t (a INTEGER CHECK (a > 0), b TEXT);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_default,
|
||||
"CREATE TABLE t (a INTEGER DEFAULT 0, b TEXT)"
|
||||
"CREATE TABLE t (a INTEGER DEFAULT 0, b TEXT);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_multiple_constraints,
|
||||
"CREATE TABLE t (a INTEGER NOT NULL UNIQUE, b TEXT DEFAULT 'default')"
|
||||
"CREATE TABLE t (a INTEGER NOT NULL UNIQUE, b TEXT DEFAULT 'default');"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_generated_column,
|
||||
"CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b))"
|
||||
"CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b));"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_generated_stored,
|
||||
"CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b) STORED)"
|
||||
"CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b) STORED);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_generated_virtual,
|
||||
"CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b) VIRTUAL)"
|
||||
"CREATE TABLE t (a INTEGER, b INTEGER, c INTEGER AS (a + b) VIRTUAL);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_quoted_columns,
|
||||
"CREATE TABLE t (\"select\" INTEGER, \"from\" TEXT)"
|
||||
"CREATE TABLE t (\"select\" INTEGER, \"from\" TEXT);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_quoted_table,
|
||||
"CREATE TABLE \"my table\" (a INTEGER)"
|
||||
"CREATE TABLE \"my table\" (a INTEGER);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_if_not_exists,
|
||||
"CREATE TABLE IF NOT EXISTS t (a INTEGER)"
|
||||
"CREATE TABLE IF NOT EXISTS t (a INTEGER);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(test_create_temp_table, "CREATE TEMP TABLE t (a INTEGER)");
|
||||
to_sql_string_test!(test_create_temp_table, "CREATE TEMP TABLE t (a INTEGER);");
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_without_rowid,
|
||||
"CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) WITHOUT ROWID"
|
||||
"CREATE TABLE t (a INTEGER PRIMARY KEY, b TEXT) WITHOUT ROWID;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_named_primary_key,
|
||||
"CREATE TABLE t (a INTEGER CONSTRAINT pk_a PRIMARY KEY)"
|
||||
"CREATE TABLE t (a INTEGER CONSTRAINT pk_a PRIMARY KEY);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_named_unique,
|
||||
"CREATE TABLE t (a INTEGER, CONSTRAINT unique_a UNIQUE (a))"
|
||||
"CREATE TABLE t (a INTEGER, CONSTRAINT unique_a UNIQUE (a));"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_named_foreign_key,
|
||||
"CREATE TABLE t2 (id INTEGER, t_id INTEGER, CONSTRAINT fk_t FOREIGN KEY (t_id) REFERENCES t(id))"
|
||||
"CREATE TABLE t2 (id INTEGER, t_id INTEGER, CONSTRAINT fk_t FOREIGN KEY (t_id) REFERENCES t(id));"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_complex,
|
||||
"CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER NOT NULL, b TEXT DEFAULT 'default', c INTEGER AS (a * 2), CONSTRAINT unique_a UNIQUE (a))"
|
||||
"CREATE TABLE t (id INTEGER PRIMARY KEY, a INTEGER NOT NULL, b TEXT DEFAULT 'default', c INTEGER AS (a * 2), CONSTRAINT unique_a UNIQUE (a));"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_create_table_multiple_foreign_keys,
|
||||
"CREATE TABLE t3 (id INTEGER PRIMARY KEY, t1_id INTEGER, t2_id INTEGER, FOREIGN KEY (t1_id) REFERENCES t1(id), FOREIGN KEY (t2_id) REFERENCES t2(id))"
|
||||
"CREATE TABLE t3 (id INTEGER PRIMARY KEY, t1_id INTEGER, t2_id INTEGER, FOREIGN KEY (t1_id) REFERENCES t1(id), FOREIGN KEY (t2_id) REFERENCES t2(id));"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use crate::{ast, to_sql_string::ToSqlString};
|
||||
impl ToSqlString for ast::CreateTrigger {
|
||||
fn to_sql_string<C: crate::to_sql_string::ToSqlContext>(&self, context: &C) -> String {
|
||||
format!(
|
||||
"CREATE{} TRIGGER {}{} {}{} ON {} {}{} BEGIN {} END",
|
||||
"CREATE{} TRIGGER {}{}{} {} ON {}{}{} BEGIN {} END;",
|
||||
self.temporary.then_some(" TEMP").unwrap_or(""),
|
||||
self.if_not_exists.then_some("IF NOT EXISTS ").unwrap_or(""),
|
||||
self.trigger_name.to_sql_string(context),
|
||||
@@ -13,15 +13,15 @@ impl ToSqlString for ast::CreateTrigger {
|
||||
)),
|
||||
self.event.to_sql_string(context),
|
||||
self.tbl_name.to_sql_string(context),
|
||||
self.for_each_row.then_some("FOR EACH ROW ").unwrap_or(""),
|
||||
self.for_each_row.then_some(" FOR EACH ROW").unwrap_or(""),
|
||||
self.when_clause
|
||||
.as_ref()
|
||||
.map_or("".to_string(), |expr| expr.to_string()),
|
||||
.map_or("".to_string(), |expr| format!(" WHEN {}", expr.to_string())),
|
||||
self.commands
|
||||
.iter()
|
||||
.map(|command| command.to_sql_string(context))
|
||||
.map(|command| format!("{};", command.to_sql_string(context)))
|
||||
.collect::<Vec<_>>()
|
||||
.join("; ")
|
||||
.join(" ")
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -234,3 +234,63 @@ impl ToSqlString for ast::TriggerCmdUpdate {
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use crate::to_sql_string_test;
|
||||
|
||||
to_sql_string_test!(
|
||||
test_log_employee_insert,
|
||||
"CREATE TRIGGER log_employee_insert
|
||||
AFTER INSERT ON employees
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
INSERT INTO employee_log (action, employee_id, timestamp)
|
||||
VALUES ('INSERT', NEW.id, CURRENT_TIMESTAMP);
|
||||
END;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_log_salary_update,
|
||||
"CREATE TRIGGER log_salary_update
|
||||
AFTER UPDATE OF salary ON employees
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
INSERT INTO employee_log (action, employee_id, old_value, new_value, timestamp)
|
||||
VALUES ('UPDATE', OLD.id, OLD.salary, NEW.salary, CURRENT_TIMESTAMP);
|
||||
END;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_log_employee_delete,
|
||||
"CREATE TRIGGER log_employee_delete
|
||||
AFTER DELETE ON employees
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
INSERT INTO employee_log (action, employee_id, timestamp)
|
||||
VALUES ('DELETE', OLD.id, CURRENT_TIMESTAMP);
|
||||
END;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_check_salary_insert,
|
||||
"CREATE TRIGGER check_salary_insert
|
||||
BEFORE INSERT ON employees
|
||||
FOR EACH ROW
|
||||
WHEN NEW.salary < 0
|
||||
BEGIN
|
||||
SELECT RAISE(FAIL, 'Salary cannot be negative');
|
||||
END;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_insert_employee_dept,
|
||||
"CREATE TRIGGER insert_employee_dept
|
||||
INSTEAD OF INSERT ON employee_dept
|
||||
FOR EACH ROW
|
||||
BEGIN
|
||||
INSERT INTO departments (name) SELECT NEW.department WHERE NOT EXISTS (SELECT 1 FROM departments WHERE name = NEW.department);
|
||||
INSERT INTO employees (name, department_id) VALUES (NEW.name, (SELECT id FROM departments WHERE name = NEW.department));
|
||||
END;"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -9,21 +9,20 @@ mod select;
|
||||
|
||||
impl ToSqlString for ast::Stmt {
|
||||
fn to_sql_string<C: super::ToSqlContext>(&self, context: &C) -> String {
|
||||
dbg!(self);
|
||||
match self {
|
||||
Self::AlterTable(alter_table) => {
|
||||
let (name, body) = alter_table.as_ref();
|
||||
format!(
|
||||
"ALTER TABLE {} {}",
|
||||
"ALTER TABLE {} {};",
|
||||
name.to_sql_string(context),
|
||||
body.to_sql_string(context)
|
||||
)
|
||||
}
|
||||
Self::Analyze(name) => {
|
||||
if let Some(name) = name {
|
||||
format!("ANALYZE {}", name.to_sql_string(context))
|
||||
format!("ANALYZE {};", name.to_sql_string(context))
|
||||
} else {
|
||||
format!("ANALYZE")
|
||||
format!("ANALYZE;")
|
||||
}
|
||||
}
|
||||
Self::Attach {
|
||||
@@ -33,7 +32,7 @@ impl ToSqlString for ast::Stmt {
|
||||
} => {
|
||||
// TODO: what is `key` in the attach syntax?
|
||||
format!(
|
||||
"ATTACH {} AS {}",
|
||||
"ATTACH {} AS {};",
|
||||
expr.to_sql_string(context),
|
||||
db_name.to_sql_string(context)
|
||||
)
|
||||
@@ -46,11 +45,11 @@ impl ToSqlString for ast::Stmt {
|
||||
ast::TransactionType::Exclusive => " EXCLUSIVE",
|
||||
ast::TransactionType::Immediate => " IMMEDIATE",
|
||||
});
|
||||
format!("BEGIN{}", t_type)
|
||||
format!("BEGIN{};", t_type)
|
||||
}
|
||||
// END or COMMIT are equivalent here, so just defaulting to COMMIT
|
||||
// TODO: again there are no names in the docs
|
||||
Self::Commit(_name) => "COMMIT".to_string(),
|
||||
Self::Commit(_name) => "COMMIT;".to_string(),
|
||||
Self::CreateIndex {
|
||||
unique,
|
||||
if_not_exists,
|
||||
@@ -60,7 +59,7 @@ impl ToSqlString for ast::Stmt {
|
||||
where_clause,
|
||||
} => {
|
||||
format!(
|
||||
"CREATE {}INDEX {}{} ON {} ({}){}",
|
||||
"CREATE {}INDEX {}{} ON {} ({}){};",
|
||||
unique.then_some("UNIQUE ").unwrap_or(""),
|
||||
if_not_exists.then_some("IF NOT EXISTS ").unwrap_or(""),
|
||||
idx_name.to_sql_string(context),
|
||||
@@ -85,7 +84,7 @@ impl ToSqlString for ast::Stmt {
|
||||
body,
|
||||
} => {
|
||||
format!(
|
||||
"CREATE{} TABLE {}{} {}",
|
||||
"CREATE{} TABLE {}{} {};",
|
||||
temporary.then_some(" TEMP").unwrap_or(""),
|
||||
if_not_exists.then_some("IF NOT EXISTS ").unwrap_or(""),
|
||||
tbl_name.to_sql_string(context),
|
||||
@@ -93,7 +92,7 @@ impl ToSqlString for ast::Stmt {
|
||||
)
|
||||
}
|
||||
Self::CreateTrigger(trigger) => trigger.to_sql_string(context),
|
||||
Self::Select(select) => select.to_sql_string(context),
|
||||
Self::Select(select) => format!("{};", select.to_sql_string(context)),
|
||||
_ => todo!(),
|
||||
}
|
||||
}
|
||||
@@ -110,7 +109,7 @@ mod tests {
|
||||
#[test]
|
||||
fn $test_name() {
|
||||
let context = crate::to_sql_string::stmt::tests::TestContext;
|
||||
let input: &str = $input;
|
||||
let input = $input.split_whitespace().collect::<Vec<&str>>().join(" ");
|
||||
let mut parser = crate::lexer::sql::Parser::new(input.as_bytes());
|
||||
let cmd = fallible_iterator::FallibleIterator::next(&mut parser)
|
||||
.unwrap()
|
||||
@@ -126,7 +125,7 @@ mod tests {
|
||||
$(#[$attribute])*
|
||||
fn $test_name() {
|
||||
let context = crate::to_sql_string::stmt::tests::TestContext;
|
||||
let input: &str = $input;
|
||||
let input = $input.split_whitespace().collect::<Vec<&str>>().join(" ");
|
||||
let mut parser = crate::lexer::sql::Parser::new(input.as_bytes());
|
||||
let cmd = fallible_iterator::FallibleIterator::next(&mut parser)
|
||||
.unwrap()
|
||||
@@ -153,71 +152,71 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
to_sql_string_test!(test_analyze, "ANALYZE");
|
||||
to_sql_string_test!(test_analyze, "ANALYZE;");
|
||||
|
||||
to_sql_string_test!(
|
||||
test_analyze_table,
|
||||
"ANALYZE table",
|
||||
"ANALYZE table;",
|
||||
ignore = "parser can't parse table name"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_analyze_schema_table,
|
||||
"ANALYZE schema.table",
|
||||
"ANALYZE schema.table;",
|
||||
ignore = "parser can't parse schema.table name"
|
||||
);
|
||||
|
||||
to_sql_string_test!(test_attach, "ATTACH './test.db' AS test_db");
|
||||
to_sql_string_test!(test_attach, "ATTACH './test.db' AS test_db;");
|
||||
|
||||
to_sql_string_test!(test_transaction, "BEGIN");
|
||||
to_sql_string_test!(test_transaction, "BEGIN;");
|
||||
|
||||
to_sql_string_test!(test_transaction_deferred, "BEGIN DEFERRED");
|
||||
to_sql_string_test!(test_transaction_deferred, "BEGIN DEFERRED;");
|
||||
|
||||
to_sql_string_test!(test_transaction_immediate, "BEGIN IMMEDIATE");
|
||||
to_sql_string_test!(test_transaction_immediate, "BEGIN IMMEDIATE;");
|
||||
|
||||
to_sql_string_test!(test_transaction_exclusive, "BEGIN EXCLUSIVE");
|
||||
to_sql_string_test!(test_transaction_exclusive, "BEGIN EXCLUSIVE;");
|
||||
|
||||
to_sql_string_test!(test_commit, "COMMIT");
|
||||
to_sql_string_test!(test_commit, "COMMIT;");
|
||||
|
||||
// Test a simple index on a single column
|
||||
to_sql_string_test!(
|
||||
test_create_index_simple,
|
||||
"CREATE INDEX idx_name ON employees (last_name)"
|
||||
"CREATE INDEX idx_name ON employees (last_name);"
|
||||
);
|
||||
|
||||
// Test a unique index to enforce uniqueness on a column
|
||||
to_sql_string_test!(
|
||||
test_create_unique_index,
|
||||
"CREATE UNIQUE INDEX idx_unique_email ON users (email)"
|
||||
"CREATE UNIQUE INDEX idx_unique_email ON users (email);"
|
||||
);
|
||||
|
||||
// Test a multi-column index
|
||||
to_sql_string_test!(
|
||||
test_create_index_multi_column,
|
||||
"CREATE INDEX idx_name_salary ON employees (last_name, salary)"
|
||||
"CREATE INDEX idx_name_salary ON employees (last_name, salary);"
|
||||
);
|
||||
|
||||
// Test a partial index with a WHERE clause
|
||||
to_sql_string_test!(
|
||||
test_create_partial_index,
|
||||
"CREATE INDEX idx_active_users ON users (username) WHERE active = true"
|
||||
"CREATE INDEX idx_active_users ON users (username) WHERE active = true;"
|
||||
);
|
||||
|
||||
// Test an index on an expression
|
||||
to_sql_string_test!(
|
||||
test_create_index_on_expression,
|
||||
"CREATE INDEX idx_upper_name ON employees (UPPER(last_name))"
|
||||
"CREATE INDEX idx_upper_name ON employees (UPPER(last_name));"
|
||||
);
|
||||
|
||||
// Test an index with descending order
|
||||
to_sql_string_test!(
|
||||
test_create_index_descending,
|
||||
"CREATE INDEX idx_salary_desc ON employees (salary DESC)"
|
||||
"CREATE INDEX idx_salary_desc ON employees (salary DESC);"
|
||||
);
|
||||
|
||||
// Test an index with mixed ascending and descending orders on multiple columns
|
||||
to_sql_string_test!(
|
||||
test_create_index_mixed_order,
|
||||
"CREATE INDEX idx_name_asc_salary_desc ON employees (last_name ASC, salary DESC)"
|
||||
"CREATE INDEX idx_name_asc_salary_desc ON employees (last_name ASC, salary DESC);"
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,7 +5,6 @@ use crate::{
|
||||
|
||||
impl ToSqlString for ast::Select {
|
||||
fn to_sql_string<C: ToSqlContext>(&self, context: &C) -> String {
|
||||
dbg!(&self);
|
||||
let mut ret = Vec::new();
|
||||
if let Some(with) = &self.with {
|
||||
let joined_expr = with
|
||||
@@ -78,12 +77,12 @@ impl ToSqlString for ast::OneSelect {
|
||||
.iter()
|
||||
.map(|e| e.to_sql_string(context))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",");
|
||||
.join(", ");
|
||||
format!("({})", joined_value)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ");
|
||||
joined_values
|
||||
format!("VALUES {}", joined_values)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -523,119 +522,125 @@ impl ToSqlString for ast::FrameExclude {
|
||||
mod tests {
|
||||
use crate::to_sql_string_test;
|
||||
|
||||
to_sql_string_test!(test_select_basic, "SELECT 1");
|
||||
to_sql_string_test!(test_select_basic, "SELECT 1;");
|
||||
|
||||
to_sql_string_test!(test_select_table, "SELECT * FROM t");
|
||||
to_sql_string_test!(test_select_table, "SELECT * FROM t;");
|
||||
|
||||
to_sql_string_test!(test_select_table_2, "SELECT a FROM t");
|
||||
to_sql_string_test!(test_select_table_2, "SELECT a FROM t;");
|
||||
|
||||
to_sql_string_test!(test_select_multiple_columns, "SELECT a, b, c FROM t");
|
||||
to_sql_string_test!(test_select_multiple_columns, "SELECT a, b, c FROM t;");
|
||||
|
||||
to_sql_string_test!(test_select_with_alias, "SELECT a AS col1 FROM t");
|
||||
to_sql_string_test!(test_select_with_alias, "SELECT a AS col1 FROM t;");
|
||||
|
||||
to_sql_string_test!(test_select_with_table_alias, "SELECT t1.a FROM t AS t1");
|
||||
to_sql_string_test!(test_select_with_table_alias, "SELECT t1.a FROM t AS t1;");
|
||||
|
||||
to_sql_string_test!(test_select_with_where, "SELECT a FROM t WHERE b = 1");
|
||||
to_sql_string_test!(test_select_with_where, "SELECT a FROM t WHERE b = 1;");
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_multiple_conditions,
|
||||
"SELECT a FROM t WHERE b = 1 AND c > 2"
|
||||
"SELECT a FROM t WHERE b = 1 AND c > 2;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(test_select_with_order_by, "SELECT a FROM t ORDER BY a DESC");
|
||||
to_sql_string_test!(
|
||||
test_select_with_order_by,
|
||||
"SELECT a FROM t ORDER BY a DESC;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(test_select_with_limit, "SELECT a FROM t LIMIT 10");
|
||||
to_sql_string_test!(test_select_with_limit, "SELECT a FROM t LIMIT 10;");
|
||||
|
||||
to_sql_string_test!(test_select_with_offset, "SELECT a FROM t LIMIT 10 OFFSET 5");
|
||||
to_sql_string_test!(
|
||||
test_select_with_offset,
|
||||
"SELECT a FROM t LIMIT 10 OFFSET 5;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_join,
|
||||
"SELECT a FROM t JOIN t2 ON t.b = t2.b"
|
||||
"SELECT a FROM t JOIN t2 ON t.b = t2.b;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_group_by,
|
||||
"SELECT a, COUNT(*) FROM t GROUP BY a"
|
||||
"SELECT a, COUNT(*) FROM t GROUP BY a;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_having,
|
||||
"SELECT a, COUNT(*) FROM t GROUP BY a HAVING COUNT(*) > 1"
|
||||
"SELECT a, COUNT(*) FROM t GROUP BY a HAVING COUNT(*) > 1;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(test_select_with_distinct, "SELECT DISTINCT a FROM t");
|
||||
to_sql_string_test!(test_select_with_distinct, "SELECT DISTINCT a FROM t;");
|
||||
|
||||
to_sql_string_test!(test_select_with_function, "SELECT COUNT(a) FROM t");
|
||||
to_sql_string_test!(test_select_with_function, "SELECT COUNT(a) FROM t;");
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_subquery,
|
||||
"SELECT a FROM (SELECT b FROM t) AS sub"
|
||||
"SELECT a FROM (SELECT b FROM t) AS sub;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_nested_subquery,
|
||||
"SELECT a FROM (SELECT b FROM (SELECT c FROM t WHERE c > 10) AS sub1 WHERE b < 20) AS sub2"
|
||||
"SELECT a FROM (SELECT b FROM (SELECT c FROM t WHERE c > 10) AS sub1 WHERE b < 20) AS sub2;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_multiple_joins,
|
||||
"SELECT t1.a, t2.b, t3.c FROM t1 JOIN t2 ON t1.id = t2.id LEFT JOIN t3 ON t2.id = t3.id"
|
||||
"SELECT t1.a, t2.b, t3.c FROM t1 JOIN t2 ON t1.id = t2.id LEFT JOIN t3 ON t2.id = t3.id;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_cte,
|
||||
"WITH cte AS (SELECT a FROM t WHERE b = 1) SELECT a FROM cte WHERE a > 10"
|
||||
"WITH cte AS (SELECT a FROM t WHERE b = 1) SELECT a FROM cte WHERE a > 10;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_window_function,
|
||||
"SELECT a, ROW_NUMBER() OVER (PARTITION BY b ORDER BY c DESC) AS rn FROM t"
|
||||
"SELECT a, ROW_NUMBER() OVER (PARTITION BY b ORDER BY c DESC) AS rn FROM t;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_complex_where,
|
||||
"SELECT a FROM t WHERE b IN (1, 2, 3) AND c BETWEEN 10 AND 20 OR d IS NULL"
|
||||
"SELECT a FROM t WHERE b IN (1, 2, 3) AND c BETWEEN 10 AND 20 OR d IS NULL;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_case,
|
||||
"SELECT CASE WHEN a > 0 THEN 'positive' ELSE 'non-positive' END AS result FROM t"
|
||||
"SELECT CASE WHEN a > 0 THEN 'positive' ELSE 'non-positive' END AS result FROM t;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(test_select_with_aggregate_and_join, "SELECT t1.a, COUNT(t2.b) FROM t1 LEFT JOIN t2 ON t1.id = t2.id GROUP BY t1.a HAVING COUNT(t2.b) > 5");
|
||||
to_sql_string_test!(test_select_with_aggregate_and_join, "SELECT t1.a, COUNT(t2.b) FROM t1 LEFT JOIN t2 ON t1.id = t2.id GROUP BY t1.a HAVING COUNT(t2.b) > 5;");
|
||||
|
||||
to_sql_string_test!(test_select_with_multiple_ctes, "WITH cte1 AS (SELECT a FROM t WHERE b = 1), cte2 AS (SELECT c FROM t2 WHERE d = 2) SELECT cte1.a, cte2.c FROM cte1 JOIN cte2 ON cte1.a = cte2.c");
|
||||
to_sql_string_test!(test_select_with_multiple_ctes, "WITH cte1 AS (SELECT a FROM t WHERE b = 1), cte2 AS (SELECT c FROM t2 WHERE d = 2) SELECT cte1.a, cte2.c FROM cte1 JOIN cte2 ON cte1.a = cte2.c;");
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_union,
|
||||
"SELECT a FROM t1 UNION SELECT b FROM t2"
|
||||
"SELECT a FROM t1 UNION SELECT b FROM t2;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_union_all,
|
||||
"SELECT a FROM t1 UNION ALL SELECT b FROM t2"
|
||||
"SELECT a FROM t1 UNION ALL SELECT b FROM t2;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_exists,
|
||||
"SELECT a FROM t WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t.a)"
|
||||
"SELECT a FROM t WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t.a);"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_correlated_subquery,
|
||||
"SELECT a, (SELECT COUNT(*) FROM t2 WHERE t2.b = t.a) AS count_b FROM t"
|
||||
"SELECT a, (SELECT COUNT(*) FROM t2 WHERE t2.b = t.a) AS count_b FROM t;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_complex_order_by,
|
||||
"SELECT a, b FROM t ORDER BY CASE WHEN a IS NULL THEN 1 ELSE 0 END, b ASC, c DESC"
|
||||
"SELECT a, b FROM t ORDER BY CASE WHEN a IS NULL THEN 1 ELSE 0 END, b ASC, c DESC;"
|
||||
);
|
||||
|
||||
to_sql_string_test!(
|
||||
test_select_with_full_outer_join,
|
||||
"SELECT t1.a, t2.b FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id",
|
||||
"SELECT t1.a, t2.b FROM t1 FULL OUTER JOIN t2 ON t1.id = t2.id;",
|
||||
ignore = "OUTER JOIN is incorrectly parsed in parser"
|
||||
);
|
||||
|
||||
to_sql_string_test!(test_select_with_aggregate_window, "SELECT a, SUM(b) OVER (PARTITION BY c ORDER BY d ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS running_sum FROM t");
|
||||
to_sql_string_test!(test_select_with_aggregate_window, "SELECT a, SUM(b) OVER (PARTITION BY c ORDER BY d ROWS BETWEEN 1 PRECEDING AND 1 FOLLOWING) AS running_sum FROM t;");
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user