From a4393b995dd7f61b7effb032d52df6cab766a9f0 Mon Sep 17 00:00:00 2001 From: photino Date: Thu, 19 Oct 2023 14:52:03 +0800 Subject: [PATCH] Remove QueryBuilder and MutationBuilder --- examples/actix-app/Cargo.toml | 3 +- examples/actix-app/src/controller/auth.rs | 1 - examples/actix-app/src/controller/stats.rs | 3 +- examples/actix-app/src/controller/user.rs | 1 - examples/actix-app/src/main.rs | 3 - examples/axum-app/Cargo.toml | 3 +- examples/axum-app/src/controller/auth.rs | 1 - examples/axum-app/src/controller/stats.rs | 3 +- examples/axum-app/src/controller/user.rs | 1 - examples/axum-app/src/main.rs | 3 - examples/dioxus-desktop/Cargo.toml | 3 +- .../dioxus-desktop/public/icons/64x64.png | Bin 0 -> 1959 bytes .../dioxus-desktop/src/service/stargazer.rs | 1 - zino-core/Cargo.toml | 6 +- zino-core/src/auth/mod.rs | 14 + zino-core/src/extension/json_value.rs | 8 + zino-core/src/format/mod.rs | 8 + zino-core/src/lib.rs | 32 +- zino-core/src/model/mod.rs | 4 +- zino-core/src/model/mutation.rs | 62 ---- zino-core/src/model/query.rs | 348 ------------------ zino-core/src/{database => orm}/accessor.rs | 0 zino-core/src/{database => orm}/column.rs | 0 zino-core/src/{database => orm}/decode.rs | 0 zino-core/src/{database => orm}/helper.rs | 0 zino-core/src/{database => orm}/mod.rs | 9 + zino-core/src/{database => orm}/mutation.rs | 0 zino-core/src/{database => orm}/mysql.rs | 0 zino-core/src/{database => orm}/postgres.rs | 0 zino-core/src/{database => orm}/query.rs | 0 zino-core/src/{database => orm}/schema.rs | 0 zino-core/src/{database => orm}/sqlite.rs | 0 zino-core/src/view/mod.rs | 9 + zino-derive/src/lib.rs | 25 +- zino-model/src/lib.rs | 1 + zino-model/src/user/jwt_auth.rs | 2 +- zino-model/src/user/mod.rs | 2 +- zino/Cargo.toml | 2 +- zino/src/controller/mod.rs | 2 +- zino/src/lib.rs | 1 + zino/src/prelude/mod.rs | 5 +- 41 files changed, 108 insertions(+), 458 deletions(-) create mode 100644 examples/dioxus-desktop/public/icons/64x64.png rename zino-core/src/{database => orm}/accessor.rs (100%) rename zino-core/src/{database => orm}/column.rs (100%) rename zino-core/src/{database => orm}/decode.rs (100%) rename zino-core/src/{database => orm}/helper.rs (100%) rename zino-core/src/{database => orm}/mod.rs (97%) rename zino-core/src/{database => orm}/mutation.rs (100%) rename zino-core/src/{database => orm}/mysql.rs (100%) rename zino-core/src/{database => orm}/postgres.rs (100%) rename zino-core/src/{database => orm}/query.rs (100%) rename zino-core/src/{database => orm}/schema.rs (100%) rename zino-core/src/{database => orm}/sqlite.rs (100%) diff --git a/examples/actix-app/Cargo.toml b/examples/actix-app/Cargo.toml index 2674f833..59ee878f 100644 --- a/examples/actix-app/Cargo.toml +++ b/examples/actix-app/Cargo.toml @@ -9,8 +9,7 @@ publish = false [dependencies] actix-web = "4.4.0" fluent = "0.16.0" -serde_json = "1.0.107" -tracing = "0.1.39" +tracing = "0.1.40" [dependencies.serde] version = "1.0.189" diff --git a/examples/actix-app/src/controller/auth.rs b/examples/actix-app/src/controller/auth.rs index 5abf0660..93c2c99c 100644 --- a/examples/actix-app/src/controller/auth.rs +++ b/examples/actix-app/src/controller/auth.rs @@ -1,4 +1,3 @@ -use serde_json::json; use zino::{prelude::*, Request, Response, Result}; use zino_model::user::{JwtAuthService, User}; diff --git a/examples/actix-app/src/controller/stats.rs b/examples/actix-app/src/controller/stats.rs index 81f30946..f3b90e45 100644 --- a/examples/actix-app/src/controller/stats.rs +++ b/examples/actix-app/src/controller/stats.rs @@ -1,4 +1,3 @@ -use serde_json::json; use zino::{prelude::*, Cluster, Request, Response, Result}; pub async fn index(req: Request) -> Result { @@ -11,7 +10,7 @@ pub async fn index(req: Request) -> Result { }); let data = json!({ "title": "Stats", - "output": serde_json::to_string_pretty(&stats).unwrap_or_default(), + "output": stats.to_string_pretty(), }); Ok(res.render("output.html", data).into()) } diff --git a/examples/actix-app/src/controller/user.rs b/examples/actix-app/src/controller/user.rs index b537fc7d..13cb770e 100644 --- a/examples/actix-app/src/controller/user.rs +++ b/examples/actix-app/src/controller/user.rs @@ -1,5 +1,4 @@ use fluent::fluent_args; -use serde_json::json; use std::time::Instant; use zino::{prelude::*, Request, Response, Result}; use zino_model::user::User; diff --git a/examples/actix-app/src/main.rs b/examples/actix-app/src/main.rs index b59f1076..e6ea9b8b 100644 --- a/examples/actix-app/src/main.rs +++ b/examples/actix-app/src/main.rs @@ -1,6 +1,3 @@ -#![feature(async_fn_in_trait)] -#![feature(lazy_cell)] - mod controller; mod domain; mod extension; diff --git a/examples/axum-app/Cargo.toml b/examples/axum-app/Cargo.toml index 27287896..483e78d7 100644 --- a/examples/axum-app/Cargo.toml +++ b/examples/axum-app/Cargo.toml @@ -9,8 +9,7 @@ publish = false [dependencies] axum = "0.6.20" fluent = "0.16.0" -serde_json = "1.0.107" -tracing = "0.1.39" +tracing = "0.1.40" [dependencies.serde] version = "1.0.189" diff --git a/examples/axum-app/src/controller/auth.rs b/examples/axum-app/src/controller/auth.rs index 5abf0660..93c2c99c 100644 --- a/examples/axum-app/src/controller/auth.rs +++ b/examples/axum-app/src/controller/auth.rs @@ -1,4 +1,3 @@ -use serde_json::json; use zino::{prelude::*, Request, Response, Result}; use zino_model::user::{JwtAuthService, User}; diff --git a/examples/axum-app/src/controller/stats.rs b/examples/axum-app/src/controller/stats.rs index 81f30946..f3b90e45 100644 --- a/examples/axum-app/src/controller/stats.rs +++ b/examples/axum-app/src/controller/stats.rs @@ -1,4 +1,3 @@ -use serde_json::json; use zino::{prelude::*, Cluster, Request, Response, Result}; pub async fn index(req: Request) -> Result { @@ -11,7 +10,7 @@ pub async fn index(req: Request) -> Result { }); let data = json!({ "title": "Stats", - "output": serde_json::to_string_pretty(&stats).unwrap_or_default(), + "output": stats.to_string_pretty(), }); Ok(res.render("output.html", data).into()) } diff --git a/examples/axum-app/src/controller/user.rs b/examples/axum-app/src/controller/user.rs index b537fc7d..13cb770e 100644 --- a/examples/axum-app/src/controller/user.rs +++ b/examples/axum-app/src/controller/user.rs @@ -1,5 +1,4 @@ use fluent::fluent_args; -use serde_json::json; use std::time::Instant; use zino::{prelude::*, Request, Response, Result}; use zino_model::user::User; diff --git a/examples/axum-app/src/main.rs b/examples/axum-app/src/main.rs index b59f1076..e6ea9b8b 100644 --- a/examples/axum-app/src/main.rs +++ b/examples/axum-app/src/main.rs @@ -1,6 +1,3 @@ -#![feature(async_fn_in_trait)] -#![feature(lazy_cell)] - mod controller; mod domain; mod extension; diff --git a/examples/dioxus-desktop/Cargo.toml b/examples/dioxus-desktop/Cargo.toml index 249a2413..26024db7 100644 --- a/examples/dioxus-desktop/Cargo.toml +++ b/examples/dioxus-desktop/Cargo.toml @@ -9,8 +9,7 @@ publish = false [dependencies] dioxus = "0.4.0" dioxus-router = "0.4.1" -serde_json = "1.0.107" -tracing = "0.1.39" +tracing = "0.1.40" [dependencies.dioxus-free-icons] version = "0.7.0" diff --git a/examples/dioxus-desktop/public/icons/64x64.png b/examples/dioxus-desktop/public/icons/64x64.png new file mode 100644 index 0000000000000000000000000000000000000000..e8b6bd7cd24de0858cae326adc9ccf52f79b2623 GIT binary patch literal 1959 zcmcJQhg*}^7stb_Oc^FXDM&F1Ap;=+LHvo4B|h~5qzG!UMv989q7~YrVkHbgkP%3L zf-D&_REA{;NWdagMMec=gzUkRFccId{to>g`aUN&Z|-~VIp6Q++~>_LU+)7tnqO)n z5D1-vUhaPIP2K!#QGqePi9Uxws33d~`Fk9=bcj$sWtzgX$P(ZRCAdEfPM*}Fj~b**n5J`dW5-DM zW!5ErheL~dy!ZvwPfa<}B{^Og=J!vIN$}B2u+<2UBR4#)E*;m|US{rT}Kp`2xGf z8S`{L1T03g_^4YP*bD1n9s*r1fjqFqse8e$an|Oc%=*4;^J&8jDr1sVErT@{xtqIo zKVL*9atsqDAmAqiSjJUKDXnv8rqJ;(`OexYVufV)-;4NC(Wb8lGW)i-AcNdIyQ^~^ zUm~*ma~jeD974Gm#MstN*|*JMbNOF01lD&&PR|ygx?0MLQVTl~OrbMhCHx9kiiyea*2y~@XFK*0|$u&wEw|_csmAwdsHrZzLAeG_Gaaajv zQHh+bF{6-5hd%n{ZLW6o8`Bgnl+gTr1e8E^@CcN^2*3nil*h9U9rNH3RDosSU{f=N z{ezDy*z^v>tnLV~d3@_4p;ONSm<2Du0c=_q3jrOuX_inX1{C0q+&DwHCm~i!HoMj^ z1Kx>MQaDQh85}_ifH3$46!=mx@P|eKZQ!}-^u-d;)3`qJMbt2`HHaUF^JBr_14HPA z`n6%zt3%KxXrk7QH>#1Zkx3I)#Ujf*0r8#$4u7AydauPI0l3eOou3vG>&VdL(f189TDGB;I5n5vy#ol@Chzx}nXo7WGe z*UllgA@@+{I=T_ss5;LN(V|;to7r;t4en(4YEXKnXuA0;EBSJ zh0KhA>fpc?C8wy6i{bV)PN6i;`Wm(S-jAjeTX!e!#8+5h?N#w1bq~*21g>5F^->QRZ#?FaSYt`4d2E}nnPYU~07~ZvBikTP^{NYfoam8r_5Cz?+K~G9 zZ%$emI{DDQ2_*X#hs%gvyWNIuSRvFs{5e9%URn0QtQNACfb)=EpvfG{)9J_a8q3uF zKC`lgHQavKG{=auzx#4Q@qC{@Rd&k7K6bBbe6d4_#d88%+vK0j6V&NFCSDrEb~Vyj z8PeI0-W*Nw-PfnTX6#E(Uml3`>FYl#9!S~piTJ;hw?7<=bYzsawzs#mv}9$C@H+*9 z*cD!EOyCQLFzSL^#gmG~E4O$%LNEWMq!oF!Ef%Yh6FBvo(eWY+i`os0c<@+9RR45# z5$Q!rfAV-?On|mtEj6#q$u_8?&AmqNvL8|}XZB?3hgGC4FRGVP8su}BYB6IiHbc|e z*^A+!g=a*|xj&h^b#JH<^~4*hS0+k4o?zb(4Gl4y)Be26RhbIptT)GXiTf+3w-eY= z)gRj#tMs+h$YhRBT8*W$y33vHlGoS8{qjgWt^e_8c|mOb4J<=Rb_C{s*0|hf8L!#= z{L#)H?;1u%FCK5($2w88T;b@|7)C;d_Vj({-Fws3uOeDWb|(M2;o9k3hNo)Ft6%dLzA3~Py1RQzKV+=R8S39&amVW`p=n3l^q5;ztUaI?$VP7 z%gOkG-}2g#D)G{J>Ss^@`(c@9T8`L+SyhOJSA? zTItMjn$@Z#wB9W#$bzkMfTGw}y<(U6uDMxYJUib-Z|%Hre^4J49P#Y4a=`JWDHq4^ ziQ#R7d$FkGh9jvSH$C}mU3UXR%$)m6=LFrOOW4oKC99sNb{(3HfIncwK@V^Dhpx1k F{{ypRA{zhz literal 0 HcmV?d00001 diff --git a/examples/dioxus-desktop/src/service/stargazer.rs b/examples/dioxus-desktop/src/service/stargazer.rs index f62dad77..7925c157 100644 --- a/examples/dioxus-desktop/src/service/stargazer.rs +++ b/examples/dioxus-desktop/src/service/stargazer.rs @@ -1,5 +1,4 @@ use crate::App; -use serde_json::json; use zino::prelude::*; pub async fn list_stargazers(per_page: u8, page: usize) -> Result, Error> { diff --git a/zino-core/Cargo.toml b/zino-core/Cargo.toml index eccf2184..1ef890d8 100644 --- a/zino-core/Cargo.toml +++ b/zino-core/Cargo.toml @@ -175,7 +175,7 @@ sha2 = "0.10.8" sysinfo = "0.29.10" task-local-extensions = "0.1.4" toml = "0.8.2" -tracing = "0.1.39" +tracing = "0.1.40" tracing-appender = "0.2.2" url = "2.4.1" @@ -204,7 +204,7 @@ version = "0.12.0" optional = true [dependencies.minijinja] -version = "1.0.8" +version = "1.0.9" optional = true features = ["debug", "loader"] @@ -294,7 +294,7 @@ features = [ ] [dependencies.uuid] -version = "1.4.1" +version = "1.5.0" features = [ "fast-rng", "serde", diff --git a/zino-core/src/auth/mod.rs b/zino-core/src/auth/mod.rs index 8449dc66..4405bc5c 100644 --- a/zino-core/src/auth/mod.rs +++ b/zino-core/src/auth/mod.rs @@ -1,4 +1,18 @@ //! Authentication and authorization. +//! +//! ## Feature flags +//! +//! The following optional features are available: +//! +//! | Name | Description | Default? | +//! |---------------|------------------------------------------------------|----------| +//! | `auth-oauth2` | Enables the integration with [`oauth2`]. | No | +//! | `auth-oidc` | Enables the integration with [`openidconnect`]. | No | +//! | `auth-totp` | Enables the integration with [`totp-rs`]. | No | +//! +//! [`oauth2`]: https://crates.io/crates/oauth2 +//! [`openidconnect`]: https://crates.io/crates/openidconnect +//! [`totp-rs`]: https://crates.io/crates/totp-rs mod access_key; mod authentication; diff --git a/zino-core/src/extension/json_value.rs b/zino-core/src/extension/json_value.rs index ff9cefa4..b801097e 100644 --- a/zino-core/src/extension/json_value.rs +++ b/zino-core/src/extension/json_value.rs @@ -86,6 +86,9 @@ pub trait JsonValueExt { /// If the vec is empty, it also returns `None`. fn parse_str_array(&self) -> Option>; + /// Returns a pretty-printed String of JSON. + fn to_string_pretty(&self) -> String; + /// Attempts to convert the JSON value to the CSV bytes. fn to_csv(&self, buffer: Vec) -> Result, csv::Error>; @@ -255,6 +258,11 @@ impl JsonValueExt for JsonValue { (!vec.is_empty()).then_some(vec) } + #[inline] + fn to_string_pretty(&self) -> String { + format!("{self:#}") + } + fn to_csv(&self, buffer: Vec) -> Result, csv::Error> { match &self { JsonValue::Array(vec) => { diff --git a/zino-core/src/format/mod.rs b/zino-core/src/format/mod.rs index b0288804..f93825f4 100644 --- a/zino-core/src/format/mod.rs +++ b/zino-core/src/format/mod.rs @@ -1,4 +1,12 @@ //! Wrappers for manipulating common file formats. +//! +//! ## Feature flags +//! +//! The following optional features are available: +//! +//! | Name | Description | Default? | +//! |---------------|------------------------------------------------------|----------| +//! | `format-pdf` | Enables the support for `PDF` documents. | No | #[cfg(feature = "format-pdf")] mod pdf_document; diff --git a/zino-core/src/lib.rs b/zino-core/src/lib.rs index be0821e0..191e4d76 100644 --- a/zino-core/src/lib.rs +++ b/zino-core/src/lib.rs @@ -8,9 +8,34 @@ //! //! Core types and traits for [`zino`]. //! +//! ## Feature flags +//! +//! The following optional features are available: +//! +//! | Name | Description | Default? | +//! |---------------------|--------------------------------------------------------|----------| +//! | `accessor` | Enables the data access layer built with [`opendal`]. | No | +//! | `cache` | Enables the cache services. | No | +//! | `chatbot` | Enables the chatbot services. | No | +//! | `connector` | Enables the data source connectors. | No | +//! | `crypto-sm` | Enables China's Standards of Encryption Algorithms. | No | +//! | `format` | Enables the support for common file formats. | No | +//! | `orm` | Enables the ORM for MySQL, PostgreSQL or **SQLite**. | No | +//! | `runtime-async-std` | Enables the [`async-std`] runtime. | No | +//! | `runtime-tokio` | Enables the [`tokio`] runtime. | Yes | +//! | `tls-native` | Enables the [`native-tls`] TLS backend. | No | +//! | `tls-rustls` | Enables the [`rustls`] TLS backend. | Yes | +//! | `view` | Enables the HTML template rendering. | No | +//! //! [`zino`]: https://github.com/photino/zino +//! [`opendal`]: https://crates.io/crates/opendal +//! [`async-std`]: https://crates.io/crates/async-std +//! [`tokio`]: https://crates.io/crates/tokio +//! [`native-tls`]: https://crates.io/crates/native-tls +//! [`rustls`]: https://crates.io/crates/rustls #![allow(async_fn_in_trait)] +#![allow(stable_features)] #![doc(html_favicon_url = "https://photino.github.io/zino-docs-zh/assets/zino-logo.png")] #![doc(html_logo_url = "https://photino.github.io/zino-docs-zh/assets/zino-logo.svg")] #![feature(associated_type_defaults)] @@ -35,10 +60,10 @@ pub mod cache; pub mod chatbot; #[cfg(feature = "connector")] pub mod connector; -#[cfg(feature = "orm")] -pub mod database; #[cfg(feature = "format")] pub mod format; +#[cfg(feature = "orm")] +pub mod orm; #[cfg(feature = "view")] pub mod view; @@ -57,6 +82,9 @@ pub mod schedule; pub mod state; pub mod trace; +#[doc(no_inline)] +pub use serde_json::json; + /// A JSON value. pub type JsonValue = serde_json::Value; diff --git a/zino-core/src/model/mod.rs b/zino-core/src/model/mod.rs index fe96ab4d..ca54733a 100644 --- a/zino-core/src/model/mod.rs +++ b/zino-core/src/model/mod.rs @@ -17,8 +17,8 @@ pub use apache_avro::schema; pub use column::{Column, EncodeColumn}; pub use context::QueryContext; pub use hook::ModelHooks; -pub use mutation::{Mutation, MutationBuilder}; -pub use query::{Query, QueryBuilder}; +pub use mutation::Mutation; +pub use query::Query; pub use reference::Reference; pub use row::DecodeRow; pub use translation::Translation; diff --git a/zino-core/src/model/mutation.rs b/zino-core/src/model/mutation.rs index b19428f6..38bba1c0 100644 --- a/zino-core/src/model/mutation.rs +++ b/zino-core/src/model/mutation.rs @@ -92,65 +92,3 @@ impl Mutation { &self.updates } } - -/// A builder type for model mutations. -#[derive(Debug, Default)] -pub struct MutationBuilder { - // Editable fields. - fields: Vec, - // Updates. - updates: Map, -} - -impl MutationBuilder { - /// Creates a new instance. - #[inline] - pub fn new() -> Self { - Self { - fields: Vec::new(), - updates: Map::new(), - } - } - - /// Sets the value of the field. - #[inline] - pub fn set(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.updates.upsert(field, value); - self - } - - /// Increments the field by a specified value - #[inline] - pub fn inc(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.updates.upsert(field, Map::from_entry("$inc", value)); - self - } - - /// Multiplies the value of a field by a number. - #[inline] - pub fn mul(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.updates.upsert(field, Map::from_entry("$mul", value)); - self - } - - /// Constructs an instance of `Mutation`. - #[inline] - pub fn build(self) -> Mutation { - Mutation { - fields: self.fields, - updates: self.updates, - } - } -} diff --git a/zino-core/src/model/query.rs b/zino-core/src/model/query.rs index 4ae2eb5e..48a06891 100644 --- a/zino-core/src/model/query.rs +++ b/zino-core/src/model/query.rs @@ -265,351 +265,3 @@ impl Default for Query { } } } - -/// A builder type for model queries. -#[derive(Debug, Default)] -pub struct QueryBuilder { - // Projection fields. - fields: Vec, - // Filters with the `AND` logic. - logical_and_filters: Map, - // Filters with the `OR` logic. - logical_or_filters: Vec, - // Aggregations. - aggregations: Map, - // Sort order. - sort_order: Vec<(SharedString, bool)>, - // Offset. - offset: usize, - // Limit. - limit: usize, -} - -impl QueryBuilder { - /// Creates a new instance. - #[inline] - pub fn new() -> Self { - Self { - fields: Vec::new(), - logical_and_filters: Map::new(), - logical_or_filters: Vec::new(), - aggregations: Map::new(), - sort_order: Vec::new(), - offset: 0, - limit: usize::MAX, - } - } - - /// Adds a field to the projection. - #[inline] - pub fn field>(mut self, field: S) -> Self { - let field = field.into(); - if !self.fields.contains(&field) { - self.fields.push(field); - } - self - } - - /// Adds a logical `AND` filter with the condition for equal parts. - #[inline] - pub fn and_eq(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_and_filters.upsert(field.into(), value); - self - } - - /// Adds a logical `AND` filter with the condition for non-equal parts. - #[inline] - pub fn and_ne(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$ne", value)); - self - } - - /// Adds a logical `AND` filter with the condition for a field less than the value. - #[inline] - pub fn and_lt(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$lt", value)); - self - } - - /// Adds a logical `AND` filter with the condition for a field not greater than the value. - #[inline] - pub fn and_le(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$le", value)); - self - } - - /// Adds a logical `AND` filter with the condition for a field greater than the value. - #[inline] - pub fn and_gt(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$gt", value)); - self - } - - /// Adds a logical `AND` filter with the condition for a field not less than the value. - #[inline] - pub fn and_ge(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$ge", value)); - self - } - - /// Adds a logical `AND` filter with the condition for a field whose value is in the list. - #[inline] - pub fn and_in(mut self, field: S, list: &[T]) -> Self - where - S: Into, - T: Into + Clone, - { - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$in", list)); - self - } - - /// Adds a logical `AND` filter with the condition for a field whose value is not in the list. - #[inline] - pub fn and_not_in(mut self, field: S, list: &[T]) -> Self - where - S: Into, - T: Into + Clone, - { - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$nin", list)); - self - } - - /// Adds a logical `AND` filter with the condition for a field whose value is within a given range. - pub fn and_between(mut self, field: S, min: T, max: T) -> Self - where - S: Into, - T: Into, - { - let values = vec![min.into(), max.into()]; - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$between", values)); - self - } - - /// Adds a logical `AND` filter with the condition to search for a specified pattern in a column. - pub fn and_like(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_and_filters - .upsert(field.into(), Map::from_entry("$like", value)); - self - } - - /// Adds a logical `OR` filter with the condition for equal parts. - #[inline] - pub fn or_eq(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_or_filters.push(Map::from_entry(field, value)); - self - } - - /// Adds a logical `OR` filter with the condition for non-equal parts. - #[inline] - pub fn or_ne(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$ne", value))); - self - } - - /// Adds a logical `OR` filter with the condition for a field less than the value. - #[inline] - pub fn or_lt(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$lt", value))); - self - } - - /// Adds a logical `OR` filter with the condition for a field not greater than the value. - #[inline] - pub fn or_le(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$le", value))); - self - } - - /// Adds a logical `OR` filter with the condition for a field greater than the value. - #[inline] - pub fn or_gt(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$gt", value))); - self - } - - /// Adds a logical `OR` filter with the condition for a field not less than the value. - #[inline] - pub fn or_ge(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$ge", value))); - self - } - - /// Adds a logical `OR` filter with the condition for a field whose value is in the list. - #[inline] - pub fn or_in(mut self, field: S, list: &[T]) -> Self - where - S: Into, - T: Into + Clone, - { - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$in", list))); - self - } - - /// Adds a logical `OR` filter with the condition for a field whose value is not in the list. - #[inline] - pub fn or_not_in(mut self, field: S, list: &[T]) -> Self - where - S: Into, - T: Into + Clone, - { - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$nin", list))); - self - } - - /// Adds a logical `OR` filter with the condition for a field whose value is within a given range. - pub fn or_between(mut self, field: S, min: T, max: T) -> Self - where - S: Into, - T: Into, - { - let values = vec![min.into(), max.into()]; - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$between", values))); - self - } - - /// Adds a logical `OR` filter with the condition to search for a specified pattern in a column. - pub fn or_like(mut self, field: S, value: T) -> Self - where - S: Into, - T: Into, - { - self.logical_or_filters - .push(Map::from_entry(field, Map::from_entry("$like", value))); - self - } - - /// Adds an aggregation filter which groups rows that have the same values into summary rows. - #[inline] - pub fn group_by>(mut self, fields: T) -> Self { - self.aggregations.upsert("$group", fields); - self - } - - /// Adds an aggregation filter which can be used with aggregate functions. - #[inline] - pub fn having>(mut self, selection: T) -> Self { - self.aggregations.upsert("$having", selection); - self - } - - /// Adds a sort with the specific order. - #[inline] - pub fn order_by>(mut self, field: S, descending: bool) -> Self { - self.sort_order.push((field.into(), descending)); - self - } - - /// Adds a sort with the ascending order. - #[inline] - pub fn order_asc>(mut self, field: S) -> Self { - self.sort_order.push((field.into(), false)); - self - } - - /// Adds a sort with the descending order. - #[inline] - pub fn order_desc>(mut self, field: S) -> Self { - self.sort_order.push((field.into(), true)); - self - } - - /// Sets the offset. - #[inline] - pub fn offset(mut self, offset: usize) -> Self { - self.offset = offset; - self - } - - /// Sets the limit. - #[inline] - pub fn limit(mut self, limit: usize) -> Self { - self.limit = limit; - self - } - - /// Constructs an instance of `Query`. - #[inline] - pub fn build(mut self) -> Query { - let mut filters = self.logical_and_filters; - let logical_or_filters = self.logical_or_filters; - if !logical_or_filters.is_empty() { - filters.upsert("$or", logical_or_filters); - } - filters.append(&mut self.aggregations); - Query { - fields: self.fields, - filters, - sort_order: self.sort_order, - offset: self.offset, - limit: self.limit, - } - } -} diff --git a/zino-core/src/database/accessor.rs b/zino-core/src/orm/accessor.rs similarity index 100% rename from zino-core/src/database/accessor.rs rename to zino-core/src/orm/accessor.rs diff --git a/zino-core/src/database/column.rs b/zino-core/src/orm/column.rs similarity index 100% rename from zino-core/src/database/column.rs rename to zino-core/src/orm/column.rs diff --git a/zino-core/src/database/decode.rs b/zino-core/src/orm/decode.rs similarity index 100% rename from zino-core/src/database/decode.rs rename to zino-core/src/orm/decode.rs diff --git a/zino-core/src/database/helper.rs b/zino-core/src/orm/helper.rs similarity index 100% rename from zino-core/src/database/helper.rs rename to zino-core/src/orm/helper.rs diff --git a/zino-core/src/database/mod.rs b/zino-core/src/orm/mod.rs similarity index 97% rename from zino-core/src/database/mod.rs rename to zino-core/src/orm/mod.rs index e7fe8190..2da0b5bd 100644 --- a/zino-core/src/database/mod.rs +++ b/zino-core/src/orm/mod.rs @@ -9,6 +9,15 @@ //! | `orm-mysql` | Enables the MySQL database driver. | No | //! | `orm-postgres` | Enables the PostgreSQL database driver. | No | //! | `orm-sqlite` | Enables the SQLite database driver. | No | +//! +//! # Design references +//! +//! The design of our ORM is inspired by [`Mongoose`], [`Prisma`], [`TypeORM`] and [`PostgREST`]. +//! +//! [`Mongoose`]: https://mongoosejs.com/ +//! [`Prisma`]: https://www.prisma.io/ +//! [`TypeORM`]: https://typeorm.io/ +//! [`PostgREST`]: https://postgrest.org/ use crate::{extension::TomlTableExt, state::State}; use convert_case::{Case, Casing}; diff --git a/zino-core/src/database/mutation.rs b/zino-core/src/orm/mutation.rs similarity index 100% rename from zino-core/src/database/mutation.rs rename to zino-core/src/orm/mutation.rs diff --git a/zino-core/src/database/mysql.rs b/zino-core/src/orm/mysql.rs similarity index 100% rename from zino-core/src/database/mysql.rs rename to zino-core/src/orm/mysql.rs diff --git a/zino-core/src/database/postgres.rs b/zino-core/src/orm/postgres.rs similarity index 100% rename from zino-core/src/database/postgres.rs rename to zino-core/src/orm/postgres.rs diff --git a/zino-core/src/database/query.rs b/zino-core/src/orm/query.rs similarity index 100% rename from zino-core/src/database/query.rs rename to zino-core/src/orm/query.rs diff --git a/zino-core/src/database/schema.rs b/zino-core/src/orm/schema.rs similarity index 100% rename from zino-core/src/database/schema.rs rename to zino-core/src/orm/schema.rs diff --git a/zino-core/src/database/sqlite.rs b/zino-core/src/orm/sqlite.rs similarity index 100% rename from zino-core/src/database/sqlite.rs rename to zino-core/src/orm/sqlite.rs diff --git a/zino-core/src/view/mod.rs b/zino-core/src/view/mod.rs index 66693346..b47ad7db 100644 --- a/zino-core/src/view/mod.rs +++ b/zino-core/src/view/mod.rs @@ -1,4 +1,13 @@ //! Building HTML views using templates. +//! +//! # Supported template engines +//! +//! The following optional features are available: +//! +//! | Feature flag | Description | Default? | +//! |------------------|------------------------------------------------------|----------| +//! | `view-minijinja` | Enables the `minijinja` template engine. | No | +//! | `view-tera` | Enables the `tera` template engine. | No | use crate::{application::Application, extension::TomlTableExt}; use std::path::Path; diff --git a/zino-derive/src/lib.rs b/zino-derive/src/lib.rs index eb1489e6..b3dd7042 100644 --- a/zino-derive/src/lib.rs +++ b/zino-derive/src/lib.rs @@ -22,7 +22,7 @@ use syn::{parse_macro_input, Data, DeriveInput, Fields}; mod parser; -/// Derives the [`Schema`](zino_core::database::Schema) trait. +/// Derives the [`Schema`](zino_core::orm::Schema) trait. #[proc_macro_derive(Schema, attributes(schema))] pub fn derive_schema(item: TokenStream) -> TokenStream { /// Integer types @@ -224,9 +224,9 @@ pub fn derive_schema(item: TokenStream) -> TokenStream { }; let output = quote! { use zino_core::{ - database::{self, ConnectionPool, Schema}, error::Error as ZinoError, model::{schema, Column}, + orm::{self, ConnectionPool, Schema}, }; static #avro_schema: std::sync::LazyLock = std::sync::LazyLock::new(|| { @@ -370,7 +370,7 @@ pub fn derive_schema(item: TokenStream) -> TokenStream { TokenStream::from(output) } -/// Derives the [`ModelAccessor`](zino_core::database::ModelAccessor) trait. +/// Derives the [`ModelAccessor`](zino_core::orm::ModelAccessor) trait. #[proc_macro_derive(ModelAccessor, attributes(schema))] pub fn derive_model_accessor(item: TokenStream) -> TokenStream { // Input @@ -861,8 +861,8 @@ pub fn derive_model_accessor(item: TokenStream) -> TokenStream { let model_user_id_type = format_ident!("{}", user_id_type); let output = quote! { use zino_core::{ - database::{ModelAccessor, ModelHelper as _}, model::Query, + orm::{ModelAccessor, ModelHelper as _}, request::Validation as ZinoValidation, Map as ZinoMap, }; @@ -949,32 +949,32 @@ pub fn derive_decode_row(item: TokenStream) -> TokenStream { } if type_name == "Map" { decode_model_fields.push(quote! { - if let JsonValue::Object(map) = database::decode(row, #name)? { + if let JsonValue::Object(map) = orm::decode(row, #name)? { model.#ident = map; } }); } else if parser::check_vec_type(&type_name) { mysql_decode_model_fields.push(quote! { - let value = database::decode::(row, #name)?; + let value = orm::decode::(row, #name)?; if let Some(vec) = value.parse_array() { model.#ident = vec; } }); postgres_decode_model_fields.push(quote! { - model.#ident = database::decode(row, #name)?; + model.#ident = orm::decode(row, #name)?; }); } else if UNSIGNED_INTEGER_TYPES.contains(&type_name.as_str()) { let integer_type_ident = format_ident!("{}", type_name.replace('u', "i")); postgres_decode_model_fields.push(quote! { - let value = database::decode::<#integer_type_ident>(row, #name)?; + let value = orm::decode::<#integer_type_ident>(row, #name)?; model.#ident = value.try_into()?; }); mysql_decode_model_fields.push(quote! { - model.#ident = database::decode(row, #name)?; + model.#ident = orm::decode(row, #name)?; }); } else { decode_model_fields.push(quote! { - model.#ident = database::decode(row, #name)?; + model.#ident = orm::decode(row, #name)?; }); } } @@ -983,10 +983,7 @@ pub fn derive_decode_row(item: TokenStream) -> TokenStream { // Output let output = quote! { - use zino_core::{ - database::DatabaseRow, - model::DecodeRow, - }; + use zino_core::{model::DecodeRow, orm::DatabaseRow}; impl DecodeRow for #name { type Error = zino_core::error::Error; diff --git a/zino-model/src/lib.rs b/zino-model/src/lib.rs index 2cdf1b90..82a4626b 100644 --- a/zino-model/src/lib.rs +++ b/zino-model/src/lib.rs @@ -11,6 +11,7 @@ //! [`zino`]: https://github.com/photino/zino #![allow(async_fn_in_trait)] +#![allow(stable_features)] #![doc(html_favicon_url = "https://photino.github.io/zino-docs-zh/assets/zino-logo.png")] #![doc(html_logo_url = "https://photino.github.io/zino-docs-zh/assets/zino-logo.svg")] #![feature(async_fn_in_trait)] diff --git a/zino-model/src/user/jwt_auth.rs b/zino-model/src/user/jwt_auth.rs index f8654ba2..56d628c4 100644 --- a/zino-model/src/user/jwt_auth.rs +++ b/zino-model/src/user/jwt_auth.rs @@ -1,11 +1,11 @@ use std::{fmt::Display, str::FromStr}; use zino_core::{ auth::JwtClaims, - database::{ModelAccessor, ModelHelper}, datetime::DateTime, error::Error, extension::JsonObjectExt, model::Query, + orm::{ModelAccessor, ModelHelper}, Map, Uuid, }; diff --git a/zino-model/src/user/mod.rs b/zino-model/src/user/mod.rs index 484167b5..07ea0b99 100644 --- a/zino-model/src/user/mod.rs +++ b/zino-model/src/user/mod.rs @@ -5,11 +5,11 @@ use serde::{Deserialize, Serialize}; use std::sync::LazyLock; use zino_core::{ auth::{AccessKeyId, UserSession}, - database::ModelHelper, datetime::DateTime, error::Error, extension::JsonObjectExt, model::{Model, ModelHooks}, + orm::ModelHelper, request::Validation, Map, Uuid, }; diff --git a/zino/Cargo.toml b/zino/Cargo.toml index 1ad6c95a..66f194a9 100644 --- a/zino/Cargo.toml +++ b/zino/Cargo.toml @@ -57,7 +57,7 @@ parking_lot = "0.12.1" serde = "1.0.189" serde_json = "1.0.107" toml = "0.8.2" -tracing = "0.1.39" +tracing = "0.1.40" [dependencies.actix-cors] version = "0.6.4" diff --git a/zino/src/controller/mod.rs b/zino/src/controller/mod.rs index 41fd3858..72a9c61c 100644 --- a/zino/src/controller/mod.rs +++ b/zino/src/controller/mod.rs @@ -39,9 +39,9 @@ pub trait DefaultController { #[cfg(any(feature = "actix", feature = "axum"))] #[cfg(feature = "orm")] use zino_core::{ - database::{ModelAccessor, ModelHelper}, extension::JsonObjectExt, model::{ModelHooks, Query}, + orm::{ModelAccessor, ModelHelper}, request::RequestContext, response::{ExtractRejection, Rejection, StatusCode}, JsonValue, Map, diff --git a/zino/src/lib.rs b/zino/src/lib.rs index 9c058103..a1a44a76 100644 --- a/zino/src/lib.rs +++ b/zino/src/lib.rs @@ -50,6 +50,7 @@ //! [`dioxus-desktop`]: https://github.com/photino/zino/tree/main/examples/dioxus-desktop #![allow(async_fn_in_trait)] +#![allow(stable_features)] #![doc(html_favicon_url = "https://photino.github.io/zino-docs-zh/assets/zino-logo.png")] #![doc(html_logo_url = "https://photino.github.io/zino-docs-zh/assets/zino-logo.svg")] #![feature(async_fn_in_trait)] diff --git a/zino/src/prelude/mod.rs b/zino/src/prelude/mod.rs index a307f259..41fdda85 100644 --- a/zino/src/prelude/mod.rs +++ b/zino/src/prelude/mod.rs @@ -12,7 +12,8 @@ pub use zino_core::{ error::Error, extension::{JsonObjectExt, JsonValueExt, TomlTableExt}, file::NamedFile, - model::{Model, ModelHooks, Mutation, MutationBuilder, Query, QueryBuilder, QueryContext}, + json, + model::{Model, ModelHooks, Mutation, Query, QueryContext}, reject, request::{RequestContext, Validation}, response::{ExtractRejection, Rejection, StatusCode, WebHook}, @@ -23,4 +24,4 @@ pub use zino_core::{ #[cfg(feature = "orm")] #[doc(no_inline)] -pub use zino_core::database::{ModelAccessor, ModelHelper, Schema}; +pub use zino_core::orm::{ModelAccessor, ModelHelper, Schema};