diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 1bda4c021..1d757f85e 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -22,7 +22,7 @@ jobs: toolchain: stable components: clippy override: true - + - uses: actions-rs/clippy-check@v1 with: token: ${{ secrets.GITHUB_TOKEN }} diff --git a/Cargo.toml b/Cargo.toml index 0c359d2e9..82ff6e405 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -68,6 +68,7 @@ with-rust_decimal = ["rust_decimal"] with-bigdecimal = ["bigdecimal"] with-uuid = ["uuid"] + [[test]] name = "test-derive" path = "tests/derive/mod.rs" diff --git a/src/backend/postgres/query.rs b/src/backend/postgres/query.rs index 16c138ee0..276d3c1dd 100644 --- a/src/backend/postgres/query.rs +++ b/src/backend/postgres/query.rs @@ -6,24 +6,6 @@ impl QueryBuilder for PostgresQueryBuilder { ("$", true) } - fn prepare_returning( - &self, - returning: &[SelectExpr], - sql: &mut SqlWriter, - collector: &mut dyn FnMut(Value), - ) { - if !returning.is_empty() { - write!(sql, " RETURNING ").unwrap(); - returning.iter().fold(true, |first, expr| { - if !first { - write!(sql, ", ").unwrap() - } - self.prepare_select_expr(expr, sql, collector); - false - }); - } - } - fn if_null_function(&self) -> &str { "COALESCE" } diff --git a/src/backend/query_builder.rs b/src/backend/query_builder.rs index b41a052bf..b49aa305c 100644 --- a/src/backend/query_builder.rs +++ b/src/backend/query_builder.rs @@ -756,10 +756,31 @@ pub trait QueryBuilder: QuotedBuilder { /// Hook to insert "RETURNING" statements. fn prepare_returning( &self, - _returning: &[SelectExpr], - _sql: &mut SqlWriter, + returning: &Returning, + sql: &mut SqlWriter, _collector: &mut dyn FnMut(Value), ) { + match returning { + Returning::All => write!(sql, " RETURNING *").unwrap(), + Returning::Columns(cols) => { + write!(sql, " RETURNING ").unwrap(); + cols.into_iter().fold(true, |first, column_ref| { + if !first { + write!(sql, ", ").unwrap() + } + match column_ref { + ColumnRef::Column(column) => column.prepare(sql, self.quote()), + ColumnRef::TableColumn(table, column) => { + table.prepare(sql, self.quote()); + write!(sql, ".").unwrap(); + column.prepare(sql, self.quote()); + } + }; + false + }); + } + Returning::Nothing => return, + } } #[doc(hidden)] diff --git a/src/query/delete.rs b/src/query/delete.rs index d8c83e2e0..c30a02d78 100644 --- a/src/query/delete.rs +++ b/src/query/delete.rs @@ -4,7 +4,7 @@ use crate::{ query::{condition::*, OrderedStatement}, types::*, value::*, - Query, QueryStatementBuilder, SelectExpr, SelectStatement, + ColumnRef, QueryStatementBuilder, Returning, }; /// Delete existing rows from the table @@ -39,7 +39,7 @@ pub struct DeleteStatement { pub(crate) wherei: ConditionHolder, pub(crate) orders: Vec, pub(crate) limit: Option, - pub(crate) returning: Vec, + pub(crate) returning: Returning, } impl Default for DeleteStatement { @@ -56,7 +56,7 @@ impl DeleteStatement { wherei: ConditionHolder::new(), orders: Vec::new(), limit: None, - returning: Vec::new(), + returning: Returning::default(), } } @@ -100,7 +100,7 @@ impl DeleteStatement { self } - /// RETURNING expressions. Postgres only. + /// RETURNING expressions. Supported fully by postgres, version deppendant on other databases /// /// ``` /// use sea_query::{tests_cfg::*, *}; @@ -108,12 +108,12 @@ impl DeleteStatement { /// let query = Query::delete() /// .from_table(Glyph::Table) /// .and_where(Expr::col(Glyph::Id).eq(1)) - /// .returning(Query::select().column(Glyph::Id).take()) + /// .returning(Returning::Columns(vec![Glyph::Id.into_column_ref()])) /// .to_owned(); /// /// assert_eq!( /// query.to_string(MysqlQueryBuilder), - /// r#"DELETE FROM `glyph` WHERE `id` = 1"# + /// r#"DELETE FROM `glyph` WHERE `id` = 1 RETURNING `id`"# /// ); /// assert_eq!( /// query.to_string(PostgresQueryBuilder), @@ -121,15 +121,15 @@ impl DeleteStatement { /// ); /// assert_eq!( /// query.to_string(SqliteQueryBuilder), - /// r#"DELETE FROM `glyph` WHERE `id` = 1"# + /// r#"DELETE FROM `glyph` WHERE `id` = 1 RETURNING `id`"# /// ); /// ``` - pub fn returning(&mut self, select: SelectStatement) -> &mut Self { - self.returning = select.selects; + pub fn returning(&mut self, returning_cols: Returning) -> &mut Self { + self.returning = returning_cols; self } - /// RETURNING a column after delete. Postgres only. + /// RETURNING a column after delete. Supported fully by postgres, version deppendant on other databases /// Wrapper over [`DeleteStatement::returning()`]. /// /// ``` @@ -143,7 +143,7 @@ impl DeleteStatement { /// /// assert_eq!( /// query.to_string(MysqlQueryBuilder), - /// r#"DELETE FROM `glyph` WHERE `id` = 1"# + /// r#"DELETE FROM `glyph` WHERE `id` = 1 RETURNING `id`"# /// ); /// assert_eq!( /// query.to_string(PostgresQueryBuilder), @@ -151,14 +151,14 @@ impl DeleteStatement { /// ); /// assert_eq!( /// query.to_string(SqliteQueryBuilder), - /// r#"DELETE FROM `glyph` WHERE `id` = 1"# + /// r#"DELETE FROM `glyph` WHERE `id` = 1 RETURNING `id`"# /// ); /// ``` pub fn returning_col(&mut self, col: C) -> &mut Self where C: IntoIden, { - self.returning(Query::select().column(col.into_iden()).take()) + self.returning(Returning::Columns(vec![ColumnRef::Column(col.into_iden())])) } } diff --git a/src/query/insert.rs b/src/query/insert.rs index 39903b953..1ead717e9 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -1,6 +1,6 @@ use crate::{ - backend::QueryBuilder, error::*, prepare::*, types::*, value::*, Expr, Query, - QueryStatementBuilder, SelectExpr, SelectStatement, SimpleExpr, + backend::QueryBuilder, error::*, prepare::*, types::*, value::*, Expr, QueryStatementBuilder, + Returning, SimpleExpr, }; /// Insert any new rows into an existing table @@ -35,7 +35,7 @@ pub struct InsertStatement { pub(crate) table: Option>, pub(crate) columns: Vec, pub(crate) values: Vec>, - pub(crate) returning: Vec, + pub(crate) returning: Returning, } impl InsertStatement { @@ -179,7 +179,7 @@ impl InsertStatement { self.exprs(values).unwrap() } - /// RETURNING expressions. Postgres only. + /// RETURNING expressions. Supported fully by postgres, version deppendant on other databases /// /// ``` /// use sea_query::{tests_cfg::*, *}; @@ -188,12 +188,12 @@ impl InsertStatement { /// .into_table(Glyph::Table) /// .columns(vec![Glyph::Image]) /// .values_panic(vec!["12A".into()]) - /// .returning(Query::select().column(Glyph::Id).take()) + /// .returning(Returning::Columns(vec![Glyph::Id.into_column_ref()])) /// .to_owned(); /// /// assert_eq!( /// query.to_string(MysqlQueryBuilder), - /// "INSERT INTO `glyph` (`image`) VALUES ('12A')" + /// "INSERT INTO `glyph` (`image`) VALUES ('12A') RETURNING `id`" /// ); /// assert_eq!( /// query.to_string(PostgresQueryBuilder), @@ -201,15 +201,15 @@ impl InsertStatement { /// ); /// assert_eq!( /// query.to_string(SqliteQueryBuilder), - /// "INSERT INTO `glyph` (`image`) VALUES ('12A')" + /// "INSERT INTO `glyph` (`image`) VALUES ('12A') RETURNING `id`" /// ); /// ``` - pub fn returning(&mut self, select: SelectStatement) -> &mut Self { - self.returning = select.selects; + pub fn returning(&mut self, returning: Returning) -> &mut Self { + self.returning = returning; self } - /// RETURNING a column after insertion. Postgres only. This is equivalent to MySQL's LAST_INSERT_ID. + /// RETURNING a column after insertion. Supported fully by postgres, version deppendant on other databases /// Wrapper over [`InsertStatement::returning()`]. /// /// ``` @@ -224,7 +224,7 @@ impl InsertStatement { /// /// assert_eq!( /// query.to_string(MysqlQueryBuilder), - /// "INSERT INTO `glyph` (`image`) VALUES ('12A')" + /// "INSERT INTO `glyph` (`image`) VALUES ('12A') RETURNING `id`" /// ); /// assert_eq!( /// query.to_string(PostgresQueryBuilder), @@ -232,14 +232,14 @@ impl InsertStatement { /// ); /// assert_eq!( /// query.to_string(SqliteQueryBuilder), - /// "INSERT INTO `glyph` (`image`) VALUES ('12A')" + /// "INSERT INTO `glyph` (`image`) VALUES ('12A') RETURNING `id`" /// ); /// ``` pub fn returning_col(&mut self, col: C) -> &mut Self where C: IntoIden, { - self.returning(Query::select().column(col.into_iden()).take()) + self.returning(Returning::Columns(vec![ColumnRef::Column(col.into_iden())])) } } diff --git a/src/query/mod.rs b/src/query/mod.rs index c30ccc77a..591bddb97 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -11,6 +11,7 @@ mod condition; mod delete; mod insert; mod ordered; +mod returning; mod select; mod shim; mod traits; @@ -20,6 +21,7 @@ pub use condition::*; pub use delete::*; pub use insert::*; pub use ordered::*; +pub use returning::*; pub use select::*; pub use traits::*; pub use update::*; diff --git a/src/query/returning.rs b/src/query/returning.rs new file mode 100644 index 000000000..9f3fc4fc2 --- /dev/null +++ b/src/query/returning.rs @@ -0,0 +1,27 @@ +use std::default::Default; + +use crate::{ColumnRef, IntoColumnRef}; + +#[derive(Clone, Debug)] +pub enum Returning { + All, + Columns(Vec), + Nothing, +} + +impl Returning { + pub fn cols(cols: I) -> Self + where + T: IntoColumnRef, + I: IntoIterator, + { + let cols: Vec<_> = cols.into_iter().map(|c| c.into_column_ref()).collect(); + Self::Columns(cols) + } +} + +impl Default for Returning { + fn default() -> Self { + Self::Nothing + } +} diff --git a/src/query/update.rs b/src/query/update.rs index 5c8af7495..cca26ff11 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -5,7 +5,7 @@ use crate::{ query::{condition::*, OrderedStatement}, types::*, value::*, - Query, QueryStatementBuilder, SelectExpr, SelectStatement, + QueryStatementBuilder, Returning, }; /// Update existing rows in the table @@ -44,7 +44,7 @@ pub struct UpdateStatement { pub(crate) wherei: ConditionHolder, pub(crate) orders: Vec, pub(crate) limit: Option, - pub(crate) returning: Vec, + pub(crate) returning: Returning, } impl Default for UpdateStatement { @@ -62,7 +62,7 @@ impl UpdateStatement { wherei: ConditionHolder::new(), orders: Vec::new(), limit: None, - returning: Vec::new(), + returning: Returning::default(), } } @@ -223,7 +223,7 @@ impl UpdateStatement { self } - /// RETURNING expressions. Postgres only. + /// RETURNING expressions. Supported fully by postgres, version deppendant on other databases /// /// ``` /// use sea_query::{tests_cfg::*, *}; @@ -233,12 +233,12 @@ impl UpdateStatement { /// .value(Glyph::Aspect, 2.1345.into()) /// .value(Glyph::Image, "235m".into()) /// .and_where(Expr::col(Glyph::Id).eq(1)) - /// .returning(Query::select().column(Glyph::Id).take()) + /// .returning(Returning::Columns(vec![Glyph::Id.into_column_ref()])) /// .to_owned(); /// /// assert_eq!( /// query.to_string(MysqlQueryBuilder), - /// r#"UPDATE `glyph` SET `aspect` = 2.1345, `image` = '235m' WHERE `id` = 1"# + /// r#"UPDATE `glyph` SET `aspect` = 2.1345, `image` = '235m' WHERE `id` = 1 RETURNING `id`"# /// ); /// assert_eq!( /// query.to_string(PostgresQueryBuilder), @@ -246,15 +246,15 @@ impl UpdateStatement { /// ); /// assert_eq!( /// query.to_string(SqliteQueryBuilder), - /// r#"UPDATE `glyph` SET `aspect` = 2.1345, `image` = '235m' WHERE `id` = 1"# + /// r#"UPDATE `glyph` SET `aspect` = 2.1345, `image` = '235m' WHERE `id` = 1 RETURNING `id`"# /// ); /// ``` - pub fn returning(&mut self, select: SelectStatement) -> &mut Self { - self.returning = select.selects; + pub fn returning(&mut self, returning_cols: Returning) -> &mut Self { + self.returning = returning_cols; self } - /// RETURNING a column after update. Postgres only. + /// RETURNING a column after update. Supported fully by postgres, version deppendant on other databases /// Wrapper over [`UpdateStatement::returning()`]. /// /// ``` @@ -271,7 +271,7 @@ impl UpdateStatement { /// /// assert_eq!( /// query.to_string(MysqlQueryBuilder), - /// r#"UPDATE `glyph` SET `aspect` = 2.1345, `image` = '235m' WHERE `id` = 1"# + /// r#"UPDATE `glyph` SET `aspect` = 2.1345, `image` = '235m' WHERE `id` = 1 RETURNING `id`"# /// ); /// assert_eq!( /// query.to_string(PostgresQueryBuilder), @@ -279,14 +279,14 @@ impl UpdateStatement { /// ); /// assert_eq!( /// query.to_string(SqliteQueryBuilder), - /// r#"UPDATE `glyph` SET `aspect` = 2.1345, `image` = '235m' WHERE `id` = 1"# + /// r#"UPDATE `glyph` SET `aspect` = 2.1345, `image` = '235m' WHERE `id` = 1 RETURNING `id`"# /// ); /// ``` pub fn returning_col(&mut self, col: C) -> &mut Self where C: IntoIden, { - self.returning(Query::select().column(col.into_iden()).take()) + self.returning(Returning::Columns(vec![ColumnRef::Column(col.into_iden())])) } } diff --git a/tests/mysql/query.rs b/tests/mysql/query.rs index 900f1c940..5a81da43c 100644 --- a/tests/mysql/query.rs +++ b/tests/mysql/query.rs @@ -861,6 +861,40 @@ fn insert_5() { ); } +#[test] +#[allow(clippy::approx_constant)] +fn insert_returning_all_columns() { + assert_eq!( + Query::insert() + .into_table(Glyph::Table) + .columns(vec![Glyph::Image, Glyph::Aspect,]) + .values_panic(vec![ + "04108048005887010020060000204E0180400400".into(), + 3.1415.into(), + ]) + .returning(Returning::All) + .to_string(MysqlQueryBuilder), + r#"INSERT INTO `glyph` (`image`, `aspect`) VALUES ('04108048005887010020060000204E0180400400', 3.1415) RETURNING *"# + ); +} + +#[test] +#[allow(clippy::approx_constant)] +fn insert_returning_specific_columns() { + assert_eq!( + Query::insert() + .into_table(Glyph::Table) + .columns(vec![Glyph::Image, Glyph::Aspect,]) + .values_panic(vec![ + "04108048005887010020060000204E0180400400".into(), + 3.1415.into(), + ]) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image,])) + .to_string(MysqlQueryBuilder), + r#"INSERT INTO `glyph` (`image`, `aspect`) VALUES ('04108048005887010020060000204E0180400400', 3.1415) RETURNING `id`, `image`"# + ); +} + #[test] fn update_1() { assert_eq!( @@ -895,6 +929,40 @@ fn update_3() { ); } +#[test] +fn update_returning_all_columns() { + assert_eq!( + Query::update() + .table(Glyph::Table) + .value_expr(Glyph::Aspect, Expr::cust("60 * 24 * 24")) + .values(vec![( + Glyph::Image, + "24B0E11951B03B07F8300FD003983F03F0780060".into() + ),]) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::All) + .to_string(MysqlQueryBuilder), + r#"UPDATE `glyph` SET `aspect` = 60 * 24 * 24, `image` = '24B0E11951B03B07F8300FD003983F03F0780060' WHERE `id` = 1 RETURNING *"# + ); +} + +#[test] +fn update_returning_specified_columns() { + assert_eq!( + Query::update() + .table(Glyph::Table) + .value_expr(Glyph::Aspect, Expr::cust("60 * 24 * 24")) + .values(vec![( + Glyph::Image, + "24B0E11951B03B07F8300FD003983F03F0780060".into() + ),]) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image])) + .to_string(MysqlQueryBuilder), + r#"UPDATE `glyph` SET `aspect` = 60 * 24 * 24, `image` = '24B0E11951B03B07F8300FD003983F03F0780060' WHERE `id` = 1 RETURNING `id`, `image`"# + ); +} + #[test] fn delete_1() { assert_eq!( @@ -907,3 +975,27 @@ fn delete_1() { "DELETE FROM `glyph` WHERE `id` = 1 ORDER BY `id` ASC LIMIT 1" ); } + +#[test] +fn delete_returning_all_columns() { + assert_eq!( + Query::delete() + .from_table(Glyph::Table) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::All) + .to_string(MysqlQueryBuilder), + r#"DELETE FROM `glyph` WHERE `id` = 1 RETURNING *"# + ); +} + +#[test] +fn delete_returning_specific_columns() { + assert_eq!( + Query::delete() + .from_table(Glyph::Table) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image,])) + .to_string(MysqlQueryBuilder), + r#"DELETE FROM `glyph` WHERE `id` = 1 RETURNING `id`, `image`"# + ); +} diff --git a/tests/postgres/query.rs b/tests/postgres/query.rs index 2a54fe948..4b6a7a69e 100644 --- a/tests/postgres/query.rs +++ b/tests/postgres/query.rs @@ -836,6 +836,40 @@ fn insert_5() { ); } +#[test] +#[allow(clippy::approx_constant)] +fn insert_returning_all_columns() { + assert_eq!( + Query::insert() + .into_table(Glyph::Table) + .columns(vec![Glyph::Image, Glyph::Aspect,]) + .values_panic(vec![ + "04108048005887010020060000204E0180400400".into(), + 3.1415.into(), + ]) + .returning(Returning::All) + .to_string(PostgresQueryBuilder), + r#"INSERT INTO "glyph" ("image", "aspect") VALUES ('04108048005887010020060000204E0180400400', 3.1415) RETURNING *"# + ); +} + +#[test] +#[allow(clippy::approx_constant)] +fn insert_returning_specific_columns() { + assert_eq!( + Query::insert() + .into_table(Glyph::Table) + .columns(vec![Glyph::Image, Glyph::Aspect,]) + .values_panic(vec![ + "04108048005887010020060000204E0180400400".into(), + 3.1415.into(), + ]) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image,])) + .to_string(PostgresQueryBuilder), + r#"INSERT INTO "glyph" ("image", "aspect") VALUES ('04108048005887010020060000204E0180400400', 3.1415) RETURNING "id", "image""# + ); +} + #[test] fn update_1() { assert_eq!( @@ -870,6 +904,40 @@ fn update_3() { ); } +#[test] +fn update_returning_all_columns() { + assert_eq!( + Query::update() + .table(Glyph::Table) + .value_expr(Glyph::Aspect, Expr::cust("60 * 24 * 24")) + .values(vec![( + Glyph::Image, + "24B0E11951B03B07F8300FD003983F03F0780060".into() + ),]) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::All) + .to_string(PostgresQueryBuilder), + r#"UPDATE "glyph" SET "aspect" = 60 * 24 * 24, "image" = '24B0E11951B03B07F8300FD003983F03F0780060' WHERE "id" = 1 RETURNING *"# + ); +} + +#[test] +fn update_returning_specified_columns() { + assert_eq!( + Query::update() + .table(Glyph::Table) + .value_expr(Glyph::Aspect, Expr::cust("60 * 24 * 24")) + .values(vec![( + Glyph::Image, + "24B0E11951B03B07F8300FD003983F03F0780060".into() + ),]) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image])) + .to_string(PostgresQueryBuilder), + r#"UPDATE "glyph" SET "aspect" = 60 * 24 * 24, "image" = '24B0E11951B03B07F8300FD003983F03F0780060' WHERE "id" = 1 RETURNING "id", "image""# + ); +} + #[test] fn delete_1() { assert_eq!( @@ -880,3 +948,27 @@ fn delete_1() { r#"DELETE FROM "glyph" WHERE "id" = 1"# ); } + +#[test] +fn delete_returning_all_columns() { + assert_eq!( + Query::delete() + .from_table(Glyph::Table) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::All) + .to_string(PostgresQueryBuilder), + r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING *"# + ); +} + +#[test] +fn delete_returning_specific_columns() { + assert_eq!( + Query::delete() + .from_table(Glyph::Table) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image,])) + .to_string(PostgresQueryBuilder), + r#"DELETE FROM "glyph" WHERE "id" = 1 RETURNING "id", "image""# + ); +} diff --git a/tests/sqlite/query.rs b/tests/sqlite/query.rs index c3a2ad82d..9cf88b5e6 100644 --- a/tests/sqlite/query.rs +++ b/tests/sqlite/query.rs @@ -861,6 +861,40 @@ fn insert_5() { ); } +#[test] +#[allow(clippy::approx_constant)] +fn insert_returning_all_columns() { + assert_eq!( + Query::insert() + .into_table(Glyph::Table) + .columns(vec![Glyph::Image, Glyph::Aspect,]) + .values_panic(vec![ + "04108048005887010020060000204E0180400400".into(), + 3.1415.into(), + ]) + .returning(Returning::All) + .to_string(SqliteQueryBuilder), + r#"INSERT INTO `glyph` (`image`, `aspect`) VALUES ('04108048005887010020060000204E0180400400', 3.1415) RETURNING *"# + ); +} + +#[test] +#[allow(clippy::approx_constant)] +fn insert_returning_specific_columns() { + assert_eq!( + Query::insert() + .into_table(Glyph::Table) + .columns(vec![Glyph::Image, Glyph::Aspect,]) + .values_panic(vec![ + "04108048005887010020060000204E0180400400".into(), + 3.1415.into(), + ]) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image,])) + .to_string(SqliteQueryBuilder), + r#"INSERT INTO `glyph` (`image`, `aspect`) VALUES ('04108048005887010020060000204E0180400400', 3.1415) RETURNING `id`, `image`"# + ); +} + #[test] fn update_1() { assert_eq!( @@ -891,6 +925,40 @@ fn update_3() { ); } +#[test] +fn update_returning_all_columns() { + assert_eq!( + Query::update() + .table(Glyph::Table) + .value_expr(Glyph::Aspect, Expr::cust("60 * 24 * 24")) + .values(vec![( + Glyph::Image, + "24B0E11951B03B07F8300FD003983F03F0780060".into() + ),]) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::All) + .to_string(SqliteQueryBuilder), + r#"UPDATE `glyph` SET `aspect` = 60 * 24 * 24, `image` = '24B0E11951B03B07F8300FD003983F03F0780060' WHERE `id` = 1 RETURNING *"# + ); +} + +#[test] +fn update_returning_specified_columns() { + assert_eq!( + Query::update() + .table(Glyph::Table) + .value_expr(Glyph::Aspect, Expr::cust("60 * 24 * 24")) + .values(vec![( + Glyph::Image, + "24B0E11951B03B07F8300FD003983F03F0780060".into() + ),]) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image])) + .to_string(SqliteQueryBuilder), + r#"UPDATE `glyph` SET `aspect` = 60 * 24 * 24, `image` = '24B0E11951B03B07F8300FD003983F03F0780060' WHERE `id` = 1 RETURNING `id`, `image`"# + ); +} + #[test] fn delete_1() { assert_eq!( @@ -901,3 +969,27 @@ fn delete_1() { "DELETE FROM `glyph` WHERE `id` = 1" ); } + +#[test] +fn delete_returning_all_columns() { + assert_eq!( + Query::delete() + .from_table(Glyph::Table) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::All) + .to_string(SqliteQueryBuilder), + r#"DELETE FROM `glyph` WHERE `id` = 1 RETURNING *"# + ); +} + +#[test] +fn delete_returning_specific_columns() { + assert_eq!( + Query::delete() + .from_table(Glyph::Table) + .and_where(Expr::col(Glyph::Id).eq(1)) + .returning(Returning::cols(vec![Glyph::Id, Glyph::Image,])) + .to_string(SqliteQueryBuilder), + r#"DELETE FROM `glyph` WHERE `id` = 1 RETURNING `id`, `image`"# + ); +}