diff --git a/LICENSE-MIT b/LICENSE-MIT index 14bf0d7d..438ca971 100644 --- a/LICENSE-MIT +++ b/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2020 Tsang Hao Fung +Copyright (c) 2021 Tsang Hao Fung Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/README.md b/README.md index c5345d22..fa05785c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ Inspired by ActiveRecord, Eloquent and TypeORM, SeaORM aims to provide you an intuitive and ergonomic API to make working with databases in Rust a first-class experience. -```rust +```markdown This is a preview of SeaORM, and is not yet released. ``` @@ -145,9 +145,9 @@ fruit::Entity::delete_many() Licensed under either of - Apache License, Version 2.0 - ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + ([LICENSE-APACHE](LICENSE-APACHE) or ) - MIT license - ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + ([LICENSE-MIT](LICENSE-MIT) or ) at your option. diff --git a/sea-orm-codegen/src/entity/entity.rs b/sea-orm-codegen/src/entity/base_entity.rs similarity index 100% rename from sea-orm-codegen/src/entity/entity.rs rename to sea-orm-codegen/src/entity/base_entity.rs diff --git a/sea-orm-codegen/src/entity/mod.rs b/sea-orm-codegen/src/entity/mod.rs index 5badda4f..c1f43126 100644 --- a/sea-orm-codegen/src/entity/mod.rs +++ b/sea-orm-codegen/src/entity/mod.rs @@ -1,13 +1,13 @@ +mod base_entity; mod column; -mod entity; mod generator; mod primary_key; mod relation; mod transformer; mod writer; +pub use base_entity::*; pub use column::*; -pub use entity::*; pub use generator::*; pub use primary_key::*; pub use relation::*; diff --git a/sea-orm-codegen/tests/mod.rs b/sea-orm-codegen/tests/mod.rs index b06d561d..efc0a4c7 100644 --- a/sea-orm-codegen/tests/mod.rs +++ b/sea-orm-codegen/tests/mod.rs @@ -2,7 +2,7 @@ mod entity; use entity::*; -use sea_orm::{entity::*, error::*, MockDatabase, MockExecResult, Syntax, Transaction}; +use sea_orm::{entity::*, error::*, DbBackend, MockDatabase, MockExecResult, Transaction}; #[async_std::test] async fn test_insert() -> Result<(), DbErr> { @@ -11,7 +11,7 @@ async fn test_insert() -> Result<(), DbErr> { rows_affected: 1, }; - let db = MockDatabase::new(Syntax::Postgres) + let db = MockDatabase::new(DbBackend::Postgres) .append_exec_results(vec![exec_result.clone()]) .into_connection(); @@ -27,7 +27,7 @@ async fn test_insert() -> Result<(), DbErr> { assert_eq!( db.into_transaction_log(), vec![Transaction::from_sql_and_values( - Syntax::Postgres, + DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1)"#, vec!["Apple Pie".into()] )] @@ -43,7 +43,7 @@ async fn test_select() -> Result<(), DbErr> { filling_id: 3, }]; - let db = MockDatabase::new(Syntax::Postgres) + let db = MockDatabase::new(DbBackend::Postgres) .append_query_results(vec![query_results.clone()]) .into_connection(); @@ -54,7 +54,7 @@ async fn test_select() -> Result<(), DbErr> { assert_eq!( db.into_transaction_log(), vec![Transaction::from_sql_and_values( - Syntax::Postgres, + DbBackend::Postgres, [ r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#, r#"WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#, @@ -73,7 +73,7 @@ async fn test_update() -> Result<(), DbErr> { rows_affected: 1, }; - let db = MockDatabase::new(Syntax::Postgres) + let db = MockDatabase::new(DbBackend::Postgres) .append_exec_results(vec![exec_result.clone()]) .into_connection(); @@ -90,7 +90,7 @@ async fn test_update() -> Result<(), DbErr> { assert_eq!( db.into_transaction_log(), vec![Transaction::from_sql_and_values( - Syntax::Postgres, + DbBackend::Postgres, r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2"#, vec!["Orange".into(), 1i32.into()] )] @@ -106,7 +106,7 @@ async fn test_delete() -> Result<(), DbErr> { rows_affected: 1, }; - let db = MockDatabase::new(Syntax::Postgres) + let db = MockDatabase::new(DbBackend::Postgres) .append_exec_results(vec![exec_result.clone()]) .into_connection(); @@ -122,7 +122,7 @@ async fn test_delete() -> Result<(), DbErr> { assert_eq!( db.into_transaction_log(), vec![Transaction::from_sql_and_values( - Syntax::Postgres, + DbBackend::Postgres, r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#, vec![3i32.into()] )] diff --git a/src/database/connection.rs b/src/database/connection.rs index bd6a6d44..ee48ed43 100644 --- a/src/database/connection.rs +++ b/src/database/connection.rs @@ -1,8 +1,5 @@ -use crate::{error::*, ExecResult, QueryResult, Statement, Syntax}; -use sea_query::{ - MysqlQueryBuilder, PostgresQueryBuilder, QueryStatementBuilder, SchemaStatementBuilder, - SqliteQueryBuilder, -}; +use crate::{error::*, ExecResult, QueryResult, Statement, StatementBuilder}; +use sea_query::{MysqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder}; pub enum DatabaseConnection { #[cfg(feature = "sqlx-mysql")] @@ -16,17 +13,14 @@ pub enum DatabaseConnection { pub type DbConn = DatabaseConnection; -pub enum QueryBuilderBackend { +#[derive(Debug, Copy, Clone, PartialEq)] +pub enum DatabaseBackend { MySql, Postgres, Sqlite, } -pub enum SchemaBuilderBackend { - MySql, - Postgres, - Sqlite, -} +pub type DbBackend = DatabaseBackend; impl Default for DatabaseConnection { fn default() -> Self { @@ -53,26 +47,14 @@ impl std::fmt::Debug for DatabaseConnection { } impl DatabaseConnection { - pub fn get_query_builder_backend(&self) -> QueryBuilderBackend { + pub fn get_database_backend(&self) -> DbBackend { match self { #[cfg(feature = "sqlx-mysql")] - DatabaseConnection::SqlxMySqlPoolConnection(_) => QueryBuilderBackend::MySql, + DatabaseConnection::SqlxMySqlPoolConnection(_) => DbBackend::MySql, #[cfg(feature = "sqlx-sqlite")] - DatabaseConnection::SqlxSqlitePoolConnection(_) => QueryBuilderBackend::Sqlite, + DatabaseConnection::SqlxSqlitePoolConnection(_) => DbBackend::Sqlite, #[cfg(feature = "mock")] - DatabaseConnection::MockDatabaseConnection(conn) => conn.get_query_builder_backend(), - DatabaseConnection::Disconnected => panic!("Disconnected"), - } - } - - pub fn get_schema_builder_backend(&self) -> SchemaBuilderBackend { - match self { - #[cfg(feature = "sqlx-mysql")] - DatabaseConnection::SqlxMySqlPoolConnection(_) => SchemaBuilderBackend::MySql, - #[cfg(feature = "sqlx-sqlite")] - DatabaseConnection::SqlxSqlitePoolConnection(_) => SchemaBuilderBackend::Sqlite, - #[cfg(feature = "mock")] - DatabaseConnection::MockDatabaseConnection(conn) => conn.get_schema_builder_backend(), + DatabaseConnection::MockDatabaseConnection(conn) => conn.get_database_backend(), DatabaseConnection::Disconnected => panic!("Disconnected"), } } @@ -133,50 +115,19 @@ impl DatabaseConnection { } } -impl QueryBuilderBackend { - pub fn syntax(&self) -> Syntax { - match self { - Self::MySql => Syntax::MySql, - Self::Postgres => Syntax::Postgres, - Self::Sqlite => Syntax::Sqlite, - } - } - +impl DbBackend { pub fn build(&self, statement: &S) -> Statement where - S: QueryStatementBuilder, + S: StatementBuilder, { - Statement::from_string_values_tuple( - self.syntax(), - match self { - Self::MySql => statement.build(MysqlQueryBuilder), - Self::Postgres => statement.build(PostgresQueryBuilder), - Self::Sqlite => statement.build(SqliteQueryBuilder), - }, - ) + statement.build(self) } -} -impl SchemaBuilderBackend { - pub fn syntax(&self) -> Syntax { + pub fn get_query_builder(&self) -> Box { match self { - Self::MySql => Syntax::MySql, - Self::Postgres => Syntax::Postgres, - Self::Sqlite => Syntax::Sqlite, + Self::MySql => Box::new(MysqlQueryBuilder), + Self::Postgres => Box::new(PostgresQueryBuilder), + Self::Sqlite => Box::new(SqliteQueryBuilder), } } - - pub fn build(&self, statement: &S) -> Statement - where - S: SchemaStatementBuilder, - { - Statement::from_string( - self.syntax(), - match self { - Self::MySql => statement.build(MysqlQueryBuilder), - Self::Postgres => statement.build(PostgresQueryBuilder), - Self::Sqlite => statement.build(SqliteQueryBuilder), - }, - ) - } } diff --git a/src/database/mock.rs b/src/database/mock.rs index 6aa5f6e6..2ca13d33 100644 --- a/src/database/mock.rs +++ b/src/database/mock.rs @@ -1,14 +1,14 @@ use crate::{ - error::*, DatabaseConnection, EntityTrait, ExecResult, ExecResultHolder, Iden, Iterable, - MockDatabaseConnection, MockDatabaseTrait, ModelTrait, QueryResult, QueryResultRow, Statement, - Syntax, Transaction, + error::*, DbBackend, DatabaseConnection, EntityTrait, ExecResult, ExecResultHolder, Iden, + Iterable, MockDatabaseConnection, MockDatabaseTrait, ModelTrait, QueryResult, QueryResultRow, + Statement, Transaction, }; use sea_query::{Value, ValueType}; use std::collections::BTreeMap; #[derive(Debug)] pub struct MockDatabase { - syntax: Syntax, + db_backend: DbBackend, transaction_log: Vec, exec_results: Vec, query_results: Vec>, @@ -43,9 +43,9 @@ where } impl MockDatabase { - pub fn new(syntax: Syntax) -> Self { + pub fn new(db_backend: DbBackend) -> Self { Self { - syntax, + db_backend, transaction_log: Vec::new(), exec_results: Vec::new(), query_results: Vec::new(), @@ -103,8 +103,8 @@ impl MockDatabaseTrait for MockDatabase { std::mem::take(&mut self.transaction_log) } - fn get_syntax(&self) -> Syntax { - self.syntax + fn get_database_backend(&self) -> DbBackend { + self.db_backend } } diff --git a/src/database/statement.rs b/src/database/statement.rs index 2b19d59a..91a1c3c8 100644 --- a/src/database/statement.rs +++ b/src/database/statement.rs @@ -1,38 +1,47 @@ -use crate::{QueryBuilderBackend, QueryBuilderWithSyntax, SchemaBuilderBackend}; +use crate::DbBackend; use sea_query::{ - inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder, - Values, + inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, SqliteQueryBuilder, Value, Values }; use std::fmt; -#[derive(Debug, Copy, Clone, PartialEq)] -pub enum Syntax { - MySql, - Postgres, - Sqlite, -} - #[derive(Debug, Clone, PartialEq)] pub struct Statement { pub sql: String, pub values: Option, - pub syntax: Syntax, + pub db_backend: DbBackend, +} + +pub trait StatementBuilder { + fn build(&self, db_backend: &DbBackend) -> Statement; } impl Statement { - pub fn from_string(syntax: Syntax, stmt: String) -> Statement { + pub fn from_string(db_backend: DbBackend, stmt: String) -> Statement { Statement { sql: stmt, values: None, - syntax, + db_backend, } } - pub fn from_string_values_tuple(syntax: Syntax, stmt: (String, Values)) -> Statement { + pub fn from_sql_and_values(db_backend: DbBackend, sql: &str, values: I) -> Self + where + I: IntoIterator, + { + Self::from_string_values_tuple( + db_backend, + (sql.to_owned(), Values(values.into_iter().collect())), + ) + } + + pub(crate) fn from_string_values_tuple( + db_backend: DbBackend, + stmt: (String, Values), + ) -> Statement { Statement { sql: stmt.0, values: Some(stmt.1), - syntax, + db_backend, } } } @@ -44,7 +53,7 @@ impl fmt::Display for Statement { let string = inject_parameters( &self.sql, values.0.clone(), - self.syntax.get_query_builder().as_ref(), + self.db_backend.get_query_builder().as_ref(), ); write!(f, "{}", &string) } @@ -55,46 +64,45 @@ impl fmt::Display for Statement { } } -impl Syntax { - pub fn get_query_builder(&self) -> Box { - match self { - Self::MySql => Box::new(MysqlQueryBuilder), - Self::Postgres => Box::new(PostgresQueryBuilder), - Self::Sqlite => Box::new(SqliteQueryBuilder), +macro_rules! build_any_stmt { + ($stmt: expr, $db_backend: expr) => { + match $db_backend { + DbBackend::MySql => $stmt.build(MysqlQueryBuilder), + DbBackend::Postgres => $stmt.build(PostgresQueryBuilder), + DbBackend::Sqlite => $stmt.build(SqliteQueryBuilder), } - } + }; +} - pub fn get_query_builder_backend(&self) -> QueryBuilderBackend { - match self { - Self::MySql => QueryBuilderBackend::MySql, - Self::Postgres => QueryBuilderBackend::Postgres, - Self::Sqlite => QueryBuilderBackend::Sqlite, +macro_rules! build_query_stmt { + ($stmt: ty) => { + impl StatementBuilder for $stmt { + fn build(&self, db_backend: &DbBackend) -> Statement { + let stmt = build_any_stmt!(self, db_backend); + Statement::from_string_values_tuple(*db_backend, stmt) + } } - } + }; +} - pub fn get_schema_builder_backend(&self) -> SchemaBuilderBackend { - match self { - Self::MySql => SchemaBuilderBackend::MySql, - Self::Postgres => SchemaBuilderBackend::Postgres, - Self::Sqlite => SchemaBuilderBackend::Sqlite, +build_query_stmt!(sea_query::InsertStatement); +build_query_stmt!(sea_query::SelectStatement); +build_query_stmt!(sea_query::UpdateStatement); +build_query_stmt!(sea_query::DeleteStatement); + +macro_rules! build_schema_stmt { + ($stmt: ty) => { + impl StatementBuilder for $stmt { + fn build(&self, db_backend: &DbBackend) -> Statement { + let stmt = build_any_stmt!(self, db_backend); + Statement::from_string(*db_backend, stmt) + } } - } + }; } -impl QueryBuilderWithSyntax for MysqlQueryBuilder { - fn syntax(&self) -> Syntax { - Syntax::MySql - } -} - -impl QueryBuilderWithSyntax for PostgresQueryBuilder { - fn syntax(&self) -> Syntax { - Syntax::Postgres - } -} - -impl QueryBuilderWithSyntax for SqliteQueryBuilder { - fn syntax(&self) -> Syntax { - Syntax::Sqlite - } -} +build_schema_stmt!(sea_query::TableCreateStatement); +build_schema_stmt!(sea_query::TableDropStatement); +build_schema_stmt!(sea_query::TableAlterStatement); +build_schema_stmt!(sea_query::TableRenameStatement); +build_schema_stmt!(sea_query::TableTruncateStatement); diff --git a/src/database/transaction.rs b/src/database/transaction.rs index 7c62da60..6bf06491 100644 --- a/src/database/transaction.rs +++ b/src/database/transaction.rs @@ -1,4 +1,4 @@ -use crate::{Statement, Syntax}; +use crate::{DbBackend, Statement}; use sea_query::{Value, Values}; #[derive(Debug, Clone, PartialEq)] @@ -7,12 +7,12 @@ pub struct Transaction { } impl Transaction { - pub fn from_sql_and_values(syntax: Syntax, sql: &str, values: I) -> Self + pub fn from_sql_and_values(db_backend: DbBackend, sql: &str, values: I) -> Self where I: IntoIterator, { Self::one(Statement::from_string_values_tuple( - syntax, + db_backend, (sql.to_string(), Values(values.into_iter().collect())), )) } diff --git a/src/driver/mock.rs b/src/driver/mock.rs index 7f6421e4..e16185ee 100644 --- a/src/driver/mock.rs +++ b/src/driver/mock.rs @@ -1,6 +1,6 @@ use crate::{ - debug_print, error::*, DatabaseConnection, ExecResult, MockDatabase, QueryBuilderBackend, - QueryResult, SchemaBuilderBackend, Statement, Syntax, Transaction, + debug_print, error::*, DbBackend, DatabaseConnection, ExecResult, MockDatabase, + QueryResult, Statement, Transaction, }; use std::sync::{ atomic::{AtomicUsize, Ordering}, @@ -21,7 +21,7 @@ pub trait MockDatabaseTrait: Send { fn drain_transaction_log(&mut self) -> Vec; - fn get_syntax(&self) -> Syntax; + fn get_database_backend(&self) -> DbBackend; } impl MockDatabaseConnector { @@ -48,13 +48,13 @@ impl MockDatabaseConnector { #[cfg(feature = "sqlx-mysql")] if crate::SqlxMySqlConnector::accepts(string) { - return connect_mock_db!(Syntax::MySql); + return connect_mock_db!(DbBackend::MySql); } #[cfg(feature = "sqlx-sqlite")] if crate::SqlxSqliteConnector::accepts(string) { - return connect_mock_db!(Syntax::Sqlite); + return connect_mock_db!(DbBackend::Sqlite); } - connect_mock_db!(Syntax::Postgres) + connect_mock_db!(DbBackend::Postgres) } } @@ -92,19 +92,7 @@ impl MockDatabaseConnection { self.mocker.lock().unwrap().query(counter, statement) } - pub fn get_query_builder_backend(&self) -> QueryBuilderBackend { - self.mocker - .lock() - .unwrap() - .get_syntax() - .get_query_builder_backend() - } - - pub fn get_schema_builder_backend(&self) -> SchemaBuilderBackend { - self.mocker - .lock() - .unwrap() - .get_syntax() - .get_schema_builder_backend() + pub fn get_database_backend(&self) -> DbBackend { + self.mocker.lock().unwrap().get_database_backend() } } diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index b64e8310..c25f035e 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -18,7 +18,8 @@ pub trait EntityName: IdenStatic + Default { Self::table_name(self) } } -/// Each table in database correspond to a Entity implemented [`EntityTrait`]. + +/// An Entity implementing `EntityTrait` represents a table in a database. /// /// This trait provides an API for you to inspect it's properties /// - Column (implemented [`ColumnTrait`]) @@ -70,9 +71,9 @@ pub trait EntityTrait: EntityName { /// /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_query_results(vec![ /// # vec![ /// # cake::Model { @@ -126,10 +127,10 @@ pub trait EntityTrait: EntityName { /// db.into_transaction_log(), /// vec![ /// Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#, vec![1u64.into()] + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake" LIMIT $1"#, vec![1u64.into()] /// ), /// Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] /// ), /// ]); /// ``` @@ -143,9 +144,9 @@ pub trait EntityTrait: EntityName { /// /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_query_results(vec![ /// # vec![ /// # cake::Model { @@ -174,15 +175,15 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = $1"#, vec![11i32.into()] + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "cake"."id" = $1"#, vec![11i32.into()] /// )]); /// ``` /// Find by composite key /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_query_results(vec![ /// # vec![ /// # cake_filling::Model { @@ -211,7 +212,7 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// Syntax::Postgres, + /// DbBackend::Postgres, /// [ /// r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#, /// r#"WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#, @@ -245,9 +246,9 @@ pub trait EntityTrait: EntityName { /// /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_exec_results(vec![ /// # MockExecResult { /// # last_insert_id: 15, @@ -276,7 +277,7 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1)"#, vec!["Apple Pie".into()] + /// DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1)"#, vec!["Apple Pie".into()] /// )]); /// ``` fn insert(model: A) -> Insert @@ -292,9 +293,9 @@ pub trait EntityTrait: EntityName { /// /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_exec_results(vec![ /// # MockExecResult { /// # last_insert_id: 28, @@ -327,7 +328,7 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1), ($2)"#, + /// DbBackend::Postgres, r#"INSERT INTO "cake" ("name") VALUES ($1), ($2)"#, /// vec!["Apple Pie".into(), "Orange Scone".into()] /// )]); /// ``` @@ -347,9 +348,9 @@ pub trait EntityTrait: EntityName { /// /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_exec_results(vec![ /// # MockExecResult { /// # last_insert_id: 0, @@ -379,7 +380,7 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2"#, vec!["Orange".into(), 1i32.into()] + /// DbBackend::Postgres, r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2"#, vec!["Orange".into(), 1i32.into()] /// )]); /// ``` fn update(model: A) -> UpdateOne @@ -397,9 +398,9 @@ pub trait EntityTrait: EntityName { /// /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_exec_results(vec![ /// # MockExecResult { /// # last_insert_id: 0, @@ -426,7 +427,7 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#, vec![Value::Null, "%Apple%".into()] + /// DbBackend::Postgres, r#"UPDATE "fruit" SET "cake_id" = $1 WHERE "fruit"."name" LIKE $2"#, vec![Value::Null, "%Apple%".into()] /// )]); /// ``` fn update_many() -> UpdateMany { @@ -441,9 +442,9 @@ pub trait EntityTrait: EntityName { /// /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_exec_results(vec![ /// # MockExecResult { /// # last_insert_id: 0, @@ -471,7 +472,7 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#, vec![3i32.into()] + /// DbBackend::Postgres, r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#, vec![3i32.into()] /// )]); /// ``` fn delete(model: A) -> DeleteOne @@ -489,9 +490,9 @@ pub trait EntityTrait: EntityName { /// /// ``` /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, Syntax}; + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, MockExecResult, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(Syntax::Postgres) + /// # let db = MockDatabase::new(DbBackend::Postgres) /// # .append_exec_results(vec![ /// # MockExecResult { /// # last_insert_id: 0, @@ -517,7 +518,7 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// Syntax::Postgres, r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE $1"#, vec!["%Apple%".into()] + /// DbBackend::Postgres, r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE $1"#, vec!["%Apple%".into()] /// )]); /// ``` fn delete_many() -> DeleteMany { diff --git a/src/entity/column.rs b/src/entity/column.rs index d6580e8f..adf54595 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -88,12 +88,12 @@ pub trait ColumnTrait: IdenStatic + Iterable { bind_oper!(lte); /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Id.between(2,3)) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` BETWEEN 2 AND 3" /// ); @@ -106,12 +106,12 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Id.not_between(2,3)) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` NOT BETWEEN 2 AND 3" /// ); @@ -124,12 +124,12 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.like("cheese")) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'" /// ); @@ -139,12 +139,12 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.not_like("cheese")) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` NOT LIKE 'cheese'" /// ); @@ -154,12 +154,12 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.starts_with("cheese")) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'" /// ); @@ -170,12 +170,12 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.ends_with("cheese")) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'" /// ); @@ -186,12 +186,12 @@ pub trait ColumnTrait: IdenStatic + Iterable { } /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Name.contains("cheese")) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'" /// ); @@ -245,29 +245,29 @@ impl ColumnDef { } } -impl Into for ColumnType { - fn into(self) -> sea_query::ColumnType { - match self { - Self::Char(s) => sea_query::ColumnType::Char(s), - Self::String(s) => sea_query::ColumnType::String(s), - Self::Text => sea_query::ColumnType::Text, - Self::TinyInteger => sea_query::ColumnType::TinyInteger(None), - Self::SmallInteger => sea_query::ColumnType::SmallInteger(None), - Self::Integer => sea_query::ColumnType::Integer(None), - Self::BigInteger => sea_query::ColumnType::BigInteger(None), - Self::Float => sea_query::ColumnType::Float(None), - Self::Double => sea_query::ColumnType::Double(None), - Self::Decimal(s) => sea_query::ColumnType::Decimal(s), - Self::DateTime => sea_query::ColumnType::DateTime(None), - Self::Timestamp => sea_query::ColumnType::Timestamp(None), - Self::Time => sea_query::ColumnType::Time(None), - Self::Date => sea_query::ColumnType::Date, - Self::Binary => sea_query::ColumnType::Binary(None), - Self::Boolean => sea_query::ColumnType::Boolean, - Self::Money(s) => sea_query::ColumnType::Money(s), - Self::Json => sea_query::ColumnType::Json, - Self::JsonBinary => sea_query::ColumnType::JsonBinary, - Self::Custom(s) => { +impl From for sea_query::ColumnType { + fn from(col: ColumnType) -> Self { + match col { + ColumnType::Char(s) => sea_query::ColumnType::Char(s), + ColumnType::String(s) => sea_query::ColumnType::String(s), + ColumnType::Text => sea_query::ColumnType::Text, + ColumnType::TinyInteger => sea_query::ColumnType::TinyInteger(None), + ColumnType::SmallInteger => sea_query::ColumnType::SmallInteger(None), + ColumnType::Integer => sea_query::ColumnType::Integer(None), + ColumnType::BigInteger => sea_query::ColumnType::BigInteger(None), + ColumnType::Float => sea_query::ColumnType::Float(None), + ColumnType::Double => sea_query::ColumnType::Double(None), + ColumnType::Decimal(s) => sea_query::ColumnType::Decimal(s), + ColumnType::DateTime => sea_query::ColumnType::DateTime(None), + ColumnType::Timestamp => sea_query::ColumnType::Timestamp(None), + ColumnType::Time => sea_query::ColumnType::Time(None), + ColumnType::Date => sea_query::ColumnType::Date, + ColumnType::Binary => sea_query::ColumnType::Binary(None), + ColumnType::Boolean => sea_query::ColumnType::Boolean, + ColumnType::Money(s) => sea_query::ColumnType::Money(s), + ColumnType::Json => sea_query::ColumnType::Json, + ColumnType::JsonBinary => sea_query::ColumnType::JsonBinary, + ColumnType::Custom(s) => { sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(&s))) } } diff --git a/src/executor/delete.rs b/src/executor/delete.rs index bbdc3bb5..807bc544 100644 --- a/src/executor/delete.rs +++ b/src/executor/delete.rs @@ -49,7 +49,7 @@ impl Deleter { self, db: &DatabaseConnection, ) -> impl Future> + '_ { - let builder = db.get_query_builder_backend(); + let builder = db.get_database_backend(); exec_delete(builder.build(&self.query), db) } } diff --git a/src/executor/insert.rs b/src/executor/insert.rs index 784d95a0..b7fd1163 100644 --- a/src/executor/insert.rs +++ b/src/executor/insert.rs @@ -34,7 +34,7 @@ impl Inserter { self, db: &DatabaseConnection, ) -> impl Future> + '_ { - let builder = db.get_query_builder_backend(); + let builder = db.get_database_backend(); exec_insert(builder.build(&self.query), db) } } diff --git a/src/executor/paginator.rs b/src/executor/paginator.rs index 6b4459cc..3698456a 100644 --- a/src/executor/paginator.rs +++ b/src/executor/paginator.rs @@ -18,6 +18,8 @@ where pub(crate) selector: PhantomData, } +// LINT: warn if paginator is used without an order by clause + impl<'db, S> Paginator<'db, S> where S: SelectorTrait + 'db, @@ -30,7 +32,7 @@ where .limit(self.page_size as u64) .offset((self.page_size * page) as u64) .to_owned(); - let builder = self.db.get_query_builder_backend(); + let builder = self.db.get_database_backend(); let stmt = builder.build(&query); let rows = self.db.query_all(stmt).await?; let mut buffer = Vec::with_capacity(rows.len()); @@ -46,12 +48,12 @@ where self.fetch_page(self.page).await } - /// Get the total number of pages - pub async fn num_pages(&self) -> Result { - let builder = self.db.get_query_builder_backend(); + /// Get the total number of items + pub async fn num_items(&self) -> Result { + let builder = self.db.get_database_backend(); let stmt = builder.build( SelectStatement::new() - .expr(Expr::cust("COUNT(*) AS num_rows")) + .expr(Expr::cust("COUNT(*) AS num_items")) .from_subquery( self.query.clone().reset_limit().reset_offset().to_owned(), Alias::new("sub_query"), @@ -61,8 +63,14 @@ where Some(res) => res, None => return Ok(0), }; - let num_rows = result.try_get::("", "num_rows")? as usize; - let num_pages = (num_rows / self.page_size) + (num_rows % self.page_size > 0) as usize; + let num_items = result.try_get::("", "num_items")? as usize; + Ok(num_items) + } + + /// Get the total number of pages + pub async fn num_pages(&self) -> Result { + let num_items = self.num_items().await?; + let num_pages = (num_items / self.page_size) + (num_items % self.page_size > 0) as usize; Ok(num_pages) } @@ -77,6 +85,26 @@ where } /// Fetch one page and increment the page counter + /// + /// ```rust + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, MockDatabase, DbBackend}; + /// # let owned_db = MockDatabase::new(DbBackend::Postgres).into_connection(); + /// # let db = &owned_db; + /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; + /// let mut cake_pages = cake::Entity::find() + /// .order_by_asc(cake::Column::Id) + /// .paginate(db, 50); + /// + /// while let Some(cakes) = cake_pages.fetch_and_next().await? { + /// // Do something on cakes: Vec + /// } + /// # + /// # Ok(()) + /// # }); + /// ``` pub async fn fetch_and_next(&mut self) -> Result>, DbErr> { let vec = self.fetch().await?; self.next(); @@ -85,6 +113,28 @@ where } /// Convert self into an async stream + /// + /// ```rust + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, MockDatabase, DbBackend}; + /// # let owned_db = MockDatabase::new(DbBackend::Postgres).into_connection(); + /// # let db = &owned_db; + /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # + /// use futures::TryStreamExt; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; + /// let mut cake_stream = cake::Entity::find() + /// .order_by_asc(cake::Column::Id) + /// .paginate(db, 50) + /// .into_stream(); + /// + /// while let Some(cakes) = cake_stream.try_next().await? { + /// // Do something on cakes: Vec + /// } + /// # + /// # Ok(()) + /// # }); + /// ``` pub fn into_stream(mut self) -> PinBoxStream<'db, Result, DbErr>> { Box::pin(stream! { loop { @@ -103,7 +153,7 @@ where mod tests { use crate::entity::prelude::*; use crate::tests_cfg::*; - use crate::{DatabaseConnection, MockDatabase, Syntax, Transaction}; + use crate::{DbBackend, DatabaseConnection, MockDatabase, Transaction}; use futures::TryStreamExt; use sea_query::{Alias, Expr, SelectStatement, Value}; @@ -129,22 +179,22 @@ mod tests { let page3 = Vec::::new(); - let db = MockDatabase::new(Syntax::Postgres) + let db = MockDatabase::new(DbBackend::Postgres) .append_query_results(vec![page1.clone(), page2.clone(), page3.clone()]) .into_connection(); (db, vec![page1, page2, page3]) } - fn setup_num_rows() -> (DatabaseConnection, i32) { - let num_rows = 3; - let db = MockDatabase::new(Syntax::Postgres) + fn setup_num_items() -> (DatabaseConnection, i32) { + let num_items = 3; + let db = MockDatabase::new(DbBackend::Postgres) .append_query_results(vec![vec![maplit::btreemap! { - "num_rows" => Into::::into(num_rows), + "num_items" => Into::::into(num_items), }]]) .into_connection(); - (db, num_rows) + (db, num_items) } #[async_std::test] @@ -166,7 +216,7 @@ mod tests { .from(fruit::Entity) .to_owned(); - let query_builder = db.get_query_builder_backend(); + let query_builder = db.get_database_backend(); let stmts = vec![ query_builder.build(select.clone().offset(0).limit(2)), query_builder.build(select.clone().offset(2).limit(2)), @@ -200,7 +250,7 @@ mod tests { .from(fruit::Entity) .to_owned(); - let query_builder = db.get_query_builder_backend(); + let query_builder = db.get_database_backend(); let stmts = vec![ query_builder.build(select.clone().offset(0).limit(2)), query_builder.build(select.clone().offset(2).limit(2)), @@ -213,11 +263,11 @@ mod tests { #[async_std::test] async fn num_pages() -> Result<(), DbErr> { - let (db, num_rows) = setup_num_rows(); + let (db, num_items) = setup_num_items(); - let num_rows = num_rows as usize; + let num_items = num_items as usize; let page_size = 2_usize; - let num_pages = (num_rows / page_size) + (num_rows % page_size > 0) as usize; + let num_pages = (num_items / page_size) + (num_items % page_size > 0) as usize; let paginator = fruit::Entity::find().paginate(&db, page_size); assert_eq!(paginator.num_pages().await?, num_pages); @@ -232,11 +282,11 @@ mod tests { .to_owned(); let select = SelectStatement::new() - .expr(Expr::cust("COUNT(*) AS num_rows")) + .expr(Expr::cust("COUNT(*) AS num_items")) .from_subquery(sub_query, Alias::new("sub_query")) .to_owned(); - let query_builder = db.get_query_builder_backend(); + let query_builder = db.get_database_backend(); let stmts = vec![query_builder.build(&select)]; assert_eq!(db.into_transaction_log(), Transaction::wrap(stmts)); @@ -283,7 +333,7 @@ mod tests { .from(fruit::Entity) .to_owned(); - let query_builder = db.get_query_builder_backend(); + let query_builder = db.get_database_backend(); let stmts = vec![ query_builder.build(select.clone().offset(0).limit(2)), query_builder.build(select.clone().offset(2).limit(2)), @@ -315,7 +365,7 @@ mod tests { .from(fruit::Entity) .to_owned(); - let query_builder = db.get_query_builder_backend(); + let query_builder = db.get_database_backend(); let stmts = vec![ query_builder.build(select.clone().offset(0).limit(2)), query_builder.build(select.clone().offset(2).limit(2)), diff --git a/src/executor/select.rs b/src/executor/select.rs index 607e0de0..ffc94d64 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -1,7 +1,7 @@ use crate::{ error::*, query::combine, DatabaseConnection, EntityTrait, FromQueryResult, Iterable, JsonValue, ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectTwo, - SelectTwoMany, + SelectTwoMany, Statement, }; use sea_query::SelectStatement; use std::marker::PhantomData; @@ -15,6 +15,15 @@ where selector: S, } +#[derive(Clone, Debug)] +pub struct SelectorRaw +where + S: SelectorTrait, +{ + stmt: Statement, + selector: S, +} + pub trait SelectorTrait { type Item: Sized; @@ -67,6 +76,56 @@ impl Select where E: EntityTrait, { + /// ``` + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; + /// # + /// # let db = MockDatabase::new(DbBackend::Postgres) + /// # .append_query_results(vec![ + /// # vec![ + /// # cake::Model { + /// # id: 1, + /// # name: "New York Cheese".to_owned(), + /// # }, + /// # ], + /// # ]) + /// # .into_connection(); + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; + /// + /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # + /// assert_eq!( + /// cake::Entity::find().from_raw_sql( + /// Statement::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] + /// ) + /// ).one(&db).await?, + /// Some(cake::Model { + /// id: 1, + /// name: "New York Cheese".to_owned(), + /// }) + /// ); + /// # + /// # Ok(()) + /// # }); + /// + /// assert_eq!( + /// db.into_transaction_log(), + /// vec![ + /// Transaction::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] + /// ), + /// ]); + /// ``` + #[allow(clippy::wrong_self_convention)] + pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw> { + SelectorRaw { + stmt, + selector: SelectModel { model: PhantomData }, + } + } + pub fn into_model(self) -> Selector> where M: FromQueryResult, @@ -86,11 +145,11 @@ where } pub async fn one(self, db: &DatabaseConnection) -> Result, DbErr> { - self.into_model::().one(db).await + self.into_model().one(db).await } pub async fn all(self, db: &DatabaseConnection) -> Result, DbErr> { - self.into_model::().all(db).await + self.into_model().all(db).await } pub fn paginate( @@ -98,7 +157,11 @@ where db: &DatabaseConnection, page_size: usize, ) -> Paginator<'_, SelectModel> { - self.into_model::().paginate(db, page_size) + self.into_model().paginate(db, page_size) + } + + pub async fn count(self, db: &DatabaseConnection) -> Result { + self.paginate(db, 1).num_items().await } } @@ -130,14 +193,26 @@ where self, db: &DatabaseConnection, ) -> Result)>, DbErr> { - self.into_model::().one(db).await + self.into_model().one(db).await } pub async fn all( self, db: &DatabaseConnection, ) -> Result)>, DbErr> { - self.into_model::().all(db).await + self.into_model().all(db).await + } + + pub fn paginate( + self, + db: &DatabaseConnection, + page_size: usize, + ) -> Paginator<'_, SelectTwoModel> { + self.into_model().paginate(db, page_size) + } + + pub async fn count(self, db: &DatabaseConnection) -> Result { + self.paginate(db, 1).num_items().await } } @@ -169,16 +244,25 @@ where self, db: &DatabaseConnection, ) -> Result)>, DbErr> { - self.into_model::().one(db).await + self.into_model().one(db).await } pub async fn all( self, db: &DatabaseConnection, ) -> Result)>, DbErr> { - let rows = self.into_model::().all(db).await?; + let rows = self.into_model().all(db).await?; Ok(consolidate_query_result::(rows)) } + + // pub fn paginate() + // we could not implement paginate easily, if the number of children for a + // parent is larger than one page, then we will end up splitting it in two pages + // so the correct way is actually perform query in two stages + // paginate the parent model and then populate the children + + // pub fn count() + // we should only count the number of items of the parent model } impl Selector @@ -186,7 +270,7 @@ where S: SelectorTrait, { pub async fn one(mut self, db: &DatabaseConnection) -> Result, DbErr> { - let builder = db.get_query_builder_backend(); + let builder = db.get_database_backend(); self.query.limit(1); let row = db.query_one(builder.build(&self.query)).await?; match row { @@ -196,7 +280,7 @@ where } pub async fn all(self, db: &DatabaseConnection) -> Result, DbErr> { - let builder = db.get_query_builder_backend(); + let builder = db.get_database_backend(); let rows = db.query_all(builder.build(&self.query)).await?; let mut models = Vec::new(); for row in rows.into_iter() { @@ -216,6 +300,28 @@ where } } +impl SelectorRaw +where + S: SelectorTrait, +{ + pub async fn one(self, db: &DatabaseConnection) -> Result, DbErr> { + let row = db.query_one(self.stmt).await?; + match row { + Some(row) => Ok(Some(S::from_raw_query_result(row)?)), + None => Ok(None), + } + } + + pub async fn all(self, db: &DatabaseConnection) -> Result, DbErr> { + let rows = db.query_all(self.stmt).await?; + let mut models = Vec::new(); + for row in rows.into_iter() { + models.push(S::from_raw_query_result(row)?); + } + Ok(models) + } +} + fn consolidate_query_result( rows: Vec<(L::Model, Option)>, ) -> Vec<(L::Model, Vec)> diff --git a/src/executor/update.rs b/src/executor/update.rs index 0f33c914..6c7a9873 100644 --- a/src/executor/update.rs +++ b/src/executor/update.rs @@ -46,7 +46,7 @@ impl Updater { self, db: &DatabaseConnection, ) -> impl Future> + '_ { - let builder = db.get_query_builder_backend(); + let builder = db.get_database_backend(); exec_update(builder.build(&self.query), db) } } diff --git a/src/lib.rs b/src/lib.rs index e80fb521..5d602897 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,7 +17,7 @@ //! Inspired by ActiveRecord, Eloquent and TypeORM, SeaORM aims to provide you an intuitive and ergonomic //! API to make working with databases in Rust a first-class experience. //! -//! ```ignore +//! ```markdown //! This is a preview of SeaORM, and is not yet released. //! ``` //! diff --git a/src/query/combine.rs b/src/query/combine.rs index f52b7925..8cce0510 100644 --- a/src/query/combine.rs +++ b/src/query/combine.rs @@ -113,8 +113,7 @@ where #[cfg(test)] mod tests { use crate::tests_cfg::{cake, fruit}; - use crate::{ColumnTrait, EntityTrait, QueryFilter, QuerySelect, QueryTrait}; - use sea_query::MysqlQueryBuilder; + use crate::{ColumnTrait, DbBackend, EntityTrait, QueryFilter, QuerySelect, QueryTrait}; #[test] fn alias_1() { @@ -122,7 +121,7 @@ mod tests { cake::Entity::find() .column_as(cake::Column::Id, "B") .apply_alias("A_") - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`, `cake`.`id` AS `A_B` FROM `cake`", ); @@ -134,7 +133,7 @@ mod tests { cake::Entity::find() .left_join(fruit::Entity) .select_also(fruit::Entity) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,", @@ -150,7 +149,7 @@ mod tests { cake::Entity::find() .left_join(fruit::Entity) .select_with(fruit::Entity) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,", @@ -169,7 +168,7 @@ mod tests { .select_also(fruit::Entity) .filter(cake::Column::Id.eq(1)) .filter(fruit::Column::Id.eq(2)) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,", @@ -188,7 +187,7 @@ mod tests { .select_with(fruit::Entity) .filter(cake::Column::Id.eq(1)) .filter(fruit::Column::Id.eq(2)) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,", diff --git a/src/query/delete.rs b/src/query/delete.rs index 467a6980..8c3b2a52 100644 --- a/src/query/delete.rs +++ b/src/query/delete.rs @@ -31,28 +31,28 @@ impl Delete { /// /// Model /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// Delete::one(cake::Model { /// id: 1, /// name: "Apple Pie".to_owned(), /// }) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#, /// ); /// ``` /// ActiveModel /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// Delete::one(cake::ActiveModel { /// id: ActiveValue::set(1), /// name: ActiveValue::set("Apple Pie".to_owned()), /// }) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#, /// ); @@ -75,12 +75,12 @@ impl Delete { /// Delete many ActiveModel /// /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::fruit, sea_query::{Expr, PostgresQueryBuilder}}; + /// use sea_orm::{entity::*, query::*, tests_cfg::fruit, DbBackend}; /// /// assert_eq!( /// Delete::many(fruit::Entity) /// .filter(fruit::Column::Name.contains("Apple")) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Apple%'"#, /// ); @@ -179,8 +179,7 @@ where #[cfg(test)] mod tests { use crate::tests_cfg::{cake, fruit}; - use crate::{entity::*, query::*}; - use sea_query::PostgresQueryBuilder; + use crate::{entity::*, query::*, DbBackend}; #[test] fn delete_1() { @@ -189,7 +188,7 @@ mod tests { id: 1, name: "Apple Pie".to_owned(), }) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#, ); @@ -198,7 +197,7 @@ mod tests { id: ActiveValue::set(1), name: ActiveValue::set("Apple Pie".to_owned()), }) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#, ); @@ -209,7 +208,7 @@ mod tests { assert_eq!( Delete::many(fruit::Entity) .filter(fruit::Column::Name.contains("Cheese")) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Cheese%'"#, ); diff --git a/src/query/helper.rs b/src/query/helper.rs index 7044c63d..79bc9d7d 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -23,13 +23,13 @@ pub trait QuerySelect: Sized { /// Add a select column /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .select_only() /// .column(cake::Column::Name) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"SELECT "cake"."name" FROM "cake""# /// ); @@ -44,13 +44,13 @@ pub trait QuerySelect: Sized { /// Add a select column with alias /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .select_only() /// .column_as(cake::Column::Id.count(), "count") - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"SELECT COUNT("cake"."id") AS "count" FROM "cake""# /// ); @@ -68,14 +68,14 @@ pub trait QuerySelect: Sized { /// Add a group by column /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .select_only() /// .column(cake::Column::Name) /// .group_by(cake::Column::Name) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"SELECT "cake"."name" FROM "cake" GROUP BY "cake"."name""# /// ); @@ -90,13 +90,13 @@ pub trait QuerySelect: Sized { /// Add an AND HAVING expression /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .having(cake::Column::Id.eq(4)) /// .having(cake::Column::Id.eq(5)) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` HAVING `cake`.`id` = 4 AND `cake`.`id` = 5" /// ); @@ -151,13 +151,13 @@ pub trait QueryOrder: Sized { /// Add an order_by expression /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .order_by(cake::Column::Id, Order::Asc) /// .order_by(cake::Column::Name, Order::Desc) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` ASC, `cake`.`name` DESC" /// ); @@ -172,12 +172,12 @@ pub trait QueryOrder: Sized { /// Add an order_by expression (ascending) /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .order_by_asc(cake::Column::Id) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` ASC" /// ); @@ -193,12 +193,12 @@ pub trait QueryOrder: Sized { /// Add an order_by expression (descending) /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .order_by_desc(cake::Column::Id) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` DESC" /// ); @@ -221,13 +221,13 @@ pub trait QueryFilter: Sized { /// Add an AND WHERE expression /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() /// .filter(cake::Column::Id.eq(4)) /// .filter(cake::Column::Id.eq(5)) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 AND `cake`.`id` = 5" /// ); @@ -235,7 +235,7 @@ pub trait QueryFilter: Sized { /// /// Add a condition tree. /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::MysqlQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// cake::Entity::find() @@ -244,7 +244,7 @@ pub trait QueryFilter: Sized { /// .add(cake::Column::Id.eq(4)) /// .add(cake::Column::Id.eq(5)) /// ) - /// .build(MysqlQueryBuilder) + /// .build(DbBackend::MySql) /// .to_string(), /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 OR `cake`.`id` = 5" /// ); diff --git a/src/query/insert.rs b/src/query/insert.rs index 5ed11a46..25d0a9ea 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -25,7 +25,7 @@ impl Insert where A: ActiveModelTrait, { - pub fn new() -> Self { + pub(crate) fn new() -> Self { Self { query: InsertStatement::new() .into_table(A::Entity::default().into_iden()) @@ -39,28 +39,28 @@ where /// /// Model /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// Insert::one(cake::Model { /// id: 1, /// name: "Apple Pie".to_owned(), /// }) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, /// ); /// ``` /// ActiveModel /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// Insert::one(cake::ActiveModel { /// id: Unset(None), /// name: Set("Apple Pie".to_owned()), /// }) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#, /// ); @@ -75,7 +75,7 @@ where /// Insert many Model or ActiveModel /// /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// Insert::many(vec![ @@ -88,7 +88,7 @@ where /// name: "Orange Scone".to_owned(), /// } /// ]) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#, /// ); @@ -162,8 +162,7 @@ where #[cfg(test)] mod tests { use crate::tests_cfg::cake; - use crate::{ActiveValue, Insert, QueryTrait}; - use sea_query::PostgresQueryBuilder; + use crate::{ActiveValue, DbBackend, Insert, QueryTrait}; #[test] fn insert_1() { @@ -173,7 +172,7 @@ mod tests { id: ActiveValue::unset(), name: ActiveValue::set("Apple Pie".to_owned()), }) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#, ); @@ -187,7 +186,7 @@ mod tests { id: ActiveValue::set(1), name: ActiveValue::set("Apple Pie".to_owned()), }) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, ); @@ -201,7 +200,7 @@ mod tests { id: 1, name: "Apple Pie".to_owned(), }) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, ); @@ -221,7 +220,7 @@ mod tests { name: "Orange Scone".to_owned(), } ]) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#, ); @@ -241,7 +240,7 @@ mod tests { assert_eq!( Insert::::new() .add_many(vec![apple, orange]) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"INSERT INTO "cake" ("id", "name") VALUES (NULL, 'Apple'), (2, 'Orange')"#, ); diff --git a/src/query/join.rs b/src/query/join.rs index 4481f5af..61c6c1b9 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -62,15 +62,14 @@ where #[cfg(test)] mod tests { use crate::tests_cfg::{cake, filling, fruit}; - use crate::{ColumnTrait, EntityTrait, ModelTrait, QueryFilter, QueryTrait}; - use sea_query::MysqlQueryBuilder; + use crate::{ColumnTrait, DbBackend, EntityTrait, ModelTrait, QueryFilter, QueryTrait}; #[test] fn join_1() { assert_eq!( cake::Entity::find() .left_join(fruit::Entity) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id`, `cake`.`name` FROM `cake`", @@ -86,7 +85,7 @@ mod tests { cake::Entity::find() .inner_join(fruit::Entity) .filter(fruit::Column::Name.contains("cherry")) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id`, `cake`.`name` FROM `cake`", @@ -102,7 +101,7 @@ mod tests { assert_eq!( fruit::Entity::find() .reverse_join(cake::Entity) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`", @@ -120,7 +119,7 @@ mod tests { assert_eq!( find_fruit .filter(cake::Column::Id.eq(11)) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`", @@ -141,7 +140,7 @@ mod tests { assert_eq!( cake_model .find_related(fruit::Entity) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`", @@ -157,7 +156,7 @@ mod tests { assert_eq!( cake::Entity::find() .left_join(filling::Entity) - .build(MysqlQueryBuilder) + .build(DbBackend::MySql) .to_string(), [ "SELECT `cake`.`id`, `cake`.`name` FROM `cake`", @@ -174,7 +173,7 @@ mod tests { let find_filling: Select = cake::Entity::find_related(); assert_eq!( - find_filling.build(MysqlQueryBuilder).to_string(), + find_filling.build(DbBackend::MySql).to_string(), [ "SELECT `filling`.`id`, `filling`.`name` FROM `filling`", "INNER JOIN `cake_filling` ON `cake_filling`.`filling_id` = `filling`.`id`", diff --git a/src/query/json.rs b/src/query/json.rs index 8284427c..1d372308 100644 --- a/src/query/json.rs +++ b/src/query/json.rs @@ -102,12 +102,12 @@ impl FromQueryResult for JsonValue { #[cfg(feature = "mock")] mod tests { use crate::tests_cfg::cake; - use crate::{entity::*, MockDatabase, Syntax}; + use crate::{entity::*, DbBackend, MockDatabase}; use sea_query::Value; #[async_std::test] async fn to_json_1() { - let db = MockDatabase::new(Syntax::Postgres) + let db = MockDatabase::new(DbBackend::Postgres) .append_query_results(vec![vec![maplit::btreemap! { "id" => Into::::into(128), "name" => Into::::into("apple") }]]) diff --git a/src/query/mod.rs b/src/query/mod.rs index 86668231..e41b8dc2 100644 --- a/src/query/mod.rs +++ b/src/query/mod.rs @@ -20,4 +20,4 @@ pub use select::*; pub use traits::*; pub use update::*; -pub use crate::executor::{InsertResult, UpdateResult}; +pub use crate::{Statement, InsertResult, UpdateResult}; \ No newline at end of file diff --git a/src/query/traits.rs b/src/query/traits.rs index 1d1d2914..f0045f52 100644 --- a/src/query/traits.rs +++ b/src/query/traits.rs @@ -1,5 +1,5 @@ -use crate::{Statement, Syntax}; -use sea_query::{QueryBuilder, QueryStatementBuilder}; +use crate::{DbBackend, Statement}; +use sea_query::QueryStatementBuilder; pub trait QueryTrait { type QueryStatement: QueryStatementBuilder; @@ -14,14 +14,11 @@ pub trait QueryTrait { fn into_query(self) -> Self::QueryStatement; /// Build the query as [`Statement`] - fn build(&self, builder: B) -> Statement - where - B: QueryBuilderWithSyntax, - { - Statement::from_string_values_tuple(builder.syntax(), self.as_query().build(builder)) + fn build(&self, db_backend: DbBackend) -> Statement { + let query_builder = db_backend.get_query_builder(); + Statement::from_string_values_tuple( + db_backend, + self.as_query().build_any(query_builder.as_ref()), + ) } } - -pub trait QueryBuilderWithSyntax: QueryBuilder { - fn syntax(&self) -> Syntax; -} diff --git a/src/query/update.rs b/src/query/update.rs index dc3ee663..ca750d88 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -30,14 +30,14 @@ impl Update { /// Update one ActiveModel /// /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend}; /// /// assert_eq!( /// Update::one(cake::ActiveModel { /// id: ActiveValue::set(1), /// name: ActiveValue::set("Apple Pie".to_owned()), /// }) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"UPDATE "cake" SET "name" = 'Apple Pie' WHERE "cake"."id" = 1"#, /// ); @@ -59,13 +59,13 @@ impl Update { /// Update many ActiveModel /// /// ``` - /// use sea_orm::{entity::*, query::*, tests_cfg::fruit, sea_query::{Expr, PostgresQueryBuilder}}; + /// use sea_orm::{entity::*, query::*, tests_cfg::fruit, sea_query::Expr, DbBackend}; /// /// assert_eq!( /// Update::many(fruit::Entity) /// .col_expr(fruit::Column::Name, Expr::value("Golden Apple")) /// .filter(fruit::Column::Name.contains("Apple")) - /// .build(PostgresQueryBuilder) + /// .build(DbBackend::Postgres) /// .to_string(), /// r#"UPDATE "fruit" SET "name" = 'Golden Apple' WHERE "fruit"."name" LIKE '%Apple%'"#, /// ); @@ -184,8 +184,8 @@ where #[cfg(test)] mod tests { use crate::tests_cfg::{cake, fruit}; - use crate::{entity::*, query::*}; - use sea_query::{Expr, PostgresQueryBuilder, Value}; + use crate::{entity::*, query::*, DbBackend}; + use sea_query::{Expr, Value}; #[test] fn update_1() { @@ -194,7 +194,7 @@ mod tests { id: ActiveValue::set(1), name: ActiveValue::set("Apple Pie".to_owned()), }) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"UPDATE "cake" SET "name" = 'Apple Pie' WHERE "cake"."id" = 1"#, ); @@ -208,7 +208,7 @@ mod tests { name: ActiveValue::set("Orange".to_owned()), cake_id: ActiveValue::unset(), }) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"#, ); @@ -222,7 +222,7 @@ mod tests { name: ActiveValue::unchanged("Apple".to_owned()), cake_id: ActiveValue::set(Some(3)), }) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"UPDATE "fruit" SET "cake_id" = 3 WHERE "fruit"."id" = 2"#, ); @@ -234,7 +234,7 @@ mod tests { Update::many(fruit::Entity) .col_expr(fruit::Column::CakeId, Expr::value(Value::Null)) .filter(fruit::Column::Id.eq(2)) - .build(PostgresQueryBuilder) + .build(DbBackend::Postgres) .to_string(), r#"UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."id" = 2"#, ); diff --git a/tests/basic.rs b/tests/basic.rs index 620fe41d..faa02a63 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -1,4 +1,4 @@ -use sea_orm::{entity::*, error::*, sea_query, tests_cfg::*, DbConn, Statement, Syntax}; +use sea_orm::{entity::*, error::*, sea_query, tests_cfg::*, DbBackend, DbConn, Statement}; mod setup; @@ -28,7 +28,7 @@ async fn setup_schema(db: &DbConn) { .build(SqliteQueryBuilder); let result = db - .execute(Statement::from_string(Syntax::Sqlite, stmt)) + .execute(Statement::from_string(DbBackend::Sqlite, stmt)) .await; println!("Create table cake: {:?}", result); } @@ -59,6 +59,12 @@ async fn crud_cake(db: &DbConn) -> Result<(), DbErr> { println!(); println!("Updated: {:?}", apple); + let count = cake::Entity::find().count(db).await?; + + println!(); + println!("Count: {:?}", count); + assert_eq!(count, 1); + let apple = cake::Entity::find_by_id(1).one(db).await?; assert_eq!( @@ -80,5 +86,11 @@ async fn crud_cake(db: &DbConn) -> Result<(), DbErr> { assert_eq!(None, apple); + let count = cake::Entity::find().count(db).await?; + + println!(); + println!("Count: {:?}", count); + assert_eq!(count, 0); + Ok(()) } diff --git a/tests/common/setup/schema.rs b/tests/common/setup/schema.rs index 6034f9fb..ed122566 100644 --- a/tests/common/setup/schema.rs +++ b/tests/common/setup/schema.rs @@ -4,7 +4,7 @@ use sea_query::{ColumnDef, ForeignKey, ForeignKeyAction, Index, TableCreateState pub use super::super::bakery_chain::*; async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result { - let builder = db.get_schema_builder_backend(); + let builder = db.get_database_backend(); db.execute(builder.build(stmt)).await }