Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat #1

Merged
merged 6 commits into from
Aug 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .cargo/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@
RUST_LOG = "info,ultimate=debug,ultimate_common=debug"

[alias]
check-all = "check --all-features"
clippy-all = "clippy --all-features -- -D warnings"
check-all = "check --all-features"

# 设置 rustc 编译器参数
# [build]
# rustflags = ["--cfg", "uuid_unstable"]
13 changes: 9 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -97,9 +97,9 @@ sqlx = { version = "0.7", features = [
"rust_decimal",
"json",
] }
modql = { version = "=0.4.0-rc.6", features = ["with-sea-query"] }
sea-query = { version = "0.31.0-rc", features = ["attr"] }
sea-query-binder = { version = "0.6.0-rc", features = [
modql = { version = "0.4.0-rc", features = ["with-sea-query"] }
sea-query = { version = "0.31", features = ["attr"] }
sea-query-binder = { version = "0.6", features = [
"sqlx-postgres",
"with-uuid",
"with-chrono",
Expand All @@ -117,7 +117,12 @@ headers = "0.4"
mime = "0.3"
reqwest = { version = "0.12", features = ["json"] }
hyper = "1"
tower-http = { version = "0.5", features = ["fs"] }
tower-http = { version = "0.5", features = [
"fs",
"trace",
"cors",
"compression-full",
] }
tower-cookies = "0.10"
cookie = "0.18"
axum = { version = "0.7", features = ["macros", "form"] }
Expand Down
13 changes: 12 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,16 @@ Rust 实用工具库,微服务融合……
- [crates](crates/): 工具库、组件库,可以包含对第 3 方服务的依赖。
- [ultimates](ultimates/): ultimate 融合库。比如:数据库、消息系统等,可以放置类似 `spring-boot` 一样的 **starter**。

## 开发

自动编译

```sh
cargo watch -d 2 -s 'cargo clippy-all && cargo build'
```

静态检查

```sh
cargo clippy-all && cargo check-all```
cargo clippy-all && cargo check-all
```
80 changes: 62 additions & 18 deletions ultimates/ultimate-db/src/base/crud_fns.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use sqlx::FromRow;
use sqlx::Row;

use crate::base::{prep_fields_for_create, prep_fields_for_update, CommonIden, DbBmc};
use crate::{Error, Result};
use crate::{Error, Page, PagePayload, Pagination, Result};
use crate::{Id, ModelManager};

use super::check_number_of_affected;
Expand Down Expand Up @@ -68,13 +68,11 @@ where
let (sql, values) = query.build_sqlx(PostgresQueryBuilder);
let sqlx_query = sqlx::query_as_with::<_, (i64,), _>(&sql, values);

mm.dbx().begin_txn().await?;
let rows = mm.dbx().fetch_all(sqlx_query).await?;
for row in rows {
let (id,): (i64,) = row;
ids.push(id);
}
mm.dbx().commit_txn().await?;

Ok(ids)
}
Expand Down Expand Up @@ -228,7 +226,22 @@ where
Ok(count)
}

pub async fn update<MC, E>(mm: &ModelManager, id: Id, data: E) -> Result<()>
pub async fn page<MC, E, F>(mm: &ModelManager, pagination: Pagination, filter: Option<F>) -> Result<PagePayload<E>>
where
MC: DbBmc,
F: Into<FilterGroups>,
E: for<'r> FromRow<'r, PgRow> + Unpin + Send,
E: HasSeaFields,
{
let filter: Option<FilterGroups> = filter.map(|f| f.into());

let total_size = count::<MC, _>(mm, filter.clone()).await?;
let records = list::<MC, E, _>(mm, filter, Some((&pagination).into())).await?;

Ok(PagePayload::new(Page::new(&pagination, total_size), records))
}

pub async fn update_by_id<MC, E>(mm: &ModelManager, id: Id, data: E) -> Result<()>
where
MC: DbBmc,
E: HasSeaFields,
Expand All @@ -255,7 +268,38 @@ where
_check_result::<MC>(count, id)
}

pub async fn delete<MC>(mm: &ModelManager, id: Id) -> Result<()>
/// 根据过滤条件更新,返回更新的记录数
pub async fn update<MC, E, F>(mm: &ModelManager, filter: F, data: E) -> Result<u64>
where
MC: DbBmc,
F: Into<FilterGroups>,
E: HasSeaFields,
{
let ctx = mm.ctx_ref()?;

// -- Prep Fields
let mut fields = data.not_none_sea_fields();
if MC::has_modification_timestamps() {
fields = prep_fields_for_update::<MC>(fields, ctx);
}

// -- Build query
let fields = fields.for_sea_update();
let mut query = Query::update();
query.table(MC::table_ref()).values(fields);
let filters: FilterGroups = filter.into();
let cond: Condition = filters.try_into()?;
query.cond_where(cond);

// -- Execute query
let (sql, values) = query.build_sqlx(PostgresQueryBuilder);
let sqlx_query = sqlx::query_with(&sql, values);
let count = mm.dbx().execute(sqlx_query).await?;

Ok(count)
}

pub async fn delete_by_id<MC>(mm: &ModelManager, id: Id) -> Result<()>
where
MC: DbBmc,
{
Expand Down Expand Up @@ -290,19 +334,7 @@ where
_check_result::<MC>(count, id)
}

/// Check result
fn _check_result<MC>(count: u64, id: Id) -> Result<()>
where
MC: DbBmc,
{
if count == 0 {
Err(Error::EntityNotFound { schema: MC::SCHEMA, entity: MC::TABLE, id })
} else {
Ok(())
}
}

pub async fn delete_many<MC>(mm: &ModelManager, ids: Vec<Id>) -> Result<u64>
pub async fn delete_by_ids<MC>(mm: &ModelManager, ids: Vec<Id>) -> Result<u64>
where
MC: DbBmc,
{
Expand Down Expand Up @@ -346,3 +378,15 @@ where
Ok(ListOptions { limit: Some(MC::LIST_LIMIT_DEFAULT), offset: None, order_bys: Some("id".into()) })
}
}

/// Check result
fn _check_result<MC>(count: u64, id: Id) -> Result<()>
where
MC: DbBmc,
{
if count == 0 {
Err(Error::EntityNotFound { schema: MC::SCHEMA, entity: MC::TABLE, id })
} else {
Ok(())
}
}
24 changes: 16 additions & 8 deletions ultimates/ultimate-db/src/base/macro_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,9 +61,9 @@ macro_rules! generate_common_bmc_fns {
pub async fn list(
mm: &ultimate_db::ModelManager,
filter: Vec<$filter>,
list_options: Option<modql::filter::ListOptions>,
pagination: Option<&ultimate_db::Pagination>,
) -> ultimate_db::Result<Vec<$entity>> {
ultimate_db::base::list::<Self, _, _>(mm, Some(filter), list_options).await
ultimate_db::base::list::<Self, _, _>(mm, Some(filter), pagination.map(Into::into)).await
}

pub async fn count(
Expand All @@ -72,26 +72,34 @@ macro_rules! generate_common_bmc_fns {
) -> ultimate_db::Result<i64> {
ultimate_db::base::count::<Self, _>(mm, Some(filter)).await
}

pub async fn page(
mm: &ultimate_db::ModelManager,
pagination: ultimate_db::Pagination,
filter: Vec<$filter>,
) -> ultimate_db::Result<ultimate_db::PagePayload<$entity>> {
ultimate_db::base::page::<Self, _, _>(mm, pagination, Some(filter)).await
}
)?

$(
pub async fn update(
pub async fn update_by_id(
mm: &ultimate_db::ModelManager,
id: impl Into<ultimate_db::Id>,
entity_u: $for_update,
) -> ultimate_db::Result<()> {
ultimate_db::base::update::<Self, _>(mm, id.into(), entity_u).await
ultimate_db::base::update_by_id::<Self, _>(mm, id.into(), entity_u).await
}
)?

pub async fn delete(
pub async fn delete_by_id(
mm: &ultimate_db::ModelManager,
id: impl Into<ultimate_db::Id>,
) -> ultimate_db::Result<()> {
ultimate_db::base::delete::<Self>(mm, id.into()).await
ultimate_db::base::delete_by_id::<Self>(mm, id.into()).await
}

pub async fn delete_many<V, I>(
pub async fn delete_by_ids<V, I>(
mm: &ultimate_db::ModelManager,
ids: I,
) -> ultimate_db::Result<u64>
Expand All @@ -100,7 +108,7 @@ macro_rules! generate_common_bmc_fns {
I: IntoIterator<Item = V>,
{
let ids = ids.into_iter().map(|v| v.into()).collect();
ultimate_db::base::delete_many::<Self>(mm, ids).await
ultimate_db::base::delete_by_ids::<Self>(mm, ids).await
}
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
use derive_more::derive::Display;
use modql::{
field::HasSeaFields,
filter::{FilterNode, ListOptions, OrderBys},
};
use modql::{field::HasSeaFields, filter::FilterNode};
use sea_query::SimpleExpr;
use serde::{Deserialize, Serialize};
use sqlx::{postgres::PgRow, FromRow};
Expand Down Expand Up @@ -31,6 +28,12 @@ impl Id {
}
}

impl From<Id> for FilterNode {
fn from(id: Id) -> Self {
id.to_filter_node("id")
}
}

impl From<Id> for SimpleExpr {
fn from(value: Id) -> Self {
match value {
Expand Down Expand Up @@ -74,71 +77,6 @@ where
ids.into_iter().map(|v| v.into()).collect()
}

#[derive(Serialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Page {
pub page: i64,
pub page_size: i64,
pub total_size: i64,
pub total_page: i64,
}

impl Page {
pub fn new(page: &Pagination, total_size: i64) -> Self {
let total_page = if total_size == 0 { 0 } else { (total_size + page.page_size - 1) / page.page_size };
Self { page: page.page, page_size: page.page_size, total_size, total_page }
}
}

#[derive(Debug, Clone, Deserialize)]
#[cfg_attr(feature = "utoipa", derive(utoipa::ToSchema))]
pub struct Pagination {
#[serde(default = "default_page")]
pub page: i64,

#[serde(default = "default_page_size")]
pub page_size: i64,

pub order_bys: Option<OrderBys>,
}

// pub static DEFAULT_PAGE_INFO: LazyLock<PageInfo> = LazyLock::new(|| PageInfo::default());

impl Pagination {
pub fn offset(&self) -> i64 {
if self.page < 2 {
return 0;
}
self.page_size * (self.page - 1)
}
}

impl Default for Pagination {
fn default() -> Self {
Self { page: default_page(), page_size: default_page_size(), order_bys: Default::default() }
}
}

impl From<Pagination> for ListOptions {
fn from(value: Pagination) -> Self {
ListOptions { limit: Some(value.page_size), offset: Some(value.offset()), order_bys: value.order_bys }
}
}

impl From<&Pagination> for ListOptions {
fn from(value: &Pagination) -> Self {
ListOptions { limit: Some(value.page_size), offset: Some(value.offset()), order_bys: value.order_bys.clone() }
}
}

fn default_page() -> i64 {
1
}

fn default_page_size() -> i64 {
20
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
9 changes: 6 additions & 3 deletions ultimates/ultimate-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ pub mod acs;
pub mod auth;
pub mod base;
mod error;
mod id;
mod model_manager;
pub mod modql_utils;
mod modql_utils;
mod page;
pub mod store;
mod types;

pub use error::{Error, Result};
pub use id::*;
pub use model_manager::*;
pub use types::*;
pub use modql_utils::*;
pub use page::*;

#[derive(Clone)]
pub struct DbState {
Expand Down
24 changes: 24 additions & 0 deletions ultimates/ultimate-db/src/modql_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,27 @@ use ultimate_common::time::UtcDateTime;
pub fn time_to_sea_value(json_value: serde_json::Value) -> modql::filter::SeaResult<sea_query::Value> {
Ok(UtcDateTime::deserialize(json_value)?.into())
}

#[cfg(feature = "utoipa")]
pub fn op_vals_integer_schema() -> utoipa::openapi::Object {
utoipa::openapi::ObjectBuilder::new()
.schema_type(utoipa::openapi::SchemaType::Object)
.description(Some("opvalfloat64"))
.build()
}

#[cfg(feature = "utoipa")]
pub fn op_vals_string_schema() -> utoipa::openapi::Object {
utoipa::openapi::ObjectBuilder::new()
.schema_type(utoipa::openapi::SchemaType::String)
.description(Some("https://github.com/jeremychone/rust-modql?tab=readme-ov-file#opvalstring-operators"))
.build()
}

#[cfg(feature = "utoipa")]
pub fn op_vals_bool_schema() -> utoipa::openapi::Object {
utoipa::openapi::ObjectBuilder::new()
.schema_type(utoipa::openapi::SchemaType::Boolean)
.description(Some("https://github.com/jeremychone/rust-modql?tab=readme-ov-file#opvalbool-operators"))
.build()
}
Loading
Loading