From 00adf334898f4a62a235cd5d96b058f8e90f621f Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 8 Aug 2021 19:11:45 +0800 Subject: [PATCH 01/52] Readme --- README.md | 11 ++++------- src/lib.rs | 11 ++++------- 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 3ced0629..a1d6e1da 100644 --- a/README.md +++ b/README.md @@ -25,13 +25,10 @@ API to make working with databases in Rust a first-class experience. This is an early release of SeaORM, the API is not stable yet. ``` -
- - [![Getting Started](https://img.shields.io/badge/Getting%20Started-blue)](https://www.sea-ql.org/SeaORM/docs/index) - [![Getting Started](https://img.shields.io/badge/Examples-orange)](https://github.com/SeaQL/sea-orm/tree/master/examples/sqlx) - [![Getting Started](https://img.shields.io/badge/Starter%20Kit-green)](https://github.com/SeaQL/sea-orm/issues/37) - -
+[![Getting Started](https://img.shields.io/badge/Getting%20Started-blue)](https://www.sea-ql.org/SeaORM/docs/index) +[![Examples](https://img.shields.io/badge/Examples-orange)](https://github.com/SeaQL/sea-orm/tree/master/examples/sqlx) +[![Starter Kit](https://img.shields.io/badge/Starter%20Kit-green)](https://github.com/SeaQL/sea-orm/issues/37) +[![Discord](https://img.shields.io/discord/873880840487206962?label=Discord)](https://discord.com/invite/uCPdDXzbdv) ## Features diff --git a/src/lib.rs b/src/lib.rs index 54ed5dc9..c4b8184f 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -25,13 +25,10 @@ //! This is an early release of SeaORM, the API is not stable yet. //! ``` //! -//!
-//! -//! [![Getting Started](https://img.shields.io/badge/Getting%20Started-blue)](https://www.sea-ql.org/SeaORM/docs/index) -//! [![Getting Started](https://img.shields.io/badge/Examples-orange)](https://github.com/SeaQL/sea-orm/tree/master/examples/sqlx) -//! [![Getting Started](https://img.shields.io/badge/Starter%20Kit-green)](https://github.com/SeaQL/sea-orm/issues/37) -//! -//!
+//! [![Getting Started](https://img.shields.io/badge/Getting%20Started-blue)](https://www.sea-ql.org/SeaORM/docs/index) +//! [![Examples](https://img.shields.io/badge/Examples-orange)](https://github.com/SeaQL/sea-orm/tree/master/examples/sqlx) +//! [![Starter Kit](https://img.shields.io/badge/Starter%20Kit-green)](https://github.com/SeaQL/sea-orm/issues/37) +//! [![Discord](https://img.shields.io/discord/873880840487206962?label=Discord)](https://discord.com/invite/uCPdDXzbdv) //! //! ## Features //! From 11931c960ece89c643d7750faa1b948c7bdf2bb4 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 9 Aug 2021 07:37:49 +0800 Subject: [PATCH 02/52] Format toml --- Cargo.toml | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6f8cadbb..ec3d5282 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,11 +20,7 @@ categories = ["database"] keywords = ["async", "orm", "mysql", "postgres", "sqlite"] [package.metadata.docs.rs] -features = [ - "default", - "sqlx-all", - "runtime-async-std-native-tls", -] +features = ["default", "sqlx-all", "runtime-async-std-native-tls"] rustdoc-args = ["--cfg", "docsrs"] [lib] @@ -69,14 +65,8 @@ macros = ["sea-orm-macros"] mock = [] with-json = ["serde_json", "sea-query/with-json"] with-chrono = ["chrono", "sea-query/with-chrono"] -with-rust_decimal = [ - "rust_decimal", - "sea-query/with-rust_decimal", -] -with-uuid = [ - "uuid", - "sea-query/with-uuid", -] +with-rust_decimal = ["rust_decimal", "sea-query/with-rust_decimal"] +with-uuid = ["uuid", "sea-query/with-uuid"] sqlx-all = ["sqlx-mysql", "sqlx-postgres", "sqlx-sqlite"] sqlx-dep = ["sqlx-json", "sqlx-chrono", "sqlx-decimal", "sqlx-uuid"] sqlx-json = ["sqlx/json", "with-json"] From 75cbbd9b40c4a5bc4a3c3409258951faf3fcdee0 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 9 Aug 2021 09:06:13 +0800 Subject: [PATCH 03/52] Readme --- README.md | 6 +++--- src/lib.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a1d6e1da..29b83bd8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@
- +

SeaORM

@@ -34,11 +34,11 @@ This is an early release of SeaORM, the API is not stable yet. 1. Async -Relying on SQLx, SeaORM is a new library with async support from day 1. +Relying on [SQLx](https://github.com/launchbadge/sqlx), SeaORM is a new library with async support from day 1. 2. Dynamic -Built upon SeaQuery, SeaORM allows you to build complex queries without 'fighting the ORM'. +Built upon [SeaQuery](https://github.com/SeaQL/sea-query), SeaORM allows you to build complex queries without 'fighting the ORM'. 3. Testable diff --git a/src/lib.rs b/src/lib.rs index c4b8184f..a81c620b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,6 +1,6 @@ //!
//! -//! +//! //! //!

SeaORM

//! @@ -34,11 +34,11 @@ //! //! 1. Async //! -//! Relying on SQLx, SeaORM is a new library with async support from day 1. +//! Relying on [SQLx](https://github.com/launchbadge/sqlx), SeaORM is a new library with async support from day 1. //! //! 2. Dynamic //! -//! Built upon SeaQuery, SeaORM allows you to build complex queries without 'fighting the ORM'. +//! Built upon [SeaQuery](https://github.com/SeaQL/sea-query), SeaORM allows you to build complex queries without 'fighting the ORM'. //! //! 3. Testable //! From 4731f1fd5eb73cd499da4e32277eac91219fd77c Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 9 Aug 2021 17:13:48 +0800 Subject: [PATCH 04/52] DateTimeWithTimeZone --- src/entity/prelude.rs | 3 +++ src/executor/query.rs | 20 +++++++++++--------- 2 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index 25ae5f67..c7182287 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -12,6 +12,9 @@ pub use serde_json::Value as Json; #[cfg(feature = "with-chrono")] pub use chrono::NaiveDateTime as DateTime; +#[cfg(feature = "with-chrono")] +pub type DateTimeWithTimeZone = chrono::DateTime; + #[cfg(feature = "with-rust_decimal")] pub use rust_decimal::Decimal; diff --git a/src/executor/query.rs b/src/executor/query.rs index b58c5a2c..99ebaba6 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -1,6 +1,4 @@ use crate::{debug_print, DbErr}; -use chrono::NaiveDateTime; -use serde_json::Value as Json; use std::fmt; #[derive(Debug)] @@ -219,7 +217,7 @@ macro_rules! try_getable_mysql { } #[cfg(feature = "sqlx-postgres")] QueryResultRow::SqlxPostgres(_) => { - panic!("{} unsupported by sqlx-sqlite", stringify!($type)) + panic!("{} unsupported by sqlx-postgres", stringify!($type)) } #[cfg(feature = "sqlx-sqlite")] QueryResultRow::SqlxSqlite(_) => { @@ -251,14 +249,15 @@ try_getable_mysql!(u64); try_getable_all!(f32); try_getable_all!(f64); try_getable_all!(String); -try_getable_all!(NaiveDateTime); -try_getable_all!(Json); -#[cfg(feature = "with-uuid")] -use uuid::Uuid; +#[cfg(feature = "with-json")] +try_getable_all!(serde_json::Value); -#[cfg(feature = "with-uuid")] -try_getable_all!(Uuid); +#[cfg(feature = "with-chrono")] +try_getable_all!(chrono::NaiveDateTime); + +// #[cfg(feature = "with-chrono")] +// try_getable_all!(chrono::DateTime); #[cfg(feature = "with-rust_decimal")] use rust_decimal::Decimal; @@ -345,3 +344,6 @@ impl TryGetable for Option { } } } + +#[cfg(feature = "with-uuid")] +try_getable_all!(uuid::Uuid); \ No newline at end of file From da2fd9204b73d0dbeba0095a3f6d8d53890283f5 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 10 Aug 2021 10:37:30 +0800 Subject: [PATCH 05/52] Run CI for all PRs --- .github/workflows/rust.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 4db1bdd7..8333661c 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -1,10 +1,8 @@ name: tests on: - push: - branches: - - master pull_request: + push: branches: - master From b1d28db5ad29f575132213a411b0712ad75dfa67 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 10 Aug 2021 10:59:20 +0800 Subject: [PATCH 06/52] Fix clippy warnings --- sea-orm-codegen/src/entity/column.rs | 1 + src/driver/mock.rs | 2 ++ src/entity/column.rs | 1 + 3 files changed, 4 insertions(+) diff --git a/sea-orm-codegen/src/entity/column.rs b/sea-orm-codegen/src/entity/column.rs index 9a6cf4dc..6a630da6 100644 --- a/sea-orm-codegen/src/entity/column.rs +++ b/sea-orm-codegen/src/entity/column.rs @@ -22,6 +22,7 @@ impl Column { } pub fn get_rs_type(&self) -> TokenStream { + #[allow(unreachable_patterns)] let ident: TokenStream = match self.col_type { ColumnType::Char(_) | ColumnType::String(_) diff --git a/src/driver/mock.rs b/src/driver/mock.rs index 7de6aaaf..0a1629bf 100644 --- a/src/driver/mock.rs +++ b/src/driver/mock.rs @@ -25,6 +25,7 @@ pub trait MockDatabaseTrait: Send { } impl MockDatabaseConnector { + #[allow(unused_variables)] pub fn accepts(string: &str) -> bool { #[cfg(feature = "sqlx-mysql")] if crate::SqlxMySqlConnector::accepts(string) { @@ -41,6 +42,7 @@ impl MockDatabaseConnector { false } + #[allow(unused_variables)] pub async fn connect(string: &str) -> Result { macro_rules! connect_mock_db { ( $syntax: expr ) => { diff --git a/src/entity/column.rs b/src/entity/column.rs index e9c3b759..045a85ba 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -290,6 +290,7 @@ impl From for sea_query::ColumnType { impl From for ColumnType { fn from(col_type: sea_query::ColumnType) -> Self { + #[allow(unreachable_patterns)] match col_type { sea_query::ColumnType::Char(s) => Self::Char(s), sea_query::ColumnType::String(s) => Self::String(s), From ba226a2b62e882586768f08cdde3369c7a901736 Mon Sep 17 00:00:00 2001 From: Billy Chan <30400950+billy1624@users.noreply.github.com> Date: Tue, 10 Aug 2021 16:35:10 +0800 Subject: [PATCH 07/52] Generate arbitrary named entity (#70) * Generate arbitrary named entity (#69) * Bump cli & codegen version * CI tests no caching * Remove local dependency path --- .github/workflows/rust.yml | 10 ---------- sea-orm-cli/Cargo.toml | 2 +- sea-orm-cli/README.md | 2 +- sea-orm-codegen/Cargo.toml | 2 +- sea-orm-codegen/src/entity/writer.rs | 8 ++++---- sea-orm-codegen/tests/entity/cake_filling.rs | 2 +- 6 files changed, 8 insertions(+), 18 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 8333661c..11315fc3 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -25,8 +25,6 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - uses: actions-rs/cargo@v1 with: command: build @@ -60,8 +58,6 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - uses: actions-rs/cargo@v1 with: command: build @@ -109,8 +105,6 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - uses: actions-rs/cargo@v1 with: command: build @@ -158,8 +152,6 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - uses: actions-rs/cargo@v1 with: command: build @@ -204,8 +196,6 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - uses: actions-rs/cargo@v1 with: command: build diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 48be929e..240eba62 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sea-orm-cli" -version = "0.1.0" +version = "0.1.1" authors = [ "Billy Chan " ] edition = "2018" description = "Command line utility for SeaORM" diff --git a/sea-orm-cli/README.md b/sea-orm-cli/README.md index b63a5c56..f5c64e52 100644 --- a/sea-orm-cli/README.md +++ b/sea-orm-cli/README.md @@ -9,5 +9,5 @@ cargo run -- -h Running Entity Generator: ```sh -cargo run -- entity generate -url mysql://sea:sea@localhost/bakery -schema bakery -o out +cargo run -- generate entity -u mysql://sea:sea@localhost/bakery -s bakery -o out ``` diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index ee48571f..3511b614 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sea-orm-codegen" -version = "0.1.1" +version = "0.1.2" authors = ["Billy Chan "] edition = "2018" description = "Code Generator for SeaORM" diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index f4167b61..d277ddac 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -34,7 +34,7 @@ impl EntityWriter { let code_blocks = Self::gen_code_blocks(entity); Self::write(&mut lines, code_blocks); OutputFile { - name: format!("{}.rs", entity.table_name), + name: format!("{}.rs", entity.get_table_name_snake_case()), content: lines.join("\n\n"), } }) @@ -123,11 +123,11 @@ impl EntityWriter { } pub fn gen_impl_entity_name(entity: &Entity) -> TokenStream { - let table_name_snake_case = entity.get_table_name_snake_case(); + let table_name = entity.table_name.as_str(); quote! { impl EntityName for Entity { fn table_name(&self) -> &str { - #table_name_snake_case + #table_name } } } @@ -341,7 +341,7 @@ mod tests { }], }, Entity { - table_name: "cake_filling".to_owned(), + table_name: "_cake_filling_".to_owned(), columns: vec![ Column { name: "cake_id".to_owned(), diff --git a/sea-orm-codegen/tests/entity/cake_filling.rs b/sea-orm-codegen/tests/entity/cake_filling.rs index 1ac64920..d0f00560 100644 --- a/sea-orm-codegen/tests/entity/cake_filling.rs +++ b/sea-orm-codegen/tests/entity/cake_filling.rs @@ -7,7 +7,7 @@ pub struct Entity; impl EntityName for Entity { fn table_name(&self) -> &str { - "cake_filling" + "_cake_filling_" } } From ff8d921343e4c4c1097cfbdd8ce7d90907bc2261 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Tue, 10 Aug 2021 16:56:11 +0800 Subject: [PATCH 08/52] DateTimeWithTimeZone Postgres support --- src/executor/query.rs | 62 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/src/executor/query.rs b/src/executor/query.rs index 99ebaba6..b1ecd988 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -237,6 +237,64 @@ macro_rules! try_getable_mysql { }; } +macro_rules! try_getable_postgres { + ( $type: ty ) => { + impl TryGetable for $type { + fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { + let column = format!("{}{}", pre, col); + match &res.row { + #[cfg(feature = "sqlx-mysql")] + QueryResultRow::SqlxMySql(_) => { + panic!("{} unsupported by sqlx-mysql", stringify!($type)) + } + #[cfg(feature = "sqlx-postgres")] + QueryResultRow::SqlxPostgres(row) => { + use sqlx::Row; + row.try_get(column.as_str()) + .map_err(crate::sqlx_error_to_query_err) + } + #[cfg(feature = "sqlx-sqlite")] + QueryResultRow::SqlxSqlite(_) => { + panic!("{} unsupported by sqlx-sqlite", stringify!($type)) + } + #[cfg(feature = "mock")] + QueryResultRow::Mock(row) => Ok(row.try_get(column.as_str())?), + } + } + } + + impl TryGetable for Option<$type> { + fn try_get(res: &QueryResult, pre: &str, col: &str) -> Result { + let column = format!("{}{}", pre, col); + match &res.row { + #[cfg(feature = "sqlx-mysql")] + QueryResultRow::SqlxMySql(_) => { + panic!("{} unsupported by sqlx-mysql", stringify!($type)) + } + #[cfg(feature = "sqlx-postgres")] + QueryResultRow::SqlxPostgres(row) => { + use sqlx::Row; + row.try_get::, _>(column.as_str()) + .map_err(crate::sqlx_error_to_query_err) + } + #[cfg(feature = "sqlx-sqlite")] + QueryResultRow::SqlxSqlite(_) => { + panic!("{} unsupported by sqlx-sqlite", stringify!($type)) + } + #[cfg(feature = "mock")] + QueryResultRow::Mock(row) => match row.try_get(column.as_str()) { + Ok(v) => Ok(Some(v)), + Err(e) => { + debug_print!("{:#?}", e.to_string()); + Ok(None) + } + }, + } + } + } + }; +} + try_getable_all!(bool); try_getable_all!(i8); try_getable_all!(i16); @@ -256,8 +314,8 @@ try_getable_all!(serde_json::Value); #[cfg(feature = "with-chrono")] try_getable_all!(chrono::NaiveDateTime); -// #[cfg(feature = "with-chrono")] -// try_getable_all!(chrono::DateTime); +#[cfg(feature = "with-chrono")] +try_getable_postgres!(chrono::DateTime); #[cfg(feature = "with-rust_decimal")] use rust_decimal::Decimal; From 10d670e47243e21c84dd51335939e8c3a64ba5db Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 10 Aug 2021 23:36:27 +0800 Subject: [PATCH 09/52] Update CLI generate entity schema argument behavior --- sea-orm-cli/README.md | 6 +++++- sea-orm-cli/src/cli.rs | 4 +++- sea-orm-cli/src/main.rs | 4 +++- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/sea-orm-cli/README.md b/sea-orm-cli/README.md index f5c64e52..531a3c46 100644 --- a/sea-orm-cli/README.md +++ b/sea-orm-cli/README.md @@ -9,5 +9,9 @@ cargo run -- -h Running Entity Generator: ```sh -cargo run -- generate entity -u mysql://sea:sea@localhost/bakery -s bakery -o out +# MySQL (`--database-schema` option is ignored) +cargo run -- generate entity -u mysql://sea:sea@localhost/bakery -o out + +# PostgreSQL +cargo run -- generate entity -u postgres://sea:sea@localhost/bakery -s public -o out ``` diff --git a/sea-orm-cli/src/cli.rs b/sea-orm-cli/src/cli.rs index de0313c2..c286ef15 100644 --- a/sea-orm-cli/src/cli.rs +++ b/sea-orm-cli/src/cli.rs @@ -21,8 +21,10 @@ pub fn build_cli() -> App<'static, 'static> { .long("database-schema") .short("s") .help("Database schema") + .long_help("Database schema\n \ + - For MySQL, this argument is ignored.\n \ + - For PostgreSQL, this argument is optional with default value 'public'.") .takes_value(true) - .required(true) .env("DATABASE_SCHEMA"), ) .arg( diff --git a/sea-orm-cli/src/main.rs b/sea-orm-cli/src/main.rs index 9a512050..377106ec 100644 --- a/sea-orm-cli/src/main.rs +++ b/sea-orm-cli/src/main.rs @@ -23,13 +23,14 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box { let url = args.value_of("DATABASE_URL").unwrap(); - let schema = args.value_of("DATABASE_SCHEMA").unwrap(); let output_dir = args.value_of("OUTPUT_DIR").unwrap(); let table_stmts = if url.starts_with("mysql://") { use sea_schema::mysql::discovery::SchemaDiscovery; use sqlx::MySqlPool; + let url_parts: Vec<&str> = url.split("/").collect(); + let schema = url_parts.last().unwrap(); let connection = MySqlPool::connect(url).await?; let schema_discovery = SchemaDiscovery::new(connection, schema); let schema = schema_discovery.discover().await; @@ -42,6 +43,7 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box Date: Wed, 11 Aug 2021 11:00:06 +0800 Subject: [PATCH 10/52] Add "--include-hidden-tables" flag --- sea-orm-cli/src/cli.rs | 6 ++++++ sea-orm-cli/src/main.rs | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/sea-orm-cli/src/cli.rs b/sea-orm-cli/src/cli.rs index c286ef15..8f2919fb 100644 --- a/sea-orm-cli/src/cli.rs +++ b/sea-orm-cli/src/cli.rs @@ -34,6 +34,12 @@ pub fn build_cli() -> App<'static, 'static> { .help("Entity file output directory") .takes_value(true) .default_value("./"), + ) + .arg( + Arg::with_name("INCLUDE_HIDDEN_TABLES") + .long("include-hidden-tables") + .help("Generate entity file for hidden tables (i.e. table name starts with an underscore)") + .takes_value(false), ), ) .setting(AppSettings::SubcommandRequiredElseHelp); diff --git a/sea-orm-cli/src/main.rs b/sea-orm-cli/src/main.rs index 377106ec..c3cc60dd 100644 --- a/sea-orm-cli/src/main.rs +++ b/sea-orm-cli/src/main.rs @@ -24,6 +24,14 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box { let url = args.value_of("DATABASE_URL").unwrap(); let output_dir = args.value_of("OUTPUT_DIR").unwrap(); + let include_hidden_tables = args.is_present("INCLUDE_HIDDEN_TABLES"); + let filter_hidden_tables = |table: &str| -> bool { + if include_hidden_tables { + true + } else { + !table.starts_with("_") + } + }; let table_stmts = if url.starts_with("mysql://") { use sea_schema::mysql::discovery::SchemaDiscovery; @@ -37,6 +45,7 @@ async fn run_generate_command(matches: &ArgMatches<'_>) -> Result<(), Box) -> Result<(), Box Date: Wed, 11 Aug 2021 13:02:25 +0800 Subject: [PATCH 11/52] sea-orm-cli 0.1.2 --- sea-orm-cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 240eba62..7af5b2ad 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sea-orm-cli" -version = "0.1.1" +version = "0.1.2" authors = [ "Billy Chan " ] edition = "2018" description = "Command line utility for SeaORM" From f5db10d6a6782b0e1a68a0a5bbafb8516de13d8d Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Wed, 11 Aug 2021 13:54:20 +0800 Subject: [PATCH 12/52] Example --- examples/sqlx/src/select.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/sqlx/src/select.rs b/examples/sqlx/src/select.rs index 9b2cf15c..ed24e742 100644 --- a/examples/sqlx/src/select.rs +++ b/examples/sqlx/src/select.rs @@ -66,7 +66,7 @@ async fn find_all(db: &DbConn) -> Result<(), DbErr> { async fn find_together(db: &DbConn) -> Result<(), DbErr> { print!("find cakes and fruits: "); - let both = Cake::find().find_also_related(Fruit).all(db).await?; + let both: Vec<(cake::Model, Option)> = Cake::find().find_also_related(Fruit).all(db).await?; println!(); for bb in both.iter() { From 106d38d20bdfa4a628d59f79c8c048accfa965e4 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 12 Aug 2021 19:06:04 +0800 Subject: [PATCH 13/52] cargo fmt --- examples/sqlx/src/select.rs | 3 ++- src/executor/query.rs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/sqlx/src/select.rs b/examples/sqlx/src/select.rs index ed24e742..ce26f9e2 100644 --- a/examples/sqlx/src/select.rs +++ b/examples/sqlx/src/select.rs @@ -66,7 +66,8 @@ async fn find_all(db: &DbConn) -> Result<(), DbErr> { async fn find_together(db: &DbConn) -> Result<(), DbErr> { print!("find cakes and fruits: "); - let both: Vec<(cake::Model, Option)> = Cake::find().find_also_related(Fruit).all(db).await?; + let both: Vec<(cake::Model, Option)> = + Cake::find().find_also_related(Fruit).all(db).await?; println!(); for bb in both.iter() { diff --git a/src/executor/query.rs b/src/executor/query.rs index b1ecd988..b7e1d12e 100644 --- a/src/executor/query.rs +++ b/src/executor/query.rs @@ -404,4 +404,4 @@ impl TryGetable for Option { } #[cfg(feature = "with-uuid")] -try_getable_all!(uuid::Uuid); \ No newline at end of file +try_getable_all!(uuid::Uuid); From 8b30ef74a22153ebdb2e0cf65afd411fe68ba8a6 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 12 Aug 2021 19:07:03 +0800 Subject: [PATCH 14/52] Customize column names --- Cargo.toml | 2 +- sea-orm-macros/src/derives/column.rs | 20 ++++++++++++++------ sea-orm-macros/src/lib.rs | 12 +++++++++++- src/entity/prelude.rs | 4 ++-- src/lib.rs | 4 ++-- src/tests_cfg/filling.rs | 13 ++++++++++++- 6 files changed, 42 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ec3d5282..aa40ea2b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ chrono = { version = "^0", optional = true } futures = { version = "^0.3" } futures-util = { version = "^0.3" } rust_decimal = { version = "^1", optional = true } -sea-orm-macros = { version = "^0.1", optional = true } +sea-orm-macros = { version = "^0.1", path = "sea-orm-macros", optional = true } sea-query = { version = "^0.12.8" } sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } diff --git a/sea-orm-macros/src/derives/column.rs b/sea-orm-macros/src/derives/column.rs index 78a72259..bf40f58c 100644 --- a/sea-orm-macros/src/derives/column.rs +++ b/sea-orm-macros/src/derives/column.rs @@ -3,7 +3,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{quote, quote_spanned}; use syn::{Data, DataEnum, Fields, Variant}; -pub fn expand_derive_column(ident: Ident, data: Data) -> syn::Result { +pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result { let variants = match data { syn::Data::Enum(DataEnum { variants, .. }) => variants, _ => { @@ -30,12 +30,10 @@ pub fn expand_derive_column(ident: Ident, data: Data) -> syn::Result &str { @@ -46,3 +44,13 @@ pub fn expand_derive_column(ident: Ident, data: Data) -> syn::Result syn::Result { + Ok(quote!( + impl sea_orm::Iden for #ident { + fn unquoted(&self, s: &mut dyn std::fmt::Write) { + write!(s, "{}", self.as_str()).unwrap(); + } + } + )) +} diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index 65b8fd15..7e3f4761 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -29,7 +29,17 @@ pub fn derive_primary_key(input: TokenStream) -> TokenStream { pub fn derive_column(input: TokenStream) -> TokenStream { let DeriveInput { ident, data, .. } = parse_macro_input!(input); - match derives::expand_derive_column(ident, data) { + match derives::expand_derive_column(&ident, &data) { + Ok(ts) => ts.into(), + Err(e) => e.to_compile_error().into(), + } +} + +#[proc_macro_derive(DeriveCustomColumn)] +pub fn derive_custom_column(input: TokenStream) -> TokenStream { + let DeriveInput { ident, .. } = parse_macro_input!(input); + + match derives::expand_derive_custom_column(&ident) { Ok(ts) => ts.into(), Err(e) => e.to_compile_error().into(), } diff --git a/src/entity/prelude.rs b/src/entity/prelude.rs index c7182287..447117b7 100644 --- a/src/entity/prelude.rs +++ b/src/entity/prelude.rs @@ -1,7 +1,7 @@ pub use crate::{ error::*, ActiveModelBehavior, ActiveModelTrait, ColumnDef, ColumnTrait, ColumnType, - DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveEntity, DeriveModel, - DerivePrimaryKey, EntityName, EntityTrait, EnumIter, Iden, IdenStatic, ModelTrait, + DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity, + DeriveModel, DerivePrimaryKey, EntityName, EntityTrait, EnumIter, Iden, IdenStatic, ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, QueryResult, Related, RelationDef, RelationTrait, Select, Value, }; diff --git a/src/lib.rs b/src/lib.rs index a81c620b..becf73eb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -219,8 +219,8 @@ pub use executor::*; pub use query::*; pub use sea_orm_macros::{ - DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveEntity, DeriveModel, - DerivePrimaryKey, FromQueryResult, + DeriveActiveModel, DeriveActiveModelBehavior, DeriveColumn, DeriveCustomColumn, DeriveEntity, + DeriveModel, DerivePrimaryKey, FromQueryResult, }; pub use sea_query; diff --git a/src/tests_cfg/filling.rs b/src/tests_cfg/filling.rs index a246d146..838f96b9 100644 --- a/src/tests_cfg/filling.rs +++ b/src/tests_cfg/filling.rs @@ -16,12 +16,23 @@ pub struct Model { pub name: String, } -#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +// If your column names are not in snake-case, derive `DeriveCustomColumn` here. +#[derive(Copy, Clone, Debug, EnumIter, DeriveCustomColumn)] pub enum Column { Id, Name, } +// Then, customize each column names here. +impl IdenStatic for Column { + fn as_str(&self) -> &str { + match self { + Self::Id => "id", + Self::Name => "name", + } + } +} + #[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] pub enum PrimaryKey { Id, From 69b0ae1177bd72e112eb2f184a9168dee474d29f Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 13 Aug 2021 11:29:48 +0800 Subject: [PATCH 15/52] Custom column names with default --- sea-orm-macros/src/derives/column.rs | 30 ++++++++++++++++++++-------- sea-orm-macros/src/lib.rs | 4 ++-- src/tests_cfg/filling.rs | 4 +++- 3 files changed, 27 insertions(+), 11 deletions(-) diff --git a/sea-orm-macros/src/derives/column.rs b/sea-orm-macros/src/derives/column.rs index bf40f58c..034e966d 100644 --- a/sea-orm-macros/src/derives/column.rs +++ b/sea-orm-macros/src/derives/column.rs @@ -3,7 +3,7 @@ use proc_macro2::{Ident, TokenStream}; use quote::{quote, quote_spanned}; use syn::{Data, DataEnum, Fields, Variant}; -pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result { +pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result { let variants = match data { syn::Data::Enum(DataEnum { variants, .. }) => variants, _ => { @@ -30,13 +30,9 @@ pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result &str { + impl #ident { + fn default_as_str(&self) -> &str { match self { #(Self::#variant => #name),* } @@ -45,8 +41,26 @@ pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result syn::Result { +pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result { + let impl_iden = expand_derive_custom_column(ident, data)?; + Ok(quote!( + #impl_iden + + impl sea_orm::IdenStatic for #ident { + fn as_str(&self) -> &str { + self.default_as_str() + } + } + )) +} + +pub fn expand_derive_custom_column(ident: &Ident, data: &Data) -> syn::Result { + let impl_default_as_str = impl_default_as_str(ident, data)?; + + Ok(quote!( + #impl_default_as_str + impl sea_orm::Iden for #ident { fn unquoted(&self, s: &mut dyn std::fmt::Write) { write!(s, "{}", self.as_str()).unwrap(); diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index 7e3f4761..2ac0ac75 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -37,9 +37,9 @@ pub fn derive_column(input: TokenStream) -> TokenStream { #[proc_macro_derive(DeriveCustomColumn)] pub fn derive_custom_column(input: TokenStream) -> TokenStream { - let DeriveInput { ident, .. } = parse_macro_input!(input); + let DeriveInput { ident, data, .. } = parse_macro_input!(input); - match derives::expand_derive_custom_column(&ident) { + match derives::expand_derive_custom_column(&ident, &data) { Ok(ts) => ts.into(), Err(e) => e.to_compile_error().into(), } diff --git a/src/tests_cfg/filling.rs b/src/tests_cfg/filling.rs index 838f96b9..b439af7b 100644 --- a/src/tests_cfg/filling.rs +++ b/src/tests_cfg/filling.rs @@ -27,8 +27,10 @@ pub enum Column { impl IdenStatic for Column { fn as_str(&self) -> &str { match self { + // Override column names Self::Id => "id", - Self::Name => "name", + // Leave all other columns using default snake-case values + _ => self.default_as_str(), } } } From e76928f1ccb7e1dc8b98882255248cf8dcd1c5a9 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 13 Aug 2021 18:40:20 +0800 Subject: [PATCH 16/52] Support join on multiple columns --- src/entity/identity.rs | 52 +++++++++++++++++++- src/entity/relation.rs | 16 ++++-- src/query/helper.rs | 6 +++ src/query/join.rs | 21 +++++++- src/tests_cfg/cake_filling.rs | 6 +++ src/tests_cfg/cake_filling_price.rs | 76 +++++++++++++++++++++++++++++ src/tests_cfg/mod.rs | 2 + 7 files changed, 171 insertions(+), 8 deletions(-) create mode 100644 src/tests_cfg/cake_filling_price.rs diff --git a/src/entity/identity.rs b/src/entity/identity.rs index af68978c..d1cc3170 100644 --- a/src/entity/identity.rs +++ b/src/entity/identity.rs @@ -1,17 +1,24 @@ -use crate::IdenStatic; +use crate::{ColumnTrait, EntityTrait, IdenStatic}; use sea_query::{DynIden, IntoIden}; #[derive(Debug, Clone)] pub enum Identity { Unary(DynIden), Binary(DynIden, DynIden), - // Ternary(DynIden, DynIden, DynIden), + Ternary(DynIden, DynIden, DynIden), } pub trait IntoIdentity { fn into_identity(self) -> Identity; } +pub trait IdentityOf +where + E: EntityTrait, +{ + fn identity_of(self) -> Identity; +} + impl IntoIdentity for T where T: IdenStatic, @@ -30,3 +37,44 @@ where Identity::Binary(self.0.into_iden(), self.1.into_iden()) } } + +impl IntoIdentity for (T, C, R) +where + T: IdenStatic, + C: IdenStatic, + R: IdenStatic, +{ + fn into_identity(self) -> Identity { + Identity::Ternary(self.0.into_iden(), self.1.into_iden(), self.2.into_iden()) + } +} + +impl IdentityOf for C +where + E: EntityTrait, + C: ColumnTrait, +{ + fn identity_of(self) -> Identity { + self.into_identity() + } +} + +impl IdentityOf for (C, C) +where + E: EntityTrait, + C: ColumnTrait, +{ + fn identity_of(self) -> Identity { + self.into_identity() + } +} + +impl IdentityOf for (C, C, C) +where + E: EntityTrait, + C: ColumnTrait, +{ + fn identity_of(self) -> Identity { + self.into_identity() + } +} diff --git a/src/entity/relation.rs b/src/entity/relation.rs index 7c9213d3..7d2059e2 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -1,4 +1,4 @@ -use crate::{EntityTrait, Identity, IntoIdentity, Iterable, QuerySelect, Select}; +use crate::{EntityTrait, Identity, IdentityOf, Iterable, QuerySelect, Select}; use core::marker::PhantomData; use sea_query::{DynIden, IntoIden, JoinType}; use std::fmt::Debug; @@ -89,13 +89,19 @@ where } } - pub fn from(mut self, identifier: E::Column) -> Self { - self.from_col = Some(identifier.into_identity()); + pub fn from(mut self, identifier: T) -> Self + where + T: IdentityOf, + { + self.from_col = Some(identifier.identity_of()); self } - pub fn to(mut self, identifier: R::Column) -> Self { - self.to_col = Some(identifier.into_identity()); + pub fn to(mut self, identifier: T) -> Self + where + T: IdentityOf, + { + self.to_col = Some(identifier.identity_of()); self } } diff --git a/src/query/helper.rs b/src/query/helper.rs index 78eaa4e7..9691e1ab 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -283,6 +283,12 @@ fn join_condition(rel: RelationDef) -> SimpleExpr { .equals(SeaRc::clone(&to_tbl), f1) .and(Expr::tbl(SeaRc::clone(&from_tbl), o2).equals(SeaRc::clone(&to_tbl), f2)) } + (Identity::Ternary(o1, o2, o3), Identity::Ternary(f1, f2, f3)) => { + Expr::tbl(SeaRc::clone(&from_tbl), o1) + .equals(SeaRc::clone(&to_tbl), f1) + .and(Expr::tbl(SeaRc::clone(&from_tbl), o2).equals(SeaRc::clone(&to_tbl), f2)) + .and(Expr::tbl(SeaRc::clone(&from_tbl), o3).equals(SeaRc::clone(&to_tbl), f3)) + } _ => panic!("Owner key and foreign key mismatch"), } } diff --git a/src/query/join.rs b/src/query/join.rs index 61c6c1b9..d6e00301 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -61,7 +61,7 @@ where #[cfg(test)] mod tests { - use crate::tests_cfg::{cake, filling, fruit}; + use crate::tests_cfg::{cake, cake_filling, cake_filling_price, filling, fruit}; use crate::{ColumnTrait, DbBackend, EntityTrait, ModelTrait, QueryFilter, QueryTrait}; #[test] @@ -182,4 +182,23 @@ mod tests { .join(" ") ); } + + #[test] + fn join_8() { + use crate::{Related, Select}; + + let find_cake_filling_price: Select = + cake_filling::Entity::find_related(); + assert_eq!( + find_cake_filling_price.build(DbBackend::MySql).to_string(), + [ + "SELECT `cake_filling_price`.`cake_id`, `cake_filling_price`.`filling_id`, `cake_filling_price`.`price`", + "FROM `cake_filling_price`", + "INNER JOIN `cake_filling` ON", + "(`cake_filling`.`cake_id` = `cake_filling_price`.`cake_id`) AND", + "(`cake_filling`.`filling_id` = `cake_filling_price`.`filling_id`)", + ] + .join(" ") + ); + } } diff --git a/src/tests_cfg/cake_filling.rs b/src/tests_cfg/cake_filling.rs index 6b5c20aa..b1151ee4 100644 --- a/src/tests_cfg/cake_filling.rs +++ b/src/tests_cfg/cake_filling.rs @@ -66,4 +66,10 @@ impl RelationTrait for Relation { } } +impl Related for Entity { + fn to() -> RelationDef { + super::cake_filling_price::Relation::CakeFilling.def().rev() + } +} + impl ActiveModelBehavior for ActiveModel {} diff --git a/src/tests_cfg/cake_filling_price.rs b/src/tests_cfg/cake_filling_price.rs new file mode 100644 index 00000000..eae07871 --- /dev/null +++ b/src/tests_cfg/cake_filling_price.rs @@ -0,0 +1,76 @@ +use crate as sea_orm; +use crate::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "cake_filling_price" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub cake_id: i32, + pub filling_id: i32, + pub price: Decimal, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + CakeId, + FillingId, + Price, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + CakeId, + FillingId, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + false + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation { + CakeFilling, +} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::CakeId => ColumnType::Integer.def(), + Self::FillingId => ColumnType::Integer.def(), + Self::Price => ColumnType::Decimal(None).def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + match self { + Self::CakeFilling => Entity::belongs_to(super::cake_filling::Entity) + .from((Column::CakeId, Column::FillingId)) + .to(( + super::cake_filling::Column::CakeId, + super::cake_filling::Column::FillingId, + )) + .into(), + } + } +} + +impl Related for Entity { + fn to() -> RelationDef { + Relation::CakeFilling.def() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/src/tests_cfg/mod.rs b/src/tests_cfg/mod.rs index ca9b8a68..afb9e115 100644 --- a/src/tests_cfg/mod.rs +++ b/src/tests_cfg/mod.rs @@ -2,10 +2,12 @@ pub mod cake; pub mod cake_filling; +pub mod cake_filling_price; pub mod filling; pub mod fruit; pub use cake::Entity as Cake; pub use cake_filling::Entity as CakeFilling; +pub use cake_filling_price::Entity as CakeFillingPrice; pub use filling::Entity as Filling; pub use fruit::Entity as Fruit; From b7408dda30ac2e55cf15d7017041c676c3a013d4 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 11 Aug 2021 16:25:27 +0800 Subject: [PATCH 17/52] Support schema prefix when specifying table name --- src/entity/base_entity.rs | 15 +++++++++++++-- src/query/delete.rs | 2 +- src/query/insert.rs | 6 +++--- src/query/select.rs | 4 ++-- src/query/update.rs | 4 ++-- 5 files changed, 21 insertions(+), 10 deletions(-) diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index 95d5603e..855a55df 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -3,7 +3,7 @@ use crate::{ ModelTrait, PrimaryKeyToColumn, PrimaryKeyTrait, QueryFilter, Related, RelationBuilder, RelationTrait, RelationType, Select, Update, UpdateMany, UpdateOne, }; -use sea_query::{Iden, IntoValueTuple}; +use sea_query::{Alias, Iden, IntoIden, IntoTableRef, IntoValueTuple, TableRef}; pub use sea_strum::IntoEnumIterator as Iterable; use std::fmt::Debug; @@ -12,10 +12,21 @@ pub trait IdenStatic: Iden + Copy + Debug + 'static { } pub trait EntityName: IdenStatic + Default { + fn schema_name(&self) -> Option<&str> { + None + } + fn table_name(&self) -> &str; fn module_name(&self) -> &str { - Self::table_name(self) + self.table_name() + } + + fn table_ref(&self) -> TableRef { + match self.schema_name() { + Some(schema) => (Alias::new(schema).into_iden(), self.into_iden()).into_table_ref(), + None => self.into_table_ref(), + } } } diff --git a/src/query/delete.rs b/src/query/delete.rs index 8c3b2a52..e5cefdef 100644 --- a/src/query/delete.rs +++ b/src/query/delete.rs @@ -65,7 +65,7 @@ impl Delete { { let myself = DeleteOne { query: DeleteStatement::new() - .from_table(A::Entity::default().into_iden()) + .from_table(A::Entity::default().table_ref()) .to_owned(), model: model.into_active_model(), }; diff --git a/src/query/insert.rs b/src/query/insert.rs index 25d0a9ea..abd52b4b 100644 --- a/src/query/insert.rs +++ b/src/query/insert.rs @@ -1,6 +1,6 @@ -use crate::{ActiveModelTrait, EntityTrait, IntoActiveModel, Iterable, QueryTrait}; +use crate::{ActiveModelTrait, EntityName, EntityTrait, IntoActiveModel, Iterable, QueryTrait}; use core::marker::PhantomData; -use sea_query::{InsertStatement, IntoIden}; +use sea_query::InsertStatement; #[derive(Clone, Debug)] pub struct Insert @@ -28,7 +28,7 @@ where pub(crate) fn new() -> Self { Self { query: InsertStatement::new() - .into_table(A::Entity::default().into_iden()) + .into_table(A::Entity::default().table_ref()) .to_owned(), columns: Vec::new(), model: PhantomData, diff --git a/src/query/select.rs b/src/query/select.rs index 91db2907..1b0c93c3 100644 --- a/src/query/select.rs +++ b/src/query/select.rs @@ -2,7 +2,7 @@ use crate::{ColumnTrait, EntityTrait, Iterable, QueryFilter, QueryOrder, QuerySe use core::fmt::Debug; use core::marker::PhantomData; pub use sea_query::JoinType; -use sea_query::{DynIden, IntoColumnRef, IntoIden, SeaRc, SelectStatement, SimpleExpr}; +use sea_query::{DynIden, IntoColumnRef, SeaRc, SelectStatement, SimpleExpr}; #[derive(Clone, Debug)] pub struct Select @@ -119,7 +119,7 @@ where } fn prepare_from(mut self) -> Self { - self.query.from(E::default().into_iden()); + self.query.from(E::default().table_ref()); self } } diff --git a/src/query/update.rs b/src/query/update.rs index ca750d88..0c60f472 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -49,7 +49,7 @@ impl Update { { let myself = UpdateOne { query: UpdateStatement::new() - .table(A::Entity::default().into_iden()) + .table(A::Entity::default().table_ref()) .to_owned(), model, }; @@ -75,7 +75,7 @@ impl Update { E: EntityTrait, { UpdateMany { - query: UpdateStatement::new().table(entity.into_iden()).to_owned(), + query: UpdateStatement::new().table(entity.table_ref()).to_owned(), entity: PhantomData, } } From f5b1496b143ff5f0d459014c50b6a4aa5e3c7301 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Fri, 13 Aug 2021 22:55:53 +0800 Subject: [PATCH 18/52] Bump 0.12.11 version --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index aa40ea2b..8e932848 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -34,7 +34,7 @@ futures = { version = "^0.3" } futures-util = { version = "^0.3" } rust_decimal = { version = "^1", optional = true } sea-orm-macros = { version = "^0.1", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.12.8" } +sea-query = { version = "^0.12.11" } sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } sqlx = { version = "^0.5", optional = true } From 38ace07e83e5de5b2399fe9726ec0d264fdcc03f Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Sat, 14 Aug 2021 17:00:03 +0800 Subject: [PATCH 19/52] Schema prefix in table join --- src/entity/relation.rs | 14 ++++++------- src/query/helper.rs | 18 ++++++++++++++--- src/query/join.rs | 31 +++++++++++++++++++++++------ src/tests_cfg/cake_filling_price.rs | 4 ++++ 4 files changed, 51 insertions(+), 16 deletions(-) diff --git a/src/entity/relation.rs b/src/entity/relation.rs index 7d2059e2..955660e2 100644 --- a/src/entity/relation.rs +++ b/src/entity/relation.rs @@ -1,6 +1,6 @@ use crate::{EntityTrait, Identity, IdentityOf, Iterable, QuerySelect, Select}; use core::marker::PhantomData; -use sea_query::{DynIden, IntoIden, JoinType}; +use sea_query::{JoinType, TableRef}; use std::fmt::Debug; #[derive(Clone, Debug)] @@ -30,8 +30,8 @@ where pub struct RelationDef { pub rel_type: RelationType, - pub from_tbl: DynIden, - pub to_tbl: DynIden, + pub from_tbl: TableRef, + pub to_tbl: TableRef, pub from_col: Identity, pub to_col: Identity, } @@ -43,8 +43,8 @@ where { entities: PhantomData<(E, R)>, rel_type: RelationType, - from_tbl: DynIden, - to_tbl: DynIden, + from_tbl: TableRef, + to_tbl: TableRef, from_col: Option, to_col: Option, } @@ -71,8 +71,8 @@ where Self { entities: PhantomData, rel_type, - from_tbl: from.into_iden(), - to_tbl: to.into_iden(), + from_tbl: from.table_ref(), + to_tbl: to.table_ref(), from_col: None, to_col: None, } diff --git a/src/query/helper.rs b/src/query/helper.rs index 9691e1ab..6ade581a 100644 --- a/src/query/helper.rs +++ b/src/query/helper.rs @@ -2,7 +2,9 @@ use crate::{ ColumnTrait, EntityTrait, Identity, IntoSimpleExpr, Iterable, ModelTrait, PrimaryKeyToColumn, RelationDef, }; -use sea_query::{Alias, Expr, IntoCondition, SeaRc, SelectExpr, SelectStatement, SimpleExpr}; +use sea_query::{ + Alias, Expr, IntoCondition, SeaRc, SelectExpr, SelectStatement, SimpleExpr, TableRef, +}; pub use sea_query::{Condition, ConditionalStatement, DynIden, JoinType, Order, OrderedStatement}; // LINT: when the column does not appear in tables selected from @@ -269,8 +271,8 @@ pub trait QueryFilter: Sized { } fn join_condition(rel: RelationDef) -> SimpleExpr { - let from_tbl = rel.from_tbl.clone(); - let to_tbl = rel.to_tbl.clone(); + let from_tbl = unpack_table_ref(&rel.from_tbl); + let to_tbl = unpack_table_ref(&rel.to_tbl); let owner_keys = rel.from_col; let foreign_keys = rel.to_col; @@ -292,3 +294,13 @@ fn join_condition(rel: RelationDef) -> SimpleExpr { _ => panic!("Owner key and foreign key mismatch"), } } + +fn unpack_table_ref(table_ref: &TableRef) -> DynIden { + match table_ref { + TableRef::Table(tbl) => SeaRc::clone(tbl), + TableRef::SchemaTable(_, tbl) => SeaRc::clone(tbl), + TableRef::TableAlias(tbl, _) => SeaRc::clone(tbl), + TableRef::SchemaTableAlias(_, tbl, _) => SeaRc::clone(tbl), + TableRef::SubQuery(_, tbl) => SeaRc::clone(tbl), + } +} diff --git a/src/query/join.rs b/src/query/join.rs index d6e00301..72726d14 100644 --- a/src/query/join.rs +++ b/src/query/join.rs @@ -190,13 +190,32 @@ mod tests { let find_cake_filling_price: Select = cake_filling::Entity::find_related(); assert_eq!( - find_cake_filling_price.build(DbBackend::MySql).to_string(), + find_cake_filling_price.build(DbBackend::Postgres).to_string(), [ - "SELECT `cake_filling_price`.`cake_id`, `cake_filling_price`.`filling_id`, `cake_filling_price`.`price`", - "FROM `cake_filling_price`", - "INNER JOIN `cake_filling` ON", - "(`cake_filling`.`cake_id` = `cake_filling_price`.`cake_id`) AND", - "(`cake_filling`.`filling_id` = `cake_filling_price`.`filling_id`)", + r#"SELECT "cake_filling_price"."cake_id", "cake_filling_price"."filling_id", "cake_filling_price"."price""#, + r#"FROM "public"."cake_filling_price""#, + r#"INNER JOIN "cake_filling" ON"#, + r#"("cake_filling"."cake_id" = "cake_filling_price"."cake_id") AND"#, + r#"("cake_filling"."filling_id" = "cake_filling_price"."filling_id")"#, + ] + .join(" ") + ); + } + + #[test] + fn join_9() { + use crate::{Related, Select}; + + let find_cake_filling: Select = + cake_filling_price::Entity::find_related(); + assert_eq!( + find_cake_filling.build(DbBackend::Postgres).to_string(), + [ + r#"SELECT "cake_filling"."cake_id", "cake_filling"."filling_id""#, + r#"FROM "cake_filling""#, + r#"INNER JOIN "public"."cake_filling_price" ON"#, + r#"("cake_filling_price"."cake_id" = "cake_filling"."cake_id") AND"#, + r#"("cake_filling_price"."filling_id" = "cake_filling"."filling_id")"#, ] .join(" ") ); diff --git a/src/tests_cfg/cake_filling_price.rs b/src/tests_cfg/cake_filling_price.rs index eae07871..c0bcbea1 100644 --- a/src/tests_cfg/cake_filling_price.rs +++ b/src/tests_cfg/cake_filling_price.rs @@ -5,6 +5,10 @@ use crate::entity::prelude::*; pub struct Entity; impl EntityName for Entity { + fn schema_name(&self) -> Option<&str> { + Some("public") + } + fn table_name(&self) -> &str { "cake_filling_price" } From d9ac5d83de6df364e750551b5816ec5a1f392df4 Mon Sep 17 00:00:00 2001 From: Billy Chan <30400950+billy1624@users.noreply.github.com> Date: Sat, 14 Aug 2021 18:43:47 +0800 Subject: [PATCH 20/52] Fix compile errors on different runtime (#84) * Fix compile errors on different runtime * Split sea-orm-cli into separate workspace * Hotfix --- .github/workflows/rust.yml | 26 ++++++++++++++++++++++++-- Cargo.toml | 1 - sea-orm-cli/Cargo.toml | 3 +++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 11315fc3..e0f4e3e0 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -30,7 +30,8 @@ jobs: command: build args: > --all - --features default + --exclude 'sea-orm-example-*' + --features default,runtime-${{ matrix.runtime }} - uses: actions-rs/cargo@v1 with: @@ -38,7 +39,28 @@ jobs: args: > --all --exclude 'sea-orm-example-*' - --features default + --features default,runtime-${{ matrix.runtime }} + + cli: + name: CLI + runs-on: ${{ matrix.os }} + strategy: + matrix: + os: [ubuntu-latest, windows-latest, macOS-latest] + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - uses: actions-rs/cargo@v1 + with: + command: install + args: > + --path sea-orm-cli sqlite: name: SQLite diff --git a/Cargo.toml b/Cargo.toml index 8e932848..4ce90956 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ members = [ ".", "sea-orm-macros", "sea-orm-codegen", - "sea-orm-cli", "examples/sqlx", ] diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 7af5b2ad..a288f7a2 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -1,3 +1,6 @@ +[workspace] +# A separate workspace for sea-orm-cli + [package] name = "sea-orm-cli" version = "0.1.2" From 2580f65696b1f7e4713e2258f8988f893176d74e Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 15 Aug 2021 18:49:29 +0800 Subject: [PATCH 21/52] #86 Use sea-query with thread-safe --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 4ce90956..b7c707ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ futures = { version = "^0.3" } futures-util = { version = "^0.3" } rust_decimal = { version = "^1", optional = true } sea-orm-macros = { version = "^0.1", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.12.11" } +sea-query = { version = "^0.14", features = ["thread-safe"] } sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } sqlx = { version = "^0.5", optional = true } From aea4ec2d54b4993bfcf110f973392c0ab3c56b69 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 17 Aug 2021 12:41:34 +0800 Subject: [PATCH 22/52] Codegen mod.rs include prelude --- sea-orm-codegen/src/entity/writer.rs | 9 ++++++++- sea-orm-codegen/tests/entity/mod.rs | 2 ++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sea-orm-codegen/src/entity/writer.rs b/sea-orm-codegen/src/entity/writer.rs index d277ddac..207864ba 100644 --- a/sea-orm-codegen/src/entity/writer.rs +++ b/sea-orm-codegen/src/entity/writer.rs @@ -44,11 +44,18 @@ impl EntityWriter { pub fn write_mod(&self) -> OutputFile { let mut lines = Vec::new(); Self::write_doc_comment(&mut lines); - let code_blocks = self + let code_blocks: Vec = self .entities .iter() .map(|entity| Self::gen_mod(entity)) .collect(); + Self::write( + &mut lines, + vec![quote! { + pub mod prelude; + }], + ); + lines.push("".to_owned()); Self::write(&mut lines, code_blocks); OutputFile { name: "mod.rs".to_owned(), diff --git a/sea-orm-codegen/tests/entity/mod.rs b/sea-orm-codegen/tests/entity/mod.rs index 395d29f9..5a8c6c21 100644 --- a/sea-orm-codegen/tests/entity/mod.rs +++ b/sea-orm-codegen/tests/entity/mod.rs @@ -1,5 +1,7 @@ //! SeaORM Entity. Generated by sea-orm-codegen 0.1.0 +pub mod prelude; + pub mod cake; pub mod cake_filling; pub mod filling; From 7bb5ff7797109c633ac14fde6a958ef6da235f0a Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 11 Aug 2021 17:23:34 +0800 Subject: [PATCH 23/52] Add `into_model` & `into_json` methods for `SelectorRaw` --- src/executor/select.rs | 165 ++++++++++++++++++++++++++++++++++------- 1 file changed, 138 insertions(+), 27 deletions(-) diff --git a/src/executor/select.rs b/src/executor/select.rs index 647b6c95..be4c2354 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -76,33 +76,6 @@ impl Select where E: EntityTrait, { - /// ``` - /// # #[cfg(feature = "mock")] - /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; - /// # - /// # let db = MockDatabase::new(DbBackend::Postgres).into_connection(); - /// # - /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; - /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { - /// # - /// let cheese: Option = cake::Entity::find().from_raw_sql( - /// Statement::from_sql_and_values( - /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = $1"#, vec![1.into()] - /// ) - /// ).one(&db).await?; - /// # - /// # Ok(()) - /// # }); - /// - /// assert_eq!( - /// db.into_transaction_log(), - /// vec![ - /// Transaction::from_sql_and_values( - /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = $1"#, vec![1.into()] - /// ), - /// ]); - /// ``` #[allow(clippy::wrong_self_convention)] pub fn from_raw_sql(self, stmt: Statement) -> SelectorRaw> { SelectorRaw { @@ -289,6 +262,117 @@ impl SelectorRaw where S: SelectorTrait, { + /// ``` + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; + /// # + /// # let db = MockDatabase::new(DbBackend::Postgres).into_connection(); + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake, FromQueryResult}; + /// + /// #[derive(Debug, FromQueryResult)] + /// struct SelectResult { + /// name: String, + /// num_of_cakes: i32, + /// } + /// + /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # + /// let _: Vec = cake::Entity::find().from_raw_sql( + /// Statement::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, vec![] + /// ) + /// ) + /// .into_model::() + /// .all(&db) + /// .await?; + /// # + /// # Ok(()) + /// # }); + /// + /// assert_eq!( + /// db.into_transaction_log(), + /// vec![ + /// Transaction::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, vec![] + /// ), + /// ]); + /// ``` + pub fn into_model(self) -> SelectorRaw> + where + M: FromQueryResult, + { + SelectorRaw { + stmt: self.stmt, + selector: SelectModel { model: PhantomData }, + } + } + + /// ``` + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; + /// # + /// # let db = MockDatabase::new(DbBackend::Postgres).into_connection(); + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; + /// + /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # + /// let _: Vec = cake::Entity::find().from_raw_sql( + /// Statement::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] + /// ) + /// ) + /// .into_json() + /// .all(&db) + /// .await?; + /// # + /// # Ok(()) + /// # }); + /// + /// assert_eq!( + /// db.into_transaction_log(), + /// vec![ + /// Transaction::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] + /// ), + /// ]); + /// ``` + #[cfg(feature = "with-json")] + pub fn into_json(self) -> SelectorRaw> { + SelectorRaw { + stmt: self.stmt, + selector: SelectModel { model: PhantomData }, + } + } + + /// ``` + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; + /// # + /// # let db = MockDatabase::new(DbBackend::Postgres).into_connection(); + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; + /// + /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # + /// let _: Option = cake::Entity::find().from_raw_sql( + /// Statement::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = $1"#, vec![1.into()] + /// ) + /// ).one(&db).await?; + /// # + /// # Ok(()) + /// # }); + /// + /// assert_eq!( + /// db.into_transaction_log(), + /// vec![ + /// Transaction::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake" WHERE "id" = $1"#, vec![1.into()] + /// ), + /// ]); + /// ``` pub async fn one(self, db: &DatabaseConnection) -> Result, DbErr> { let row = db.query_one(self.stmt).await?; match row { @@ -297,6 +381,33 @@ where } } + /// ``` + /// # #[cfg(feature = "mock")] + /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; + /// # + /// # let db = MockDatabase::new(DbBackend::Postgres).into_connection(); + /// # + /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; + /// + /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # + /// let _: Vec = cake::Entity::find().from_raw_sql( + /// Statement::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] + /// ) + /// ).all(&db).await?; + /// # + /// # Ok(()) + /// # }); + /// + /// assert_eq!( + /// db.into_transaction_log(), + /// vec![ + /// Transaction::from_sql_and_values( + /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] + /// ), + /// ]); + /// ``` pub async fn all(self, db: &DatabaseConnection) -> Result, DbErr> { let rows = db.query_all(self.stmt).await?; let mut models = Vec::new(); From 1442fcf10f7d018f453d403f9af170bfb7e179fd Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 17 Aug 2021 12:25:59 +0800 Subject: [PATCH 24/52] Assert against structs --- src/executor/select.rs | 60 ++++++++++++++++++++++++++++++++++++++---- 1 file changed, 55 insertions(+), 5 deletions(-) diff --git a/src/executor/select.rs b/src/executor/select.rs index be4c2354..2997448a 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -266,11 +266,22 @@ where /// # #[cfg(feature = "mock")] /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(DbBackend::Postgres).into_connection(); + /// # let db = MockDatabase::new(DbBackend::Postgres) + /// # .append_query_results(vec![vec![ + /// # maplit::btreemap! { + /// # "name" => Into::::into("Chocolate Forest"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # maplit::btreemap! { + /// # "name" => Into::::into("New York Cheese"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # ]]) + /// # .into_connection(); /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake, FromQueryResult}; /// - /// #[derive(Debug, FromQueryResult)] + /// #[derive(Debug, PartialEq, FromQueryResult)] /// struct SelectResult { /// name: String, /// num_of_cakes: i32, @@ -278,7 +289,7 @@ where /// /// # let _: Result<(), DbErr> = async_std::task::block_on(async { /// # - /// let _: Vec = cake::Entity::find().from_raw_sql( + /// let res: Vec = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( /// DbBackend::Postgres, r#"SELECT "cake"."name", count("cake"."id") AS "num_of_cakes" FROM "cake""#, vec![] /// ) @@ -286,6 +297,20 @@ where /// .into_model::() /// .all(&db) /// .await?; + /// + /// assert_eq!( + /// res, + /// vec![ + /// SelectResult { + /// name: "Chocolate Forest".to_owned(), + /// num_of_cakes: 1, + /// }, + /// SelectResult { + /// name: "New York Cheese".to_owned(), + /// num_of_cakes: 1, + /// }, + /// ] + /// ); /// # /// # Ok(()) /// # }); @@ -312,13 +337,24 @@ where /// # #[cfg(feature = "mock")] /// # use sea_orm::{error::*, tests_cfg::*, MockDatabase, Transaction, DbBackend}; /// # - /// # let db = MockDatabase::new(DbBackend::Postgres).into_connection(); + /// # let db = MockDatabase::new(DbBackend::Postgres) + /// # .append_query_results(vec![vec![ + /// # maplit::btreemap! { + /// # "name" => Into::::into("Chocolate Forest"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # maplit::btreemap! { + /// # "name" => Into::::into("New York Cheese"), + /// # "num_of_cakes" => Into::::into(1), + /// # }, + /// # ]]) + /// # .into_connection(); /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// /// # let _: Result<(), DbErr> = async_std::task::block_on(async { /// # - /// let _: Vec = cake::Entity::find().from_raw_sql( + /// let res: Vec = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( /// DbBackend::Postgres, r#"SELECT "cake"."id", "cake"."name" FROM "cake""#, vec![] /// ) @@ -326,6 +362,20 @@ where /// .into_json() /// .all(&db) /// .await?; + /// + /// assert_eq!( + /// res, + /// vec![ + /// serde_json::json!({ + /// "name": "Chocolate Forest", + /// "num_of_cakes": 1, + /// }), + /// serde_json::json!({ + /// "name": "New York Cheese", + /// "num_of_cakes": 1, + /// }), + /// ] + /// ); /// # /// # Ok(()) /// # }); From a5a4535e145f5076794c980026484bfbc3e64ae7 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 20 Aug 2021 17:49:08 +0800 Subject: [PATCH 25/52] Add CHANGELOG.md --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..620542b7 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/) +and this project adheres to [Semantic Versioning](http://semver.org/). + +## 0.1.1 - 2021-08-08 + +- Early release of SeaORM From 514e12a335cf7ac0ac0afffe8bed58f6be5d114f Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Fri, 20 Aug 2021 22:47:15 +0800 Subject: [PATCH 26/52] Readme --- Design.md | 2 ++ README.md | 3 +-- src/lib.rs | 3 +-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/Design.md b/Design.md index 860afcef..73e88227 100644 --- a/Design.md +++ b/Design.md @@ -1,5 +1,7 @@ # Design Goals +We are heavily inspired by ActiveRecord, Eloquent and TypeORM. + 1. Intuitive and ergonomic API should state the intention clearly. Provide syntax sugar for common things. diff --git a/README.md b/README.md index 29b83bd8..f2d262e9 100644 --- a/README.md +++ b/README.md @@ -18,8 +18,7 @@ # SeaORM -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. +SeaORM is a relational ORM to help you build light weight and concurrent web services in Rust. ```markdown This is an early release of SeaORM, the API is not stable yet. diff --git a/src/lib.rs b/src/lib.rs index becf73eb..93ec2545 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,8 +18,7 @@ //! //! # SeaORM //! -//! 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. +//! SeaORM is a relational ORM to help you build light weight and concurrent web services in Rust. //! //! ```markdown //! This is an early release of SeaORM, the API is not stable yet. From 2cfaa34a3390eb7ad4c57ee120f263df8e10c0af Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Tue, 17 Aug 2021 16:40:53 +0800 Subject: [PATCH 27/52] Test against all supported runtime --- sea-orm-macros/src/lib.rs | 20 ++++++++++++++++++++ src/entity/base_entity.rs | 18 +++++++++--------- src/executor/paginator.rs | 16 ++++++++-------- src/executor/select.rs | 8 ++++---- src/lib.rs | 2 ++ src/query/json.rs | 8 +++++--- src/runtime.rs | 33 +++++++++++++++++++++++++++++++++ tests/basic.rs | 4 +--- tests/crud_tests.rs | 4 +--- tests/query_tests.rs | 32 ++++++++------------------------ tests/relational_tests.rs | 20 +++++--------------- tests/sequential_op_tests.rs | 4 +--- 12 files changed, 97 insertions(+), 72 deletions(-) create mode 100644 src/runtime.rs diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index 2ac0ac75..a04d17a0 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -84,3 +84,23 @@ pub fn derive_from_query_result(input: TokenStream) -> TokenStream { Err(e) => e.to_compile_error().into(), } } + +#[doc(hidden)] +#[proc_macro_attribute] +pub fn test(_: TokenStream, input: TokenStream) -> TokenStream { + let input = syn::parse_macro_input!(input as syn::ItemFn); + + let ret = &input.sig.output; + let name = &input.sig.ident; + let body = &input.block; + let attrs = &input.attrs; + + quote::quote! ( + #[test] + #(#attrs)* + fn #name() #ret { + ::sea_orm::block_on!(async { #body }) + } + ) + .into() +} diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index 855a55df..a810d7ac 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -107,7 +107,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// assert_eq!( /// cake::Entity::find().one(&db).await?, @@ -170,7 +170,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// assert_eq!( /// cake::Entity::find_by_id(11).all(&db).await?, @@ -207,7 +207,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling}; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// assert_eq!( /// cake_filling::Entity::find_by_id((2, 3)).all(&db).await?, @@ -275,7 +275,7 @@ pub trait EntityTrait: EntityName { /// ..Default::default() /// }; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let insert_result = cake::Entity::insert(apple).exec(&db).await?; /// @@ -326,7 +326,7 @@ pub trait EntityTrait: EntityName { /// ..Default::default() /// }; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let insert_result = cake::Entity::insert_many(vec![apple, orange]).exec(&db).await?; /// @@ -378,7 +378,7 @@ pub trait EntityTrait: EntityName { /// ..Default::default() /// }; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// assert_eq!( /// fruit::Entity::update(orange.clone()).exec(&db).await?, // Clone here because we need to assert_eq @@ -422,7 +422,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::fruit, sea_query::{Expr, Value}}; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let update_result = fruit::Entity::update_many() /// .col_expr(fruit::Column::CakeId, Expr::value(Value::Null)) @@ -471,7 +471,7 @@ pub trait EntityTrait: EntityName { /// ..Default::default() /// }; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let delete_result = fruit::Entity::delete(orange).exec(&db).await?; /// @@ -514,7 +514,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::fruit}; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let delete_result = fruit::Entity::delete_many() /// .filter(fruit::Column::Name.contains("Apple")) diff --git a/src/executor/paginator.rs b/src/executor/paginator.rs index d44bbc5e..cbf50bf5 100644 --- a/src/executor/paginator.rs +++ b/src/executor/paginator.rs @@ -97,7 +97,7 @@ where /// # 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 { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// let mut cake_pages = cake::Entity::find() @@ -125,7 +125,7 @@ where /// # 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 { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// use futures::TryStreamExt; /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; @@ -203,7 +203,7 @@ mod tests { (db, num_items) } - #[async_std::test] + #[sea_orm_macros::test] async fn fetch_page() -> Result<(), DbErr> { let (db, pages) = setup(); @@ -233,7 +233,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[sea_orm_macros::test] async fn fetch() -> Result<(), DbErr> { let (db, pages) = setup(); @@ -267,7 +267,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[sea_orm_macros::test] async fn num_pages() -> Result<(), DbErr> { let (db, num_items) = setup_num_items(); @@ -299,7 +299,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[sea_orm_macros::test] async fn next_and_cur_page() -> Result<(), DbErr> { let (db, _) = setup(); @@ -315,7 +315,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[sea_orm_macros::test] async fn fetch_and_next() -> Result<(), DbErr> { let (db, pages) = setup(); @@ -350,7 +350,7 @@ mod tests { Ok(()) } - #[async_std::test] + #[sea_orm_macros::test] async fn into_stream() -> Result<(), DbErr> { let (db, pages) = setup(); diff --git a/src/executor/select.rs b/src/executor/select.rs index 2997448a..9d355049 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -287,7 +287,7 @@ where /// num_of_cakes: i32, /// } /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let res: Vec = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( @@ -352,7 +352,7 @@ where /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let res: Vec = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( @@ -404,7 +404,7 @@ where /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let _: Option = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( @@ -439,7 +439,7 @@ where /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = async_std::task::block_on(async { + /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { /// # /// let _: Vec = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( diff --git a/src/lib.rs b/src/lib.rs index 93ec2545..2451cb5a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -207,6 +207,8 @@ pub mod error; mod executor; pub mod query; #[doc(hidden)] +pub mod runtime; +#[doc(hidden)] pub mod tests_cfg; mod util; diff --git a/src/query/json.rs b/src/query/json.rs index 95538032..b1872ab6 100644 --- a/src/query/json.rs +++ b/src/query/json.rs @@ -140,11 +140,11 @@ impl FromQueryResult for JsonValue { #[cfg(feature = "mock")] mod tests { use crate::tests_cfg::cake; - use crate::{entity::*, DbBackend, MockDatabase}; + use crate::{entity::*, DbBackend, DbErr, MockDatabase}; use sea_query::Value; - #[async_std::test] - async fn to_json_1() { + #[sea_orm_macros::test] + async fn to_json_1() -> Result<(), DbErr> { let db = MockDatabase::new(DbBackend::Postgres) .append_query_results(vec![vec![maplit::btreemap! { "id" => Into::::into(128), "name" => Into::::into("apple") @@ -158,5 +158,7 @@ mod tests { "name": "apple" })) ); + + Ok(()) } } diff --git a/src/runtime.rs b/src/runtime.rs new file mode 100644 index 00000000..31d7b866 --- /dev/null +++ b/src/runtime.rs @@ -0,0 +1,33 @@ +#[cfg(any( + feature = "runtime-async-std", + all( + not(feature = "runtime-async-std"), + not(feature = "runtime-actix"), + not(feature = "runtime-tokio"), + ), +))] +#[macro_export] +macro_rules! block_on { + ($($expr:tt)*) => { + ::async_std::task::block_on( $($expr)* ) + }; +} + +#[cfg(feature = "runtime-actix")] +#[macro_export] +macro_rules! block_on { + ($($expr:tt)*) => { + ::actix_rt::System::new() + .block_on( $($expr)* ) + }; +} + +#[cfg(feature = "runtime-tokio")] +#[macro_export] +macro_rules! block_on { + ($($expr:tt)*) => { + ::tokio::runtime::Runtime::new() + .unwrap() + .block_on( $($expr)* ) + }; +} diff --git a/tests/basic.rs b/tests/basic.rs index db38a7d5..8101d1f2 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -2,9 +2,7 @@ use sea_orm::{entity::*, error::*, sea_query, tests_cfg::*, Database, DbConn}; // DATABASE_URL="sqlite::memory:" cargo test --features sqlx-sqlit,runtime-async-std --test basic -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(feature = "sqlx-sqlite")] async fn main() { use std::env; diff --git a/tests/crud_tests.rs b/tests/crud_tests.rs index 94412a4d..3c26ddfd 100644 --- a/tests/crud_tests.rs +++ b/tests/crud_tests.rs @@ -8,9 +8,7 @@ mod crud; // Run the test locally: // DATABASE_URL="mysql://root:root@localhost" cargo test --features sqlx-mysql,runtime-async-std --test crud_tests // DATABASE_URL="postgres://root:root@localhost" cargo test --features sqlx-postgres,runtime-async-std --test crud_tests -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", diff --git a/tests/query_tests.rs b/tests/query_tests.rs index 2791f908..4e905686 100644 --- a/tests/query_tests.rs +++ b/tests/query_tests.rs @@ -6,9 +6,7 @@ pub use common::{bakery_chain::*, setup::*, TestContext}; // Run the test locally: // DATABASE_URL="mysql://root:@localhost" cargo test --features sqlx-mysql,runtime-async-std --test query_tests -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -23,9 +21,7 @@ pub async fn find_one_with_no_result() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -50,9 +46,7 @@ pub async fn find_one_with_result() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -67,9 +61,7 @@ pub async fn find_by_id_with_no_result() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -98,9 +90,7 @@ pub async fn find_by_id_with_result() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -115,9 +105,7 @@ pub async fn find_all_with_no_result() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -151,9 +139,7 @@ pub async fn find_all_with_result() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -191,9 +177,7 @@ pub async fn find_all_filter_no_result() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", diff --git a/tests/relational_tests.rs b/tests/relational_tests.rs index 85fdee41..ae1236a2 100644 --- a/tests/relational_tests.rs +++ b/tests/relational_tests.rs @@ -8,9 +8,7 @@ pub use common::{bakery_chain::*, setup::*, TestContext}; // Run the test locally: // DATABASE_URL="mysql://root:@localhost" cargo test --features sqlx-mysql,runtime-async-std --test relational_tests -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -91,9 +89,7 @@ pub async fn left_join() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any(feature = "sqlx-mysql", feature = "sqlx-postgres"))] pub async fn right_join() { let ctx = TestContext::new("test_right_join").await; @@ -174,9 +170,7 @@ pub async fn right_join() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -265,9 +259,7 @@ pub async fn inner_join() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", @@ -371,9 +363,7 @@ pub async fn group_by() { ctx.delete().await; } -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any( feature = "sqlx-mysql", feature = "sqlx-sqlite", diff --git a/tests/sequential_op_tests.rs b/tests/sequential_op_tests.rs index d734ceac..a854c768 100644 --- a/tests/sequential_op_tests.rs +++ b/tests/sequential_op_tests.rs @@ -9,9 +9,7 @@ pub use common::{bakery_chain::*, setup::*, TestContext}; // Run the test locally: // DATABASE_URL="mysql://root:@localhost" cargo test --features sqlx-mysql,runtime-async-std --test sequential_op_tests -#[cfg_attr(feature = "runtime-async-std", async_std::test)] -#[cfg_attr(feature = "runtime-actix", actix_rt::test)] -#[cfg_attr(feature = "runtime-tokio", tokio::test)] +#[sea_orm_macros::test] #[cfg(any(feature = "sqlx-mysql", feature = "sqlx-postgres"))] pub async fn test_multiple_operations() { let ctx = TestContext::new("multiple_sequential_operations").await; From 09c328bb0d5ef687fe3dcaaf0f72ebb6913d814b Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 18 Aug 2021 17:53:59 +0800 Subject: [PATCH 28/52] Use smol async-runtime and require one of the supported runtime for integration tests --- .github/workflows/rust.yml | 26 ++++++++++++++++---------- Cargo.toml | 2 ++ sea-orm-macros/src/lib.rs | 2 +- src/entity/base_entity.rs | 18 +++++++++--------- src/executor/paginator.rs | 16 ++++++++-------- src/executor/select.rs | 8 ++++---- src/lib.rs | 2 -- src/query/json.rs | 2 +- tests/basic.rs | 2 ++ tests/common/mod.rs | 6 ++++-- {src => tests/common}/runtime.rs | 9 +-------- 11 files changed, 48 insertions(+), 45 deletions(-) rename {src => tests/common}/runtime.rs (72%) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e0f4e3e0..6c6e8516 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -13,9 +13,6 @@ jobs: test: name: Unit Test runs-on: ubuntu-20.04 - strategy: - matrix: - runtime: [async-std-native-tls, async-std-rustls, actix-native-tls, actix-rustls, tokio-native-tls, tokio-rustls] steps: - uses: actions/checkout@v2 @@ -25,13 +22,14 @@ jobs: toolchain: stable override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 with: command: build args: > --all --exclude 'sea-orm-example-*' - --features default,runtime-${{ matrix.runtime }} - uses: actions-rs/cargo@v1 with: @@ -39,7 +37,6 @@ jobs: args: > --all --exclude 'sea-orm-example-*' - --features default,runtime-${{ matrix.runtime }} cli: name: CLI @@ -56,6 +53,8 @@ jobs: toolchain: stable override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 with: command: install @@ -69,8 +68,7 @@ jobs: DATABASE_URL: "sqlite::memory:" strategy: matrix: - # runtime: [async-std-native-tls, async-std-rustls, actix-native-tls, actix-rustls, tokio-native-tls, tokio-rustls] - runtime: [async-std-native-tls] + runtime: [async-std-native-tls, actix-native-tls, tokio-native-tls] steps: - uses: actions/checkout@v2 @@ -80,6 +78,8 @@ jobs: toolchain: stable override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 with: command: build @@ -100,7 +100,7 @@ jobs: strategy: matrix: version: [8.0, 5.7] - runtime: [async-std-native-tls] + runtime: [async-std-native-tls, actix-native-tls, tokio-native-tls] services: mysql: image: mysql:${{ matrix.version }} @@ -127,6 +127,8 @@ jobs: toolchain: stable override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 with: command: build @@ -147,7 +149,7 @@ jobs: strategy: matrix: version: [10.6] - runtime: [async-std-native-tls] + runtime: [async-std-native-tls, actix-native-tls, tokio-native-tls] services: mysql: image: mariadb:${{ matrix.version }} @@ -174,6 +176,8 @@ jobs: toolchain: stable override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 with: command: build @@ -194,7 +198,7 @@ jobs: strategy: matrix: version: [13.3, 12.7, 11.12, 10.17, 9.6.22] - runtime: [async-std-native-tls] + runtime: [async-std-native-tls, actix-native-tls, tokio-native-tls] services: postgres: image: postgres:${{ matrix.version }} @@ -218,6 +222,8 @@ jobs: toolchain: stable override: true + - uses: Swatinem/rust-cache@v1 + - uses: actions-rs/cargo@v1 with: command: build diff --git a/Cargo.toml b/Cargo.toml index b7c707ba..58e2c897 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,8 @@ serde_json = { version = "^1", optional = true } uuid = { version = "0.8", features = ["serde", "v4"], optional = true } [dev-dependencies] +smol = { version = "^1.2" } +smol-potat = { version = "^1.1" } async-std = { version = "^1.9", features = ["attributes"] } tokio = { version = "^1.6", features = ["full"] } actix-rt = { version = "2.2.0" } diff --git a/sea-orm-macros/src/lib.rs b/sea-orm-macros/src/lib.rs index a04d17a0..a2217aa8 100644 --- a/sea-orm-macros/src/lib.rs +++ b/sea-orm-macros/src/lib.rs @@ -99,7 +99,7 @@ pub fn test(_: TokenStream, input: TokenStream) -> TokenStream { #[test] #(#attrs)* fn #name() #ret { - ::sea_orm::block_on!(async { #body }) + crate::block_on!(async { #body }) } ) .into() diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index a810d7ac..e318da40 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -107,7 +107,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// assert_eq!( /// cake::Entity::find().one(&db).await?, @@ -170,7 +170,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// assert_eq!( /// cake::Entity::find_by_id(11).all(&db).await?, @@ -207,7 +207,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake_filling}; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// assert_eq!( /// cake_filling::Entity::find_by_id((2, 3)).all(&db).await?, @@ -275,7 +275,7 @@ pub trait EntityTrait: EntityName { /// ..Default::default() /// }; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let insert_result = cake::Entity::insert(apple).exec(&db).await?; /// @@ -326,7 +326,7 @@ pub trait EntityTrait: EntityName { /// ..Default::default() /// }; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let insert_result = cake::Entity::insert_many(vec![apple, orange]).exec(&db).await?; /// @@ -378,7 +378,7 @@ pub trait EntityTrait: EntityName { /// ..Default::default() /// }; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// assert_eq!( /// fruit::Entity::update(orange.clone()).exec(&db).await?, // Clone here because we need to assert_eq @@ -422,7 +422,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::fruit, sea_query::{Expr, Value}}; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let update_result = fruit::Entity::update_many() /// .col_expr(fruit::Column::CakeId, Expr::value(Value::Null)) @@ -471,7 +471,7 @@ pub trait EntityTrait: EntityName { /// ..Default::default() /// }; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let delete_result = fruit::Entity::delete(orange).exec(&db).await?; /// @@ -514,7 +514,7 @@ pub trait EntityTrait: EntityName { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::fruit}; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let delete_result = fruit::Entity::delete_many() /// .filter(fruit::Column::Name.contains("Apple")) diff --git a/src/executor/paginator.rs b/src/executor/paginator.rs index cbf50bf5..0cc7acbc 100644 --- a/src/executor/paginator.rs +++ b/src/executor/paginator.rs @@ -97,7 +97,7 @@ where /// # use sea_orm::{error::*, MockDatabase, DbBackend}; /// # let owned_db = MockDatabase::new(DbBackend::Postgres).into_connection(); /// # let db = &owned_db; - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// let mut cake_pages = cake::Entity::find() @@ -125,7 +125,7 @@ where /// # use sea_orm::{error::*, MockDatabase, DbBackend}; /// # let owned_db = MockDatabase::new(DbBackend::Postgres).into_connection(); /// # let db = &owned_db; - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// use futures::TryStreamExt; /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; @@ -203,7 +203,7 @@ mod tests { (db, num_items) } - #[sea_orm_macros::test] + #[smol_potat::test] async fn fetch_page() -> Result<(), DbErr> { let (db, pages) = setup(); @@ -233,7 +233,7 @@ mod tests { Ok(()) } - #[sea_orm_macros::test] + #[smol_potat::test] async fn fetch() -> Result<(), DbErr> { let (db, pages) = setup(); @@ -267,7 +267,7 @@ mod tests { Ok(()) } - #[sea_orm_macros::test] + #[smol_potat::test] async fn num_pages() -> Result<(), DbErr> { let (db, num_items) = setup_num_items(); @@ -299,7 +299,7 @@ mod tests { Ok(()) } - #[sea_orm_macros::test] + #[smol_potat::test] async fn next_and_cur_page() -> Result<(), DbErr> { let (db, _) = setup(); @@ -315,7 +315,7 @@ mod tests { Ok(()) } - #[sea_orm_macros::test] + #[smol_potat::test] async fn fetch_and_next() -> Result<(), DbErr> { let (db, pages) = setup(); @@ -350,7 +350,7 @@ mod tests { Ok(()) } - #[sea_orm_macros::test] + #[smol_potat::test] async fn into_stream() -> Result<(), DbErr> { let (db, pages) = setup(); diff --git a/src/executor/select.rs b/src/executor/select.rs index 9d355049..6196ec73 100644 --- a/src/executor/select.rs +++ b/src/executor/select.rs @@ -287,7 +287,7 @@ where /// num_of_cakes: i32, /// } /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let res: Vec = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( @@ -352,7 +352,7 @@ where /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let res: Vec = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( @@ -404,7 +404,7 @@ where /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let _: Option = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( @@ -439,7 +439,7 @@ where /// # /// use sea_orm::{entity::*, query::*, tests_cfg::cake}; /// - /// # let _: Result<(), DbErr> = sea_orm::block_on!(async { + /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let _: Vec = cake::Entity::find().from_raw_sql( /// Statement::from_sql_and_values( diff --git a/src/lib.rs b/src/lib.rs index 2451cb5a..93ec2545 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -207,8 +207,6 @@ pub mod error; mod executor; pub mod query; #[doc(hidden)] -pub mod runtime; -#[doc(hidden)] pub mod tests_cfg; mod util; diff --git a/src/query/json.rs b/src/query/json.rs index b1872ab6..589f0fad 100644 --- a/src/query/json.rs +++ b/src/query/json.rs @@ -143,7 +143,7 @@ mod tests { use crate::{entity::*, DbBackend, DbErr, MockDatabase}; use sea_query::Value; - #[sea_orm_macros::test] + #[smol_potat::test] async fn to_json_1() -> Result<(), DbErr> { let db = MockDatabase::new(DbBackend::Postgres) .append_query_results(vec![vec![maplit::btreemap! { diff --git a/tests/basic.rs b/tests/basic.rs index 8101d1f2..78e3f25c 100644 --- a/tests/basic.rs +++ b/tests/basic.rs @@ -1,3 +1,5 @@ +pub mod common; + #[allow(unused_imports)] use sea_orm::{entity::*, error::*, sea_query, tests_cfg::*, Database, DbConn}; diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 5729aabb..54630999 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -1,7 +1,9 @@ -pub mod setup; -use sea_orm::DatabaseConnection; pub mod bakery_chain; +pub mod runtime; +pub mod setup; + pub use bakery_chain::*; +use sea_orm::DatabaseConnection; use std::env; pub struct TestContext { diff --git a/src/runtime.rs b/tests/common/runtime.rs similarity index 72% rename from src/runtime.rs rename to tests/common/runtime.rs index 31d7b866..bc02f003 100644 --- a/src/runtime.rs +++ b/tests/common/runtime.rs @@ -1,11 +1,4 @@ -#[cfg(any( - feature = "runtime-async-std", - all( - not(feature = "runtime-async-std"), - not(feature = "runtime-actix"), - not(feature = "runtime-tokio"), - ), -))] +#[cfg(feature = "runtime-async-std")] #[macro_export] macro_rules! block_on { ($($expr:tt)*) => { From 318fa9f9bf5d6d8d1f14de3a91e2dae9519adcc5 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 18 Aug 2021 18:47:54 +0800 Subject: [PATCH 29/52] Update GitHub Actions --- .github/workflows/rust.yml | 130 +++++++++++++++++++++++-------------- 1 file changed, 82 insertions(+), 48 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6c6e8516..20603225 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -22,15 +22,6 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - - uses: actions-rs/cargo@v1 - with: - command: build - args: > - --all - --exclude 'sea-orm-example-*' - - uses: actions-rs/cargo@v1 with: command: test @@ -43,7 +34,7 @@ jobs: runs-on: ${{ matrix.os }} strategy: matrix: - os: [ubuntu-latest, windows-latest, macOS-latest] + os: [ubuntu-latest] steps: - uses: actions/checkout@v2 @@ -53,22 +44,20 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - uses: actions-rs/cargo@v1 with: command: install args: > --path sea-orm-cli - sqlite: - name: SQLite + compile: + name: Compile runs-on: ubuntu-20.04 - env: - DATABASE_URL: "sqlite::memory:" strategy: matrix: - runtime: [async-std-native-tls, actix-native-tls, tokio-native-tls] + database: [sqlite, mysql, postgres] + runtime: [async-std, actix, tokio] + tls: [native-tls, rustls] steps: - uses: actions/checkout@v2 @@ -78,29 +67,67 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - - uses: actions-rs/cargo@v1 + - uses: actions/cache@v2 with: - command: build - args: > - --features default,runtime-${{ matrix.runtime }} + path: | + ~/.cargo/registry + ~/.cargo/git + Cargo.lock + target + key: ${{ runner.os }}-${{ matrix.database }}-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: command: test args: > - --features default,sqlx-sqlite,runtime-${{ matrix.runtime }} + --features default,sqlx-${{ matrix.database }},runtime-${{ matrix.runtime }}-${{ matrix.tls }} + --no-run + + sqlite: + name: SQLite + runs-on: ubuntu-20.04 + needs: compile + env: + DATABASE_URL: "sqlite::memory:" + strategy: + matrix: + runtime: [async-std, actix, tokio] + tls: [native-tls, rustls] + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + Cargo.lock + target + key: ${{ runner.os }}-sqlite-${{ matrix.runtime }}-${{ matrix.tls }} + + - uses: actions-rs/cargo@v1 + with: + command: test + args: > + --features default,sqlx-sqlite,runtime-${{ matrix.runtime }}-${{ matrix.tls }} mysql: name: MySQL runs-on: ubuntu-20.04 + needs: compile env: DATABASE_URL: "mysql://root:@localhost" strategy: matrix: version: [8.0, 5.7] - runtime: [async-std-native-tls, actix-native-tls, tokio-native-tls] + runtime: [async-std, actix, tokio] + tls: [native-tls, rustls] services: mysql: image: mysql:${{ matrix.version }} @@ -127,29 +154,32 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - - uses: actions-rs/cargo@v1 + - uses: actions/cache@v2 with: - command: build - args: > - --features default,runtime-${{ matrix.runtime }} + path: | + ~/.cargo/registry + ~/.cargo/git + Cargo.lock + target + key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: command: test args: > - --features default,sqlx-mysql,runtime-${{ matrix.runtime }} + --features default,sqlx-mysql,runtime-${{ matrix.runtime }}-${{ matrix.tls }} mariadb: name: MariaDB runs-on: ubuntu-20.04 + needs: compile env: DATABASE_URL: "mysql://root:@localhost" strategy: matrix: version: [10.6] - runtime: [async-std-native-tls, actix-native-tls, tokio-native-tls] + runtime: [async-std, actix, tokio] + tls: [native-tls, rustls] services: mysql: image: mariadb:${{ matrix.version }} @@ -176,29 +206,32 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - - uses: actions-rs/cargo@v1 + - uses: actions/cache@v2 with: - command: build - args: > - --features default,runtime-${{ matrix.runtime }} + path: | + ~/.cargo/registry + ~/.cargo/git + Cargo.lock + target + key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: command: test args: > - --features default,sqlx-mysql,runtime-${{ matrix.runtime }} + --features default,sqlx-mysql,runtime-${{ matrix.runtime }}-${{ matrix.tls }} postgres: name: Postgres runs-on: ubuntu-20.04 + needs: compile env: DATABASE_URL: "postgres://root:root@localhost" strategy: matrix: version: [13.3, 12.7, 11.12, 10.17, 9.6.22] - runtime: [async-std-native-tls, actix-native-tls, tokio-native-tls] + runtime: [async-std, actix, tokio] + tls: [native-tls, rustls] services: postgres: image: postgres:${{ matrix.version }} @@ -222,16 +255,17 @@ jobs: toolchain: stable override: true - - uses: Swatinem/rust-cache@v1 - - - uses: actions-rs/cargo@v1 + - uses: actions/cache@v2 with: - command: build - args: > - --features default,runtime-${{ matrix.runtime }} + path: | + ~/.cargo/registry + ~/.cargo/git + Cargo.lock + target + key: ${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: command: test args: > - --features default,sqlx-postgres,runtime-${{ matrix.runtime }} + --features default,sqlx-postgres,runtime-${{ matrix.runtime }}-${{ matrix.tls }} From caa85d7fbaaf90f843a14f5cd695c710ee2ca30f Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Thu, 19 Aug 2021 18:17:02 +0800 Subject: [PATCH 30/52] Try typed mull value SeaQL/sea-query#107 --- Cargo.toml | 2 +- src/entity/base_entity.rs | 4 ++-- src/lib.rs | 2 +- src/query/update.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 58e2c897..bd3bf4f3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ futures = { version = "^0.3" } futures-util = { version = "^0.3" } rust_decimal = { version = "^1", optional = true } sea-orm-macros = { version = "^0.1", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.14", features = ["thread-safe"] } +sea-query = { version = "^0.14", features = ["thread-safe"], git = "https://github.com/SeaQL/sea-query.git", branch = "typed-null-value" } sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } sqlx = { version = "^0.5", optional = true } diff --git a/src/entity/base_entity.rs b/src/entity/base_entity.rs index e318da40..d0740307 100644 --- a/src/entity/base_entity.rs +++ b/src/entity/base_entity.rs @@ -425,7 +425,7 @@ pub trait EntityTrait: EntityName { /// # let _: Result<(), DbErr> = smol::block_on(async { /// # /// let update_result = fruit::Entity::update_many() - /// .col_expr(fruit::Column::CakeId, Expr::value(Value::Null)) + /// .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None))) /// .filter(fruit::Column::Name.contains("Apple")) /// .exec(&db) /// .await?; @@ -438,7 +438,7 @@ pub trait EntityTrait: EntityName { /// assert_eq!( /// db.into_transaction_log(), /// vec![Transaction::from_sql_and_values( - /// DbBackend::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::Int(None), "%Apple%".into()] /// )]); /// ``` fn update_many() -> UpdateMany { diff --git a/src/lib.rs b/src/lib.rs index 93ec2545..377bd62b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -129,7 +129,7 @@ //! //! // update many: UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."name" LIKE '%Apple%' //! Fruit::update_many() -//! .col_expr(fruit::Column::CakeId, Expr::value(Value::Null)) +//! .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None))) //! .filter(fruit::Column::Name.contains("Apple")) //! .exec(db) //! .await?; diff --git a/src/query/update.rs b/src/query/update.rs index 0c60f472..21fd39cb 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -232,7 +232,7 @@ mod tests { fn update_4() { assert_eq!( Update::many(fruit::Entity) - .col_expr(fruit::Column::CakeId, Expr::value(Value::Null)) + .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None))) .filter(fruit::Column::Id.eq(2)) .build(DbBackend::Postgres) .to_string(), From d7e61b09c9c6b50be7c12149e00ac7b81063fff0 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Fri, 20 Aug 2021 18:59:18 +0800 Subject: [PATCH 31/52] Update GitHub ACtions --- .github/workflows/rust.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 20603225..d699b5fc 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -74,7 +74,7 @@ jobs: ~/.cargo/git Cargo.lock target - key: ${{ runner.os }}-${{ matrix.database }}-${{ matrix.runtime }}-${{ matrix.tls }} + key: ${{ github.sha }}-${{ github.run_id }}-${{ runner.os }}-${{ matrix.database }}-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: @@ -109,7 +109,7 @@ jobs: ~/.cargo/git Cargo.lock target - key: ${{ runner.os }}-sqlite-${{ matrix.runtime }}-${{ matrix.tls }} + key: ${{ github.sha }}-${{ github.run_id }}-${{ runner.os }}-sqlite-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: @@ -161,7 +161,7 @@ jobs: ~/.cargo/git Cargo.lock target - key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ matrix.tls }} + key: ${{ github.sha }}-${{ github.run_id }}-${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: @@ -213,7 +213,7 @@ jobs: ~/.cargo/git Cargo.lock target - key: ${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ matrix.tls }} + key: ${{ github.sha }}-${{ github.run_id }}-${{ runner.os }}-mysql-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: @@ -262,7 +262,7 @@ jobs: ~/.cargo/git Cargo.lock target - key: ${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ matrix.tls }} + key: ${{ github.sha }}-${{ github.run_id }}-${{ runner.os }}-postgres-${{ matrix.runtime }}-${{ matrix.tls }} - uses: actions-rs/cargo@v1 with: From 6ec985dbd8f1bf46166151021a097457e4829e9d Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sat, 21 Aug 2021 22:57:36 +0800 Subject: [PATCH 32/52] Upgrade sea-query to 0.15 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bd3bf4f3..48db2698 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,7 +33,7 @@ futures = { version = "^0.3" } futures-util = { version = "^0.3" } rust_decimal = { version = "^1", optional = true } sea-orm-macros = { version = "^0.1", path = "sea-orm-macros", optional = true } -sea-query = { version = "^0.14", features = ["thread-safe"], git = "https://github.com/SeaQL/sea-query.git", branch = "typed-null-value" } +sea-query = { version = "^0.15", features = ["thread-safe"] } sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } sqlx = { version = "^0.5", optional = true } From 2db5c5e8c91f0f8532f70461e1468b8db4253627 Mon Sep 17 00:00:00 2001 From: Billy Chan Date: Wed, 18 Aug 2021 12:47:01 +0800 Subject: [PATCH 33/52] Change manifest for SeaQL/sea-schema#14 --- sea-orm-cli/Cargo.toml | 4 ++-- sea-orm-codegen/Cargo.toml | 2 +- sea-orm-codegen/src/entity/column.rs | 10 ++++++++-- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index a288f7a2..771a1f41 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -22,13 +22,13 @@ clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } sea-orm = { version = "^0.1", features = [ "sqlx-all" ] } -sea-orm-codegen = { version = "^0.1" } +sea-orm-codegen = { version = "^0.1", path = "../sea-orm-codegen" } sea-schema = { version = "^0.2.4", default-features = false, features = [ "sqlx-mysql", "sqlx-postgres", "discovery", "writer", -] } +], git = "https://github.com/SeaQL/sea-schema.git", branch = "pg-pk-generated-expr" } sqlx = { version = "^0.5", default-features = false, features = [ "mysql", "postgres" ] } [features] diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index 3511b614..624e6458 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -15,7 +15,7 @@ name = "sea_orm_codegen" path = "src/lib.rs" [dependencies] -sea-query = { version = "^0.12.8" } +sea-query = { version = "^0.14" } syn = { version = "^1", default-features = false, features = [ "derive", "parsing", diff --git a/sea-orm-codegen/src/entity/column.rs b/sea-orm-codegen/src/entity/column.rs index 6a630da6..a2c3b4f5 100644 --- a/sea-orm-codegen/src/entity/column.rs +++ b/sea-orm-codegen/src/entity/column.rs @@ -285,7 +285,7 @@ mod tests { #[test] fn test_from_column_def() { - let column: Column = ColumnDef::new(Alias::new("id")).string().into(); + let column: Column = ColumnDef::new(Alias::new("id")).string().to_owned().into(); assert_eq!( column.get_def().to_string(), quote! { @@ -294,13 +294,18 @@ mod tests { .to_string() ); - let column: Column = ColumnDef::new(Alias::new("id")).string().not_null().into(); + let column: Column = ColumnDef::new(Alias::new("id")) + .string() + .not_null() + .to_owned() + .into(); assert!(column.not_null); let column: Column = ColumnDef::new(Alias::new("id")) .string() .unique_key() .not_null() + .to_owned() .into(); assert!(column.unique); assert!(column.not_null); @@ -310,6 +315,7 @@ mod tests { .auto_increment() .unique_key() .not_null() + .to_owned() .into(); assert!(column.auto_increment); assert!(column.unique); From af26afcf718625a8ed6bebc8431d20144b6849b4 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sat, 21 Aug 2021 23:01:24 +0800 Subject: [PATCH 34/52] Upgrade sea-schema to 0.2.5 --- sea-orm-cli/Cargo.toml | 4 ++-- sea-orm-codegen/Cargo.toml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 771a1f41..5769c385 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -23,12 +23,12 @@ dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } sea-orm = { version = "^0.1", features = [ "sqlx-all" ] } sea-orm-codegen = { version = "^0.1", path = "../sea-orm-codegen" } -sea-schema = { version = "^0.2.4", default-features = false, features = [ +sea-schema = { version = "^0.2.5", default-features = false, features = [ "sqlx-mysql", "sqlx-postgres", "discovery", "writer", -], git = "https://github.com/SeaQL/sea-schema.git", branch = "pg-pk-generated-expr" } +] } sqlx = { version = "^0.5", default-features = false, features = [ "mysql", "postgres" ] } [features] diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index 624e6458..0eeb58aa 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -15,7 +15,7 @@ name = "sea_orm_codegen" path = "src/lib.rs" [dependencies] -sea-query = { version = "^0.14" } +sea-query = { version = "^0.15" } syn = { version = "^1", default-features = false, features = [ "derive", "parsing", From 35c9cbe60a35c8058661c2c9ebbd04ef8f3d0599 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sat, 21 Aug 2021 23:25:25 +0800 Subject: [PATCH 35/52] GitHub Action --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index d699b5fc..e0294929 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -230,8 +230,8 @@ jobs: strategy: matrix: version: [13.3, 12.7, 11.12, 10.17, 9.6.22] - runtime: [async-std, actix, tokio] - tls: [native-tls, rustls] + runtime: [tokio] + tls: [native-tls] services: postgres: image: postgres:${{ matrix.version }} From c8989dfb232361c1dd766dce8ea2964ad6983ca7 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 22 Aug 2021 02:00:00 +0800 Subject: [PATCH 36/52] GitHub Action --- .github/workflows/rust.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index e0294929..c93a5586 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -127,7 +127,7 @@ jobs: matrix: version: [8.0, 5.7] runtime: [async-std, actix, tokio] - tls: [native-tls, rustls] + tls: [native-tls] services: mysql: image: mysql:${{ matrix.version }} @@ -179,7 +179,7 @@ jobs: matrix: version: [10.6] runtime: [async-std, actix, tokio] - tls: [native-tls, rustls] + tls: [rustls] services: mysql: image: mariadb:${{ matrix.version }} From 46a4cafaa9d9979bd37e24eb1b277244e706ae69 Mon Sep 17 00:00:00 2001 From: Ari Seyhun Date: Wed, 18 Aug 2021 15:20:33 +0930 Subject: [PATCH 37/52] Implement `FromStr` for `DeriveColumn` --- sea-orm-macros/src/derives/column.rs | 45 ++++++++++++++++++++++++++-- src/entity/column.rs | 25 ++++++++++++++++ src/query/combine.rs | 4 +-- src/query/update.rs | 2 +- src/tests_cfg/fruit.rs | 2 +- 5 files changed, 72 insertions(+), 6 deletions(-) diff --git a/sea-orm-macros/src/derives/column.rs b/sea-orm-macros/src/derives/column.rs index 034e966d..0315fa1e 100644 --- a/sea-orm-macros/src/derives/column.rs +++ b/sea-orm-macros/src/derives/column.rs @@ -1,6 +1,6 @@ -use heck::SnakeCase; +use heck::{MixedCase, SnakeCase}; use proc_macro2::{Ident, TokenStream}; -use quote::{quote, quote_spanned}; +use quote::{format_ident, quote, quote_spanned}; use syn::{Data, DataEnum, Fields, Variant}; pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result { @@ -41,6 +41,44 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result syn::Result { + let parse_error_iden = format_ident!("Parse{}Err", ident); + + let data_enum = match data { + Data::Enum(data_enum) => data_enum, + _ => { + return Ok(quote_spanned! { + ident.span() => compile_error!("you can only derive DeriveColumn on enums"); + }) + } + }; + + let columns = data_enum.variants.iter().map(|column| { + let column_iden = column.ident.clone(); + let column_str_snake = column_iden.to_string().to_snake_case(); + let column_str_mixed = column_iden.to_string().to_mixed_case(); + quote!( + #column_str_snake | #column_str_mixed => Ok(#ident::#column_iden) + ) + }); + + Ok(quote!( + #[derive(Debug, Clone, Copy, PartialEq)] + pub struct #parse_error_iden; + + impl std::str::FromStr for #ident { + type Err = #parse_error_iden; + + fn from_str(s: &str) -> Result { + match s { + #(#columns),*, + _ => Err(#parse_error_iden), + } + } + } + )) +} + pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result { let impl_iden = expand_derive_custom_column(ident, data)?; @@ -57,10 +95,13 @@ pub fn expand_derive_column(ident: &Ident, data: &Data) -> syn::Result syn::Result { let impl_default_as_str = impl_default_as_str(ident, data)?; + let impl_col_from_str = impl_col_from_str(ident, data)?; Ok(quote!( #impl_default_as_str + #impl_col_from_str + impl sea_orm::Iden for #ident { fn unquoted(&self, s: &mut dyn std::fmt::Write) { write!(s, "{}", self.as_str()).unwrap(); diff --git a/src/entity/column.rs b/src/entity/column.rs index 045a85ba..2456aba7 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -324,6 +324,7 @@ mod tests { tests_cfg::*, ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, }; use sea_query::Query; + use std::str::FromStr; #[test] fn test_in_subquery() { @@ -348,4 +349,28 @@ mod tests { .join(" ") ); } + + #[test] + fn test_col_from_str() { + match fruit::Column::from_str("id") { + Ok(col) => assert_eq!(col, fruit::Column::Id), + Err(_) => panic!("fruit from_str fails"), + } + match fruit::Column::from_str("name") { + Ok(col) => assert_eq!(col, fruit::Column::Name), + Err(_) => panic!("fruit from_str fails"), + } + match fruit::Column::from_str("cake_id") { + Ok(col) => assert_eq!(col, fruit::Column::CakeId), + Err(_) => panic!("fruit from_str fails"), + } + match fruit::Column::from_str("cakeId") { + Ok(col) => assert_eq!(col, fruit::Column::CakeId), + Err(_) => panic!("fruit from_str fails"), + } + match fruit::Column::from_str("does_not_exist") { + Ok(_) => panic!("fruit from_str found match when it shouldn't have"), + Err(err) => assert_eq!(err, fruit::ParseColumnErr), + } + } } diff --git a/src/query/combine.rs b/src/query/combine.rs index 8cce0510..71783e8b 100644 --- a/src/query/combine.rs +++ b/src/query/combine.rs @@ -167,7 +167,7 @@ mod tests { .left_join(fruit::Entity) .select_also(fruit::Entity) .filter(cake::Column::Id.eq(1)) - .filter(fruit::Column::Id.eq(2)) + .filter(ColumnTrait::eq(&fruit::Column::Id, 2)) .build(DbBackend::MySql) .to_string(), [ @@ -186,7 +186,7 @@ mod tests { .left_join(fruit::Entity) .select_with(fruit::Entity) .filter(cake::Column::Id.eq(1)) - .filter(fruit::Column::Id.eq(2)) + .filter(ColumnTrait::eq(&fruit::Column::Id, 2)) .build(DbBackend::MySql) .to_string(), [ diff --git a/src/query/update.rs b/src/query/update.rs index 21fd39cb..014f6ae1 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -233,7 +233,7 @@ mod tests { assert_eq!( Update::many(fruit::Entity) .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None))) - .filter(fruit::Column::Id.eq(2)) + .filter(ColumnTrait::eq(&fruit::Column::Id, 2)) .build(DbBackend::Postgres) .to_string(), r#"UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."id" = 2"#, diff --git a/src/tests_cfg/fruit.rs b/src/tests_cfg/fruit.rs index 0511ae58..48d7fcfb 100644 --- a/src/tests_cfg/fruit.rs +++ b/src/tests_cfg/fruit.rs @@ -17,7 +17,7 @@ pub struct Model { pub cake_id: Option, } -#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +#[derive(Copy, Clone, PartialEq, Debug, EnumIter, DeriveColumn)] pub enum Column { Id, Name, From 332ab3ccf588798ffcdb53fca185ae869e6ca27c Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Sun, 22 Aug 2021 22:15:40 +0800 Subject: [PATCH 38/52] Remove derive PartialEq --- sea-orm-macros/src/derives/column.rs | 2 +- src/entity/column.rs | 16 +++++++--------- src/query/combine.rs | 4 ++-- src/query/update.rs | 2 +- src/tests_cfg/fruit.rs | 2 +- 5 files changed, 12 insertions(+), 14 deletions(-) diff --git a/sea-orm-macros/src/derives/column.rs b/sea-orm-macros/src/derives/column.rs index 0315fa1e..917dc669 100644 --- a/sea-orm-macros/src/derives/column.rs +++ b/sea-orm-macros/src/derives/column.rs @@ -63,7 +63,7 @@ pub fn impl_col_from_str(ident: &Ident, data: &Data) -> syn::Result }); Ok(quote!( - #[derive(Debug, Clone, Copy, PartialEq)] + #[derive(Debug, Clone, Copy)] pub struct #parse_error_iden; impl std::str::FromStr for #ident { diff --git a/src/entity/column.rs b/src/entity/column.rs index 2456aba7..85100421 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -324,7 +324,6 @@ mod tests { tests_cfg::*, ColumnTrait, Condition, DbBackend, EntityTrait, QueryFilter, QueryTrait, }; use sea_query::Query; - use std::str::FromStr; #[test] fn test_in_subquery() { @@ -352,25 +351,24 @@ mod tests { #[test] fn test_col_from_str() { + use std::str::FromStr; + match fruit::Column::from_str("id") { - Ok(col) => assert_eq!(col, fruit::Column::Id), + Ok(col) => assert!(matches!(col, fruit::Column::Id)), Err(_) => panic!("fruit from_str fails"), } match fruit::Column::from_str("name") { - Ok(col) => assert_eq!(col, fruit::Column::Name), + Ok(col) => assert!(matches!(col, fruit::Column::Name)), Err(_) => panic!("fruit from_str fails"), } match fruit::Column::from_str("cake_id") { - Ok(col) => assert_eq!(col, fruit::Column::CakeId), + Ok(col) => assert!(matches!(col, fruit::Column::CakeId)), Err(_) => panic!("fruit from_str fails"), } match fruit::Column::from_str("cakeId") { - Ok(col) => assert_eq!(col, fruit::Column::CakeId), + Ok(col) => assert!(matches!(col, fruit::Column::CakeId)), Err(_) => panic!("fruit from_str fails"), } - match fruit::Column::from_str("does_not_exist") { - Ok(_) => panic!("fruit from_str found match when it shouldn't have"), - Err(err) => assert_eq!(err, fruit::ParseColumnErr), - } + assert!(matches!(fruit::Column::from_str("does_not_exist"), Err(_))); } } diff --git a/src/query/combine.rs b/src/query/combine.rs index 71783e8b..8cce0510 100644 --- a/src/query/combine.rs +++ b/src/query/combine.rs @@ -167,7 +167,7 @@ mod tests { .left_join(fruit::Entity) .select_also(fruit::Entity) .filter(cake::Column::Id.eq(1)) - .filter(ColumnTrait::eq(&fruit::Column::Id, 2)) + .filter(fruit::Column::Id.eq(2)) .build(DbBackend::MySql) .to_string(), [ @@ -186,7 +186,7 @@ mod tests { .left_join(fruit::Entity) .select_with(fruit::Entity) .filter(cake::Column::Id.eq(1)) - .filter(ColumnTrait::eq(&fruit::Column::Id, 2)) + .filter(fruit::Column::Id.eq(2)) .build(DbBackend::MySql) .to_string(), [ diff --git a/src/query/update.rs b/src/query/update.rs index 014f6ae1..21fd39cb 100644 --- a/src/query/update.rs +++ b/src/query/update.rs @@ -233,7 +233,7 @@ mod tests { assert_eq!( Update::many(fruit::Entity) .col_expr(fruit::Column::CakeId, Expr::value(Value::Int(None))) - .filter(ColumnTrait::eq(&fruit::Column::Id, 2)) + .filter(fruit::Column::Id.eq(2)) .build(DbBackend::Postgres) .to_string(), r#"UPDATE "fruit" SET "cake_id" = NULL WHERE "fruit"."id" = 2"#, diff --git a/src/tests_cfg/fruit.rs b/src/tests_cfg/fruit.rs index 48d7fcfb..0511ae58 100644 --- a/src/tests_cfg/fruit.rs +++ b/src/tests_cfg/fruit.rs @@ -17,7 +17,7 @@ pub struct Model { pub cake_id: Option, } -#[derive(Copy, Clone, PartialEq, Debug, EnumIter, DeriveColumn)] +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] pub enum Column { Id, Name, From e5f290380a093f589fa883852c827b87e2c32514 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 01:04:13 +0800 Subject: [PATCH 39/52] Use ColumnFromStrErr --- sea-orm-macros/src/derives/column.rs | 11 +++-------- src/error.rs | 11 +++++++++++ 2 files changed, 14 insertions(+), 8 deletions(-) diff --git a/sea-orm-macros/src/derives/column.rs b/sea-orm-macros/src/derives/column.rs index 917dc669..16f9bb22 100644 --- a/sea-orm-macros/src/derives/column.rs +++ b/sea-orm-macros/src/derives/column.rs @@ -1,6 +1,6 @@ use heck::{MixedCase, SnakeCase}; use proc_macro2::{Ident, TokenStream}; -use quote::{format_ident, quote, quote_spanned}; +use quote::{quote, quote_spanned}; use syn::{Data, DataEnum, Fields, Variant}; pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result { @@ -42,8 +42,6 @@ pub fn impl_default_as_str(ident: &Ident, data: &Data) -> syn::Result syn::Result { - let parse_error_iden = format_ident!("Parse{}Err", ident); - let data_enum = match data { Data::Enum(data_enum) => data_enum, _ => { @@ -63,16 +61,13 @@ pub fn impl_col_from_str(ident: &Ident, data: &Data) -> syn::Result }); Ok(quote!( - #[derive(Debug, Clone, Copy)] - pub struct #parse_error_iden; - impl std::str::FromStr for #ident { - type Err = #parse_error_iden; + type Err = sea_orm::ColumnFromStrErr; fn from_str(s: &str) -> Result { match s { #(#columns),*, - _ => Err(#parse_error_iden), + _ => Err(sea_orm::ColumnFromStrErr(format!("Failed to parse '{}' as `{}`", s, stringify!(#ident)))), } } } diff --git a/src/error.rs b/src/error.rs index eff99912..8a695dac 100644 --- a/src/error.rs +++ b/src/error.rs @@ -16,3 +16,14 @@ impl std::fmt::Display for DbErr { } } } + +#[derive(Debug, Clone)] +pub struct ColumnFromStrErr(pub String); + +impl std::error::Error for ColumnFromStrErr {} + +impl std::fmt::Display for ColumnFromStrErr { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + write!(f, "{}", self.0.as_str()) + } +} From 4c3bc32fd80cd90082e9f1682a5b24ecce1e495c Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 01:11:36 +0800 Subject: [PATCH 40/52] Refactor test case --- src/entity/column.rs | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/entity/column.rs b/src/entity/column.rs index 85100421..8ffb7275 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -353,22 +353,25 @@ mod tests { fn test_col_from_str() { use std::str::FromStr; - match fruit::Column::from_str("id") { - Ok(col) => assert!(matches!(col, fruit::Column::Id)), - Err(_) => panic!("fruit from_str fails"), - } - match fruit::Column::from_str("name") { - Ok(col) => assert!(matches!(col, fruit::Column::Name)), - Err(_) => panic!("fruit from_str fails"), - } - match fruit::Column::from_str("cake_id") { - Ok(col) => assert!(matches!(col, fruit::Column::CakeId)), - Err(_) => panic!("fruit from_str fails"), - } - match fruit::Column::from_str("cakeId") { - Ok(col) => assert!(matches!(col, fruit::Column::CakeId)), - Err(_) => panic!("fruit from_str fails"), - } - assert!(matches!(fruit::Column::from_str("does_not_exist"), Err(_))); + assert!(matches!( + fruit::Column::from_str("id"), + Ok(fruit::Column::Id) + )); + assert!(matches!( + fruit::Column::from_str("name"), + Ok(fruit::Column::Name) + )); + assert!(matches!( + fruit::Column::from_str("cake_id"), + Ok(fruit::Column::CakeId) + )); + assert!(matches!( + fruit::Column::from_str("cakeId"), + Ok(fruit::Column::CakeId) + )); + assert!(matches!( + fruit::Column::from_str("does_not_exist"), + Err(crate::ColumnFromStrErr(_)) + )); } } From 5966100244e8b327734773e4e8f3332d47ac283a Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 01:16:00 +0800 Subject: [PATCH 41/52] ColumnTrait extends FromStr --- src/entity/column.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/entity/column.rs b/src/entity/column.rs index 8ffb7275..16546057 100644 --- a/src/entity/column.rs +++ b/src/entity/column.rs @@ -1,3 +1,4 @@ +use std::str::FromStr; use crate::{EntityName, IdenStatic, Iterable}; use sea_query::{DynIden, Expr, SeaRc, SelectStatement, SimpleExpr, Value}; @@ -77,7 +78,7 @@ macro_rules! bind_subquery_func { // LINT: when the operand value does not match column type /// Wrapper of the identically named method in [`sea_query::Expr`] -pub trait ColumnTrait: IdenStatic + Iterable { +pub trait ColumnTrait: IdenStatic + Iterable + FromStr { type EntityName: EntityName; fn def(&self) -> ColumnDef; From 63826e2f6120baf7aa883ab852f254c63be0e5f5 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 01:53:39 +0800 Subject: [PATCH 42/52] Fix build error --- sea-orm-macros/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-macros/Cargo.toml b/sea-orm-macros/Cargo.toml index 2fdfd11a..3be66622 100644 --- a/sea-orm-macros/Cargo.toml +++ b/sea-orm-macros/Cargo.toml @@ -16,7 +16,7 @@ path = "src/lib.rs" proc-macro = true [dependencies] -syn = { version = "^1", default-features = false, features = [ "derive", "clone-impls", "parsing", "proc-macro", "printing" ] } +syn = { version = "^1", default-features = false, features = [ "full", "derive", "clone-impls", "parsing", "proc-macro", "printing" ] } quote = "^1" heck = "^0.3" proc-macro2 = "^1" From 6a078d0ac732a790a553be7ca066559d3d5606bd Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 01:49:36 +0800 Subject: [PATCH 43/52] sea-orm-macros 0.1.1 --- sea-orm-macros/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-macros/Cargo.toml b/sea-orm-macros/Cargo.toml index 3be66622..312adeaa 100644 --- a/sea-orm-macros/Cargo.toml +++ b/sea-orm-macros/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sea-orm-macros" -version = "0.1.0" +version = "0.1.1" authors = [ "Billy Chan " ] edition = "2018" description = "Derive macros for SeaORM" From 5a963fb2b42e19e965b66a29c26dedfe3bbd4453 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 01:54:53 +0800 Subject: [PATCH 44/52] Bump sea-orm-macros to 0.1.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 48db2698..f097a9f2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -32,7 +32,7 @@ chrono = { version = "^0", optional = true } futures = { version = "^0.3" } futures-util = { version = "^0.3" } rust_decimal = { version = "^1", optional = true } -sea-orm-macros = { version = "^0.1", path = "sea-orm-macros", optional = true } +sea-orm-macros = { version = "^0.1.1", optional = true } sea-query = { version = "^0.15", features = ["thread-safe"] } sea-strum = { version = "^0.21", features = ["derive", "sea-orm"] } serde = { version = "^1.0", features = ["derive"] } From 7705c819c040ebeb139bd86b942df4b65a4bb348 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 02:13:14 +0800 Subject: [PATCH 45/52] 0.1.2 --- CHANGELOG.md | 8 ++++++++ Cargo.toml | 2 +- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 620542b7..d764b4de 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,14 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](http://keepachangelog.com/) and this project adheres to [Semantic Versioning](http://semver.org/). +## 0.1.2 - 2021-08-23 + +- [[#68]] Added `DateTimeWithTimeZone` as supported attribute type +- [[#70]] Generate arbitrary named entity +- [[#80]] Custom column name +- [[#81]] Support join on multiple columns +- [[#99]] Implement FromStr for ColumnTrait + ## 0.1.1 - 2021-08-08 - Early release of SeaORM diff --git a/Cargo.toml b/Cargo.toml index f097a9f2..c806196c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,7 +8,7 @@ members = [ [package] name = "sea-orm" -version = "0.1.1" +version = "0.1.2" authors = ["Chris Tsang "] edition = "2018" description = "🐚 An async & dynamic ORM for Rust" From 5d472fda715ff86301f29fb1c369bbea18826eda Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 02:23:50 +0800 Subject: [PATCH 46/52] Links --- CHANGELOG.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index d764b4de..5eba8d3c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,12 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [[#81]] Support join on multiple columns - [[#99]] Implement FromStr for ColumnTrait +[#68]: https://github.com/SeaQL/sea-query/issues/68 +[#70]: https://github.com/SeaQL/sea-query/issues/70 +[#80]: https://github.com/SeaQL/sea-query/issues/80 +[#81]: https://github.com/SeaQL/sea-query/issues/81 +[#99]: https://github.com/SeaQL/sea-query/issues/99 + ## 0.1.1 - 2021-08-08 - Early release of SeaORM From c086a5d4fbe373ef95af69cc1e3e1d2d66e13049 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 02:37:26 +0800 Subject: [PATCH 47/52] Bump sea-schema to 0.2.7 --- sea-orm-cli/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index 5769c385..e47d84c9 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -23,7 +23,7 @@ dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } sea-orm = { version = "^0.1", features = [ "sqlx-all" ] } sea-orm-codegen = { version = "^0.1", path = "../sea-orm-codegen" } -sea-schema = { version = "^0.2.5", default-features = false, features = [ +sea-schema = { version = "^0.2.7", default-features = false, features = [ "sqlx-mysql", "sqlx-postgres", "discovery", From f722ce333668b6c64d65128feb272364b7671490 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 03:48:58 +0800 Subject: [PATCH 48/52] sea-orm-codegen 0.1.3 --- sea-orm-codegen/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sea-orm-codegen/Cargo.toml b/sea-orm-codegen/Cargo.toml index 0eeb58aa..9080bd2b 100644 --- a/sea-orm-codegen/Cargo.toml +++ b/sea-orm-codegen/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "sea-orm-codegen" -version = "0.1.2" +version = "0.1.3" authors = ["Billy Chan "] edition = "2018" description = "Code Generator for SeaORM" From ab983a31fe71af1745b06b25c8bab48b89eb76c4 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 02:48:15 +0800 Subject: [PATCH 49/52] sea-orm-cli 0.1.3 --- sea-orm-cli/Cargo.toml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index e47d84c9..f66353e8 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -3,7 +3,7 @@ [package] name = "sea-orm-cli" -version = "0.1.2" +version = "0.1.3" authors = [ "Billy Chan " ] edition = "2018" description = "Command line utility for SeaORM" @@ -21,8 +21,8 @@ path = "src/main.rs" clap = { version = "^2.33.3" } dotenv = { version = "^0.15" } async-std = { version = "^1.9", features = [ "attributes" ] } -sea-orm = { version = "^0.1", features = [ "sqlx-all" ] } -sea-orm-codegen = { version = "^0.1", path = "../sea-orm-codegen" } +sea-orm = { version = "^0.1.2", features = [ "sqlx-all" ] } +sea-orm-codegen = { version = "^0.1.3" } sea-schema = { version = "^0.2.7", default-features = false, features = [ "sqlx-mysql", "sqlx-postgres", From 8437f885257b7cc7b3e6beae1f06a697cafcdd72 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 04:16:57 +0800 Subject: [PATCH 50/52] Links --- CHANGELOG.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5eba8d3c..1ef38d62 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,11 +13,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - [[#81]] Support join on multiple columns - [[#99]] Implement FromStr for ColumnTrait -[#68]: https://github.com/SeaQL/sea-query/issues/68 -[#70]: https://github.com/SeaQL/sea-query/issues/70 -[#80]: https://github.com/SeaQL/sea-query/issues/80 -[#81]: https://github.com/SeaQL/sea-query/issues/81 -[#99]: https://github.com/SeaQL/sea-query/issues/99 +[#68]: https://github.com/SeaQL/sea-orm/issues/68 +[#70]: https://github.com/SeaQL/sea-orm/issues/70 +[#80]: https://github.com/SeaQL/sea-orm/issues/80 +[#81]: https://github.com/SeaQL/sea-orm/issues/81 +[#99]: https://github.com/SeaQL/sea-orm/issues/99 ## 0.1.1 - 2021-08-08 From 3f7de132aa6e94d0f030bfc0d28d3e21b043d285 Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 15:23:36 +0800 Subject: [PATCH 51/52] Update examples --- .github/workflows/rust.yml | 13 ++++- Cargo.toml | 1 - examples/{sqlx => async-std}/Cargo.toml | 5 +- examples/{sqlx => async-std}/Readme.md | 0 examples/{sqlx => async-std}/bakery.sql | 0 examples/{sqlx => async-std}/import.sh | 0 examples/{sqlx => async-std}/src/entities.rs | 0 .../{sqlx => async-std}/src/example_cake.rs | 0 .../src/example_cake_filling.rs | 0 .../src/example_filling.rs | 0 .../{sqlx => async-std}/src/example_fruit.rs | 0 examples/{sqlx => async-std}/src/main.rs | 0 examples/{sqlx => async-std}/src/operation.rs | 0 examples/{sqlx => async-std}/src/select.rs | 0 examples/tokio/Cargo.toml | 12 ++++ examples/tokio/src/cake.rs | 55 +++++++++++++++++++ examples/tokio/src/main.rs | 14 +++++ sea-orm-cli/Cargo.toml | 2 +- 18 files changed, 98 insertions(+), 4 deletions(-) rename examples/{sqlx => async-std}/Cargo.toml (75%) rename examples/{sqlx => async-std}/Readme.md (100%) rename examples/{sqlx => async-std}/bakery.sql (100%) rename examples/{sqlx => async-std}/import.sh (100%) rename examples/{sqlx => async-std}/src/entities.rs (100%) rename examples/{sqlx => async-std}/src/example_cake.rs (100%) rename examples/{sqlx => async-std}/src/example_cake_filling.rs (100%) rename examples/{sqlx => async-std}/src/example_filling.rs (100%) rename examples/{sqlx => async-std}/src/example_fruit.rs (100%) rename examples/{sqlx => async-std}/src/main.rs (100%) rename examples/{sqlx => async-std}/src/operation.rs (100%) rename examples/{sqlx => async-std}/src/select.rs (100%) create mode 100644 examples/tokio/Cargo.toml create mode 100644 examples/tokio/src/cake.rs create mode 100644 examples/tokio/src/main.rs diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index c93a5586..6cd35f28 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -27,7 +27,6 @@ jobs: command: test args: > --all - --exclude 'sea-orm-example-*' cli: name: CLI @@ -83,6 +82,18 @@ jobs: --features default,sqlx-${{ matrix.database }},runtime-${{ matrix.runtime }}-${{ matrix.tls }} --no-run + - uses: actions-rs/cargo@v1 + with: + command: build + args: > + --path examples/async-std + + - uses: actions-rs/cargo@v1 + with: + command: build + args: > + --path examples/tokio + sqlite: name: SQLite runs-on: ubuntu-20.04 diff --git a/Cargo.toml b/Cargo.toml index c806196c..ca61c819 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,6 @@ members = [ ".", "sea-orm-macros", "sea-orm-codegen", - "examples/sqlx", ] [package] diff --git a/examples/sqlx/Cargo.toml b/examples/async-std/Cargo.toml similarity index 75% rename from examples/sqlx/Cargo.toml rename to examples/async-std/Cargo.toml index 97d1340f..c2be9d88 100644 --- a/examples/sqlx/Cargo.toml +++ b/examples/async-std/Cargo.toml @@ -1,5 +1,8 @@ +[workspace] +# A separate workspace + [package] -name = "sea-orm-example-sqlx" +name = "sea-orm-example-async-std" version = "0.1.0" edition = "2018" publish = false diff --git a/examples/sqlx/Readme.md b/examples/async-std/Readme.md similarity index 100% rename from examples/sqlx/Readme.md rename to examples/async-std/Readme.md diff --git a/examples/sqlx/bakery.sql b/examples/async-std/bakery.sql similarity index 100% rename from examples/sqlx/bakery.sql rename to examples/async-std/bakery.sql diff --git a/examples/sqlx/import.sh b/examples/async-std/import.sh similarity index 100% rename from examples/sqlx/import.sh rename to examples/async-std/import.sh diff --git a/examples/sqlx/src/entities.rs b/examples/async-std/src/entities.rs similarity index 100% rename from examples/sqlx/src/entities.rs rename to examples/async-std/src/entities.rs diff --git a/examples/sqlx/src/example_cake.rs b/examples/async-std/src/example_cake.rs similarity index 100% rename from examples/sqlx/src/example_cake.rs rename to examples/async-std/src/example_cake.rs diff --git a/examples/sqlx/src/example_cake_filling.rs b/examples/async-std/src/example_cake_filling.rs similarity index 100% rename from examples/sqlx/src/example_cake_filling.rs rename to examples/async-std/src/example_cake_filling.rs diff --git a/examples/sqlx/src/example_filling.rs b/examples/async-std/src/example_filling.rs similarity index 100% rename from examples/sqlx/src/example_filling.rs rename to examples/async-std/src/example_filling.rs diff --git a/examples/sqlx/src/example_fruit.rs b/examples/async-std/src/example_fruit.rs similarity index 100% rename from examples/sqlx/src/example_fruit.rs rename to examples/async-std/src/example_fruit.rs diff --git a/examples/sqlx/src/main.rs b/examples/async-std/src/main.rs similarity index 100% rename from examples/sqlx/src/main.rs rename to examples/async-std/src/main.rs diff --git a/examples/sqlx/src/operation.rs b/examples/async-std/src/operation.rs similarity index 100% rename from examples/sqlx/src/operation.rs rename to examples/async-std/src/operation.rs diff --git a/examples/sqlx/src/select.rs b/examples/async-std/src/select.rs similarity index 100% rename from examples/sqlx/src/select.rs rename to examples/async-std/src/select.rs diff --git a/examples/tokio/Cargo.toml b/examples/tokio/Cargo.toml new file mode 100644 index 00000000..173e9906 --- /dev/null +++ b/examples/tokio/Cargo.toml @@ -0,0 +1,12 @@ +[workspace] +# A separate workspace + +[package] +name = "sea-orm-example-tokio" +version = "0.1.0" +edition = "2018" +publish = false + +[dependencies] +sea-orm = { path = "../../", features = [ "sqlx-all", "runtime-tokio-native-tls" ] } +tokio = { version = "1", features = ["full"] } diff --git a/examples/tokio/src/cake.rs b/examples/tokio/src/cake.rs new file mode 100644 index 00000000..0b1a4439 --- /dev/null +++ b/examples/tokio/src/cake.rs @@ -0,0 +1,55 @@ +use sea_orm::entity::prelude::*; + +#[derive(Copy, Clone, Default, Debug, DeriveEntity)] +pub struct Entity; + +impl EntityName for Entity { + fn table_name(&self) -> &str { + "cake" + } +} + +#[derive(Clone, Debug, PartialEq, DeriveModel, DeriveActiveModel)] +pub struct Model { + pub id: i32, + pub name: String, +} + +#[derive(Copy, Clone, Debug, EnumIter, DeriveColumn)] +pub enum Column { + Id, + Name, +} + +#[derive(Copy, Clone, Debug, EnumIter, DerivePrimaryKey)] +pub enum PrimaryKey { + Id, +} + +impl PrimaryKeyTrait for PrimaryKey { + fn auto_increment() -> bool { + true + } +} + +#[derive(Copy, Clone, Debug, EnumIter)] +pub enum Relation {} + +impl ColumnTrait for Column { + type EntityName = Entity; + + fn def(&self) -> ColumnDef { + match self { + Self::Id => ColumnType::Integer.def(), + Self::Name => ColumnType::String(None).def(), + } + } +} + +impl RelationTrait for Relation { + fn def(&self) -> RelationDef { + unreachable!() + } +} + +impl ActiveModelBehavior for ActiveModel {} diff --git a/examples/tokio/src/main.rs b/examples/tokio/src/main.rs new file mode 100644 index 00000000..dd81b4ab --- /dev/null +++ b/examples/tokio/src/main.rs @@ -0,0 +1,14 @@ +mod cake; +use sea_orm::*; + +#[tokio::main] +pub async fn main() { + let db = Database::connect("sql://sea:sea@localhost/bakery") + .await + .unwrap(); + + tokio::spawn(async move { + cake::Entity::find().one(&db).await.unwrap(); + }) + .await.unwrap(); +} \ No newline at end of file diff --git a/sea-orm-cli/Cargo.toml b/sea-orm-cli/Cargo.toml index f66353e8..7c9ec510 100644 --- a/sea-orm-cli/Cargo.toml +++ b/sea-orm-cli/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -# A separate workspace for sea-orm-cli +# A separate workspace [package] name = "sea-orm-cli" From 8cfa14233d2d6bce27857cce8b12a95be414d2cc Mon Sep 17 00:00:00 2001 From: Chris Tsang Date: Mon, 23 Aug 2021 15:32:29 +0800 Subject: [PATCH 52/52] GitHub Workflow --- .github/workflows/rust.yml | 66 +++++++++++++++++++++++--------------- 1 file changed, 41 insertions(+), 25 deletions(-) diff --git a/.github/workflows/rust.yml b/.github/workflows/rust.yml index 6cd35f28..2aa1f90d 100644 --- a/.github/workflows/rust.yml +++ b/.github/workflows/rust.yml @@ -10,6 +10,40 @@ env: CARGO_TERM_COLOR: always jobs: + + compile: + name: Compile + runs-on: ubuntu-20.04 + strategy: + matrix: + database: [sqlite, mysql, postgres] + runtime: [async-std, actix, tokio] + tls: [native-tls, rustls] + steps: + - uses: actions/checkout@v2 + + - uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: stable + override: true + + - uses: actions/cache@v2 + with: + path: | + ~/.cargo/registry + ~/.cargo/git + Cargo.lock + target + key: ${{ github.sha }}-${{ github.run_id }}-${{ runner.os }}-${{ matrix.database }}-${{ matrix.runtime }}-${{ matrix.tls }} + + - uses: actions-rs/cargo@v1 + with: + command: test + args: > + --features default,sqlx-${{ matrix.database }},runtime-${{ matrix.runtime }}-${{ matrix.tls }} + --no-run + test: name: Unit Test runs-on: ubuntu-20.04 @@ -49,14 +83,12 @@ jobs: args: > --path sea-orm-cli - compile: - name: Compile - runs-on: ubuntu-20.04 + examples: + name: Examples + runs-on: ${{ matrix.os }} strategy: matrix: - database: [sqlite, mysql, postgres] - runtime: [async-std, actix, tokio] - tls: [native-tls, rustls] + os: [ubuntu-latest] steps: - uses: actions/checkout@v2 @@ -66,33 +98,17 @@ jobs: toolchain: stable override: true - - uses: actions/cache@v2 - with: - path: | - ~/.cargo/registry - ~/.cargo/git - Cargo.lock - target - key: ${{ github.sha }}-${{ github.run_id }}-${{ runner.os }}-${{ matrix.database }}-${{ matrix.runtime }}-${{ matrix.tls }} - - uses: actions-rs/cargo@v1 with: - command: test + command: build args: > - --features default,sqlx-${{ matrix.database }},runtime-${{ matrix.runtime }}-${{ matrix.tls }} - --no-run + --manifest-path examples/async-std/Cargo.toml - uses: actions-rs/cargo@v1 with: command: build args: > - --path examples/async-std - - - uses: actions-rs/cargo@v1 - with: - command: build - args: > - --path examples/tokio + --manifest-path examples/tokio/Cargo.toml sqlite: name: SQLite