diff --git a/src/delete/delete_internal.rs b/src/delete/delete_internal.rs index 4f7f71d..589e69b 100644 --- a/src/delete/delete_internal.rs +++ b/src/delete/delete_internal.rs @@ -10,10 +10,23 @@ impl Concat for Delete { fn concat(&self, fmts: &fmt::Formatter) -> String { let mut query = "".to_string(); - query = self.concat_raw(query, &fmts, &self._raw); + #[cfg(not(any(feature = "postgresql", feature = "sqlite", feature = "mysql")))] + { + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_delete_from(query, &fmts); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + DeleteClause::Where, + &self._where, + ); + } - #[cfg(any(feature = "postgresql", feature = "sqlite", feature = "mysql"))] + #[cfg(feature = "postgresql")] { + query = self.concat_raw(query, &fmts, &self._raw); query = self.concat_with( &self._raw_before, &self._raw_after, @@ -22,15 +35,66 @@ impl Concat for Delete { DeleteClause::With, &self._with, ); + query = self.concat_delete_from(query, &fmts); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + DeleteClause::Where, + &self._where, + ); + query = self.concat_returning( + &self._raw_before, + &self._raw_after, + query, + &fmts, + DeleteClause::Returning, + &self._returning, + ); } - #[cfg(not(feature = "mysql"))] + #[cfg(feature = "sqlite")] { + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_with( + &self._raw_before, + &self._raw_after, + query, + &fmts, + DeleteClause::With, + &self._with, + ); query = self.concat_delete_from(query, &fmts); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + DeleteClause::Where, + &self._where, + ); + query = self.concat_returning( + &self._raw_before, + &self._raw_after, + query, + &fmts, + DeleteClause::Returning, + &self._returning, + ); } #[cfg(feature = "mysql")] { + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_with( + &self._raw_before, + &self._raw_after, + query, + &fmts, + DeleteClause::With, + &self._with, + ); query = self.concat_delete_from_mysql(query, &fmts); query = self.concat_join( &self._raw_before, @@ -48,19 +112,14 @@ impl Concat for Delete { DeleteClause::Partition, &self._partition, ); - } - - query = self.concat_where( - &self._raw_before, - &self._raw_after, - query, - &fmts, - DeleteClause::Where, - &self._where, - ); - - #[cfg(feature = "mysql")] - { + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + DeleteClause::Where, + &self._where, + ); query = self.concat_order_by( &self._raw_before, &self._raw_after, @@ -79,18 +138,6 @@ impl Concat for Delete { ); } - #[cfg(any(feature = "postgresql", feature = "sqlite"))] - { - query = self.concat_returning( - &self._raw_before, - &self._raw_after, - query, - &fmts, - DeleteClause::Returning, - &self._returning, - ); - } - query.trim_end().to_string() } } diff --git a/src/select/select_internal.rs b/src/select/select_internal.rs index 4b6238a..7d82fb4 100644 --- a/src/select/select_internal.rs +++ b/src/select/select_internal.rs @@ -18,10 +18,52 @@ impl Concat for Select { fn concat(&self, fmts: &fmt::Formatter) -> String { let mut query = "".to_string(); - query = self.concat_raw(query, &fmts, &self._raw); + #[cfg(not(any(feature = "postgresql", feature = "sqlite", feature = "mysql")))] + { + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_select(query, &fmts); + query = self.concat_from( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::From, + &self._from, + ); + query = self.concat_join( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Join, + &self._join, + ); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Where, + &self._where, + ); + query = self.concat_group_by(query, &fmts); + query = self.concat_having(query, &fmts); + query = self.concat_window(query, &fmts); + query = self.concat_order_by( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::OrderBy, + &self._order_by, + ); + } - #[cfg(any(feature = "postgresql", feature = "sqlite", feature = "mysql"))] + #[cfg(feature = "postgresql")] { + use crate::structure::Combinator; + + query = self.concat_raw(query, &fmts, &self._raw); query = self.concat_with( &self._raw_before, &self._raw_after, @@ -30,28 +72,149 @@ impl Concat for Select { SelectClause::With, &self._with, ); + query = self.concat_select(query, &fmts); + query = self.concat_from( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::From, + &self._from, + ); + query = self.concat_join( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Join, + &self._join, + ); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Where, + &self._where, + ); + query = self.concat_group_by(query, &fmts); + query = self.concat_having(query, &fmts); + query = self.concat_window(query, &fmts); + query = self.concat_order_by( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::OrderBy, + &self._order_by, + ); + query = self.concat_limit( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Limit, + &self._limit, + ); + query = self.concat_offset(query, &fmts); + query = self.concat_combinator(query, &fmts, Combinator::Except); + query = self.concat_combinator(query, &fmts, Combinator::Intersect); + query = self.concat_combinator(query, &fmts, Combinator::Union); } - query = self.concat_select(query, &fmts); - query = self.concat_from( - &self._raw_before, - &self._raw_after, - query, - &fmts, - SelectClause::From, - &self._from, - ); - query = self.concat_join( - &self._raw_before, - &self._raw_after, - query, - &fmts, - SelectClause::Join, - &self._join, - ); + #[cfg(feature = "sqlite")] + { + use crate::structure::Combinator; + + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_with( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::With, + &self._with, + ); + query = self.concat_select(query, &fmts); + query = self.concat_from( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::From, + &self._from, + ); + query = self.concat_join( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Join, + &self._join, + ); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Where, + &self._where, + ); + query = self.concat_group_by(query, &fmts); + query = self.concat_having(query, &fmts); + query = self.concat_window(query, &fmts); + query = self.concat_order_by( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::OrderBy, + &self._order_by, + ); + query = self.concat_limit( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Limit, + &self._limit, + ); + query = self.concat_offset(query, &fmts); + query = self.concat_combinator(query, &fmts, Combinator::Except); + query = self.concat_combinator(query, &fmts, Combinator::Intersect); + query = self.concat_combinator(query, &fmts, Combinator::Union); + } #[cfg(feature = "mysql")] { + use crate::structure::Combinator; + + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_with( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::With, + &self._with, + ); + query = self.concat_select(query, &fmts); + query = self.concat_from( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::From, + &self._from, + ); + query = self.concat_join( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Join, + &self._join, + ); query = self.concat_partition( &self._raw_before, &self._raw_after, @@ -60,30 +223,25 @@ impl Concat for Select { SelectClause::Partition, &self._partition, ); - } - - query = self.concat_where( - &self._raw_before, - &self._raw_after, - query, - &fmts, - SelectClause::Where, - &self._where, - ); - query = self.concat_group_by(query, &fmts); - query = self.concat_having(query, &fmts); - query = self.concat_window(query, &fmts); - query = self.concat_order_by( - &self._raw_before, - &self._raw_after, - query, - &fmts, - SelectClause::OrderBy, - &self._order_by, - ); - - #[cfg(any(feature = "postgresql", feature = "sqlite", feature = "mysql"))] - { + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::Where, + &self._where, + ); + query = self.concat_group_by(query, &fmts); + query = self.concat_having(query, &fmts); + query = self.concat_window(query, &fmts); + query = self.concat_order_by( + &self._raw_before, + &self._raw_after, + query, + &fmts, + SelectClause::OrderBy, + &self._order_by, + ); query = self.concat_limit( &self._raw_before, &self._raw_after, @@ -93,11 +251,6 @@ impl Concat for Select { &self._limit, ); query = self.concat_offset(query, &fmts); - } - - #[cfg(any(feature = "postgresql", feature = "sqlite", feature = "mysql"))] - { - use crate::structure::Combinator; query = self.concat_combinator(query, &fmts, Combinator::Except); query = self.concat_combinator(query, &fmts, Combinator::Intersect); query = self.concat_combinator(query, &fmts, Combinator::Union); diff --git a/src/update/update_internal.rs b/src/update/update_internal.rs index db2427a..7b67b51 100644 --- a/src/update/update_internal.rs +++ b/src/update/update_internal.rs @@ -16,10 +16,31 @@ impl Concat for Update { fn concat(&self, fmts: &fmt::Formatter) -> String { let mut query = "".to_string(); - query = self.concat_raw(query, &fmts, &self._raw); + #[cfg(not(any(feature = "postgresql", feature = "sqlite", feature = "mysql")))] + { + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_update(query, &fmts); + query = self.concat_set( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Set, + &self._set, + ); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Where, + &self._where, + ); + } - #[cfg(any(feature = "postgresql", feature = "sqlite"))] + #[cfg(feature = "postgresql")] { + query = self.concat_raw(query, &fmts, &self._raw); query = self.concat_with( &self._raw_before, &self._raw_after, @@ -28,29 +49,61 @@ impl Concat for Update { UpdateClause::With, &self._with, ); - } - - #[cfg(not(feature = "sqlite"))] - { query = self.concat_update(query, &fmts); + query = self.concat_set( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Set, + &self._set, + ); + query = self.concat_from( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::From, + &self._from, + ); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Where, + &self._where, + ); + query = self.concat_returning( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Returning, + &self._returning, + ); } #[cfg(feature = "sqlite")] { + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_with( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::With, + &self._with, + ); query = self.concat_update(&self._raw_before, &self._raw_after, query, &fmts, &self._update); - } - - query = self.concat_set( - &self._raw_before, - &self._raw_after, - query, - &fmts, - UpdateClause::Set, - &self._set, - ); - - #[cfg(any(feature = "postgresql", feature = "sqlite"))] - { + query = self.concat_set( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Set, + &self._set, + ); query = self.concat_from( &self._raw_before, &self._raw_after, @@ -59,10 +112,6 @@ impl Concat for Update { UpdateClause::From, &self._from, ); - } - - #[cfg(feature = "sqlite")] - { query = self.concat_join( &self._raw_before, &self._raw_after, @@ -71,19 +120,44 @@ impl Concat for Update { UpdateClause::Join, &self._join, ); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Where, + &self._where, + ); + query = self.concat_returning( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Returning, + &self._returning, + ); } - query = self.concat_where( - &self._raw_before, - &self._raw_after, - query, - &fmts, - UpdateClause::Where, - &self._where, - ); - #[cfg(feature = "mysql")] { + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_update(query, &fmts); + query = self.concat_set( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Set, + &self._set, + ); + query = self.concat_where( + &self._raw_before, + &self._raw_after, + query, + &fmts, + UpdateClause::Where, + &self._where, + ); query = self.concat_order_by( &self._raw_before, &self._raw_after, @@ -102,18 +176,6 @@ impl Concat for Update { ); } - #[cfg(any(feature = "postgresql", feature = "sqlite"))] - { - query = self.concat_returning( - &self._raw_before, - &self._raw_after, - query, - &fmts, - UpdateClause::Returning, - &self._returning, - ); - } - query.trim_end().to_string() } } diff --git a/tests/command_alter_table_spec.rs b/tests/command_alter_table_spec.rs index babcc45..c7d3532 100644 --- a/tests/command_alter_table_spec.rs +++ b/tests/command_alter_table_spec.rs @@ -1,3 +1,100 @@ +mod full_api { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[cfg(not(any(feature = "postgresql", feature = "mysql")))] + #[test] + fn sql_standard_with_all_methods() { + let query = sql::AlterTable::new() + // required + .alter_table("users") + // at least one + .add("COLUMN age int not null") + .drop("column login") + .as_string(); + + let expected_query = "\ + ALTER TABLE users \ + DROP column login\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "postgresql")] + #[test] + fn postgres_with_all_methods() { + let query = sql::AlterTable::new() + // required + .alter_table("users") + // at least one + .add("COLUMN age int not null") + .alter("COLUMN created_at SET DEFAULT now()") + .drop("column login") + .rename("COLUMN address TO city") + .rename_to("users_old") + .as_string(); + + let expected_query = "\ + ALTER TABLE users \ + RENAME COLUMN address TO city \ + RENAME TO users_old \ + ADD COLUMN age int not null, \ + ALTER COLUMN created_at SET DEFAULT now(), \ + DROP column login\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "sqlite")] + #[test] + fn sqlite_with_all_methods() { + let query = sql::AlterTable::new() + // required + .alter_table("users") + // at least one + .add("COLUMN age int not null") + .drop("column login") + .rename("COLUMN address TO city") + .rename_to("users_old") + .as_string(); + + let expected_query = "\ + ALTER TABLE users \ + RENAME COLUMN address TO city \ + RENAME TO users_old \ + DROP column login\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "mysql")] + #[test] + fn mysql_with_all_methods() { + let query = sql::AlterTable::new() + // required + .alter_table("users") + // at least one + .add("COLUMN age int not null") + .alter("COLUMN created_at SET DEFAULT now()") + .drop("column login") + .rename("COLUMN address TO city") + .as_string(); + + let expected_query = "\ + ALTER TABLE users \ + ADD COLUMN age int not null, \ + ALTER COLUMN created_at SET DEFAULT now(), \ + DROP column login, \ + RENAME COLUMN address TO city\ + "; + + assert_eq!(expected_query, query); + } +} + mod builder_features { use pretty_assertions::assert_eq; use sql_query_builder as sql; diff --git a/tests/command_create_table_spec.rs b/tests/command_create_table_spec.rs index f90a55e..6d570f9 100644 --- a/tests/command_create_table_spec.rs +++ b/tests/command_create_table_spec.rs @@ -1,16 +1,41 @@ -#[cfg(any(feature = "postgresql", feature = "sqlite", feature = "mysql"))] mod full_api { use pretty_assertions::assert_eq; use sql_query_builder as sql; + #[test] + fn sql_standard_with_all_methods() { + let query = sql::CreateTable::new() + // at least one + .create_table("users") + .create_table_if_not_exists("users") + // required + .column("id serial, login varchar(100) not null") + // optional + .primary_key("(id)") + .foreign_key("(address_id) references addresses(id)") + .constraint("login users_login_key unique(login)") + .as_string(); + + let expected_query = "\ + CREATE TABLE IF NOT EXISTS users (\ + id serial, login varchar(100) not null, \ + PRIMARY KEY(id), \ + CONSTRAINT login users_login_key unique(login), \ + FOREIGN KEY(address_id) references addresses(id)\ + )\ + "; + + assert_eq!(expected_query, query); + } + #[cfg(feature = "postgresql")] #[test] fn postgres_with_all_methods() { let query = sql::CreateTable::new() - // at least one of methods + // at least one .create_table("users") .create_table_if_not_exists("users") - // optional methods + // optional .column("id serial, login varchar(100) not null") .primary_key("(id)") .foreign_key("(address_id) references addresses(id)") @@ -33,12 +58,12 @@ mod full_api { #[test] fn sqlite_with_all_methods() { let query = sql::CreateTable::new() - // at least one of methods + // at least one .create_table("users") .create_table_if_not_exists("users") - // required methods + // required .column("id integer, login varchar(100) not null") - // optional methods + // optional .primary_key("(id)") .foreign_key("(address_id) references addresses(id)") .constraint("login users_login_key unique(login)") @@ -63,8 +88,9 @@ mod full_api { // at least one of methods .create_table("users") .create_table_if_not_exists("users") - // optional methods + // required .column("id int not null auto_increment, login varchar(100) not null") + // optional methods .primary_key("(id)") .foreign_key("(address_id) references addresses(id)") .constraint("login users_login_key unique(login)") diff --git a/tests/command_delete_spec.rs b/tests/command_delete_spec.rs index c3cffe1..f5f1164 100644 --- a/tests/command_delete_spec.rs +++ b/tests/command_delete_spec.rs @@ -1,3 +1,140 @@ +mod full_api { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn sql_standard_with_all_methods() { + let query = sql::Delete::new() + // required + .delete_from("orders") + // at least one + .where_clause("login = $1") + .where_and("product_id = $2") + .where_or("login = 'bar'") + .as_string(); + + let expected_query = "\ + DELETE FROM orders \ + WHERE login = $1 \ + AND product_id = $2 \ + OR login = 'bar'\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "postgresql")] + #[test] + fn postgres_with_all_methods() { + let deactivated_users = sql::Select::new() + .select("id") + .from("users") + .where_clause("ative = false"); + + let query = sql::Delete::new() + // required + .delete_from("orders") + // at least one is required + .where_clause("login = $1") + .where_and("product_id = $2") + .where_or("login = 'bar'") + // optional + .returning("id") + .with("deactivated_users", deactivated_users) + .as_string(); + + let expected_query = "\ + WITH deactivated_users AS (SELECT id FROM users WHERE ative = false) \ + DELETE FROM orders \ + WHERE login = $1 \ + AND product_id = $2 \ + OR login = 'bar' \ + RETURNING id\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "sqlite")] + #[test] + fn sqlite_with_all_methods() { + let deactivated_users = sql::Select::new() + .select("id") + .from("users") + .where_clause("ative = false"); + + let query = sql::Delete::new() + // required + .delete_from("orders") + // at least one is required + .where_clause("login = $1") + .where_and("product_id = $2") + .where_or("login = 'bar'") + // optional + .returning("id") + .with("deactivated_users", deactivated_users) + .as_string(); + + let expected_query = "\ + WITH deactivated_users AS (SELECT id FROM users WHERE ative = false) \ + DELETE FROM orders \ + WHERE login = $1 \ + AND product_id = $2 \ + OR login = 'bar' \ + RETURNING id\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "mysql")] + #[test] + fn mysql_with_all_methods() { + let deactivated_users = sql::Select::new() + .select("id") + .from("users") + .where_clause("ative = false"); + + let query = sql::Delete::new() + // one of is required + .delete_from("orders") + // methods below as a group + .delete("low_priority") + .from("address") + // at least one is required + .where_clause("login = $1") + .where_and("product_id = $2") + .where_or("login = 'bar'") + // optional + .cross_join("addresses") + .inner_join("addresses on addresses.user_login = users.login") + .left_join("addresses on addresses.user_login = users.login") + .limit("123") + .order_by("created_at asc") + .partition("p1") + .right_join("addresses on addresses.user_login = users.login") + .with("deactivated_users", deactivated_users) + .as_string(); + + let expected_query = "\ + WITH deactivated_users AS (SELECT id FROM users WHERE ative = false) \ + DELETE low_priority FROM orders, address \ + CROSS JOIN addresses \ + INNER JOIN addresses on addresses.user_login = users.login \ + LEFT JOIN addresses on addresses.user_login = users.login \ + RIGHT JOIN addresses on addresses.user_login = users.login \ + PARTITION (p1) \ + WHERE login = $1 \ + AND product_id = $2 \ + OR login = 'bar' \ + ORDER BY created_at asc \ + LIMIT 123\ + "; + + assert_eq!(expected_query, query); + } +} + mod builder_features { use pretty_assertions::assert_eq; use sql_query_builder as sql; diff --git a/tests/command_select_spec.rs b/tests/command_select_spec.rs index f57d4ac..122640c 100644 --- a/tests/command_select_spec.rs +++ b/tests/command_select_spec.rs @@ -1,3 +1,225 @@ +mod full_api { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn sql_standard_with_all_methods() { + let query = sql::Select::new() + // required + .select("login, name, status") + // optional + .from("users") + .group_by("login") + .having("status != 'disabled'") + .cross_join("addresses") + .inner_join("addresses on addresses.user_login = users.login") + .left_join("addresses on addresses.user_login = users.login") + .right_join("addresses on addresses.user_login = users.login") + .order_by("login asc") + .where_clause("login = $1") + .where_and("login in ($2)") + .where_or("login in ($3)") + .window("win as (partition by department)") + .as_string(); + + let expected_query = "\ + SELECT login, name, status \ + FROM users \ + CROSS JOIN addresses \ + INNER JOIN addresses on addresses.user_login = users.login \ + LEFT JOIN addresses on addresses.user_login = users.login \ + RIGHT JOIN addresses on addresses.user_login = users.login \ + WHERE login = $1 \ + AND login in ($2) \ + OR login in ($3) \ + GROUP BY login \ + HAVING status != 'disabled' \ + WINDOW win as (partition by department) \ + ORDER BY login asc\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "postgresql")] + #[test] + fn postgres_with_all_methods() { + let query = sql::Select::new() + // required + .select("login, name, status") + // optional + .from("users") + .group_by("login") + .having("status != 'disabled'") + .cross_join("addresses") + .inner_join("addresses on addresses.user_login = users.login") + .left_join("addresses on addresses.user_login = users.login") + .right_join("addresses on addresses.user_login = users.login") + .order_by("login asc") + .where_clause("login = $1") + .where_and("login in ($2)") + .where_or("login in ($3)") + .window("win as (partition by department)") + .limit("1") + .offset("10") + .except(sql::Select::new().select("login, name, status")) + .intersect(sql::Select::new().select("login, name, status")) + .union(sql::Select::new().select("login, name, status")) + .with("foo", sql::Select::new().select("login, name, status")) + .as_string(); + + let expected_query = "\ + (((\ + WITH foo AS (SELECT login, name, status) \ + SELECT login, name, status \ + FROM users \ + CROSS JOIN addresses \ + INNER JOIN addresses on addresses.user_login = users.login \ + LEFT JOIN addresses on addresses.user_login = users.login \ + RIGHT JOIN addresses on addresses.user_login = users.login \ + WHERE login = $1 \ + AND login in ($2) \ + OR login in ($3) \ + GROUP BY login \ + HAVING status != 'disabled' \ + WINDOW win as (partition by department) \ + ORDER BY login asc \ + LIMIT 1 \ + OFFSET 10\ + ) \ + EXCEPT \ + (SELECT login, name, status)\ + ) \ + INTERSECT \ + (SELECT login, name, status)\ + ) \ + UNION \ + (SELECT login, name, status)\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "sqlite")] + #[test] + fn sqlite_with_all_methods() { + let query = sql::Select::new() + // required + .select("login, name, status") + // optional + .from("users") + .group_by("login") + .having("status != 'disabled'") + .cross_join("addresses") + .inner_join("addresses on addresses.user_login = users.login") + .left_join("addresses on addresses.user_login = users.login") + .right_join("addresses on addresses.user_login = users.login") + .order_by("login asc") + .where_clause("login = $1") + .where_and("login in ($2)") + .where_or("login in ($3)") + .window("win as (partition by department)") + .limit("1") + .offset("10") + .except(sql::Select::new().select("login, name, status")) + .intersect(sql::Select::new().select("login, name, status")) + .union(sql::Select::new().select("login, name, status")) + .with("foo", sql::Select::new().select("login, name, status")) + .as_string(); + + let expected_query = "\ + (((\ + WITH foo AS (SELECT login, name, status) \ + SELECT login, name, status \ + FROM users \ + CROSS JOIN addresses \ + INNER JOIN addresses on addresses.user_login = users.login \ + LEFT JOIN addresses on addresses.user_login = users.login \ + RIGHT JOIN addresses on addresses.user_login = users.login \ + WHERE login = $1 \ + AND login in ($2) \ + OR login in ($3) \ + GROUP BY login \ + HAVING status != 'disabled' \ + WINDOW win as (partition by department) \ + ORDER BY login asc \ + LIMIT 1 \ + OFFSET 10\ + ) \ + EXCEPT \ + (SELECT login, name, status)\ + ) \ + INTERSECT \ + (SELECT login, name, status)\ + ) \ + UNION \ + (SELECT login, name, status)\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "mysql")] + #[test] + fn mysql_with_all_methods() { + let query = sql::Select::new() + // required + .select("login, name, status") + // optional + .from("users") + .group_by("login") + .having("status != 'disabled'") + .cross_join("addresses") + .inner_join("addresses on addresses.user_login = users.login") + .left_join("addresses on addresses.user_login = users.login") + .right_join("addresses on addresses.user_login = users.login") + .partition("p1") + .order_by("login asc") + .where_clause("login = $1") + .where_and("login in ($2)") + .where_or("login in ($3)") + .window("win as (partition by department)") + .limit("1") + .offset("10") + .except(sql::Select::new().select("login, name, status")) + .intersect(sql::Select::new().select("login, name, status")) + .union(sql::Select::new().select("login, name, status")) + .with("foo", sql::Select::new().select("login, name, status")) + .as_string(); + + let expected_query = "\ + (((\ + WITH foo AS (SELECT login, name, status) \ + SELECT login, name, status \ + FROM users \ + CROSS JOIN addresses \ + INNER JOIN addresses on addresses.user_login = users.login \ + LEFT JOIN addresses on addresses.user_login = users.login \ + RIGHT JOIN addresses on addresses.user_login = users.login \ + PARTITION (p1) \ + WHERE login = $1 \ + AND login in ($2) \ + OR login in ($3) \ + GROUP BY login \ + HAVING status != 'disabled' \ + WINDOW win as (partition by department) \ + ORDER BY login asc \ + LIMIT 1 \ + OFFSET 10\ + ) \ + EXCEPT \ + (SELECT login, name, status)\ + ) \ + INTERSECT \ + (SELECT login, name, status)\ + ) \ + UNION \ + (SELECT login, name, status)\ + "; + + assert_eq!(expected_query, query); + } +} mod builder_features { use pretty_assertions::assert_eq; use sql_query_builder as sql; diff --git a/tests/command_update_spec.rs b/tests/command_update_spec.rs index 06aae2d..1148c79 100644 --- a/tests/command_update_spec.rs +++ b/tests/command_update_spec.rs @@ -1,3 +1,129 @@ +mod full_api { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn sql_standard_with_all_methods() { + let query = sql::Update::new() + // required + .update("orders") + .set("name = 'Foo'") + // optional + .where_clause("login = $1") + .where_and("product_id = $2") + .where_or("ref_id = $3") + .as_string(); + + let expected_query = "\ + UPDATE orders \ + SET name = 'Foo' \ + WHERE login = $1 \ + AND product_id = $2 \ + OR ref_id = $3\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "postgresql")] + #[test] + fn postgres_with_all_methods() { + let query = sql::Update::new() + // required + .update("orders") + .set("name = 'Foo'") + // optional + .with("foo", sql::Select::new().select("login")) + .from("products p") + .where_clause("login = $1") + .where_and("product_id = $2") + .where_or("p.ref_id = $3") + .returning("*") + .as_string(); + + let expected_query = "\ + WITH foo AS (SELECT login) \ + UPDATE orders \ + SET name = 'Foo' \ + FROM products p \ + WHERE login = $1 \ + AND product_id = $2 \ + OR p.ref_id = $3 \ + RETURNING *\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "sqlite")] + #[test] + fn sqlite_with_all_methods() { + let query = sql::Update::new() + // one of is required + .update("orders") + .update_or("users") + // required + .set("name = 'Foo'") + // optional + .with("foo", sql::Select::new().select("login")) + .from("products p") + .cross_join("addresses") + .inner_join("addresses on addresses.user_login = users.login") + .left_join("addresses on addresses.user_login = users.login") + .right_join("addresses on addresses.user_login = users.login") + .where_clause("login = $1") + .where_and("product_id = $2") + .where_or("p.ref_id = $3") + .returning("*") + .as_string(); + + let expected_query = "\ + WITH foo AS (SELECT login) \ + UPDATE OR users \ + SET name = 'Foo' \ + FROM products p \ + CROSS JOIN addresses \ + INNER JOIN addresses on addresses.user_login = users.login \ + LEFT JOIN addresses on addresses.user_login = users.login \ + RIGHT JOIN addresses on addresses.user_login = users.login \ + WHERE login = $1 \ + AND product_id = $2 \ + OR p.ref_id = $3 \ + RETURNING *\ + "; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "mysql")] + #[test] + fn mysql_with_all_methods() { + let query = sql::Update::new() + // required + .update("orders") + .set("name = 'Foo'") + // optional + .where_clause("login = $1") + .where_and("product_id = $2") + .where_or("ref_id = $3") + .order_by("id desc") + .limit("1") + .as_string(); + + let expected_query = "\ + UPDATE orders \ + SET name = 'Foo' \ + WHERE login = $1 \ + AND product_id = $2 \ + OR ref_id = $3 \ + ORDER BY id desc \ + LIMIT 1\ + "; + + assert_eq!(expected_query, query); + } +} + mod builder_features { use pretty_assertions::assert_eq; use sql_query_builder as sql;