Merge branch 'master' into ss/test_suite

This commit is contained in:
Sam Samai 2021-07-18 12:56:22 +10:00
commit f5838f8cbd
29 changed files with 461 additions and 352 deletions

View File

@ -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 Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated person obtaining a copy of this software and associated

View File

@ -17,7 +17,7 @@
Inspired by ActiveRecord, Eloquent and TypeORM, SeaORM aims to provide you an intuitive and ergonomic 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. 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. This is a preview of SeaORM, and is not yet released.
``` ```
@ -145,9 +145,9 @@ fruit::Entity::delete_many()
Licensed under either of Licensed under either of
- Apache License, Version 2.0 - Apache License, Version 2.0
([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) ([LICENSE-APACHE](LICENSE-APACHE) or <http://www.apache.org/licenses/LICENSE-2.0>)
- MIT license - MIT license
([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) ([LICENSE-MIT](LICENSE-MIT) or <http://opensource.org/licenses/MIT>)
at your option. at your option.

View File

@ -1,13 +1,13 @@
mod base_entity;
mod column; mod column;
mod entity;
mod generator; mod generator;
mod primary_key; mod primary_key;
mod relation; mod relation;
mod transformer; mod transformer;
mod writer; mod writer;
pub use base_entity::*;
pub use column::*; pub use column::*;
pub use entity::*;
pub use generator::*; pub use generator::*;
pub use primary_key::*; pub use primary_key::*;
pub use relation::*; pub use relation::*;

View File

@ -2,7 +2,7 @@ mod entity;
use 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_std::test]
async fn test_insert() -> Result<(), DbErr> { async fn test_insert() -> Result<(), DbErr> {
@ -11,7 +11,7 @@ async fn test_insert() -> Result<(), DbErr> {
rows_affected: 1, rows_affected: 1,
}; };
let db = MockDatabase::new(Syntax::Postgres) let db = MockDatabase::new(DbBackend::Postgres)
.append_exec_results(vec![exec_result.clone()]) .append_exec_results(vec![exec_result.clone()])
.into_connection(); .into_connection();
@ -27,7 +27,7 @@ async fn test_insert() -> Result<(), DbErr> {
assert_eq!( assert_eq!(
db.into_transaction_log(), db.into_transaction_log(),
vec![Transaction::from_sql_and_values( vec![Transaction::from_sql_and_values(
Syntax::Postgres, DbBackend::Postgres,
r#"INSERT INTO "cake" ("name") VALUES ($1)"#, r#"INSERT INTO "cake" ("name") VALUES ($1)"#,
vec!["Apple Pie".into()] vec!["Apple Pie".into()]
)] )]
@ -43,7 +43,7 @@ async fn test_select() -> Result<(), DbErr> {
filling_id: 3, filling_id: 3,
}]; }];
let db = MockDatabase::new(Syntax::Postgres) let db = MockDatabase::new(DbBackend::Postgres)
.append_query_results(vec![query_results.clone()]) .append_query_results(vec![query_results.clone()])
.into_connection(); .into_connection();
@ -54,7 +54,7 @@ async fn test_select() -> Result<(), DbErr> {
assert_eq!( assert_eq!(
db.into_transaction_log(), db.into_transaction_log(),
vec![Transaction::from_sql_and_values( vec![Transaction::from_sql_and_values(
Syntax::Postgres, DbBackend::Postgres,
[ [
r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#, 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"#, 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, rows_affected: 1,
}; };
let db = MockDatabase::new(Syntax::Postgres) let db = MockDatabase::new(DbBackend::Postgres)
.append_exec_results(vec![exec_result.clone()]) .append_exec_results(vec![exec_result.clone()])
.into_connection(); .into_connection();
@ -90,7 +90,7 @@ async fn test_update() -> Result<(), DbErr> {
assert_eq!( assert_eq!(
db.into_transaction_log(), db.into_transaction_log(),
vec![Transaction::from_sql_and_values( vec![Transaction::from_sql_and_values(
Syntax::Postgres, DbBackend::Postgres,
r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2"#, r#"UPDATE "fruit" SET "name" = $1 WHERE "fruit"."id" = $2"#,
vec!["Orange".into(), 1i32.into()] vec!["Orange".into(), 1i32.into()]
)] )]
@ -106,7 +106,7 @@ async fn test_delete() -> Result<(), DbErr> {
rows_affected: 1, rows_affected: 1,
}; };
let db = MockDatabase::new(Syntax::Postgres) let db = MockDatabase::new(DbBackend::Postgres)
.append_exec_results(vec![exec_result.clone()]) .append_exec_results(vec![exec_result.clone()])
.into_connection(); .into_connection();
@ -122,7 +122,7 @@ async fn test_delete() -> Result<(), DbErr> {
assert_eq!( assert_eq!(
db.into_transaction_log(), db.into_transaction_log(),
vec![Transaction::from_sql_and_values( vec![Transaction::from_sql_and_values(
Syntax::Postgres, DbBackend::Postgres,
r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#, r#"DELETE FROM "fruit" WHERE "fruit"."id" = $1"#,
vec![3i32.into()] vec![3i32.into()]
)] )]

View File

@ -1,8 +1,5 @@
use crate::{error::*, ExecResult, QueryResult, Statement, Syntax}; use crate::{error::*, ExecResult, QueryResult, Statement, StatementBuilder};
use sea_query::{ use sea_query::{MysqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder};
MysqlQueryBuilder, PostgresQueryBuilder, QueryStatementBuilder, SchemaStatementBuilder,
SqliteQueryBuilder,
};
pub enum DatabaseConnection { pub enum DatabaseConnection {
#[cfg(feature = "sqlx-mysql")] #[cfg(feature = "sqlx-mysql")]
@ -16,17 +13,14 @@ pub enum DatabaseConnection {
pub type DbConn = DatabaseConnection; pub type DbConn = DatabaseConnection;
pub enum QueryBuilderBackend { #[derive(Debug, Copy, Clone, PartialEq)]
pub enum DatabaseBackend {
MySql, MySql,
Postgres, Postgres,
Sqlite, Sqlite,
} }
pub enum SchemaBuilderBackend { pub type DbBackend = DatabaseBackend;
MySql,
Postgres,
Sqlite,
}
impl Default for DatabaseConnection { impl Default for DatabaseConnection {
fn default() -> Self { fn default() -> Self {
@ -53,26 +47,14 @@ impl std::fmt::Debug for DatabaseConnection {
} }
impl DatabaseConnection { impl DatabaseConnection {
pub fn get_query_builder_backend(&self) -> QueryBuilderBackend { pub fn get_database_backend(&self) -> DbBackend {
match self { match self {
#[cfg(feature = "sqlx-mysql")] #[cfg(feature = "sqlx-mysql")]
DatabaseConnection::SqlxMySqlPoolConnection(_) => QueryBuilderBackend::MySql, DatabaseConnection::SqlxMySqlPoolConnection(_) => DbBackend::MySql,
#[cfg(feature = "sqlx-sqlite")] #[cfg(feature = "sqlx-sqlite")]
DatabaseConnection::SqlxSqlitePoolConnection(_) => QueryBuilderBackend::Sqlite, DatabaseConnection::SqlxSqlitePoolConnection(_) => DbBackend::Sqlite,
#[cfg(feature = "mock")] #[cfg(feature = "mock")]
DatabaseConnection::MockDatabaseConnection(conn) => conn.get_query_builder_backend(), DatabaseConnection::MockDatabaseConnection(conn) => conn.get_database_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::Disconnected => panic!("Disconnected"), DatabaseConnection::Disconnected => panic!("Disconnected"),
} }
} }
@ -133,50 +115,19 @@ impl DatabaseConnection {
} }
} }
impl QueryBuilderBackend { impl DbBackend {
pub fn syntax(&self) -> Syntax {
match self {
Self::MySql => Syntax::MySql,
Self::Postgres => Syntax::Postgres,
Self::Sqlite => Syntax::Sqlite,
}
}
pub fn build<S>(&self, statement: &S) -> Statement pub fn build<S>(&self, statement: &S) -> Statement
where where
S: QueryStatementBuilder, S: StatementBuilder,
{ {
Statement::from_string_values_tuple( statement.build(self)
self.syntax(),
match self {
Self::MySql => statement.build(MysqlQueryBuilder),
Self::Postgres => statement.build(PostgresQueryBuilder),
Self::Sqlite => statement.build(SqliteQueryBuilder),
},
)
} }
}
impl SchemaBuilderBackend { pub fn get_query_builder(&self) -> Box<dyn QueryBuilder> {
pub fn syntax(&self) -> Syntax {
match self { match self {
Self::MySql => Syntax::MySql, Self::MySql => Box::new(MysqlQueryBuilder),
Self::Postgres => Syntax::Postgres, Self::Postgres => Box::new(PostgresQueryBuilder),
Self::Sqlite => Syntax::Sqlite, Self::Sqlite => Box::new(SqliteQueryBuilder),
} }
} }
pub fn build<S>(&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),
},
)
}
} }

View File

@ -1,14 +1,14 @@
use crate::{ use crate::{
error::*, DatabaseConnection, EntityTrait, ExecResult, ExecResultHolder, Iden, Iterable, error::*, DbBackend, DatabaseConnection, EntityTrait, ExecResult, ExecResultHolder, Iden,
MockDatabaseConnection, MockDatabaseTrait, ModelTrait, QueryResult, QueryResultRow, Statement, Iterable, MockDatabaseConnection, MockDatabaseTrait, ModelTrait, QueryResult, QueryResultRow,
Syntax, Transaction, Statement, Transaction,
}; };
use sea_query::{Value, ValueType}; use sea_query::{Value, ValueType};
use std::collections::BTreeMap; use std::collections::BTreeMap;
#[derive(Debug)] #[derive(Debug)]
pub struct MockDatabase { pub struct MockDatabase {
syntax: Syntax, db_backend: DbBackend,
transaction_log: Vec<Transaction>, transaction_log: Vec<Transaction>,
exec_results: Vec<MockExecResult>, exec_results: Vec<MockExecResult>,
query_results: Vec<Vec<MockRow>>, query_results: Vec<Vec<MockRow>>,
@ -43,9 +43,9 @@ where
} }
impl MockDatabase { impl MockDatabase {
pub fn new(syntax: Syntax) -> Self { pub fn new(db_backend: DbBackend) -> Self {
Self { Self {
syntax, db_backend,
transaction_log: Vec::new(), transaction_log: Vec::new(),
exec_results: Vec::new(), exec_results: Vec::new(),
query_results: Vec::new(), query_results: Vec::new(),
@ -103,8 +103,8 @@ impl MockDatabaseTrait for MockDatabase {
std::mem::take(&mut self.transaction_log) std::mem::take(&mut self.transaction_log)
} }
fn get_syntax(&self) -> Syntax { fn get_database_backend(&self) -> DbBackend {
self.syntax self.db_backend
} }
} }

View File

@ -1,38 +1,47 @@
use crate::{QueryBuilderBackend, QueryBuilderWithSyntax, SchemaBuilderBackend}; use crate::DbBackend;
use sea_query::{ use sea_query::{
inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, QueryBuilder, SqliteQueryBuilder, inject_parameters, MysqlQueryBuilder, PostgresQueryBuilder, SqliteQueryBuilder, Value, Values
Values,
}; };
use std::fmt; use std::fmt;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum Syntax {
MySql,
Postgres,
Sqlite,
}
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
pub struct Statement { pub struct Statement {
pub sql: String, pub sql: String,
pub values: Option<Values>, pub values: Option<Values>,
pub syntax: Syntax, pub db_backend: DbBackend,
}
pub trait StatementBuilder {
fn build(&self, db_backend: &DbBackend) -> Statement;
} }
impl Statement { impl Statement {
pub fn from_string(syntax: Syntax, stmt: String) -> Statement { pub fn from_string(db_backend: DbBackend, stmt: String) -> Statement {
Statement { Statement {
sql: stmt, sql: stmt,
values: None, values: None,
syntax, db_backend,
} }
} }
pub fn from_string_values_tuple(syntax: Syntax, stmt: (String, Values)) -> Statement { pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self
where
I: IntoIterator<Item = Value>,
{
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 { Statement {
sql: stmt.0, sql: stmt.0,
values: Some(stmt.1), values: Some(stmt.1),
syntax, db_backend,
} }
} }
} }
@ -44,7 +53,7 @@ impl fmt::Display for Statement {
let string = inject_parameters( let string = inject_parameters(
&self.sql, &self.sql,
values.0.clone(), values.0.clone(),
self.syntax.get_query_builder().as_ref(), self.db_backend.get_query_builder().as_ref(),
); );
write!(f, "{}", &string) write!(f, "{}", &string)
} }
@ -55,46 +64,45 @@ impl fmt::Display for Statement {
} }
} }
impl Syntax { macro_rules! build_any_stmt {
pub fn get_query_builder(&self) -> Box<dyn QueryBuilder> { ($stmt: expr, $db_backend: expr) => {
match self { match $db_backend {
Self::MySql => Box::new(MysqlQueryBuilder), DbBackend::MySql => $stmt.build(MysqlQueryBuilder),
Self::Postgres => Box::new(PostgresQueryBuilder), DbBackend::Postgres => $stmt.build(PostgresQueryBuilder),
Self::Sqlite => Box::new(SqliteQueryBuilder), DbBackend::Sqlite => $stmt.build(SqliteQueryBuilder),
} }
} };
}
pub fn get_query_builder_backend(&self) -> QueryBuilderBackend { macro_rules! build_query_stmt {
match self { ($stmt: ty) => {
Self::MySql => QueryBuilderBackend::MySql, impl StatementBuilder for $stmt {
Self::Postgres => QueryBuilderBackend::Postgres, fn build(&self, db_backend: &DbBackend) -> Statement {
Self::Sqlite => QueryBuilderBackend::Sqlite, let stmt = build_any_stmt!(self, db_backend);
Statement::from_string_values_tuple(*db_backend, stmt)
}
} }
} };
}
pub fn get_schema_builder_backend(&self) -> SchemaBuilderBackend { build_query_stmt!(sea_query::InsertStatement);
match self { build_query_stmt!(sea_query::SelectStatement);
Self::MySql => SchemaBuilderBackend::MySql, build_query_stmt!(sea_query::UpdateStatement);
Self::Postgres => SchemaBuilderBackend::Postgres, build_query_stmt!(sea_query::DeleteStatement);
Self::Sqlite => SchemaBuilderBackend::Sqlite,
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 { build_schema_stmt!(sea_query::TableCreateStatement);
fn syntax(&self) -> Syntax { build_schema_stmt!(sea_query::TableDropStatement);
Syntax::MySql build_schema_stmt!(sea_query::TableAlterStatement);
} build_schema_stmt!(sea_query::TableRenameStatement);
} build_schema_stmt!(sea_query::TableTruncateStatement);
impl QueryBuilderWithSyntax for PostgresQueryBuilder {
fn syntax(&self) -> Syntax {
Syntax::Postgres
}
}
impl QueryBuilderWithSyntax for SqliteQueryBuilder {
fn syntax(&self) -> Syntax {
Syntax::Sqlite
}
}

View File

@ -1,4 +1,4 @@
use crate::{Statement, Syntax}; use crate::{DbBackend, Statement};
use sea_query::{Value, Values}; use sea_query::{Value, Values};
#[derive(Debug, Clone, PartialEq)] #[derive(Debug, Clone, PartialEq)]
@ -7,12 +7,12 @@ pub struct Transaction {
} }
impl Transaction { impl Transaction {
pub fn from_sql_and_values<I>(syntax: Syntax, sql: &str, values: I) -> Self pub fn from_sql_and_values<I>(db_backend: DbBackend, sql: &str, values: I) -> Self
where where
I: IntoIterator<Item = Value>, I: IntoIterator<Item = Value>,
{ {
Self::one(Statement::from_string_values_tuple( Self::one(Statement::from_string_values_tuple(
syntax, db_backend,
(sql.to_string(), Values(values.into_iter().collect())), (sql.to_string(), Values(values.into_iter().collect())),
)) ))
} }

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
debug_print, error::*, DatabaseConnection, ExecResult, MockDatabase, QueryBuilderBackend, debug_print, error::*, DbBackend, DatabaseConnection, ExecResult, MockDatabase,
QueryResult, SchemaBuilderBackend, Statement, Syntax, Transaction, QueryResult, Statement, Transaction,
}; };
use std::sync::{ use std::sync::{
atomic::{AtomicUsize, Ordering}, atomic::{AtomicUsize, Ordering},
@ -21,7 +21,7 @@ pub trait MockDatabaseTrait: Send {
fn drain_transaction_log(&mut self) -> Vec<Transaction>; fn drain_transaction_log(&mut self) -> Vec<Transaction>;
fn get_syntax(&self) -> Syntax; fn get_database_backend(&self) -> DbBackend;
} }
impl MockDatabaseConnector { impl MockDatabaseConnector {
@ -48,13 +48,13 @@ impl MockDatabaseConnector {
#[cfg(feature = "sqlx-mysql")] #[cfg(feature = "sqlx-mysql")]
if crate::SqlxMySqlConnector::accepts(string) { if crate::SqlxMySqlConnector::accepts(string) {
return connect_mock_db!(Syntax::MySql); return connect_mock_db!(DbBackend::MySql);
} }
#[cfg(feature = "sqlx-sqlite")] #[cfg(feature = "sqlx-sqlite")]
if crate::SqlxSqliteConnector::accepts(string) { 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) self.mocker.lock().unwrap().query(counter, statement)
} }
pub fn get_query_builder_backend(&self) -> QueryBuilderBackend { pub fn get_database_backend(&self) -> DbBackend {
self.mocker self.mocker.lock().unwrap().get_database_backend()
.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()
} }
} }

View File

@ -18,7 +18,8 @@ pub trait EntityName: IdenStatic + Default {
Self::table_name(self) 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 /// This trait provides an API for you to inspect it's properties
/// - Column (implemented [`ColumnTrait`]) /// - Column (implemented [`ColumnTrait`])
@ -70,9 +71,9 @@ pub trait EntityTrait: EntityName {
/// ///
/// ``` /// ```
/// # #[cfg(feature = "mock")] /// # #[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![ /// # .append_query_results(vec![
/// # vec![ /// # vec![
/// # cake::Model { /// # cake::Model {
@ -126,10 +127,10 @@ pub trait EntityTrait: EntityName {
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![ /// vec![
/// Transaction::from_sql_and_values( /// 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( /// 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")] /// # #[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![ /// # .append_query_results(vec![
/// # vec![ /// # vec![
/// # cake::Model { /// # cake::Model {
@ -174,15 +175,15 @@ pub trait EntityTrait: EntityName {
/// assert_eq!( /// assert_eq!(
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values( /// 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 /// Find by composite key
/// ``` /// ```
/// # #[cfg(feature = "mock")] /// # #[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![ /// # .append_query_results(vec![
/// # vec![ /// # vec![
/// # cake_filling::Model { /// # cake_filling::Model {
@ -211,7 +212,7 @@ pub trait EntityTrait: EntityName {
/// assert_eq!( /// assert_eq!(
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values( /// vec![Transaction::from_sql_and_values(
/// Syntax::Postgres, /// DbBackend::Postgres,
/// [ /// [
/// r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id" FROM "cake_filling""#, /// 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"#, /// r#"WHERE "cake_filling"."cake_id" = $1 AND "cake_filling"."filling_id" = $2"#,
@ -245,9 +246,9 @@ pub trait EntityTrait: EntityName {
/// ///
/// ``` /// ```
/// # #[cfg(feature = "mock")] /// # #[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![ /// # .append_exec_results(vec![
/// # MockExecResult { /// # MockExecResult {
/// # last_insert_id: 15, /// # last_insert_id: 15,
@ -276,7 +277,7 @@ pub trait EntityTrait: EntityName {
/// assert_eq!( /// assert_eq!(
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values( /// 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<A>(model: A) -> Insert<A> fn insert<A>(model: A) -> Insert<A>
@ -292,9 +293,9 @@ pub trait EntityTrait: EntityName {
/// ///
/// ``` /// ```
/// # #[cfg(feature = "mock")] /// # #[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![ /// # .append_exec_results(vec![
/// # MockExecResult { /// # MockExecResult {
/// # last_insert_id: 28, /// # last_insert_id: 28,
@ -327,7 +328,7 @@ pub trait EntityTrait: EntityName {
/// assert_eq!( /// assert_eq!(
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values( /// 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()] /// vec!["Apple Pie".into(), "Orange Scone".into()]
/// )]); /// )]);
/// ``` /// ```
@ -347,9 +348,9 @@ pub trait EntityTrait: EntityName {
/// ///
/// ``` /// ```
/// # #[cfg(feature = "mock")] /// # #[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![ /// # .append_exec_results(vec![
/// # MockExecResult { /// # MockExecResult {
/// # last_insert_id: 0, /// # last_insert_id: 0,
@ -379,7 +380,7 @@ pub trait EntityTrait: EntityName {
/// assert_eq!( /// assert_eq!(
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values( /// 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<A>(model: A) -> UpdateOne<A> fn update<A>(model: A) -> UpdateOne<A>
@ -397,9 +398,9 @@ pub trait EntityTrait: EntityName {
/// ///
/// ``` /// ```
/// # #[cfg(feature = "mock")] /// # #[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![ /// # .append_exec_results(vec![
/// # MockExecResult { /// # MockExecResult {
/// # last_insert_id: 0, /// # last_insert_id: 0,
@ -426,7 +427,7 @@ pub trait EntityTrait: EntityName {
/// assert_eq!( /// assert_eq!(
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values( /// 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<Self> { fn update_many() -> UpdateMany<Self> {
@ -441,9 +442,9 @@ pub trait EntityTrait: EntityName {
/// ///
/// ``` /// ```
/// # #[cfg(feature = "mock")] /// # #[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![ /// # .append_exec_results(vec![
/// # MockExecResult { /// # MockExecResult {
/// # last_insert_id: 0, /// # last_insert_id: 0,
@ -471,7 +472,7 @@ pub trait EntityTrait: EntityName {
/// assert_eq!( /// assert_eq!(
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values( /// 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<A>(model: A) -> DeleteOne<A> fn delete<A>(model: A) -> DeleteOne<A>
@ -489,9 +490,9 @@ pub trait EntityTrait: EntityName {
/// ///
/// ``` /// ```
/// # #[cfg(feature = "mock")] /// # #[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![ /// # .append_exec_results(vec![
/// # MockExecResult { /// # MockExecResult {
/// # last_insert_id: 0, /// # last_insert_id: 0,
@ -517,7 +518,7 @@ pub trait EntityTrait: EntityName {
/// assert_eq!( /// assert_eq!(
/// db.into_transaction_log(), /// db.into_transaction_log(),
/// vec![Transaction::from_sql_and_values( /// 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<Self> { fn delete_many() -> DeleteMany<Self> {

View File

@ -88,12 +88,12 @@ pub trait ColumnTrait: IdenStatic + Iterable {
bind_oper!(lte); 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .filter(cake::Column::Id.between(2,3)) /// .filter(cake::Column::Id.between(2,3))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` BETWEEN 2 AND 3" /// "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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .filter(cake::Column::Id.not_between(2,3)) /// .filter(cake::Column::Id.not_between(2,3))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` NOT BETWEEN 2 AND 3" /// "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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .filter(cake::Column::Name.like("cheese")) /// .filter(cake::Column::Name.like("cheese"))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese'" /// "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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .filter(cake::Column::Name.not_like("cheese")) /// .filter(cake::Column::Name.not_like("cheese"))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` NOT LIKE 'cheese'" /// "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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .filter(cake::Column::Name.starts_with("cheese")) /// .filter(cake::Column::Name.starts_with("cheese"))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE 'cheese%'" /// "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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .filter(cake::Column::Name.ends_with("cheese")) /// .filter(cake::Column::Name.ends_with("cheese"))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese'" /// "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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .filter(cake::Column::Name.contains("cheese")) /// .filter(cake::Column::Name.contains("cheese"))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'" /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`name` LIKE '%cheese%'"
/// ); /// );
@ -245,29 +245,29 @@ impl ColumnDef {
} }
} }
impl Into<sea_query::ColumnType> for ColumnType { impl From<ColumnType> for sea_query::ColumnType {
fn into(self) -> sea_query::ColumnType { fn from(col: ColumnType) -> Self {
match self { match col {
Self::Char(s) => sea_query::ColumnType::Char(s), ColumnType::Char(s) => sea_query::ColumnType::Char(s),
Self::String(s) => sea_query::ColumnType::String(s), ColumnType::String(s) => sea_query::ColumnType::String(s),
Self::Text => sea_query::ColumnType::Text, ColumnType::Text => sea_query::ColumnType::Text,
Self::TinyInteger => sea_query::ColumnType::TinyInteger(None), ColumnType::TinyInteger => sea_query::ColumnType::TinyInteger(None),
Self::SmallInteger => sea_query::ColumnType::SmallInteger(None), ColumnType::SmallInteger => sea_query::ColumnType::SmallInteger(None),
Self::Integer => sea_query::ColumnType::Integer(None), ColumnType::Integer => sea_query::ColumnType::Integer(None),
Self::BigInteger => sea_query::ColumnType::BigInteger(None), ColumnType::BigInteger => sea_query::ColumnType::BigInteger(None),
Self::Float => sea_query::ColumnType::Float(None), ColumnType::Float => sea_query::ColumnType::Float(None),
Self::Double => sea_query::ColumnType::Double(None), ColumnType::Double => sea_query::ColumnType::Double(None),
Self::Decimal(s) => sea_query::ColumnType::Decimal(s), ColumnType::Decimal(s) => sea_query::ColumnType::Decimal(s),
Self::DateTime => sea_query::ColumnType::DateTime(None), ColumnType::DateTime => sea_query::ColumnType::DateTime(None),
Self::Timestamp => sea_query::ColumnType::Timestamp(None), ColumnType::Timestamp => sea_query::ColumnType::Timestamp(None),
Self::Time => sea_query::ColumnType::Time(None), ColumnType::Time => sea_query::ColumnType::Time(None),
Self::Date => sea_query::ColumnType::Date, ColumnType::Date => sea_query::ColumnType::Date,
Self::Binary => sea_query::ColumnType::Binary(None), ColumnType::Binary => sea_query::ColumnType::Binary(None),
Self::Boolean => sea_query::ColumnType::Boolean, ColumnType::Boolean => sea_query::ColumnType::Boolean,
Self::Money(s) => sea_query::ColumnType::Money(s), ColumnType::Money(s) => sea_query::ColumnType::Money(s),
Self::Json => sea_query::ColumnType::Json, ColumnType::Json => sea_query::ColumnType::Json,
Self::JsonBinary => sea_query::ColumnType::JsonBinary, ColumnType::JsonBinary => sea_query::ColumnType::JsonBinary,
Self::Custom(s) => { ColumnType::Custom(s) => {
sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(&s))) sea_query::ColumnType::Custom(sea_query::SeaRc::new(sea_query::Alias::new(&s)))
} }
} }

View File

@ -49,7 +49,7 @@ impl Deleter {
self, self,
db: &DatabaseConnection, db: &DatabaseConnection,
) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_ { ) -> impl Future<Output = Result<DeleteResult, DbErr>> + '_ {
let builder = db.get_query_builder_backend(); let builder = db.get_database_backend();
exec_delete(builder.build(&self.query), db) exec_delete(builder.build(&self.query), db)
} }
} }

View File

@ -34,7 +34,7 @@ impl Inserter {
self, self,
db: &DatabaseConnection, db: &DatabaseConnection,
) -> impl Future<Output = Result<InsertResult, DbErr>> + '_ { ) -> impl Future<Output = Result<InsertResult, DbErr>> + '_ {
let builder = db.get_query_builder_backend(); let builder = db.get_database_backend();
exec_insert(builder.build(&self.query), db) exec_insert(builder.build(&self.query), db)
} }
} }

View File

@ -18,6 +18,8 @@ where
pub(crate) selector: PhantomData<S>, pub(crate) selector: PhantomData<S>,
} }
// LINT: warn if paginator is used without an order by clause
impl<'db, S> Paginator<'db, S> impl<'db, S> Paginator<'db, S>
where where
S: SelectorTrait + 'db, S: SelectorTrait + 'db,
@ -30,7 +32,7 @@ where
.limit(self.page_size as u64) .limit(self.page_size as u64)
.offset((self.page_size * page) as u64) .offset((self.page_size * page) as u64)
.to_owned(); .to_owned();
let builder = self.db.get_query_builder_backend(); let builder = self.db.get_database_backend();
let stmt = builder.build(&query); let stmt = builder.build(&query);
let rows = self.db.query_all(stmt).await?; let rows = self.db.query_all(stmt).await?;
let mut buffer = Vec::with_capacity(rows.len()); let mut buffer = Vec::with_capacity(rows.len());
@ -46,12 +48,12 @@ where
self.fetch_page(self.page).await self.fetch_page(self.page).await
} }
/// Get the total number of pages /// Get the total number of items
pub async fn num_pages(&self) -> Result<usize, DbErr> { pub async fn num_items(&self) -> Result<usize, DbErr> {
let builder = self.db.get_query_builder_backend(); let builder = self.db.get_database_backend();
let stmt = builder.build( let stmt = builder.build(
SelectStatement::new() SelectStatement::new()
.expr(Expr::cust("COUNT(*) AS num_rows")) .expr(Expr::cust("COUNT(*) AS num_items"))
.from_subquery( .from_subquery(
self.query.clone().reset_limit().reset_offset().to_owned(), self.query.clone().reset_limit().reset_offset().to_owned(),
Alias::new("sub_query"), Alias::new("sub_query"),
@ -61,8 +63,14 @@ where
Some(res) => res, Some(res) => res,
None => return Ok(0), None => return Ok(0),
}; };
let num_rows = result.try_get::<i32>("", "num_rows")? as usize; let num_items = result.try_get::<i32>("", "num_items")? as usize;
let num_pages = (num_rows / self.page_size) + (num_rows % self.page_size > 0) as usize; Ok(num_items)
}
/// Get the total number of pages
pub async fn num_pages(&self) -> Result<usize, DbErr> {
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) Ok(num_pages)
} }
@ -77,6 +85,26 @@ where
} }
/// Fetch one page and increment the page counter /// 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<cake::Model>
/// }
/// #
/// # Ok(())
/// # });
/// ```
pub async fn fetch_and_next(&mut self) -> Result<Option<Vec<S::Item>>, DbErr> { pub async fn fetch_and_next(&mut self) -> Result<Option<Vec<S::Item>>, DbErr> {
let vec = self.fetch().await?; let vec = self.fetch().await?;
self.next(); self.next();
@ -85,6 +113,28 @@ where
} }
/// Convert self into an async stream /// 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<cake::Model>
/// }
/// #
/// # Ok(())
/// # });
/// ```
pub fn into_stream(mut self) -> PinBoxStream<'db, Result<Vec<S::Item>, DbErr>> { pub fn into_stream(mut self) -> PinBoxStream<'db, Result<Vec<S::Item>, DbErr>> {
Box::pin(stream! { Box::pin(stream! {
loop { loop {
@ -103,7 +153,7 @@ where
mod tests { mod tests {
use crate::entity::prelude::*; use crate::entity::prelude::*;
use crate::tests_cfg::*; use crate::tests_cfg::*;
use crate::{DatabaseConnection, MockDatabase, Syntax, Transaction}; use crate::{DbBackend, DatabaseConnection, MockDatabase, Transaction};
use futures::TryStreamExt; use futures::TryStreamExt;
use sea_query::{Alias, Expr, SelectStatement, Value}; use sea_query::{Alias, Expr, SelectStatement, Value};
@ -129,22 +179,22 @@ mod tests {
let page3 = Vec::<fruit::Model>::new(); let page3 = Vec::<fruit::Model>::new();
let db = MockDatabase::new(Syntax::Postgres) let db = MockDatabase::new(DbBackend::Postgres)
.append_query_results(vec![page1.clone(), page2.clone(), page3.clone()]) .append_query_results(vec![page1.clone(), page2.clone(), page3.clone()])
.into_connection(); .into_connection();
(db, vec![page1, page2, page3]) (db, vec![page1, page2, page3])
} }
fn setup_num_rows() -> (DatabaseConnection, i32) { fn setup_num_items() -> (DatabaseConnection, i32) {
let num_rows = 3; let num_items = 3;
let db = MockDatabase::new(Syntax::Postgres) let db = MockDatabase::new(DbBackend::Postgres)
.append_query_results(vec![vec![maplit::btreemap! { .append_query_results(vec![vec![maplit::btreemap! {
"num_rows" => Into::<Value>::into(num_rows), "num_items" => Into::<Value>::into(num_items),
}]]) }]])
.into_connection(); .into_connection();
(db, num_rows) (db, num_items)
} }
#[async_std::test] #[async_std::test]
@ -166,7 +216,7 @@ mod tests {
.from(fruit::Entity) .from(fruit::Entity)
.to_owned(); .to_owned();
let query_builder = db.get_query_builder_backend(); let query_builder = db.get_database_backend();
let stmts = vec![ let stmts = vec![
query_builder.build(select.clone().offset(0).limit(2)), query_builder.build(select.clone().offset(0).limit(2)),
query_builder.build(select.clone().offset(2).limit(2)), query_builder.build(select.clone().offset(2).limit(2)),
@ -200,7 +250,7 @@ mod tests {
.from(fruit::Entity) .from(fruit::Entity)
.to_owned(); .to_owned();
let query_builder = db.get_query_builder_backend(); let query_builder = db.get_database_backend();
let stmts = vec![ let stmts = vec![
query_builder.build(select.clone().offset(0).limit(2)), query_builder.build(select.clone().offset(0).limit(2)),
query_builder.build(select.clone().offset(2).limit(2)), query_builder.build(select.clone().offset(2).limit(2)),
@ -213,11 +263,11 @@ mod tests {
#[async_std::test] #[async_std::test]
async fn num_pages() -> Result<(), DbErr> { 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 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); let paginator = fruit::Entity::find().paginate(&db, page_size);
assert_eq!(paginator.num_pages().await?, num_pages); assert_eq!(paginator.num_pages().await?, num_pages);
@ -232,11 +282,11 @@ mod tests {
.to_owned(); .to_owned();
let select = SelectStatement::new() 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")) .from_subquery(sub_query, Alias::new("sub_query"))
.to_owned(); .to_owned();
let query_builder = db.get_query_builder_backend(); let query_builder = db.get_database_backend();
let stmts = vec![query_builder.build(&select)]; let stmts = vec![query_builder.build(&select)];
assert_eq!(db.into_transaction_log(), Transaction::wrap(stmts)); assert_eq!(db.into_transaction_log(), Transaction::wrap(stmts));
@ -283,7 +333,7 @@ mod tests {
.from(fruit::Entity) .from(fruit::Entity)
.to_owned(); .to_owned();
let query_builder = db.get_query_builder_backend(); let query_builder = db.get_database_backend();
let stmts = vec![ let stmts = vec![
query_builder.build(select.clone().offset(0).limit(2)), query_builder.build(select.clone().offset(0).limit(2)),
query_builder.build(select.clone().offset(2).limit(2)), query_builder.build(select.clone().offset(2).limit(2)),
@ -315,7 +365,7 @@ mod tests {
.from(fruit::Entity) .from(fruit::Entity)
.to_owned(); .to_owned();
let query_builder = db.get_query_builder_backend(); let query_builder = db.get_database_backend();
let stmts = vec![ let stmts = vec![
query_builder.build(select.clone().offset(0).limit(2)), query_builder.build(select.clone().offset(0).limit(2)),
query_builder.build(select.clone().offset(2).limit(2)), query_builder.build(select.clone().offset(2).limit(2)),

View File

@ -1,7 +1,7 @@
use crate::{ use crate::{
error::*, query::combine, DatabaseConnection, EntityTrait, FromQueryResult, Iterable, error::*, query::combine, DatabaseConnection, EntityTrait, FromQueryResult, Iterable,
JsonValue, ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectTwo, JsonValue, ModelTrait, Paginator, PrimaryKeyToColumn, QueryResult, Select, SelectTwo,
SelectTwoMany, SelectTwoMany, Statement,
}; };
use sea_query::SelectStatement; use sea_query::SelectStatement;
use std::marker::PhantomData; use std::marker::PhantomData;
@ -15,6 +15,15 @@ where
selector: S, selector: S,
} }
#[derive(Clone, Debug)]
pub struct SelectorRaw<S>
where
S: SelectorTrait,
{
stmt: Statement,
selector: S,
}
pub trait SelectorTrait { pub trait SelectorTrait {
type Item: Sized; type Item: Sized;
@ -67,6 +76,56 @@ impl<E> Select<E>
where where
E: EntityTrait, 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<SelectModel<E::Model>> {
SelectorRaw {
stmt,
selector: SelectModel { model: PhantomData },
}
}
pub fn into_model<M>(self) -> Selector<SelectModel<M>> pub fn into_model<M>(self) -> Selector<SelectModel<M>>
where where
M: FromQueryResult, M: FromQueryResult,
@ -86,11 +145,11 @@ where
} }
pub async fn one(self, db: &DatabaseConnection) -> Result<Option<E::Model>, DbErr> { pub async fn one(self, db: &DatabaseConnection) -> Result<Option<E::Model>, DbErr> {
self.into_model::<E::Model>().one(db).await self.into_model().one(db).await
} }
pub async fn all(self, db: &DatabaseConnection) -> Result<Vec<E::Model>, DbErr> { pub async fn all(self, db: &DatabaseConnection) -> Result<Vec<E::Model>, DbErr> {
self.into_model::<E::Model>().all(db).await self.into_model().all(db).await
} }
pub fn paginate( pub fn paginate(
@ -98,7 +157,11 @@ where
db: &DatabaseConnection, db: &DatabaseConnection,
page_size: usize, page_size: usize,
) -> Paginator<'_, SelectModel<E::Model>> { ) -> Paginator<'_, SelectModel<E::Model>> {
self.into_model::<E::Model>().paginate(db, page_size) self.into_model().paginate(db, page_size)
}
pub async fn count(self, db: &DatabaseConnection) -> Result<usize, DbErr> {
self.paginate(db, 1).num_items().await
} }
} }
@ -130,14 +193,26 @@ where
self, self,
db: &DatabaseConnection, db: &DatabaseConnection,
) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr> { ) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr> {
self.into_model::<E::Model, F::Model>().one(db).await self.into_model().one(db).await
} }
pub async fn all( pub async fn all(
self, self,
db: &DatabaseConnection, db: &DatabaseConnection,
) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr> { ) -> Result<Vec<(E::Model, Option<F::Model>)>, DbErr> {
self.into_model::<E::Model, F::Model>().all(db).await self.into_model().all(db).await
}
pub fn paginate(
self,
db: &DatabaseConnection,
page_size: usize,
) -> Paginator<'_, SelectTwoModel<E::Model, F::Model>> {
self.into_model().paginate(db, page_size)
}
pub async fn count(self, db: &DatabaseConnection) -> Result<usize, DbErr> {
self.paginate(db, 1).num_items().await
} }
} }
@ -169,16 +244,25 @@ where
self, self,
db: &DatabaseConnection, db: &DatabaseConnection,
) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr> { ) -> Result<Option<(E::Model, Option<F::Model>)>, DbErr> {
self.into_model::<E::Model, F::Model>().one(db).await self.into_model().one(db).await
} }
pub async fn all( pub async fn all(
self, self,
db: &DatabaseConnection, db: &DatabaseConnection,
) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr> { ) -> Result<Vec<(E::Model, Vec<F::Model>)>, DbErr> {
let rows = self.into_model::<E::Model, F::Model>().all(db).await?; let rows = self.into_model().all(db).await?;
Ok(consolidate_query_result::<E, F>(rows)) Ok(consolidate_query_result::<E, F>(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<S> Selector<S> impl<S> Selector<S>
@ -186,7 +270,7 @@ where
S: SelectorTrait, S: SelectorTrait,
{ {
pub async fn one(mut self, db: &DatabaseConnection) -> Result<Option<S::Item>, DbErr> { pub async fn one(mut self, db: &DatabaseConnection) -> Result<Option<S::Item>, DbErr> {
let builder = db.get_query_builder_backend(); let builder = db.get_database_backend();
self.query.limit(1); self.query.limit(1);
let row = db.query_one(builder.build(&self.query)).await?; let row = db.query_one(builder.build(&self.query)).await?;
match row { match row {
@ -196,7 +280,7 @@ where
} }
pub async fn all(self, db: &DatabaseConnection) -> Result<Vec<S::Item>, DbErr> { pub async fn all(self, db: &DatabaseConnection) -> Result<Vec<S::Item>, 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 rows = db.query_all(builder.build(&self.query)).await?;
let mut models = Vec::new(); let mut models = Vec::new();
for row in rows.into_iter() { for row in rows.into_iter() {
@ -216,6 +300,28 @@ where
} }
} }
impl<S> SelectorRaw<S>
where
S: SelectorTrait,
{
pub async fn one(self, db: &DatabaseConnection) -> Result<Option<S::Item>, 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<Vec<S::Item>, 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<L, R>( fn consolidate_query_result<L, R>(
rows: Vec<(L::Model, Option<R::Model>)>, rows: Vec<(L::Model, Option<R::Model>)>,
) -> Vec<(L::Model, Vec<R::Model>)> ) -> Vec<(L::Model, Vec<R::Model>)>

View File

@ -46,7 +46,7 @@ impl Updater {
self, self,
db: &DatabaseConnection, db: &DatabaseConnection,
) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_ { ) -> impl Future<Output = Result<UpdateResult, DbErr>> + '_ {
let builder = db.get_query_builder_backend(); let builder = db.get_database_backend();
exec_update(builder.build(&self.query), db) exec_update(builder.build(&self.query), db)
} }
} }

View File

@ -17,7 +17,7 @@
//! Inspired by ActiveRecord, Eloquent and TypeORM, SeaORM aims to provide you an intuitive and ergonomic //! 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. //! 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. //! This is a preview of SeaORM, and is not yet released.
//! ``` //! ```
//! //!

View File

@ -113,8 +113,7 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests_cfg::{cake, fruit}; use crate::tests_cfg::{cake, fruit};
use crate::{ColumnTrait, EntityTrait, QueryFilter, QuerySelect, QueryTrait}; use crate::{ColumnTrait, DbBackend, EntityTrait, QueryFilter, QuerySelect, QueryTrait};
use sea_query::MysqlQueryBuilder;
#[test] #[test]
fn alias_1() { fn alias_1() {
@ -122,7 +121,7 @@ mod tests {
cake::Entity::find() cake::Entity::find()
.column_as(cake::Column::Id, "B") .column_as(cake::Column::Id, "B")
.apply_alias("A_") .apply_alias("A_")
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`, `cake`.`id` AS `A_B` FROM `cake`", "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() cake::Entity::find()
.left_join(fruit::Entity) .left_join(fruit::Entity)
.select_also(fruit::Entity) .select_also(fruit::Entity)
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,", "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",
@ -150,7 +149,7 @@ mod tests {
cake::Entity::find() cake::Entity::find()
.left_join(fruit::Entity) .left_join(fruit::Entity)
.select_with(fruit::Entity) .select_with(fruit::Entity)
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,", "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",
@ -169,7 +168,7 @@ mod tests {
.select_also(fruit::Entity) .select_also(fruit::Entity)
.filter(cake::Column::Id.eq(1)) .filter(cake::Column::Id.eq(1))
.filter(fruit::Column::Id.eq(2)) .filter(fruit::Column::Id.eq(2))
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,", "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",
@ -188,7 +187,7 @@ mod tests {
.select_with(fruit::Entity) .select_with(fruit::Entity)
.filter(cake::Column::Id.eq(1)) .filter(cake::Column::Id.eq(1))
.filter(fruit::Column::Id.eq(2)) .filter(fruit::Column::Id.eq(2))
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,", "SELECT `cake`.`id` AS `A_id`, `cake`.`name` AS `A_name`,",

View File

@ -31,28 +31,28 @@ impl Delete {
/// ///
/// Model /// Model
/// ``` /// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
/// ///
/// assert_eq!( /// assert_eq!(
/// Delete::one(cake::Model { /// Delete::one(cake::Model {
/// id: 1, /// id: 1,
/// name: "Apple Pie".to_owned(), /// name: "Apple Pie".to_owned(),
/// }) /// })
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#, /// r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
/// ); /// );
/// ``` /// ```
/// ActiveModel /// ActiveModel
/// ``` /// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
/// ///
/// assert_eq!( /// assert_eq!(
/// Delete::one(cake::ActiveModel { /// Delete::one(cake::ActiveModel {
/// id: ActiveValue::set(1), /// id: ActiveValue::set(1),
/// name: ActiveValue::set("Apple Pie".to_owned()), /// name: ActiveValue::set("Apple Pie".to_owned()),
/// }) /// })
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#, /// r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
/// ); /// );
@ -75,12 +75,12 @@ impl Delete {
/// Delete many ActiveModel /// 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!( /// assert_eq!(
/// Delete::many(fruit::Entity) /// Delete::many(fruit::Entity)
/// .filter(fruit::Column::Name.contains("Apple")) /// .filter(fruit::Column::Name.contains("Apple"))
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Apple%'"#, /// r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Apple%'"#,
/// ); /// );
@ -179,8 +179,7 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests_cfg::{cake, fruit}; use crate::tests_cfg::{cake, fruit};
use crate::{entity::*, query::*}; use crate::{entity::*, query::*, DbBackend};
use sea_query::PostgresQueryBuilder;
#[test] #[test]
fn delete_1() { fn delete_1() {
@ -189,7 +188,7 @@ mod tests {
id: 1, id: 1,
name: "Apple Pie".to_owned(), name: "Apple Pie".to_owned(),
}) })
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#, r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
); );
@ -198,7 +197,7 @@ mod tests {
id: ActiveValue::set(1), id: ActiveValue::set(1),
name: ActiveValue::set("Apple Pie".to_owned()), name: ActiveValue::set("Apple Pie".to_owned()),
}) })
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#, r#"DELETE FROM "cake" WHERE "cake"."id" = 1"#,
); );
@ -209,7 +208,7 @@ mod tests {
assert_eq!( assert_eq!(
Delete::many(fruit::Entity) Delete::many(fruit::Entity)
.filter(fruit::Column::Name.contains("Cheese")) .filter(fruit::Column::Name.contains("Cheese"))
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Cheese%'"#, r#"DELETE FROM "fruit" WHERE "fruit"."name" LIKE '%Cheese%'"#,
); );

View File

@ -23,13 +23,13 @@ pub trait QuerySelect: Sized {
/// Add a select column /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .select_only() /// .select_only()
/// .column(cake::Column::Name) /// .column(cake::Column::Name)
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"SELECT "cake"."name" FROM "cake""# /// r#"SELECT "cake"."name" FROM "cake""#
/// ); /// );
@ -44,13 +44,13 @@ pub trait QuerySelect: Sized {
/// Add a select column with alias /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .select_only() /// .select_only()
/// .column_as(cake::Column::Id.count(), "count") /// .column_as(cake::Column::Id.count(), "count")
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"SELECT COUNT("cake"."id") AS "count" FROM "cake""# /// r#"SELECT COUNT("cake"."id") AS "count" FROM "cake""#
/// ); /// );
@ -68,14 +68,14 @@ pub trait QuerySelect: Sized {
/// Add a group by column /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .select_only() /// .select_only()
/// .column(cake::Column::Name) /// .column(cake::Column::Name)
/// .group_by(cake::Column::Name) /// .group_by(cake::Column::Name)
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"SELECT "cake"."name" FROM "cake" GROUP BY "cake"."name""# /// r#"SELECT "cake"."name" FROM "cake" GROUP BY "cake"."name""#
/// ); /// );
@ -90,13 +90,13 @@ pub trait QuerySelect: Sized {
/// Add an AND HAVING expression /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .having(cake::Column::Id.eq(4)) /// .having(cake::Column::Id.eq(4))
/// .having(cake::Column::Id.eq(5)) /// .having(cake::Column::Id.eq(5))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` HAVING `cake`.`id` = 4 AND `cake`.`id` = 5" /// "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 /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .order_by(cake::Column::Id, Order::Asc) /// .order_by(cake::Column::Id, Order::Asc)
/// .order_by(cake::Column::Name, Order::Desc) /// .order_by(cake::Column::Name, Order::Desc)
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` ASC, `cake`.`name` DESC" /// "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) /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .order_by_asc(cake::Column::Id) /// .order_by_asc(cake::Column::Id)
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` ASC" /// "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) /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .order_by_desc(cake::Column::Id) /// .order_by_desc(cake::Column::Id)
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` ORDER BY `cake`.`id` DESC" /// "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 /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
/// .filter(cake::Column::Id.eq(4)) /// .filter(cake::Column::Id.eq(4))
/// .filter(cake::Column::Id.eq(5)) /// .filter(cake::Column::Id.eq(5))
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 AND `cake`.`id` = 5" /// "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. /// 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!( /// assert_eq!(
/// cake::Entity::find() /// cake::Entity::find()
@ -244,7 +244,7 @@ pub trait QueryFilter: Sized {
/// .add(cake::Column::Id.eq(4)) /// .add(cake::Column::Id.eq(4))
/// .add(cake::Column::Id.eq(5)) /// .add(cake::Column::Id.eq(5))
/// ) /// )
/// .build(MysqlQueryBuilder) /// .build(DbBackend::MySql)
/// .to_string(), /// .to_string(),
/// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 OR `cake`.`id` = 5" /// "SELECT `cake`.`id`, `cake`.`name` FROM `cake` WHERE `cake`.`id` = 4 OR `cake`.`id` = 5"
/// ); /// );

View File

@ -25,7 +25,7 @@ impl<A> Insert<A>
where where
A: ActiveModelTrait, A: ActiveModelTrait,
{ {
pub fn new() -> Self { pub(crate) fn new() -> Self {
Self { Self {
query: InsertStatement::new() query: InsertStatement::new()
.into_table(A::Entity::default().into_iden()) .into_table(A::Entity::default().into_iden())
@ -39,28 +39,28 @@ where
/// ///
/// Model /// Model
/// ``` /// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
/// ///
/// assert_eq!( /// assert_eq!(
/// Insert::one(cake::Model { /// Insert::one(cake::Model {
/// id: 1, /// id: 1,
/// name: "Apple Pie".to_owned(), /// name: "Apple Pie".to_owned(),
/// }) /// })
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, /// r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
/// ); /// );
/// ``` /// ```
/// ActiveModel /// ActiveModel
/// ``` /// ```
/// use sea_orm::{entity::*, query::*, tests_cfg::cake, sea_query::PostgresQueryBuilder}; /// use sea_orm::{entity::*, query::*, tests_cfg::cake, DbBackend};
/// ///
/// assert_eq!( /// assert_eq!(
/// Insert::one(cake::ActiveModel { /// Insert::one(cake::ActiveModel {
/// id: Unset(None), /// id: Unset(None),
/// name: Set("Apple Pie".to_owned()), /// name: Set("Apple Pie".to_owned()),
/// }) /// })
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#, /// r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#,
/// ); /// );
@ -75,7 +75,7 @@ where
/// Insert many Model or ActiveModel /// 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!( /// assert_eq!(
/// Insert::many(vec![ /// Insert::many(vec![
@ -88,7 +88,7 @@ where
/// name: "Orange Scone".to_owned(), /// name: "Orange Scone".to_owned(),
/// } /// }
/// ]) /// ])
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#, /// r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#,
/// ); /// );
@ -162,8 +162,7 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests_cfg::cake; use crate::tests_cfg::cake;
use crate::{ActiveValue, Insert, QueryTrait}; use crate::{ActiveValue, DbBackend, Insert, QueryTrait};
use sea_query::PostgresQueryBuilder;
#[test] #[test]
fn insert_1() { fn insert_1() {
@ -173,7 +172,7 @@ mod tests {
id: ActiveValue::unset(), id: ActiveValue::unset(),
name: ActiveValue::set("Apple Pie".to_owned()), name: ActiveValue::set("Apple Pie".to_owned()),
}) })
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#, r#"INSERT INTO "cake" ("name") VALUES ('Apple Pie')"#,
); );
@ -187,7 +186,7 @@ mod tests {
id: ActiveValue::set(1), id: ActiveValue::set(1),
name: ActiveValue::set("Apple Pie".to_owned()), name: ActiveValue::set("Apple Pie".to_owned()),
}) })
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
); );
@ -201,7 +200,7 @@ mod tests {
id: 1, id: 1,
name: "Apple Pie".to_owned(), name: "Apple Pie".to_owned(),
}) })
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#, r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie')"#,
); );
@ -221,7 +220,7 @@ mod tests {
name: "Orange Scone".to_owned(), name: "Orange Scone".to_owned(),
} }
]) ])
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#, r#"INSERT INTO "cake" ("id", "name") VALUES (1, 'Apple Pie'), (2, 'Orange Scone')"#,
); );
@ -241,7 +240,7 @@ mod tests {
assert_eq!( assert_eq!(
Insert::<cake::ActiveModel>::new() Insert::<cake::ActiveModel>::new()
.add_many(vec![apple, orange]) .add_many(vec![apple, orange])
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"INSERT INTO "cake" ("id", "name") VALUES (NULL, 'Apple'), (2, 'Orange')"#, r#"INSERT INTO "cake" ("id", "name") VALUES (NULL, 'Apple'), (2, 'Orange')"#,
); );

View File

@ -62,15 +62,14 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests_cfg::{cake, filling, fruit}; use crate::tests_cfg::{cake, filling, fruit};
use crate::{ColumnTrait, EntityTrait, ModelTrait, QueryFilter, QueryTrait}; use crate::{ColumnTrait, DbBackend, EntityTrait, ModelTrait, QueryFilter, QueryTrait};
use sea_query::MysqlQueryBuilder;
#[test] #[test]
fn join_1() { fn join_1() {
assert_eq!( assert_eq!(
cake::Entity::find() cake::Entity::find()
.left_join(fruit::Entity) .left_join(fruit::Entity)
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `cake`.`id`, `cake`.`name` FROM `cake`", "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
@ -86,7 +85,7 @@ mod tests {
cake::Entity::find() cake::Entity::find()
.inner_join(fruit::Entity) .inner_join(fruit::Entity)
.filter(fruit::Column::Name.contains("cherry")) .filter(fruit::Column::Name.contains("cherry"))
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `cake`.`id`, `cake`.`name` FROM `cake`", "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
@ -102,7 +101,7 @@ mod tests {
assert_eq!( assert_eq!(
fruit::Entity::find() fruit::Entity::find()
.reverse_join(cake::Entity) .reverse_join(cake::Entity)
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`", "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`",
@ -120,7 +119,7 @@ mod tests {
assert_eq!( assert_eq!(
find_fruit find_fruit
.filter(cake::Column::Id.eq(11)) .filter(cake::Column::Id.eq(11))
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`", "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`",
@ -141,7 +140,7 @@ mod tests {
assert_eq!( assert_eq!(
cake_model cake_model
.find_related(fruit::Entity) .find_related(fruit::Entity)
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`", "SELECT `fruit`.`id`, `fruit`.`name`, `fruit`.`cake_id` FROM `fruit`",
@ -157,7 +156,7 @@ mod tests {
assert_eq!( assert_eq!(
cake::Entity::find() cake::Entity::find()
.left_join(filling::Entity) .left_join(filling::Entity)
.build(MysqlQueryBuilder) .build(DbBackend::MySql)
.to_string(), .to_string(),
[ [
"SELECT `cake`.`id`, `cake`.`name` FROM `cake`", "SELECT `cake`.`id`, `cake`.`name` FROM `cake`",
@ -174,7 +173,7 @@ mod tests {
let find_filling: Select<filling::Entity> = cake::Entity::find_related(); let find_filling: Select<filling::Entity> = cake::Entity::find_related();
assert_eq!( assert_eq!(
find_filling.build(MysqlQueryBuilder).to_string(), find_filling.build(DbBackend::MySql).to_string(),
[ [
"SELECT `filling`.`id`, `filling`.`name` FROM `filling`", "SELECT `filling`.`id`, `filling`.`name` FROM `filling`",
"INNER JOIN `cake_filling` ON `cake_filling`.`filling_id` = `filling`.`id`", "INNER JOIN `cake_filling` ON `cake_filling`.`filling_id` = `filling`.`id`",

View File

@ -102,12 +102,12 @@ impl FromQueryResult for JsonValue {
#[cfg(feature = "mock")] #[cfg(feature = "mock")]
mod tests { mod tests {
use crate::tests_cfg::cake; use crate::tests_cfg::cake;
use crate::{entity::*, MockDatabase, Syntax}; use crate::{entity::*, DbBackend, MockDatabase};
use sea_query::Value; use sea_query::Value;
#[async_std::test] #[async_std::test]
async fn to_json_1() { async fn to_json_1() {
let db = MockDatabase::new(Syntax::Postgres) let db = MockDatabase::new(DbBackend::Postgres)
.append_query_results(vec![vec![maplit::btreemap! { .append_query_results(vec![vec![maplit::btreemap! {
"id" => Into::<Value>::into(128), "name" => Into::<Value>::into("apple") "id" => Into::<Value>::into(128), "name" => Into::<Value>::into("apple")
}]]) }]])

View File

@ -20,4 +20,4 @@ pub use select::*;
pub use traits::*; pub use traits::*;
pub use update::*; pub use update::*;
pub use crate::executor::{InsertResult, UpdateResult}; pub use crate::{Statement, InsertResult, UpdateResult};

View File

@ -1,5 +1,5 @@
use crate::{Statement, Syntax}; use crate::{DbBackend, Statement};
use sea_query::{QueryBuilder, QueryStatementBuilder}; use sea_query::QueryStatementBuilder;
pub trait QueryTrait { pub trait QueryTrait {
type QueryStatement: QueryStatementBuilder; type QueryStatement: QueryStatementBuilder;
@ -14,14 +14,11 @@ pub trait QueryTrait {
fn into_query(self) -> Self::QueryStatement; fn into_query(self) -> Self::QueryStatement;
/// Build the query as [`Statement`] /// Build the query as [`Statement`]
fn build<B>(&self, builder: B) -> Statement fn build(&self, db_backend: DbBackend) -> Statement {
where let query_builder = db_backend.get_query_builder();
B: QueryBuilderWithSyntax, Statement::from_string_values_tuple(
{ db_backend,
Statement::from_string_values_tuple(builder.syntax(), self.as_query().build(builder)) self.as_query().build_any(query_builder.as_ref()),
)
} }
} }
pub trait QueryBuilderWithSyntax: QueryBuilder {
fn syntax(&self) -> Syntax;
}

View File

@ -30,14 +30,14 @@ impl Update {
/// Update one ActiveModel /// 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!( /// assert_eq!(
/// Update::one(cake::ActiveModel { /// Update::one(cake::ActiveModel {
/// id: ActiveValue::set(1), /// id: ActiveValue::set(1),
/// name: ActiveValue::set("Apple Pie".to_owned()), /// name: ActiveValue::set("Apple Pie".to_owned()),
/// }) /// })
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"UPDATE "cake" SET "name" = 'Apple Pie' WHERE "cake"."id" = 1"#, /// r#"UPDATE "cake" SET "name" = 'Apple Pie' WHERE "cake"."id" = 1"#,
/// ); /// );
@ -59,13 +59,13 @@ impl Update {
/// Update many ActiveModel /// 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!( /// assert_eq!(
/// Update::many(fruit::Entity) /// Update::many(fruit::Entity)
/// .col_expr(fruit::Column::Name, Expr::value("Golden Apple")) /// .col_expr(fruit::Column::Name, Expr::value("Golden Apple"))
/// .filter(fruit::Column::Name.contains("Apple")) /// .filter(fruit::Column::Name.contains("Apple"))
/// .build(PostgresQueryBuilder) /// .build(DbBackend::Postgres)
/// .to_string(), /// .to_string(),
/// r#"UPDATE "fruit" SET "name" = 'Golden Apple' WHERE "fruit"."name" LIKE '%Apple%'"#, /// r#"UPDATE "fruit" SET "name" = 'Golden Apple' WHERE "fruit"."name" LIKE '%Apple%'"#,
/// ); /// );
@ -184,8 +184,8 @@ where
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::tests_cfg::{cake, fruit}; use crate::tests_cfg::{cake, fruit};
use crate::{entity::*, query::*}; use crate::{entity::*, query::*, DbBackend};
use sea_query::{Expr, PostgresQueryBuilder, Value}; use sea_query::{Expr, Value};
#[test] #[test]
fn update_1() { fn update_1() {
@ -194,7 +194,7 @@ mod tests {
id: ActiveValue::set(1), id: ActiveValue::set(1),
name: ActiveValue::set("Apple Pie".to_owned()), name: ActiveValue::set("Apple Pie".to_owned()),
}) })
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"UPDATE "cake" SET "name" = 'Apple Pie' WHERE "cake"."id" = 1"#, r#"UPDATE "cake" SET "name" = 'Apple Pie' WHERE "cake"."id" = 1"#,
); );
@ -208,7 +208,7 @@ mod tests {
name: ActiveValue::set("Orange".to_owned()), name: ActiveValue::set("Orange".to_owned()),
cake_id: ActiveValue::unset(), cake_id: ActiveValue::unset(),
}) })
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"#, r#"UPDATE "fruit" SET "name" = 'Orange' WHERE "fruit"."id" = 1"#,
); );
@ -222,7 +222,7 @@ mod tests {
name: ActiveValue::unchanged("Apple".to_owned()), name: ActiveValue::unchanged("Apple".to_owned()),
cake_id: ActiveValue::set(Some(3)), cake_id: ActiveValue::set(Some(3)),
}) })
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"UPDATE "fruit" SET "cake_id" = 3 WHERE "fruit"."id" = 2"#, r#"UPDATE "fruit" SET "cake_id" = 3 WHERE "fruit"."id" = 2"#,
); );
@ -234,7 +234,7 @@ mod tests {
Update::many(fruit::Entity) Update::many(fruit::Entity)
.col_expr(fruit::Column::CakeId, Expr::value(Value::Null)) .col_expr(fruit::Column::CakeId, Expr::value(Value::Null))
.filter(fruit::Column::Id.eq(2)) .filter(fruit::Column::Id.eq(2))
.build(PostgresQueryBuilder) .build(DbBackend::Postgres)
.to_string(), .to_string(),
r#"UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."id" = 2"#, r#"UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."id" = 2"#,
); );

View File

@ -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; mod setup;
@ -28,7 +28,7 @@ async fn setup_schema(db: &DbConn) {
.build(SqliteQueryBuilder); .build(SqliteQueryBuilder);
let result = db let result = db
.execute(Statement::from_string(Syntax::Sqlite, stmt)) .execute(Statement::from_string(DbBackend::Sqlite, stmt))
.await; .await;
println!("Create table cake: {:?}", result); println!("Create table cake: {:?}", result);
} }
@ -59,6 +59,12 @@ async fn crud_cake(db: &DbConn) -> Result<(), DbErr> {
println!(); println!();
println!("Updated: {:?}", apple); 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?; let apple = cake::Entity::find_by_id(1).one(db).await?;
assert_eq!( assert_eq!(
@ -80,5 +86,11 @@ async fn crud_cake(db: &DbConn) -> Result<(), DbErr> {
assert_eq!(None, apple); assert_eq!(None, apple);
let count = cake::Entity::find().count(db).await?;
println!();
println!("Count: {:?}", count);
assert_eq!(count, 0);
Ok(()) Ok(())
} }

View File

@ -4,7 +4,7 @@ use sea_query::{ColumnDef, ForeignKey, ForeignKeyAction, Index, TableCreateState
pub use super::super::bakery_chain::*; pub use super::super::bakery_chain::*;
async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result<ExecResult, DbErr> { async fn create_table(db: &DbConn, stmt: &TableCreateStatement) -> Result<ExecResult, DbErr> {
let builder = db.get_schema_builder_backend(); let builder = db.get_database_backend();
db.execute(builder.build(stmt)).await db.execute(builder.build(stmt)).await
} }