diff --git a/CHANGELOG.md b/CHANGELOG.md index ba980056..3dea11e7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,11 @@ 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/). -## 1.0.2 - 2023-03-25 + +## 1.0.3 - pending +* add `update_mutation` to allow the Update mutation. The mutation takes entity data and filter condition, updates the entities and returns the updated result + +## 1.0.2 - pending * add `create_one_mutation` @@ -41,7 +45,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). * start error handling -## 1.0.1 - 2023-03-25 +## 1.0.1 - pending * slim down code generation for the `query_root.rs` file of a generated project @@ -49,11 +53,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/). * update examples -## 1.0.0 - 2023-03-25 +## 1.0.0 - Pending + +`1.0.0-rc.1`: 2023-07-28 Introduction the functional API of Seaography. Warning, this version has breaking changes, but it was a sacrifice in order to make the project easier to maintain. With this version we have support for field guards and field renames. ### Breaking changes + * Dropped the derive API in favor of a functional API SeaORM is a dynamic ORM for rust, this means that we can inspect the Tables, Columns properties on runtime. Recently async-graphql added support for dynamic creation of GraphQL nodes. Utilizing the dynamic nature of both libraries the Derive API is no longer needed and we developed a functional approach API. Moreover, the project in order to live long it needs to be maintainable (easy to maintain) and extensible (easy to extend), but the Derive API was fairly complex compared to a functional API. In order to make the migration easier we updated the seaography generator to generate using the new API diff --git a/Cargo.toml b/Cargo.toml index 526cb7b3..73253906 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,7 +7,7 @@ members = [ [package] name = "seaography" -version = "1.0.0" +version = "1.0.0-rc.1" edition = "2021" rust-version = "1.60" authors = ["Panagiotis Karatakis "] @@ -21,7 +21,7 @@ categories = ["database"] [dependencies] async-graphql = { version = "5.0.10", features = ["decimal", "chrono", "dataloader", "dynamic-schema"] } -sea-orm = { version = "0.12.0-rc.5", default-features = false, features = ["seaography"] } +sea-orm = { version = "0.12.0", default-features = false, features = ["seaography"] } itertools = { version = "0.11.0" } heck = { version = "0.4.1" } thiserror = "1.0.44" diff --git a/README.md b/README.md index 9a44825c..66125392 100644 --- a/README.md +++ b/README.md @@ -39,8 +39,8 @@ ### Install ```sh -cargo install sea-orm-cli # used to generate entities -cargo install seaography-cli +cargo install sea-orm-cli@^0.12 # used to generate entities +cargo install seaography-cli@1 ``` ### MySQL diff --git a/build-tools/cargo-publish.sh b/build-tools/cargo-publish.sh index f1905f08..cbb62000 100644 --- a/build-tools/cargo-publish.sh +++ b/build-tools/cargo-publish.sh @@ -4,11 +4,9 @@ set -e cd generator cargo publish cd .. -sleep 10 cd cli cargo publish cd .. -sleep 10 cargo publish \ No newline at end of file diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 0db47f74..e7ca4c61 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "seaography-cli" -version = "1.0.0" +version = "1.0.0-rc.1" edition = "2021" rust-version = "1.60" authors = ["Panagiotis Karatakis "] @@ -15,5 +15,5 @@ categories = ["database"] [dependencies] async-std = { version = "1.12.0", features = [ "attributes", "tokio1" ] } clap = { version = "4.3.19", features = ["derive"] } -seaography-generator = { version = "^1.0.0", path = "../generator" } +seaography-generator = { version = "^1.0.0-rc.1", path = "../generator" } url = "2.4.0" \ No newline at end of file diff --git a/cli/src/main.rs b/cli/src/main.rs index f9c3d478..ed2de028 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -4,19 +4,19 @@ use seaography_generator::write_project; #[derive(clap::Parser)] #[clap(author, version, about, long_about = None)] pub struct Args { - /// project destination folder + /// Project destination folder pub destination: String, - /// entities folder to depend on + /// SeaORM entities folder pub entities: String, - /// database URL to write it in .env + /// Database URL to write in .env pub database_url: String, - /// crate name for generated project + /// Crate name for generated project pub crate_name: String, - /// web framework + /// Which web framework to use #[clap(short, long, value_enum, default_value_t = WebFrameworkEnum::Poem)] pub framework: WebFrameworkEnum, diff --git a/examples/mysql/Cargo.toml b/examples/mysql/Cargo.toml index 4aa43e5b..d8520e85 100644 --- a/examples/mysql/Cargo.toml +++ b/examples/mysql/Cargo.toml @@ -9,7 +9,7 @@ async-graphql-poem = { version = "5.0.10" } async-graphql = { version = "5.0.10", features = ["decimal", "chrono", "dataloader", "dynamic-schema"] } async-trait = { version = "0.1.72" } dotenv = "0.15.0" -sea-orm = { version = "0.12.0-rc.5", features = ["sqlx-mysql", "runtime-async-std-native-tls", "seaography"] } +sea-orm = { version = "0.12.0", features = ["sqlx-mysql", "runtime-async-std-native-tls", "seaography"] } tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] } tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.17" } @@ -17,7 +17,7 @@ lazy_static = { version = "1.4.0" } [dependencies.seaography] path = "../../" -version = "^1.0.0" # seaography version +version = "^1.0.0-rc.1" # seaography version features = ["with-decimal", "with-chrono"] [dev-dependencies] diff --git a/examples/mysql/src/entities/actor.rs b/examples/mysql/src/entities/actor.rs index 049a4113..a59866be 100644 --- a/examples/mysql/src/entities/actor.rs +++ b/examples/mysql/src/entities/actor.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/address.rs b/examples/mysql/src/entities/address.rs index d1e5a0ab..1cd67bfe 100644 --- a/examples/mysql/src/entities/address.rs +++ b/examples/mysql/src/entities/address.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/category.rs b/examples/mysql/src/entities/category.rs index 7eaf7e7e..8ffdd8e8 100644 --- a/examples/mysql/src/entities/category.rs +++ b/examples/mysql/src/entities/category.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/city.rs b/examples/mysql/src/entities/city.rs index aee384e6..5d8647d5 100644 --- a/examples/mysql/src/entities/city.rs +++ b/examples/mysql/src/entities/city.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/country.rs b/examples/mysql/src/entities/country.rs index 46a40349..ec4e85f1 100644 --- a/examples/mysql/src/entities/country.rs +++ b/examples/mysql/src/entities/country.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/customer.rs b/examples/mysql/src/entities/customer.rs index f7c59851..e6f5b16f 100644 --- a/examples/mysql/src/entities/customer.rs +++ b/examples/mysql/src/entities/customer.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; @@ -14,7 +14,7 @@ pub struct Model { pub address_id: i32, pub active: i8, pub create_date: DateTime, - pub last_update: DateTimeUtc, + pub last_update: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/examples/mysql/src/entities/film.rs b/examples/mysql/src/entities/film.rs index 60a1a828..63a1f901 100644 --- a/examples/mysql/src/entities/film.rs +++ b/examples/mysql/src/entities/film.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use super::sea_orm_active_enums::Rating; use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/film_actor.rs b/examples/mysql/src/entities/film_actor.rs index cc0cacf8..14012fb6 100644 --- a/examples/mysql/src/entities/film_actor.rs +++ b/examples/mysql/src/entities/film_actor.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/film_category.rs b/examples/mysql/src/entities/film_category.rs index 1ffc02e3..51d3edaf 100644 --- a/examples/mysql/src/entities/film_category.rs +++ b/examples/mysql/src/entities/film_category.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/film_text.rs b/examples/mysql/src/entities/film_text.rs index df005546..4ddf1e54 100644 --- a/examples/mysql/src/entities/film_text.rs +++ b/examples/mysql/src/entities/film_text.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/inventory.rs b/examples/mysql/src/entities/inventory.rs index f483f722..9ac24f6e 100644 --- a/examples/mysql/src/entities/inventory.rs +++ b/examples/mysql/src/entities/inventory.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/language.rs b/examples/mysql/src/entities/language.rs index 6fe0690f..de699fd9 100644 --- a/examples/mysql/src/entities/language.rs +++ b/examples/mysql/src/entities/language.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/mod.rs b/examples/mysql/src/entities/mod.rs index d71df32a..66213dd0 100644 --- a/examples/mysql/src/entities/mod.rs +++ b/examples/mysql/src/entities/mod.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 pub mod prelude; diff --git a/examples/mysql/src/entities/payment.rs b/examples/mysql/src/entities/payment.rs index 60e71fd4..a91fe251 100644 --- a/examples/mysql/src/entities/payment.rs +++ b/examples/mysql/src/entities/payment.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; @@ -13,7 +13,7 @@ pub struct Model { #[sea_orm(column_type = "Decimal(Some((5, 2)))")] pub amount: Decimal, pub payment_date: DateTime, - pub last_update: DateTimeUtc, + pub last_update: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/examples/mysql/src/entities/prelude.rs b/examples/mysql/src/entities/prelude.rs index 3b2c48d9..bd7ba9da 100644 --- a/examples/mysql/src/entities/prelude.rs +++ b/examples/mysql/src/entities/prelude.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 pub use super::actor::Entity as Actor; pub use super::address::Entity as Address; diff --git a/examples/mysql/src/entities/rental.rs b/examples/mysql/src/entities/rental.rs index 18d4e312..a923ebc7 100644 --- a/examples/mysql/src/entities/rental.rs +++ b/examples/mysql/src/entities/rental.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/sea_orm_active_enums.rs b/examples/mysql/src/entities/sea_orm_active_enums.rs index efc9020d..686bdec2 100644 --- a/examples/mysql/src/entities/sea_orm_active_enums.rs +++ b/examples/mysql/src/entities/sea_orm_active_enums.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/staff.rs b/examples/mysql/src/entities/staff.rs index 58d4738f..21db6b05 100644 --- a/examples/mysql/src/entities/staff.rs +++ b/examples/mysql/src/entities/staff.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/entities/store.rs b/examples/mysql/src/entities/store.rs index 384aa5c6..fe0093c4 100644 --- a/examples/mysql/src/entities/store.rs +++ b/examples/mysql/src/entities/store.rs @@ -1,4 +1,4 @@ -//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.0-rc.5 +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.12.1 use sea_orm::entity::prelude::*; diff --git a/examples/mysql/src/query_root.rs b/examples/mysql/src/query_root.rs index 408d2132..f7c83fb8 100644 --- a/examples/mysql/src/query_root.rs +++ b/examples/mysql/src/query_root.rs @@ -15,22 +15,22 @@ pub fn schema( seaography::register_entities!( builder, [ - film_actor, - rental, + actor, + address, category, - staff, + city, country, + customer, film, - actor, - language, - city, - inventory, - film_text, + film_actor, film_category, - customer, - store, + film_text, + inventory, + language, payment, - address, + rental, + staff, + store, ] ); builder.register_enumeration::(); diff --git a/examples/mysql/tests/query_tests.rs b/examples/mysql/tests/query_tests.rs index d19fc994..6d925f1e 100644 --- a/examples/mysql/tests/query_tests.rs +++ b/examples/mysql/tests/query_tests.rs @@ -620,6 +620,87 @@ async fn related_queries_filters() { } } "#, + ); + + assert_eq( + schema + .execute( + r#" + { + film(filters:{filmId: {eq: 1}}) { + nodes { + title + description + releaseYear + actor { + nodes { + firstName + lastName + } + } + } + } + } + "#, + ) + .await, + r#" + { + "film": { + "nodes": [ + { + "title": "ACADEMY DINOSAUR", + "description": "A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies", + "releaseYear": 2006, + "actor": { + "nodes": [ + { + "firstName": "PENELOPE", + "lastName": "GUINESS" + }, + { + "firstName": "CHRISTIAN", + "lastName": "GABLE" + }, + { + "firstName": "LUCILLE", + "lastName": "TRACY" + }, + { + "firstName": "SANDRA", + "lastName": "PECK" + }, + { + "firstName": "JOHNNY", + "lastName": "CAGE" + }, + { + "firstName": "MENA", + "lastName": "TEMPLE" + }, + { + "firstName": "WARREN", + "lastName": "NOLTE" + }, + { + "firstName": "OPRAH", + "lastName": "KILMER" + }, + { + "firstName": "ROCK", + "lastName": "DUKAKIS" + }, + { + "firstName": "MARY", + "lastName": "KEITEL" + } + ] + } + } + ] + } + } + "#, ) } diff --git a/examples/postgres/Cargo.toml b/examples/postgres/Cargo.toml index 510a6452..60cf448d 100644 --- a/examples/postgres/Cargo.toml +++ b/examples/postgres/Cargo.toml @@ -9,7 +9,7 @@ async-graphql-poem = { version = "5.0.10" } async-graphql = { version = "5.0.10", features = ["decimal", "chrono", "dataloader", "dynamic-schema"] } async-trait = { version = "0.1.72" } dotenv = "0.15.0" -sea-orm = { version = "0.12.0-rc.5", features = ["sqlx-postgres", "runtime-async-std-native-tls", "seaography"] } +sea-orm = { version = "0.12.0", features = ["sqlx-postgres", "runtime-async-std-native-tls", "seaography"] } tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] } tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.17" } @@ -17,7 +17,7 @@ lazy_static = { version = "1.4.0" } [dependencies.seaography] path = "../../" -version = "^1.0.0" # seaography version +version = "^1.0.0-rc.1" # seaography version features = ["with-decimal", "with-chrono"] [dev-dependencies] diff --git a/examples/postgres/tests/query_tests.rs b/examples/postgres/tests/query_tests.rs index f7ca2f79..510844af 100644 --- a/examples/postgres/tests/query_tests.rs +++ b/examples/postgres/tests/query_tests.rs @@ -622,6 +622,87 @@ async fn related_queries_filters() { } } "#, + ); + + assert_eq( + schema + .execute( + r#" + { + film(filters:{filmId: {eq: 1}}) { + nodes { + title + description + releaseYear + actor { + nodes { + firstName + lastName + } + } + } + } + } + "#, + ) + .await, + r#" + { + "film": { + "nodes": [ + { + "title": "ACADEMY DINOSAUR", + "description": "A Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies", + "releaseYear": 2006, + "actor": { + "nodes": [ + { + "firstName": "PENELOPE", + "lastName": "GUINESS" + }, + { + "firstName": "CHRISTIAN", + "lastName": "GABLE" + }, + { + "firstName": "LUCILLE", + "lastName": "TRACY" + }, + { + "firstName": "SANDRA", + "lastName": "PECK" + }, + { + "firstName": "JOHNNY", + "lastName": "CAGE" + }, + { + "firstName": "MENA", + "lastName": "TEMPLE" + }, + { + "firstName": "WARREN", + "lastName": "NOLTE" + }, + { + "firstName": "OPRAH", + "lastName": "KILMER" + }, + { + "firstName": "ROCK", + "lastName": "DUKAKIS" + }, + { + "firstName": "MARY", + "lastName": "KEITEL" + } + ] + } + } + ] + } + } + "#, ) } diff --git a/examples/sqlite/Cargo.toml b/examples/sqlite/Cargo.toml index dd8ddba3..8cf513ab 100644 --- a/examples/sqlite/Cargo.toml +++ b/examples/sqlite/Cargo.toml @@ -9,7 +9,7 @@ async-graphql-poem = { version = "5.0.10" } async-graphql = { version = "5.0.10", features = ["decimal", "chrono", "dataloader", "dynamic-schema"] } async-trait = { version = "0.1.72" } dotenv = "0.15.0" -sea-orm = { version = "0.12.0-rc.5", features = ["sqlx-sqlite", "runtime-async-std-native-tls", "seaography"] } +sea-orm = { version = "0.12.0", features = ["sqlx-sqlite", "runtime-async-std-native-tls", "seaography"] } tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] } tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.17" } @@ -17,7 +17,7 @@ lazy_static = { version = "1.4.0" } [dependencies.seaography] path = "../../" -version = "^1.0.0" # seaography version +version = "^1.0.0-rc.1" # seaography version features = ["with-decimal", "with-chrono"] [dev-dependencies] diff --git a/examples/sqlite/tests/guard_tests.rs b/examples/sqlite/tests/guard_tests.rs index f97886a4..2d897dee 100644 --- a/examples/sqlite/tests/guard_tests.rs +++ b/examples/sqlite/tests/guard_tests.rs @@ -13,11 +13,11 @@ lazy_static::lazy_static! { let context = BuilderContext::default(); let mut entity_guards: BTreeMap = BTreeMap::new(); entity_guards.insert("FilmCategory".into(), Box::new(|_ctx| { - true + seaography::GuardAction::Block(None) })); let mut field_guards: BTreeMap = BTreeMap::new(); field_guards.insert("Language.lastUpdate".into(), Box::new(|_ctx| { - true + seaography::GuardAction::Block(None) })); BuilderContext { guards: GuardsConfig { diff --git a/examples/sqlite/tests/query_tests.rs b/examples/sqlite/tests/query_tests.rs index cebcaeab..88d2de6d 100644 --- a/examples/sqlite/tests/query_tests.rs +++ b/examples/sqlite/tests/query_tests.rs @@ -619,6 +619,99 @@ async fn related_queries_filters() { } } "#, + ); + + assert_eq( + schema + .execute( + r#" + { + film(filters:{filmId: {eq: 1}}) { + nodes { + title + description + releaseYear + actor { + nodes { + firstName + lastName + } + } + category { + nodes { + name + } + } + } + } + } + "#, + ) + .await, + r#" + { + "film": { + "nodes": [ + { + "title": "ACADEMY DINOSAUR", + "description": "An Epic Drama of a Feminist And a Mad Scientist who must Battle a Teacher in The Canadian Rockies", + "releaseYear": "2006", + "actor": { + "nodes": [ + { + "firstName": "PENELOPE", + "lastName": "GUINESS" + }, + { + "firstName": "CHRISTIAN", + "lastName": "GABLE" + }, + { + "firstName": "LUCILLE", + "lastName": "TRACY" + }, + { + "firstName": "SANDRA", + "lastName": "PECK" + }, + { + "firstName": "JOHNNY", + "lastName": "CAGE" + }, + { + "firstName": "MENA", + "lastName": "TEMPLE" + }, + { + "firstName": "WARREN", + "lastName": "NOLTE" + }, + { + "firstName": "OPRAH", + "lastName": "KILMER" + }, + { + "firstName": "ROCK", + "lastName": "DUKAKIS" + }, + { + "firstName": "MARY", + "lastName": "KEITEL" + } + ] + }, + "category": { + "nodes": [ + { + "name": "Documentary" + } + ] + } + } + ] + } + } + "#, ) } diff --git a/generator/Cargo.toml b/generator/Cargo.toml index 74844693..17410976 100644 --- a/generator/Cargo.toml +++ b/generator/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "seaography-generator" -version = "1.0.0" +version = "1.0.0-rc.1" edition = "2021" rust-version = "1.60" authors = ["Panagiotis Karatakis "] diff --git a/generator/src/templates/actix_cargo.toml b/generator/src/templates/actix_cargo.toml index 7b8324f7..f3681d56 100644 --- a/generator/src/templates/actix_cargo.toml +++ b/generator/src/templates/actix_cargo.toml @@ -9,7 +9,7 @@ async-graphql-actix-web = { version = "5.0.10" } async-graphql = { version = "5.0.10", features = ["decimal", "chrono", "dataloader", "dynamic-schema"] } async-trait = { version = "0.1.72" } dotenv = "0.15.0" -sea-orm = { version = "0.12.0-rc.5", features = ["", "runtime-async-std-native-tls", "seaography"] } +sea-orm = { version = "0.12.0", features = ["", "runtime-async-std-native-tls", "seaography"] } tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] } tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.17" } diff --git a/generator/src/templates/poem_cargo.toml b/generator/src/templates/poem_cargo.toml index 8e74f96a..acc80bcf 100644 --- a/generator/src/templates/poem_cargo.toml +++ b/generator/src/templates/poem_cargo.toml @@ -9,7 +9,7 @@ async-graphql-poem = { version = "5.0.10" } async-graphql = { version = "5.0.10", features = ["decimal", "chrono", "dataloader", "dynamic-schema"] } async-trait = { version = "0.1.72" } dotenv = "0.15.0" -sea-orm = { version = "0.12.0-rc.5", features = ["", "runtime-async-std-native-tls", "seaography"] } +sea-orm = { version = "0.12.0", features = ["", "runtime-async-std-native-tls", "seaography"] } tokio = { version = "1.29.1", features = ["macros", "rt-multi-thread"] } tracing = { version = "0.1.37" } tracing-subscriber = { version = "0.3.17" } diff --git a/generator/src/writer.rs b/generator/src/writer.rs index 785496d5..a721cae8 100644 --- a/generator/src/writer.rs +++ b/generator/src/writer.rs @@ -10,7 +10,7 @@ use crate::{ }; pub fn generate_query_root>(entities_path: &P) -> TokenStream { - let entities_paths = std::fs::read_dir(entities_path) + let mut entities_paths: Vec<_> = std::fs::read_dir(entities_path) .unwrap() .into_iter() .filter(|r| r.is_ok()) @@ -26,9 +26,12 @@ pub fn generate_query_root>(entities_path: &P) -> TokenStream { } else { false } - }); + }) + .collect(); + entities_paths.sort(); let entities: Vec = entities_paths + .into_iter() .map(|path| { let file_name = path.file_name().unwrap().to_str().unwrap(); parse_entity(file_name.into()) diff --git a/src/builder_context/guards.rs b/src/builder_context/guards.rs index 000a1d5b..f0a1fa6c 100644 --- a/src/builder_context/guards.rs +++ b/src/builder_context/guards.rs @@ -13,4 +13,10 @@ pub struct GuardsConfig { } /// guards are functions that receive the application context -pub type FnGuard = Box bool + Sync + Send>; +pub type FnGuard = Box GuardAction + Sync + Send>; + +#[derive(Debug, Clone, Eq, PartialEq)] +pub enum GuardAction { + Block(Option), + Allow, +} diff --git a/src/outputs/entity_object.rs b/src/outputs/entity_object.rs index 561228b3..acfedf1a 100644 --- a/src/outputs/entity_object.rs +++ b/src/outputs/entity_object.rs @@ -27,7 +27,7 @@ impl std::default::Default for EntityObjectConfig { } } -use crate::{BuilderContext, TypesMapHelper}; +use crate::{ActiveEnumBuilder, BuilderContext, GuardAction}; /// This builder produces the GraphQL object of a SeaORM entity pub struct EntityObjectBuilder { @@ -146,15 +146,18 @@ impl EntityObjectBuilder { let guard_flag = if let Some(guard) = guard { (*guard)(&ctx) } else { - false + GuardAction::Allow }; - if guard_flag { + if let GuardAction::Block(reason) = guard_flag { return FieldFuture::new(async move { - if guard_flag { - Err(Error::new("Field guard triggered.")) - } else { - Ok(Some(Value::from(false))) + match reason { + Some(reason) => { + Err::, async_graphql::Error>(Error::new(reason)) + } + None => Err::, async_graphql::Error>(Error::new( + "Field guard triggered.", + )), } }); } diff --git a/src/query/entity_object_relation.rs b/src/query/entity_object_relation.rs index ea701bb2..25b6b292 100644 --- a/src/query/entity_object_relation.rs +++ b/src/query/entity_object_relation.rs @@ -10,7 +10,7 @@ use sea_orm::{ use crate::{ apply_order, apply_pagination, get_filter_conditions, BuilderContext, ConnectionObjectBuilder, - EntityObjectBuilder, FilterInputBuilder, OrderInputBuilder, + EntityObjectBuilder, FilterInputBuilder, GuardAction, OrderInputBuilder, }; /// This builder produces a GraphQL field for an SeaORM entity relationship @@ -65,11 +65,18 @@ impl EntityObjectRelationBuilder { let guard_flag = if let Some(guard) = guard { (*guard)(&ctx) } else { - false + GuardAction::Allow }; - if guard_flag { - return Err(Error::new("Entity guard triggered.")); + if let GuardAction::Block(reason) = guard_flag { + return match reason { + Some(reason) => { + Err::, async_graphql::Error>(Error::new(reason)) + } + None => Err::, async_graphql::Error>(Error::new( + "Entity guard triggered.", + )), + }; } let parent: &T::Model = ctx @@ -104,11 +111,18 @@ impl EntityObjectRelationBuilder { let guard_flag = if let Some(guard) = guard { (*guard)(&ctx) } else { - false + GuardAction::Allow }; - if guard_flag { - return Err(Error::new("Entity guard triggered.")); + if let GuardAction::Block(reason) = guard_flag { + return match reason { + Some(reason) => { + Err::, async_graphql::Error>(Error::new(reason)) + } + None => Err::, async_graphql::Error>(Error::new( + "Entity guard triggered.", + )), + }; } // FIXME: optimize union queries diff --git a/src/query/entity_object_via_relation.rs b/src/query/entity_object_via_relation.rs index 88ea0dd4..9b638d54 100644 --- a/src/query/entity_object_via_relation.rs +++ b/src/query/entity_object_via_relation.rs @@ -9,7 +9,7 @@ use sea_orm::{ use crate::{ apply_order, apply_pagination, get_filter_conditions, BuilderContext, ConnectionObjectBuilder, - EntityObjectBuilder, FilterInputBuilder, OrderInputBuilder, + EntityObjectBuilder, FilterInputBuilder, GuardAction, OrderInputBuilder, }; /// This builder produces a GraphQL field for an SeaORM entity related trait @@ -32,9 +32,9 @@ impl EntityObjectViaRelationBuilder { { let context: &'static BuilderContext = self.context; let to_relation_definition = >::to(); - let via_relation_definition = match >::via() { - Some(def) => def, - None => >::to(), + let (via_relation_definition, is_via_relation) = match >::via() { + Some(def) => (def, true), + None => (>::to(), false), }; let entity_object_builder = EntityObjectBuilder { context }; @@ -71,11 +71,18 @@ impl EntityObjectViaRelationBuilder { let guard_flag = if let Some(guard) = guard { (*guard)(&ctx) } else { - false + GuardAction::Allow }; - if guard_flag { - return Err(Error::new("Entity guard triggered.")); + if let GuardAction::Block(reason) = guard_flag { + return match reason { + Some(reason) => { + Err::, async_graphql::Error>(Error::new(reason)) + } + None => Err::, async_graphql::Error>(Error::new( + "Entity guard triggered.", + )), + }; } let parent: &T::Model = ctx @@ -114,11 +121,18 @@ impl EntityObjectViaRelationBuilder { let guard_flag = if let Some(guard) = guard { (*guard)(&ctx) } else { - false + GuardAction::Allow }; - if guard_flag { - return Err(Error::new("Entity guard triggered.")); + if let GuardAction::Block(reason) = guard_flag { + return match reason { + Some(reason) => { + Err::, async_graphql::Error>(Error::new(reason)) + } + None => Err::, async_graphql::Error>(Error::new( + "Entity guard triggered.", + )), + }; } // FIXME: optimize union queries @@ -134,7 +148,11 @@ impl EntityObjectViaRelationBuilder { R::find() }; - let condition = Condition::all().add(to_col.eq(parent.get(from_col))); + let condition = if is_via_relation { + Condition::all().add(from_col.eq(parent.get(from_col))) + } else { + Condition::all().add(to_col.eq(parent.get(from_col))) + }; let filters = ctx.args.get(&context.entity_query_field.filters); let order_by = ctx.args.get(&context.entity_query_field.order_by); diff --git a/src/query/entity_query_field.rs b/src/query/entity_query_field.rs index 6c1a6636..936c4921 100644 --- a/src/query/entity_query_field.rs +++ b/src/query/entity_query_field.rs @@ -7,7 +7,8 @@ use sea_orm::{DatabaseConnection, EntityTrait, QueryFilter}; use crate::{ apply_order, apply_pagination, get_filter_conditions, BuilderContext, ConnectionObjectBuilder, - EntityObjectBuilder, FilterInputBuilder, OrderInputBuilder, PaginationInputBuilder, + EntityObjectBuilder, FilterInputBuilder, GuardAction, OrderInputBuilder, + PaginationInputBuilder, }; /// The configuration structure for EntityQueryFieldBuilder @@ -91,11 +92,18 @@ impl EntityQueryFieldBuilder { let guard_flag = if let Some(guard) = guard { (*guard)(&ctx) } else { - false + GuardAction::Allow }; - if guard_flag { - return Err(Error::new("Entity guard triggered.")); + if let GuardAction::Block(reason) = guard_flag { + return match reason { + Some(reason) => { + Err::, async_graphql::Error>(Error::new(reason)) + } + None => Err::, async_graphql::Error>(Error::new( + "Entity guard triggered.", + )), + }; } let filters = ctx.args.get(&context.entity_query_field.filters);