From 0a5df7af3a5f577280669eb24a825cd987d6b8cc Mon Sep 17 00:00:00 2001 From: Belchior Oliveira Date: Sat, 7 Sep 2024 15:36:31 -0300 Subject: [PATCH 1/2] Adds drop index command --- src/drop_index/drop_index.rs | 271 ++++++++++++++++++ src/drop_index/drop_index_internal.rs | 51 ++++ src/drop_index/mod.rs | 2 + src/drop_table/drop_table.rs | 6 +- src/fmt.rs | 2 + src/lib.rs | 6 + src/select/select_internal.rs | 5 +- src/structure.rs | 40 +++ src/transaction/transaction.rs | 43 +++ tests/command_drop_index_spec.rs | 397 ++++++++++++++++++++++++++ tests/command_drop_table_spec.rs | 74 ++--- tests/command_transaction_spec.rs | 29 ++ 12 files changed, 886 insertions(+), 40 deletions(-) create mode 100644 src/drop_index/drop_index.rs create mode 100644 src/drop_index/drop_index_internal.rs create mode 100644 src/drop_index/mod.rs create mode 100644 tests/command_drop_index_spec.rs diff --git a/src/drop_index/drop_index.rs b/src/drop_index/drop_index.rs new file mode 100644 index 0000000..685d5b4 --- /dev/null +++ b/src/drop_index/drop_index.rs @@ -0,0 +1,271 @@ +use crate::{ + behavior::{push_unique, Concat, TransactionQuery}, + fmt, + structure::{DropIndex, DropIndexParams}, +}; + +impl TransactionQuery for DropIndex {} + +impl DropIndex { + /// Gets the current state of the [DropIndex] and returns it as string + /// + /// ### Example + /// + /// ``` + /// # use sql_query_builder as sql; + /// let query = sql::DropIndex::new() + /// .drop_index("users_name_idx") + /// .as_string(); + /// + /// # let expected = "DROP INDEX users_name_idx"; + /// # assert_eq!(expected, query); + /// ``` + /// + /// Output + /// + /// ```sql + /// DROP INDEX users_name_idx + /// ``` + pub fn as_string(&self) -> String { + let fmts = fmt::one_line(); + self.concat(&fmts) + } + + /// Defines a drop index command, this method overrides the previous value + /// + /// ### Example 1 + /// + ///``` + /// # #[cfg(not(feature = "postgresql"))] + /// # { + /// # use sql_query_builder as sql; + /// let query = sql::DropIndex::new() + /// .drop_index("users_name_idx") + /// .drop_index("orders_product_name_idx") + /// .as_string(); + /// + /// # let expected = "DROP INDEX orders_product_name_idx"; + /// # assert_eq!(expected, query); + /// # } + /// ``` + /// + /// Outputs + /// + /// ```sql + /// DROP INDEX orders_product_name_idx + /// ``` + /// + /// ### Example 2 `crate features postgresql only` + /// + /// Multiples call will concatenates all values + /// + ///``` + /// # #[cfg(feature = "postgresql")] + /// # { + /// # use sql_query_builder as sql; + /// let query = sql::DropIndex::new() + /// .drop_index("users_name_idx") + /// .drop_index("orders_product_name_idx") + /// .as_string(); + /// + /// # let expected = "DROP INDEX users_name_idx, orders_product_name_idx"; + /// # assert_eq!(expected, query); + /// # } + /// ``` + /// + /// Outputs + /// + /// ```sql + /// DROP INDEX users_name_idx, orders_product_name_idx + /// ``` + pub fn drop_index(mut self, table_name: &str) -> Self { + push_unique(&mut self._drop_index, table_name.trim().to_string()); + self + } + + /// Defines a drop index comand with the modifer `if exists`, this method overrides the previous value + /// + /// ### Example 1 + /// + /// ``` + /// # #[cfg(not(feature = "postgresql"))] + /// # { + /// # use sql_query_builder as sql; + /// let query = sql::DropIndex::new() + /// .drop_index("users_name_idx") + /// .drop_index_if_exists("orders_product_name_idx") + /// .to_string(); + /// + /// # let expected = "DROP INDEX IF EXISTS orders_product_name_idx"; + /// # assert_eq!(expected, query); + /// # } + /// ``` + /// + /// Outputs + /// + /// ```sql + /// DROP INDEX IF EXISTS orders_product_name_idx + /// ``` + /// + /// ### Example 2 `crate features postgresql only` + /// + /// Multiples call will concatenates all values + /// + /// ``` + /// # #[cfg(feature = "postgresql")] + /// # { + /// # use sql_query_builder as sql; + /// let query = sql::DropIndex::new() + /// .drop_index("users_name_idx") + /// .drop_index_if_exists("orders_product_name_idx") + /// .to_string(); + /// + /// # let expected = "DROP INDEX IF EXISTS users_name_idx, orders_product_name_idx"; + /// # assert_eq!(expected, query); + /// # } + /// ``` + /// + /// Outputs + /// + /// ```sql + /// DROP INDEX IF EXISTS users_name_idx, orders_product_name_idx + /// ``` + pub fn drop_index_if_exists(mut self, table_name: &str) -> Self { + push_unique(&mut self._drop_index, table_name.trim().to_string()); + self._if_exists = true; + self + } + + /// Prints the current state of the [DropIndex] to the standard output in a more ease to read version. + /// This method is useful to debug complex queries or just print the generated SQL while you type + /// + /// ### Example + /// + /// ``` + /// # use sql_query_builder as sql; + /// let query = sql::DropIndex::new() + /// .drop_index("users_name_idx") + /// .debug() + /// .as_string(); + /// ``` + /// + /// Prints to the standard output + /// + /// ```sql + /// -- ------------------------------------------------------------------------------ + /// DROP INDEX users_name_idx + /// -- ------------------------------------------------------------------------------ + /// ``` + pub fn debug(self) -> Self { + let fmts = fmt::multiline(); + println!("{}", fmt::format(self.concat(&fmts), &fmts)); + self + } + + /// Creates instance of the [DropIndex] command + pub fn new() -> Self { + Self::default() + } + + /// Prints the current state of the [DropIndex] to the standard output similar to debug method, + /// the difference is that this method prints in one line. + pub fn print(self) -> Self { + let fmts = fmt::one_line(); + println!("{}", fmt::format(self.concat(&fmts), &fmts)); + self + } + + /// Adds at the beginning a raw SQL query. Is useful to create a more complex drop index signature like the example below. + /// + /// ### Example + /// + /// ``` + /// # use sql_query_builder as sql; + /// let drop_index_query = sql::DropIndex::new() + /// .raw("/* drop index command */") + /// .drop_index("users_name_idx") + /// .as_string(); + /// + /// # let expected = "/* drop index command */ DROP INDEX users_name_idx"; + /// # assert_eq!(expected, drop_index_query); + /// ``` + /// + /// Output + /// + /// ```sql + /// /* drop index command */ DROP INDEX users_name_idx + /// ``` + pub fn raw(mut self, raw_sql: &str) -> Self { + push_unique(&mut self._raw, raw_sql.trim().to_string()); + self + } + + /// Adds a raw SQL query after a specified parameter. + /// + /// The `DropIndexParams::DropIndex` works for both `.drop_index` and `.drop_index_if_exist` methods + /// + /// ### Example + /// + /// ``` + /// # use sql_query_builder as sql; + /// let query = sql::DropIndex::new() + /// .drop_index("users_name_idx") + /// .raw_after(sql::DropIndexParams::DropIndex, "/* end drop index */") + /// .as_string(); + /// + /// # let expected = "DROP INDEX users_name_idx /* end drop index */"; + /// # assert_eq!(expected, query); + /// ``` + /// + /// Output + /// + /// ```sql + /// DROP INDEX users_name_idx /* end drop index */ + /// ``` + pub fn raw_after(mut self, param: DropIndexParams, raw_sql: &str) -> Self { + self._raw_after.push((param, raw_sql.trim().to_string())); + self + } + + /// Adds a raw SQL query before a specified parameter. + /// + /// The `DropIndexParams::DropIndex` works for both `.drop_index` and `.drop_index_if_exist` methods + /// + /// ### Example + /// + /// ``` + /// # use sql_query_builder as sql; + /// let raw = "/* drop index command */"; + /// + /// let query = sql::DropIndex::new() + /// .raw_before(sql::DropIndexParams::DropIndex, raw) + /// .drop_index("users_name_idx") + /// .as_string(); + /// + /// # let expected = "/* drop index command */ DROP INDEX users_name_idx"; + /// # assert_eq!(expected, query); + /// ``` + /// + /// Output + /// + /// ```sql + /// /* drop index command */ DROP INDEX users_name_idx + /// ``` + pub fn raw_before(mut self, param: DropIndexParams, raw_sql: &str) -> Self { + self._raw_before.push((param, raw_sql.trim().to_string())); + self + } +} + +impl std::fmt::Display for DropIndex { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.as_string()) + } +} + +impl std::fmt::Debug for DropIndex { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + let fmts = fmt::multiline(); + write!(f, "{}", fmt::format(self.concat(&fmts), &fmts)) + } +} diff --git a/src/drop_index/drop_index_internal.rs b/src/drop_index/drop_index_internal.rs new file mode 100644 index 0000000..7a46537 --- /dev/null +++ b/src/drop_index/drop_index_internal.rs @@ -0,0 +1,51 @@ +use crate::{ + behavior::{concat_raw_before_after, Concat, ConcatSqlStandard}, + fmt, + structure::{DropIndex, DropIndexParams}, +}; + +impl ConcatSqlStandard for DropIndex {} + +impl DropIndex { + fn concat_drop_index(&self, query: String, fmts: &fmt::Formatter) -> String { + let fmt::Formatter { comma, lb, space, .. } = fmts; + + let sql = if self._drop_index.len() != 0 { + let if_exists = if self._if_exists { + format!("IF EXISTS{space}") + } else { + "".to_string() + }; + + let index_names = if cfg!(any(feature = "postgresql")) { + self._drop_index.join(comma) + } else { + self._drop_index.last().unwrap().to_string() + }; + + format!("DROP INDEX{space}{if_exists}{index_names}{space}{lb}") + } else { + "".to_string() + }; + + concat_raw_before_after( + &self._raw_before, + &self._raw_after, + query, + fmts, + DropIndexParams::DropIndex, + sql, + ) + } +} + +impl Concat for DropIndex { + fn concat(&self, fmts: &fmt::Formatter) -> String { + let mut query = "".to_string(); + + query = self.concat_raw(query, &fmts, &self._raw); + query = self.concat_drop_index(query, &fmts); + + query.trim_end().to_string() + } +} diff --git a/src/drop_index/mod.rs b/src/drop_index/mod.rs new file mode 100644 index 0000000..d077c48 --- /dev/null +++ b/src/drop_index/mod.rs @@ -0,0 +1,2 @@ +mod drop_index; +mod drop_index_internal; diff --git a/src/drop_table/drop_table.rs b/src/drop_table/drop_table.rs index ffc291b..2702eb7 100644 --- a/src/drop_table/drop_table.rs +++ b/src/drop_table/drop_table.rs @@ -210,17 +210,17 @@ impl DropTable { /// # use sql_query_builder as sql; /// let query = sql::DropTable::new() /// .drop_table("users") - /// .raw_after(sql::DropTableParams::DropTable, "CASCADE RESTRICT") + /// .raw_after(sql::DropTableParams::DropTable, "CASCADE") /// .as_string(); /// - /// # let expected = "DROP TABLE users CASCADE RESTRICT"; + /// # let expected = "DROP TABLE users CASCADE"; /// # assert_eq!(expected, query); /// ``` /// /// Output /// /// ```sql - /// DROP TABLE users CASCADE RESTRICT + /// DROP TABLE users CASCADE /// ``` pub fn raw_after(mut self, param: DropTableParams, raw_sql: &str) -> Self { self._raw_after.push((param, raw_sql.trim().to_string())); diff --git a/src/fmt.rs b/src/fmt.rs index 1133be6..3720fb7 100644 --- a/src/fmt.rs +++ b/src/fmt.rs @@ -40,11 +40,13 @@ pub fn colorize(query: String) -> String { (blue, "DEFERRABLE", "deferrable"), (blue, "DELETE ", "delete "), (blue, "DISTINCT", "distinct"), + (blue, "DROP", "drop"), (blue, "EXCEPT", "except"), (blue, "EXISTS", "exists"), (blue, "FROM ", "from "), (blue, "GROUP BY", "group by"), (blue, "HAVING", "having"), + (blue, "INDEX", "index"), (blue, "INNER", "inner"), (blue, "INSERT", "insert"), (blue, "INTERSECT", "intersect"), diff --git a/src/lib.rs b/src/lib.rs index 48d0e28..70116d5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,3 +18,9 @@ pub use crate::structure::{ AlterTable, AlterTableAction, CreateTable, CreateTableParams, Delete, DeleteClause, DropTable, DropTableParams, Insert, InsertClause, Select, SelectClause, Transaction, Update, UpdateClause, Values, ValuesClause, }; + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +mod drop_index; + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +pub use crate::structure::{DropIndex, DropIndexParams}; diff --git a/src/select/select_internal.rs b/src/select/select_internal.rs index f4fb8dc..9735382 100644 --- a/src/select/select_internal.rs +++ b/src/select/select_internal.rs @@ -1,11 +1,12 @@ -#[cfg(any(feature = "postgresql", feature = "sqlite"))] -use crate::behavior::ConcatCommon; use crate::{ behavior::{concat_raw_before_after, Concat, ConcatSqlStandard}, fmt, structure::{Select, SelectClause}, }; +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +use crate::behavior::ConcatCommon; + impl ConcatSqlStandard for Select {} impl Concat for Select { diff --git a/src/structure.rs b/src/structure.rs index e82d9ac..011b615 100644 --- a/src/structure.rs +++ b/src/structure.rs @@ -136,6 +136,46 @@ pub enum CreateTableParams { PrimaryKey, } +/// Builder to contruct a [DropIndex] command. This command is available only for the crate features `postgresql` and `sqlite` +/// +/// Basic API +/// ``` +/// # #[cfg(any(feature = "postgresql", feature = "sqlite"))] +/// # { +/// use sql_query_builder as sql; +/// +/// let query = sql::DropIndex::new() +/// .drop_index("users_name_idx") +/// .as_string(); +/// +/// # let expected = "DROP INDEX users_name_idx"; +/// # assert_eq!(expected, query); +/// # } +/// ``` +/// +/// +/// Output +/// +/// ```sql +/// DROP INDEX users_name_idx +/// ``` +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +#[derive(Default, Clone)] +pub struct DropIndex { + pub(crate) _drop_index: Vec, + pub(crate) _if_exists: bool, + pub(crate) _raw_after: Vec<(DropIndexParams, String)>, + pub(crate) _raw_before: Vec<(DropIndexParams, String)>, + pub(crate) _raw: Vec, +} + +/// All available params to be used in [DropIndex::raw_before] and [DropIndex::raw_after] methods on [DropIndex] builder +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +#[derive(PartialEq, Clone)] +pub enum DropIndexParams { + DropIndex, +} + /// Builder to contruct a [DropTable] command /// /// Basic API diff --git a/src/transaction/transaction.rs b/src/transaction/transaction.rs index 759c725..409da11 100644 --- a/src/transaction/transaction.rs +++ b/src/transaction/transaction.rs @@ -6,6 +6,9 @@ use crate::{ }, }; +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +use crate::structure::DropIndex; + impl Transaction { /// Gets the current state of the [Transaction] and returns it as string /// @@ -227,6 +230,46 @@ impl Transaction { self } + /// The `drop index` command, access the [DropIndex] for more info + /// + /// # Example + /// + /// ``` + /// # #[cfg(not(feature = "sqlite"))] + /// # { + /// # use sql_query_builder as sql; + /// let drop_index_name = sql::DropIndex::new() + /// .drop_index("users_name_idx"); + /// + /// let query = sql::Transaction::new() + /// .start_transaction("") + /// .drop_index(drop_index_name) + /// .commit("") + /// .as_string(); + /// + /// # let expected = "\ + /// # START TRANSACTION; \ + /// # DROP INDEX users_name_idx; \ + /// # COMMIT;\ + /// # "; + /// # assert_eq!(expected, query); + /// # } + /// ``` + /// + /// Output (indented for readability) + /// + /// ```sql + /// START TRANSACTION; + /// DROP INDEX users_name_idx; + /// COMMIT; + /// ``` + #[cfg(any(feature = "postgresql", feature = "sqlite"))] + pub fn drop_index(mut self, drop_index: DropIndex) -> Self { + let cmd = Box::new(drop_index); + self._ordered_commands.push(cmd); + self + } + /// The `drop table` command, access the [DropTable] for more info /// /// # Example diff --git a/tests/command_drop_index_spec.rs b/tests/command_drop_index_spec.rs new file mode 100644 index 0000000..bb75fed --- /dev/null +++ b/tests/command_drop_index_spec.rs @@ -0,0 +1,397 @@ +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +mod builder_features { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn drop_index_builder_should_be_displayable() { + let drop_index = sql::DropIndex::new().drop_index("users_name_idx"); + + println!("{}", drop_index); + + let query = drop_index.as_string(); + let expected_query = "DROP INDEX users_name_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn drop_index_builder_should_be_debuggable() { + let drop_index = sql::DropIndex::new().drop_index("users_name_idx"); + + println!("{:?}", drop_index); + + let expected_query = "DROP INDEX users_name_idx"; + let query = drop_index.as_string(); + + assert_eq!(expected_query, query); + } + + #[cfg(not(feature = "postgresql"))] + #[test] + fn drop_index_builder_should_be_able_to_conditionally_add_clauses() { + let mut drop_index = sql::DropIndex::new().drop_index("users_name_idx"); + + if true { + drop_index = drop_index.drop_index("users_name_idx"); + } + + let query = drop_index.as_string(); + let expected_query = "DROP INDEX users_name_idx"; + + assert_eq!(expected_query, query); + } + + #[cfg(feature = "postgresql")] + #[test] + fn drop_index_builder_should_be_able_to_conditionally_add_clauses() { + let mut drop_index = sql::DropIndex::new().drop_index("users_name_idx"); + + if true { + drop_index = drop_index.drop_index("users_age_idx"); + } + + let expected_query = "DROP INDEX users_name_idx, users_age_idx"; + + assert_eq!(expected_query, drop_index.as_string()); + } + + #[cfg(not(feature = "postgresql"))] + #[test] + fn drop_index_builder_should_be_cloneable() { + let drop_users = sql::DropIndex::new().drop_index("users_name_idx"); + let drop_users_and_users_name_idx = drop_users.clone().drop_index("users_name_idx"); + + let expected_drop_users = "DROP INDEX users_name_idx"; + let expected_drop_users_and_users_name_idx = "DROP INDEX users_name_idx"; + + assert_eq!(expected_drop_users, drop_users.as_string()); + assert_eq!( + expected_drop_users_and_users_name_idx, + drop_users_and_users_name_idx.as_string() + ); + } + + #[cfg(feature = "postgresql")] + #[test] + fn drop_index_builder_should_be_cloneable() { + let drop_index_name = sql::DropIndex::new().drop_index("users_name_idx"); + let drop_index_name_and_age = drop_index_name.clone().drop_index("users_age_idx"); + + let expected_drop_index_name = "DROP INDEX users_name_idx"; + assert_eq!(expected_drop_index_name, drop_index_name.as_string()); + + let expected_drop_index_name_and_age = "DROP INDEX users_name_idx, users_age_idx"; + assert_eq!(expected_drop_index_name_and_age, drop_index_name_and_age.as_string()); + } + + #[test] + fn drop_index_builder_should_be_composable() { + fn add_comment(select: sql::DropIndex) -> sql::DropIndex { + select.raw("/* drop command */") + } + + fn drop_users_name_idx(select: sql::DropIndex) -> sql::DropIndex { + select.drop_index("users_name_idx") + } + + fn as_string(select: sql::DropIndex) -> String { + select.as_string() + } + + let query = Some(sql::DropIndex::new()) + .map(add_comment) + .map(drop_users_name_idx) + .map(as_string) + .unwrap(); + + let expected_query = "/* drop command */ DROP INDEX users_name_idx"; + + assert_eq!(expected_query, query); + } +} + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +mod builder_methods { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn method_new_should_initialize_as_empty_string() { + let query = sql::DropIndex::new().as_string(); + let expected_query = ""; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_as_string_should_convert_the_current_state_into_string() { + let query = sql::DropIndex::new().as_string(); + let expected_query = ""; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_debug_should_print_at_console_in_a_human_readable_format() { + let query = sql::DropIndex::new() + .drop_index_if_exists("users_name_idx") + .debug() + .as_string(); + + let expected_query = "DROP INDEX IF EXISTS users_name_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_print_should_print_in_one_line_the_current_state_of_builder() { + let query = sql::DropIndex::new() + .drop_index_if_exists("users_name_idx") + .print() + .as_string(); + + let expected_query = "DROP INDEX IF EXISTS users_name_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_should_add_raw_sql() { + let query = sql::DropIndex::new().raw("drop index users_name_idx").as_string(); + + let expected_query = "drop index users_name_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_should_accumulate_values_on_consecutive_calls() { + let query = sql::DropIndex::new() + .raw("drop index") + .raw("users_name_idx") + .as_string(); + + let expected_query = "drop index users_name_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_should_be_the_first_to_be_concatenated() { + let query = sql::DropIndex::new() + .raw("/* drop index command */") + .drop_index("users_name_idx") + .as_string(); + + let expected_query = "/* drop index command */ DROP INDEX users_name_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_should_not_accumulate_arguments_with_the_same_content() { + let query = sql::DropIndex::new() + .raw("drop index users_name_idx") + .raw("drop index users_name_idx") + .as_string(); + + let expected_query = "drop index users_name_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_after_should_trim_space_of_the_argument() { + let query = sql::DropIndex::new() + .drop_index("users_name_idx") + .raw_after(sql::DropIndexParams::DropIndex, " /* end drop index */ ") + .as_string(); + let expected_query = "DROP INDEX users_name_idx /* end drop index */"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_before_should_trim_space_of_the_argument() { + let query = sql::DropIndex::new() + .raw_before(sql::DropIndexParams::DropIndex, " /* drop index command */ ") + .drop_index("users_name_idx") + .as_string(); + let expected_query = "/* drop index command */ DROP INDEX users_name_idx"; + + assert_eq!(expected_query, query); + } +} + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +mod method_drop_index { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn method_drop_index_should_add_the_drop_index_signature() { + let query = sql::DropIndex::new().drop_index("films_title_idx").as_string(); + let expected_query = "DROP INDEX films_title_idx"; + + assert_eq!(expected_query, query); + } + + #[cfg(not(feature = "postgresql"))] + #[test] + fn method_drop_index_should_overrides_previous_value_on_consecutive_calls() { + let query = sql::DropIndex::new() + .drop_index("films_title_idx") + .drop_index("films_published_at_idx") + .as_string(); + + let expected_query = "DROP INDEX films_published_at_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_drop_index_should_trim_space_of_the_argument() { + let query = sql::DropIndex::new().drop_index(" films_title_idx ").as_string(); + let expected_query = "DROP INDEX films_title_idx"; + + assert_eq!(expected_query, query); + } + + #[cfg(not(feature = "postgresql"))] + #[test] + fn method_drop_index_should_not_accumulate_arguments_with_the_same_content() { + let query = sql::DropIndex::new() + .drop_index("films_title_idx") + .drop_index("films_title_idx") + .as_string(); + let expected_query = "DROP INDEX films_title_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_before_should_add_raw_sql_before_method_drop_index() { + let query = sql::DropIndex::new() + .raw_before(sql::DropIndexParams::DropIndex, "/* drop command */") + .drop_index("films_title_idx") + .as_string(); + let expected_query = "/* drop command */ DROP INDEX films_title_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_after_should_add_raw_sql_after_method_drop_index() { + let query = sql::DropIndex::new() + .drop_index("films_title_idx") + .raw_after(sql::DropIndexParams::DropIndex, "/* end drop index */") + .as_string(); + let expected_query = "DROP INDEX films_title_idx /* end drop index */"; + + assert_eq!(expected_query, query); + } +} + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +mod method_drop_index_if_exists { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn method_drop_index_if_exists_should_add_the_drop_index_signature() { + let query = sql::DropIndex::new() + .drop_index_if_exists("films_title_idx") + .as_string(); + let expected_query = "DROP INDEX IF EXISTS films_title_idx"; + + assert_eq!(expected_query, query); + } + + #[cfg(not(feature = "postgresql"))] + #[test] + fn method_drop_index_if_exists_should_overrides_previous_value_on_consecutive_calls() { + let query = sql::DropIndex::new() + .drop_index_if_exists("films_title_idx") + .drop_index_if_exists("films_published_at_idx") + .as_string(); + + let expected_query = "DROP INDEX IF EXISTS films_published_at_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_drop_index_if_exists_should_trim_space_of_the_argument() { + let query = sql::DropIndex::new() + .drop_index_if_exists(" films_title_idx ") + .as_string(); + let expected_query = "DROP INDEX IF EXISTS films_title_idx"; + + assert_eq!(expected_query, query); + } + + #[cfg(not(feature = "postgresql"))] + #[test] + fn method_drop_index_if_exists_should_not_accumulate_arguments_with_the_same_content() { + let query = sql::DropIndex::new() + .drop_index_if_exists("films_title_idx") + .drop_index_if_exists("films_title_idx") + .as_string(); + let expected_query = "DROP INDEX IF EXISTS films_title_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_before_should_add_raw_sql_before_method_drop_index_if_exists() { + let query = sql::DropIndex::new() + .raw_before(sql::DropIndexParams::DropIndex, "/* drop command */") + .drop_index_if_exists("films_title_idx") + .as_string(); + let expected_query = "/* drop command */ DROP INDEX IF EXISTS films_title_idx"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_raw_after_should_add_raw_sql_after_method_drop_index_if_exists() { + let query = sql::DropIndex::new() + .drop_index_if_exists("films_title_idx") + .raw_after(sql::DropIndexParams::DropIndex, "/* end drop index */") + .as_string(); + let expected_query = "DROP INDEX IF EXISTS films_title_idx /* end drop index */"; + + assert_eq!(expected_query, query); + } +} + +#[cfg(feature = "postgresql")] +mod postgres_feature_flag { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn method_drop_index_should_accumulate_values_on_consecutive_calls() { + let query = sql::DropIndex::new() + .drop_index("films_title_idx") + .drop_index("series") + .as_string(); + + let expected_query = "DROP INDEX films_title_idx, series"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_drop_index_if_exists_should_accumulate_values_on_consecutive_calls() { + let query = sql::DropIndex::new() + .drop_index_if_exists("films_title_idx") + .drop_index_if_exists("series") + .as_string(); + + let expected_query = "DROP INDEX IF EXISTS films_title_idx, series"; + + assert_eq!(expected_query, query); + } +} diff --git a/tests/command_drop_table_spec.rs b/tests/command_drop_table_spec.rs index c04c6d6..c40c085 100644 --- a/tests/command_drop_table_spec.rs +++ b/tests/command_drop_table_spec.rs @@ -28,18 +28,20 @@ mod builder_features { #[cfg(not(feature = "postgresql"))] #[test] - fn drop_table_builder_should_be_cloneable() { - let drop_users = sql::DropTable::new().drop_table("users"); - let drop_users_and_orders = drop_users.clone().drop_table("orders"); + fn drop_table_builder_should_be_able_to_conditionally_add_clauses() { + let mut drop_table = sql::DropTable::new().drop_table("orders"); - let expected_drop_users = "DROP TABLE users"; - let expected_drop_users_and_orders = "DROP TABLE orders"; + if true { + drop_table = drop_table.drop_table("users"); + } - assert_eq!(expected_drop_users, drop_users.as_string()); - assert_eq!(expected_drop_users_and_orders, drop_users_and_orders.as_string()); + let query = drop_table.as_string(); + let expected_query = "DROP TABLE users"; + + assert_eq!(expected_query, query); } - #[cfg(not(feature = "postgresql"))] + #[cfg(feature = "postgresql")] #[test] fn drop_table_builder_should_be_able_to_conditionally_add_clauses() { let mut drop_table = sql::DropTable::new().drop_table("orders"); @@ -49,11 +51,37 @@ mod builder_features { } let query = drop_table.as_string(); - let expected_query = "DROP TABLE users"; + let expected_query = "DROP TABLE orders, users"; assert_eq!(expected_query, query); } + #[cfg(not(feature = "postgresql"))] + #[test] + fn drop_table_builder_should_be_cloneable() { + let drop_users = sql::DropTable::new().drop_table("users"); + let drop_users_and_orders = drop_users.clone().drop_table("orders"); + + let expected_drop_users = "DROP TABLE users"; + let expected_drop_users_and_orders = "DROP TABLE orders"; + + assert_eq!(expected_drop_users, drop_users.as_string()); + assert_eq!(expected_drop_users_and_orders, drop_users_and_orders.as_string()); + } + + #[cfg(feature = "postgresql")] + #[test] + fn drop_table_builder_should_be_cloneable() { + let drop_users = sql::DropTable::new().drop_table("users"); + let drop_users_and_orders = drop_users.clone().drop_table("orders"); + + let expected_drop_users = "DROP TABLE users"; + let expected_drop_users_and_orders = "DROP TABLE users, orders"; + + assert_eq!(expected_drop_users, drop_users.as_string()); + assert_eq!(expected_drop_users_and_orders, drop_users_and_orders.as_string()); + } + #[test] fn drop_table_builder_should_be_composable() { fn add_comment(select: sql::DropTable) -> sql::DropTable { @@ -216,6 +244,7 @@ mod method_drop_table { assert_eq!(expected_query, query); } + #[cfg(not(feature = "postgresql"))] #[test] fn method_drop_table_should_not_accumulate_arguments_with_the_same_content() { let query = sql::DropTable::new() @@ -283,6 +312,7 @@ mod method_drop_table_if_exists { assert_eq!(expected_query, query); } + #[cfg(not(feature = "postgresql"))] #[test] fn method_drop_table_if_exists_should_not_accumulate_arguments_with_the_same_content() { let query = sql::DropTable::new() @@ -322,32 +352,6 @@ mod postgres_feature_flag { use pretty_assertions::assert_eq; use sql_query_builder as sql; - #[test] - fn drop_table_builder_should_be_able_to_conditionally_add_clauses() { - let mut drop_table = sql::DropTable::new().drop_table("orders"); - - if true { - drop_table = drop_table.drop_table("users"); - } - - let query = drop_table.as_string(); - let expected_query = "DROP TABLE orders, users"; - - assert_eq!(expected_query, query); - } - - #[test] - fn drop_table_builder_should_be_cloneable() { - let drop_users = sql::DropTable::new().drop_table("users"); - let drop_users_and_orders = drop_users.clone().drop_table("orders"); - - let expected_drop_users = "DROP TABLE users"; - let expected_drop_users_and_orders = "DROP TABLE users, orders"; - - assert_eq!(expected_drop_users, drop_users.as_string()); - assert_eq!(expected_drop_users_and_orders, drop_users_and_orders.as_string()); - } - #[test] fn method_drop_table_should_accumulate_values_on_consecutive_calls() { let query = sql::DropTable::new() diff --git a/tests/command_transaction_spec.rs b/tests/command_transaction_spec.rs index 0bd4e91..da8cc81 100644 --- a/tests/command_transaction_spec.rs +++ b/tests/command_transaction_spec.rs @@ -385,6 +385,35 @@ mod delete_method { } } +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +mod drop_index_method { + use pretty_assertions::assert_eq; + use sql_query_builder as sql; + + #[test] + fn method_drop_index_should_add_a_drop_index_command() { + let query = sql::Transaction::new() + .drop_index(sql::DropIndex::new().drop_index("users_name_idx")) + .as_string(); + + let expected_query = "DROP INDEX users_name_idx;"; + + assert_eq!(expected_query, query); + } + + #[test] + fn method_drop_index_should_accumulate_values_on_consecutive_calls() { + let query = sql::Transaction::new() + .drop_index(sql::DropIndex::new().drop_index("users_name_idx")) + .drop_index(sql::DropIndex::new().drop_index("orders_product_name_idx")) + .as_string(); + + let expected_query = "DROP INDEX users_name_idx; DROP INDEX orders_product_name_idx;"; + + assert_eq!(expected_query, query); + } +} + mod drop_table_method { use pretty_assertions::assert_eq; use sql_query_builder as sql; From 6cee525d42d183a950dbc86e64e327f637ddc76c Mon Sep 17 00:00:00 2001 From: Belchior Oliveira Date: Sat, 7 Sep 2024 16:40:58 -0300 Subject: [PATCH 2/2] fix dead code warning on standard --- src/behavior.rs | 1 + src/delete/delete.rs | 11 ++++++++--- src/insert/insert.rs | 16 +++++++++++----- src/select/select.rs | 11 ++++++++--- src/update/update.rs | 16 +++++++++++----- src/values/values.rs | 10 +++++++--- 6 files changed, 46 insertions(+), 19 deletions(-) diff --git a/src/behavior.rs b/src/behavior.rs index 32f300b..23b205f 100644 --- a/src/behavior.rs +++ b/src/behavior.rs @@ -11,6 +11,7 @@ pub trait Concat { pub trait TransactionQuery: Concat {} /// Represents all commands that can be used inside the with method +#[cfg(any(feature = "postgresql", feature = "sqlite"))] pub trait WithQuery: Concat {} pub(crate) trait ConcatSqlStandard { diff --git a/src/delete/delete.rs b/src/delete/delete.rs index d648d99..26321a3 100644 --- a/src/delete/delete.rs +++ b/src/delete/delete.rs @@ -1,11 +1,9 @@ use crate::{ - behavior::{push_unique, Concat, TransactionQuery, WithQuery}, + behavior::{push_unique, Concat, TransactionQuery}, fmt, structure::{Delete, DeleteClause, LogicalOperator}, }; -impl WithQuery for Delete {} - impl TransactionQuery for Delete {} impl Delete { @@ -267,6 +265,12 @@ impl Delete { } } +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +use crate::behavior::WithQuery; + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +impl WithQuery for Delete {} + #[cfg(any(doc, feature = "postgresql", feature = "sqlite"))] #[cfg_attr(docsrs, doc(cfg(feature = "postgresql")))] #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))] @@ -338,6 +342,7 @@ impl Delete { /// DELETE FROM users /// WHERE id in (select * from deactivated_users) /// ``` + #[cfg(any(feature = "postgresql", feature = "sqlite"))] pub fn with(mut self, name: &str, query: impl WithQuery + 'static) -> Self { self._with.push((name.trim().to_string(), std::sync::Arc::new(query))); self diff --git a/src/insert/insert.rs b/src/insert/insert.rs index c37c2ae..55fa04c 100644 --- a/src/insert/insert.rs +++ b/src/insert/insert.rs @@ -1,13 +1,9 @@ -#[cfg(feature = "sqlite")] -use crate::structure::InsertVars; use crate::{ - behavior::{push_unique, Concat, TransactionQuery, WithQuery}, + behavior::{push_unique, Concat, TransactionQuery}, fmt, structure::{Insert, InsertClause, Select}, }; -impl WithQuery for Insert {} - impl TransactionQuery for Insert {} impl Insert { @@ -325,6 +321,12 @@ impl Insert { } } +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +use crate::behavior::WithQuery; + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +impl WithQuery for Insert {} + #[cfg(any(doc, feature = "postgresql", feature = "sqlite"))] #[cfg_attr(docsrs, doc(cfg(feature = "postgresql")))] #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))] @@ -403,12 +405,16 @@ impl Insert { /// SELECT * /// FROM active_users /// ``` + #[cfg(any(feature = "postgresql", feature = "sqlite"))] pub fn with(mut self, name: &str, query: impl WithQuery + 'static) -> Self { self._with.push((name.trim().to_string(), std::sync::Arc::new(query))); self } } +#[cfg(feature = "sqlite")] +use crate::structure::InsertVars; + #[cfg(any(doc, feature = "sqlite"))] #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))] impl Insert { diff --git a/src/select/select.rs b/src/select/select.rs index e5727ae..74ae4ce 100644 --- a/src/select/select.rs +++ b/src/select/select.rs @@ -1,13 +1,11 @@ use crate::{ - behavior::{push_unique, Concat, TransactionQuery, WithQuery}, + behavior::{push_unique, Concat, TransactionQuery}, fmt, structure::{LogicalOperator, Select, SelectClause}, }; impl TransactionQuery for Select {} -impl WithQuery for Select {} - impl Select { /// Gets the current state of the [Select] and returns it as string /// @@ -558,6 +556,12 @@ impl Select { } } +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +use crate::behavior::WithQuery; + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +impl WithQuery for Select {} + #[cfg(any(doc, feature = "postgresql", feature = "sqlite"))] #[cfg_attr(docsrs, doc(cfg(feature = "postgresql")))] #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))] @@ -779,6 +783,7 @@ impl Select { /// WHERE owner_login in (select * from logins) /// -- ------------------------------------------------------------------------------ /// ``` + #[cfg(any(feature = "postgresql", feature = "sqlite"))] pub fn with(mut self, name: &str, query: impl WithQuery + 'static) -> Self { self._with.push((name.trim().to_string(), std::sync::Arc::new(query))); self diff --git a/src/update/update.rs b/src/update/update.rs index 489ef53..68ada6f 100644 --- a/src/update/update.rs +++ b/src/update/update.rs @@ -1,13 +1,9 @@ -#[cfg(feature = "sqlite")] -use crate::structure::UpdateVars; use crate::{ - behavior::{push_unique, Concat, TransactionQuery, WithQuery}, + behavior::{push_unique, Concat, TransactionQuery}, fmt, structure::{LogicalOperator, Update, UpdateClause}, }; -impl WithQuery for Update {} - impl TransactionQuery for Update {} impl Update { @@ -293,6 +289,12 @@ impl Update { } } +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +use crate::behavior::WithQuery; + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +impl WithQuery for Update {} + #[cfg(any(doc, feature = "postgresql", feature = "sqlite"))] #[cfg_attr(docsrs, doc(cfg(feature = "postgresql")))] #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))] @@ -414,12 +416,16 @@ impl Update { /// WHERE id = (select group_id from user) /// -- ------------------------------------------------------------------------------ /// ``` + #[cfg(any(feature = "postgresql", feature = "sqlite"))] pub fn with(mut self, name: &str, query: impl WithQuery + 'static) -> Self { self._with.push((name.trim().to_string(), std::sync::Arc::new(query))); self } } +#[cfg(feature = "sqlite")] +use crate::structure::UpdateVars; + #[cfg(any(doc, feature = "sqlite"))] #[cfg_attr(docsrs, doc(cfg(feature = "sqlite")))] impl Update { diff --git a/src/values/values.rs b/src/values/values.rs index a690d33..108ceb5 100644 --- a/src/values/values.rs +++ b/src/values/values.rs @@ -1,9 +1,15 @@ use crate::{ - behavior::{push_unique, Concat, WithQuery}, + behavior::{push_unique, Concat}, fmt, structure::{Values, ValuesClause}, }; +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +use crate::behavior::WithQuery; + +#[cfg(any(feature = "postgresql", feature = "sqlite"))] +impl WithQuery for Values {} + impl Values { /// Gets the current state of the [Values] and returns it as string /// @@ -180,8 +186,6 @@ impl Values { } } -impl WithQuery for Values {} - impl std::fmt::Display for Values { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!(f, "{}", self.as_string())