#[cfg(feature = "mongo")]
pub mod mongo;
#[cfg(feature = "mongo")]
pub use mongo::*;
use chrono::{DateTime, Utc};
use sea_orm::entity::prelude::*;
use serde::{Deserialize, Serialize};
pub trait BaseEntity: EntityTrait {
fn id_column() -> Self::Column;
fn create_time_column() -> Self::Column;
fn update_time_column() -> Self::Column;
}
pub trait SoftDeleteEntity: BaseEntity {
fn delete_time_column() -> Self::Column;
}
pub trait TenantEntity: BaseEntity {
fn tenant_id_column() -> Self::Column;
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct BaseFields {
#[serde(rename = "createTime")]
pub create_time: Option<DateTime<Utc>>,
#[serde(rename = "updateTime")]
pub update_time: Option<DateTime<Utc>>,
}
impl Default for BaseFields {
fn default() -> Self {
let now = Utc::now();
Self {
create_time: Some(now),
update_time: Some(now),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct SoftDeleteFields {
#[serde(rename = "deleteTime", skip_serializing_if = "Option::is_none")]
pub delete_time: Option<DateTime<Utc>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Default)]
pub struct TenantFields {
#[serde(rename = "tenantId", skip_serializing_if = "Option::is_none")]
pub tenant_id: Option<i64>,
}
pub type Id = i64;
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct PageQuery {
#[serde(default = "default_page")]
pub page: u64,
#[serde(default = "default_size")]
pub size: u64,
pub order: Option<String>,
pub sort: Option<String>,
#[serde(rename = "keyWord")]
pub key_word: Option<String>,
}
fn default_page() -> u64 {
1
}
fn default_size() -> u64 {
20
}
impl PageQuery {
pub fn offset(&self) -> u64 {
(self.page.saturating_sub(1)) * self.size
}
pub fn is_asc(&self) -> bool {
self.sort
.as_ref()
.map(|s| s.to_lowercase() == "asc")
.unwrap_or(false)
}
}
#[derive(Debug, Clone, Serialize, Deserialize, Default)]
pub struct ListQuery {
pub order: Option<String>,
pub sort: Option<String>,
#[serde(rename = "keyWord")]
pub key_word: Option<String>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct DeleteParam {
pub ids: Vec<Id>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AddResult {
pub id: Id,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct BatchAddResult {
pub ids: Vec<Id>,
}
#[derive(Debug, Clone, Default)]
pub struct QueryOption {
pub key_word_like_fields: Vec<String>,
pub select: Vec<String>,
pub field_like: Vec<FieldCondition>,
pub field_eq: Vec<FieldCondition>,
pub order_by: Vec<(String, bool)>, pub joins: Vec<JoinOption>,
pub where_and: Vec<String>,
pub left_join: Vec<JoinOption>,
pub extra_where: Vec<WhereFragment>,
}
impl QueryOption {
pub fn new() -> Self {
Self::default()
}
pub fn key_word_like_fields<I, S>(mut self, fields: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.key_word_like_fields = fields.into_iter().map(Into::into).collect();
self
}
pub fn select<I, S>(mut self, fields: I) -> Self
where
I: IntoIterator<Item = S>,
S: Into<String>,
{
self.select = fields.into_iter().map(Into::into).collect();
self
}
pub fn add_field_eq(
mut self,
column: impl Into<String>,
request_param: impl Into<String>,
) -> Self {
self.field_eq
.push(FieldCondition::with_param(column, request_param));
self
}
pub fn add_field_like(
mut self,
column: impl Into<String>,
request_param: impl Into<String>,
) -> Self {
self.field_like
.push(FieldCondition::with_param(column, request_param));
self
}
pub fn add_order_by(mut self, column: impl Into<String>, asc: bool) -> Self {
self.order_by.push((column.into(), asc));
self
}
pub fn add_left_join(
mut self,
entity: impl Into<String>,
alias: impl Into<String>,
condition: impl Into<String>,
join_type: JoinType,
) -> Self {
self.left_join.push(JoinOption {
entity: entity.into(),
alias: alias.into(),
condition: condition.into(),
join_type,
});
self
}
pub fn add_where_and(mut self, cond: impl Into<String>) -> Self {
self.where_and.push(cond.into());
self
}
pub fn add_where_raw<I, V>(mut self, sql: impl Into<String>, params: I) -> Self
where
I: IntoIterator<Item = V>,
V: Into<serde_json::Value>,
{
self.extra_where.push(WhereFragment {
sql: sql.into(),
params: params.into_iter().map(Into::into).collect(),
});
self
}
pub fn add_where_with<F>(mut self, f: F) -> Self
where
F: FnOnce(WhereBuilder) -> WhereBuilder,
{
let builder = f(WhereBuilder::new());
self.extra_where.extend(builder.build());
self
}
}
#[derive(Debug, Clone)]
pub struct FieldCondition {
pub column: String,
pub request_param: String,
}
impl FieldCondition {
pub fn new(column: impl Into<String>) -> Self {
let col = column.into();
Self {
request_param: col.clone(),
column: col,
}
}
pub fn with_param(column: impl Into<String>, request_param: impl Into<String>) -> Self {
Self {
column: column.into(),
request_param: request_param.into(),
}
}
}
#[derive(Debug, Clone)]
pub struct JoinOption {
pub entity: String,
pub alias: String,
pub condition: String,
pub join_type: JoinType,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum JoinType {
Inner,
#[default]
Left,
}
#[derive(Debug, Clone)]
pub struct WhereFragment {
pub sql: String,
pub params: Vec<serde_json::Value>,
}
#[derive(Default)]
pub struct WhereBuilder {
frags: Vec<WhereFragment>,
}
impl WhereBuilder {
pub fn new() -> Self {
Self { frags: Vec::new() }
}
pub fn eq(mut self, column: impl Into<String>, value: impl Into<serde_json::Value>) -> Self {
self.frags.push(WhereFragment {
sql: format!("{} = ?", column.into()),
params: vec![value.into()],
});
self
}
pub fn like(mut self, column: impl Into<String>, value: impl Into<String>) -> Self {
self.frags.push(WhereFragment {
sql: format!("{} LIKE ?", column.into()),
params: vec![serde_json::Value::String(format!("%{}%", value.into()))],
});
self
}
pub fn raw<I, V>(mut self, sql: impl Into<String>, params: I) -> Self
where
I: IntoIterator<Item = V>,
V: Into<serde_json::Value>,
{
self.frags.push(WhereFragment {
sql: sql.into(),
params: params.into_iter().map(Into::into).collect(),
});
self
}
pub fn build(self) -> Vec<WhereFragment> {
self.frags
}
}