Skip to content

Commit

Permalink
Add more methods for QueryBuilder
Browse files Browse the repository at this point in the history
  • Loading branch information
photino committed Aug 6, 2023
1 parent 17680ac commit d943ab7
Show file tree
Hide file tree
Showing 16 changed files with 71 additions and 33 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ which emphasizes **simplicity**, **extensibility** and **productivity**.

[![Crates.io](https://img.shields.io/crates/v/zino)][zino]
[![Documentation](https://shields.io/docsrs/zino)][zino-docs]
[![Downloads](https://img.shields.io/crates/d/zino)][zino]
[![License](https://img.shields.io/crates/l/zino)][license]

## Highlights
Expand Down
2 changes: 1 addition & 1 deletion examples/actix-app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ serde_json = "1.0.104"
tracing = "0.1.37"

[dependencies.serde]
version = "1.0.178"
version = "1.0.180"
features = ["derive"]

[dependencies.zino]
Expand Down
6 changes: 3 additions & 3 deletions examples/actix-app/src/controller/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use zino::{prelude::*, Cluster, Request, Response, Result};
pub async fn upload(mut req: Request) -> Result {
let (mut body, files) = req.parse_form_data::<Map>().await?;

let dir = Cluster::project_dir().join("assets/uploads");
let dir = Cluster::relative_path("assets/uploads");
let expires = DateTime::now() + Duration::from_secs(600);
let mut encryption_duration = Duration::ZERO;
let mut uploads = Vec::new();
Expand Down Expand Up @@ -48,13 +48,13 @@ pub async fn decrypt(req: Request) -> Result {
let secret_key = SecretAccessKey::new(&access_key_id);
let security_token = req.parse_security_token(secret_key.as_ref())?;
if security_token.is_expired() {
reject!(req, forbidden, "the seurity token has expired");
reject!(req, forbidden, "the security token has expired");
}

let Some(file_name) = query.get_str("file_name") else {
reject!(req, "file_name", "it should be specified");
};
let file_path = Cluster::project_dir().join(format!("assets/uploads/{file_name}"));
let file_path = Cluster::relative_path(format!("assets/uploads/{file_name}"));

let mut file = NamedFile::try_from_local(file_path).extract(&req)?;
let decryption_start_time = Instant::now();
Expand Down
2 changes: 1 addition & 1 deletion examples/axum-app/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ serde_json = "1.0.104"
tracing = "0.1.37"

[dependencies.serde]
version = "1.0.178"
version = "1.0.180"
features = ["derive"]

[dependencies.zino]
Expand Down
6 changes: 3 additions & 3 deletions examples/axum-app/src/controller/file.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use zino::{prelude::*, Cluster, Request, Response, Result};
pub async fn upload(mut req: Request) -> Result {
let (mut body, files) = req.parse_form_data::<Map>().await?;

let dir = Cluster::project_dir().join("assets/uploads");
let dir = Cluster::relative_path("assets/uploads");
let expires = DateTime::now() + Duration::from_secs(600);
let mut encryption_duration = Duration::ZERO;
let mut uploads = Vec::new();
Expand Down Expand Up @@ -48,13 +48,13 @@ pub async fn decrypt(req: Request) -> Result {
let secret_key = SecretAccessKey::new(&access_key_id);
let security_token = req.parse_security_token(secret_key.as_ref())?;
if security_token.is_expired() {
reject!(req, forbidden, "the seurity token has expired");
reject!(req, forbidden, "the security token has expired");
}

let Some(file_name) = query.get_str("file_name") else {
reject!(req, "file_name", "it should be specified");
};
let file_path = Cluster::project_dir().join(format!("assets/uploads/{file_name}"));
let file_path = Cluster::relative_path(format!("assets/uploads/{file_name}"));

let mut file = NamedFile::try_from_local(file_path).extract(&req)?;
let decryption_start_time = Instant::now();
Expand Down
4 changes: 2 additions & 2 deletions zino-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ reqwest-tracing = "0.4.5"
rmp-serde = "1.1.2"
serde_qs = "0.12.0"
sha2 = "0.10.7"
sysinfo = "0.29.6"
sysinfo = "0.29.7"
task-local-extensions = "0.1.4"
toml = "0.7.6"
tracing = "0.1.37"
Expand Down Expand Up @@ -163,7 +163,7 @@ features = [
]

[dependencies.serde]
version = "1.0.178"
version = "1.0.180"
features = ["derive"]

[dependencies.serde_json]
Expand Down
13 changes: 12 additions & 1 deletion zino-core/src/application/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,12 @@ use crate::{
};
use reqwest::Response;
use serde::de::DeserializeOwned;
use std::{env, fs, path::PathBuf, sync::LazyLock, thread};
use std::{
env, fs,
path::{Path, PathBuf},
sync::LazyLock,
thread,
};
use toml::value::Table;
use utoipa::openapi::{Info, OpenApi, OpenApiBuilder};

Expand Down Expand Up @@ -151,6 +156,12 @@ pub trait Application {
LazyLock::force(&PROJECT_DIR)
}

/// Returns the path relative to the project directory.
#[inline]
fn relative_path<P: AsRef<Path>>(path: P) -> PathBuf {
PROJECT_DIR.join(path)
}

/// Returns the secret key for the application.
/// It should have at least 64 bytes.
///
Expand Down
10 changes: 7 additions & 3 deletions zino-core/src/database/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ pub(super) trait QueryExt<DB> {
}

/// Formats projection fields.
fn format_fields(&self) -> Cow<'_, str> {
fn format_projection(&self) -> Cow<'_, str> {
let fields = self.query_fields();
if fields.is_empty() {
"*".into()
Expand Down Expand Up @@ -133,9 +133,13 @@ pub(super) trait QueryExt<DB> {
expression += &format!("WHERE {}", conditions.join(" AND "));
};
if let Some(groups) = filters.parse_str_array("$group") {
let groups = groups.join(", ");
let groups = groups
.into_iter()
.map(Self::format_field)
.collect::<Vec<_>>()
.join(", ");
expression += &format!(" GROUP BY {groups}");
if let Some(JsonValue::Object(selection)) = filters.get("$match") {
if let Some(JsonValue::Object(selection)) = filters.get("$having") {
let condition = Self::format_selection::<M>(selection, " AND ");
expression += &format!(" HAVING {condition}");
}
Expand Down
18 changes: 9 additions & 9 deletions zino-core/src/database/schema.rs
Original file line number Diff line number Diff line change
Expand Up @@ -592,7 +592,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
Self::before_query(query).await?;

let table_name = Self::table_name();
let projection = query.format_fields();
let projection = query.format_projection();
let filters = query.format_filters::<Self>();
let sort = query.format_sort();
let pagination = query.format_pagination();
Expand Down Expand Up @@ -634,7 +634,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
Self::before_query(query).await?;

let table_name = Self::table_name();
let projection = query.format_fields();
let projection = query.format_projection();
let filters = query.format_filters::<Self>();
let sort = query.format_sort();
let sql = format!("SELECT {projection} FROM {table_name} {filters} {sort} LIMIT 1;");
Expand Down Expand Up @@ -677,7 +677,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
Self::before_query(query).await?;

let table_name = Self::table_name();
let projection = query.format_fields();
let projection = query.format_projection();
let filters = query.format_filters::<Self>();
let sort = query.format_sort();
let sql = format!("SELECT {projection} FROM {table_name} {filters} {sort} LIMIT 1;");
Expand All @@ -701,7 +701,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
Self::before_query(query).await?;

let table_name = Self::table_name();
let projection = query.format_fields();
let projection = query.format_projection();
let filters = query.format_filters::<Self>();
let sort = query.format_sort();
let pagination = query.format_pagination();
Expand Down Expand Up @@ -751,7 +751,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
}

let table_name = Self::table_name();
let projection = query.format_fields();
let projection = query.format_projection();
let filters = query.format_filters::<Self>();
let sql = format!("SELECT {projection} FROM {table_name} {filters};");

Expand Down Expand Up @@ -829,7 +829,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
}

let table_name = Self::table_name();
let projection = query.format_fields();
let projection = query.format_projection();
let filters = query.format_filters::<Self>();
let sql = format!("SELECT {projection} FROM {table_name} {filters};");

Expand Down Expand Up @@ -892,7 +892,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
let model_name = Query::format_field(Self::model_name());
let other_table_name = M::table_name();
let other_model_name = Query::format_field(M::model_name());
let projection = query.format_fields();
let projection = query.format_projection();
let filters = query.format_filters::<Self>();
let sort = query.format_sort();
let pagination = query.format_pagination();
Expand Down Expand Up @@ -1187,7 +1187,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
let table_name = Self::table_name();
let primary_key_name = Self::PRIMARY_KEY_NAME;
let query = Self::default_query();
let projection = query.format_fields();
let projection = query.format_projection();
let sql = if cfg!(feature = "orm-mysql") {
let placeholder = Query::placeholder(1);
format!(
Expand Down Expand Up @@ -1225,7 +1225,7 @@ pub trait Schema: 'static + Send + Sync + ModelHooks {
let table_name = Self::table_name();
let primary_key_name = Self::PRIMARY_KEY_NAME;
let query = Self::default_query();
let projection = query.format_fields();
let projection = query.format_projection();
let sql = if cfg!(feature = "orm-mysql") {
let placeholder = Query::placeholder(1);
format!(
Expand Down
2 changes: 1 addition & 1 deletion zino-core/src/model/mutation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl Mutation {
}
}

/// A builder for model mutations.
/// A builder type for model mutations.
#[derive(Debug, Default)]
pub struct MutationBuilder {
// Editable fields.
Expand Down
30 changes: 27 additions & 3 deletions zino-core/src/model/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -369,23 +369,47 @@ impl QueryBuilder {
.upsert(field.into(), Map::from_entry("$nin", list));
}

/// Adds a filter with the condition for a field whose value is within a given range.
pub fn and_between<S, T>(&mut self, field: S, min: T, max: T)
where
S: Into<String>,
T: Into<JsonValue>,
{
self.filters.upsert(
field.into(),
Map::from_entry("$range", vec![min.into(), max.into()]),
);
}

/// Adds a filter which groups rows that have the same values into summary rows.
#[inline]
pub fn group_by<T: Into<JsonValue>>(&mut self, fields: T) {
self.filters.upsert("$group", fields);
}

/// Adds a filter which can be used with aggregate functions.
#[inline]
pub fn having<T: Into<JsonValue>>(&mut self, selection: T) {
self.filters.upsert("$having", selection);
}

/// Adds a sort with the specific order.
#[inline]
pub fn order_by(&mut self, field: impl Into<SharedString>, descending: bool) -> &mut Self {
pub fn order_by<S: Into<SharedString>>(&mut self, field: S, descending: bool) -> &mut Self {
self.sort_order.push((field.into(), descending));
self
}

/// Adds a sort with the ascending order.
#[inline]
pub fn order_asc(&mut self, field: impl Into<SharedString>) -> &mut Self {
pub fn order_asc<S: Into<SharedString>>(&mut self, field: S) -> &mut Self {
self.sort_order.push((field.into(), false));
self
}

/// Adds a sort with the descending order.
#[inline]
pub fn order_desc(&mut self, field: impl Into<SharedString>) -> &mut Self {
pub fn order_desc<S: Into<SharedString>>(&mut self, field: S) -> &mut Self {
self.sort_order.push((field.into(), true));
self
}
Expand Down
2 changes: 1 addition & 1 deletion zino-derive/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ proc-macro = true
convert_case = "0.6.0"
proc-macro2 = "1.0.66"
quote = "1.0.32"
syn = "2.0.27"
syn = "2.0.28"

[dependencies.zino-core]
path = "../zino-core"
Expand Down
2 changes: 1 addition & 1 deletion zino-model/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ regex = "1.9.1"
strum_macros = "0.25.1"

[dependencies.serde]
version = "1.0.178"
version = "1.0.180"
features = ["derive"]

[dependencies.zino-core]
Expand Down
2 changes: 1 addition & 1 deletion zino/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ cfg-if = "1.0"
futures = "0.3.28"
hyper = "0.14.27"
parking_lot = "0.12.1"
serde = "1.0.178"
serde = "1.0.180"
serde_json = "1.0.104"
toml = "0.7.6"
tracing = "0.1.37"
Expand Down
2 changes: 1 addition & 1 deletion zino/src/application/actix_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ impl Application for ActixCluster {
// Server config
let mut body_limit = 100 * 1024 * 1024; // 100MB
let mut public_dir = PathBuf::new();
let default_public_dir = Self::project_dir().join("public");
let default_public_dir = Self::relative_path("public");
if let Some(server) = Self::config().get_table("server") {
if let Some(limit) = server.get_usize("body-limit") {
body_limit = limit;
Expand Down
2 changes: 1 addition & 1 deletion zino/src/application/axum_cluster.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ impl Application for AxumCluster {
let mut body_limit = 100 * 1024 * 1024; // 100MB
let mut request_timeout = Duration::from_secs(10); // 10 seconds
let mut public_dir = PathBuf::new();
let default_public_dir = Self::project_dir().join("public");
let default_public_dir = Self::relative_path("public");
if let Some(server) = Self::config().get_table("server") {
if let Some(limit) = server.get_usize("body-limit") {
body_limit = limit;
Expand Down

0 comments on commit d943ab7

Please sign in to comment.