From 60daad0fa12b6843108586aaf14e85508c0768d0 Mon Sep 17 00:00:00 2001 From: Fabien Penso Date: Mon, 27 Jan 2025 14:48:51 +0100 Subject: [PATCH] Add dynamic tables --- src/query/delete.rs | 50 ++++++++++++++++++++++++++++++++++++++++++++- src/query/insert.rs | 31 ++++++++++++++++++++++++++-- src/query/select.rs | 40 +++++++++++++++++++++++++++++++++++- src/query/update.rs | 49 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 164 insertions(+), 6 deletions(-) diff --git a/src/query/delete.rs b/src/query/delete.rs index 73cd430241..4dc4855933 100644 --- a/src/query/delete.rs +++ b/src/query/delete.rs @@ -3,7 +3,7 @@ use crate::{ PrimaryKeyToColumn, QueryFilter, QueryTrait, }; use core::marker::PhantomData; -use sea_query::DeleteStatement; +use sea_query::{DeleteStatement, IntoTableRef}; /// Defines the structure for a delete operation #[derive(Clone, Debug)] @@ -101,6 +101,20 @@ impl Delete { } } +impl DeleteMany +where + E: EntityTrait, +{ + /// Specify which table to delete. + pub fn with_table(mut self, table_name: T) -> Self + where + T: IntoTableRef, + { + self.query.from_table(table_name); + self + } +} + impl DeleteOne where A: ActiveModelTrait, @@ -118,6 +132,15 @@ where } self } + + /// Specify which table to delete. + pub fn with_table(mut self, table_name: T) -> Self + where + T: IntoTableRef, + { + self.query.from_table(table_name); + self + } } impl QueryFilter for DeleteOne @@ -184,6 +207,31 @@ where mod tests { use crate::tests_cfg::{cake, fruit}; use crate::{entity::*, query::*, DbBackend}; + use sea_query::Alias; + + #[test] + fn delete_with_specific_table() { + assert_eq!( + Delete::one(cake::Model { + id: 1, + name: "Apple Pie".to_owned(), + }) + .with_table(Alias::new("cake2")) + .build(DbBackend::Postgres) + .to_string(), + r#"DELETE FROM "cake2" WHERE "cake2"."id" = 1"#, + ); + assert_eq!( + Delete::one(cake::ActiveModel { + id: ActiveValue::set(1), + name: ActiveValue::set("Apple Pie".to_owned()), + }) + .with_table(Alias::new("cake2")) + .build(DbBackend::Postgres) + .to_string(), + r#"DELETE FROM "cake2" WHERE "cake2"."id" = 1"#, + ); + } #[test] fn delete_1() { diff --git a/src/query/insert.rs b/src/query/insert.rs index 697f208d2a..f638a4fe60 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -3,7 +3,9 @@ use crate::{ PrimaryKeyTrait, QueryTrait, }; use core::marker::PhantomData; -use sea_query::{Expr, InsertStatement, Keyword, OnConflict, SimpleExpr, Value, ValueTuple}; +use sea_query::{ + Expr, InsertStatement, IntoTableRef, Keyword, OnConflict, SimpleExpr, Value, ValueTuple, +}; /// Performs INSERT operations on a ActiveModel #[derive(Debug)] @@ -285,6 +287,16 @@ where self } + /// Specify which table to insert into. + /// + pub fn with_table(mut self, table_name: T) -> Self + where + T: IntoTableRef, + { + self.query.into_table(table_name); + self + } + /// Allow insert statement to return without error if nothing's been inserted pub fn do_nothing(self) -> TryInsert where @@ -464,7 +476,7 @@ where } #[cfg(test)] mod tests { - use sea_query::OnConflict; + use sea_query::{Alias, OnConflict}; use crate::tests_cfg::{cake, cake_filling}; use crate::{ @@ -472,6 +484,21 @@ mod tests { Set, }; + #[test] + fn insert_with_specific_table() { + assert_eq!( + Insert::::new() + .with_table(Alias::new("cake2")) + .add(cake::ActiveModel { + id: ActiveValue::not_set(), + name: ActiveValue::set("Apple Pie".to_owned()), + }) + .build(DbBackend::Postgres) + .to_string(), + r#"INSERT INTO "cake2" ("name") VALUES ('Apple Pie')"#, + ); + } + #[test] fn insert_1() { assert_eq!( diff --git a/src/query/select.rs b/src/query/select.rs index 4ac04aeb9e..779283426f 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -1,7 +1,7 @@ use crate::{ColumnTrait, EntityTrait, Iterable, QueryFilter, QueryOrder, QuerySelect, QueryTrait}; use core::fmt::Debug; use core::marker::PhantomData; -use sea_query::{Expr, IntoColumnRef, SelectStatement, SimpleExpr}; +use sea_query::{DynIden, Expr, Iden, IntoColumnRef, SelectStatement, SimpleExpr}; /// Defines a structure to perform select operations #[derive(Clone, Debug)] @@ -133,6 +133,26 @@ where self.query.from(E::default().table_ref()); self } + + fn column_list_with_table(&self, table_name: DynIden) -> Vec { + E::Column::iter() + .map(|col| Expr::col((table_name.clone(), col.as_column_ref().1)).into()) + .collect() + } + + /// Specify which table to select. + pub fn with_table(mut self, table_name: T) -> Self + where + T: Clone + Iden + 'static, + { + self.query.clear_selects(); + self.query + .exprs(self.column_list_with_table(DynIden::new(table_name.clone()))); + + self.query.from_clear(); + self.query.from(table_name); + self + } } impl QueryTrait for Select @@ -174,3 +194,21 @@ macro_rules! select_two { select_two!(SelectTwo); select_two!(SelectTwoMany); + +#[cfg(test)] +mod tests { + use crate::tests_cfg::cake; + use crate::{DbBackend, EntityTrait, QueryTrait}; + use sea_query::Alias; + + #[test] + fn select_with_specific_table() { + assert_eq!( + cake::Entity::find() + .with_table(Alias::new("cake2")) + .build(DbBackend::MySql) + .to_string(), + "SELECT `cake2`.`id`, `cake2`.`name` FROM `cake2`", + ); + } +} diff --git a/src/query/update.rs b/src/query/update.rs index 9863af6fcf..887a5a2363 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -3,7 +3,7 @@ use crate::{ QueryFilter, QueryTrait, }; use core::marker::PhantomData; -use sea_query::{Expr, IntoIden, SimpleExpr, UpdateStatement}; +use sea_query::{Expr, IntoIden, IntoTableRef, SimpleExpr, UpdateStatement}; /// Defines a structure to perform UPDATE query operations on a ActiveModel #[derive(Clone, Debug)] @@ -117,6 +117,15 @@ where } self } + + /// Specify which table to update. + pub fn with_table(mut self, table_name: T) -> Self + where + T: IntoTableRef, + { + self.query.table(table_name); + self + } } impl QueryFilter for UpdateOne @@ -208,13 +217,49 @@ where self.query.value(col, expr); self } + + /// Specify which table to update. + pub fn with_table(mut self, table_name: T) -> Self + where + T: IntoTableRef, + { + self.query.table(table_name); + self + } } #[cfg(test)] mod tests { use crate::tests_cfg::{cake, fruit, lunch_set, sea_orm_active_enums::Tea}; use crate::{entity::*, query::*, DbBackend}; - use sea_query::{Expr, Value}; + use sea_query::{Alias, Expr, Value}; + + #[test] + fn update_one_with_specific_table() { + assert_eq!( + Update::one(cake::ActiveModel { + id: ActiveValue::set(1), + name: ActiveValue::set("Apple Pie".to_owned()), + }) + .with_table(Alias::new("cake2")) + .build(DbBackend::Postgres) + .to_string(), + r#"UPDATE "cake2" SET "name" = 'Apple Pie' WHERE "cake"."id" = 1"#, + ); + } + + #[test] + fn update_many_with_specific_table() { + assert_eq!( + Update::many(fruit::Entity) + .with_table(Alias::new("fruit2")) + .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None))) + .filter(fruit::Column::Id.eq(2)) + .build(DbBackend::Postgres) + .to_string(), + r#"UPDATE "fruit2" SET "cake_id" = NULL WHERE "fruit"."id" = 2"#, + ); + } #[test] fn update_1() {