feat(project): init
This commit is contained in:
174
src/infrastructure/repositories/column.rs
Normal file
174
src/infrastructure/repositories/column.rs
Normal file
@@ -0,0 +1,174 @@
|
||||
use crate::domain::models::Column;
|
||||
use common_telemetry::AppError;
|
||||
use sqlx::PgPool;
|
||||
use uuid::Uuid;
|
||||
|
||||
pub async fn create_column(
|
||||
pool: &PgPool,
|
||||
tenant_id: Uuid,
|
||||
name: String,
|
||||
slug: String,
|
||||
description: Option<String>,
|
||||
parent_id: Option<Uuid>,
|
||||
sort_order: i32,
|
||||
) -> Result<Column, AppError> {
|
||||
let column = sqlx::query_as::<_, Column>(
|
||||
r#"
|
||||
INSERT INTO cms_columns (tenant_id, name, slug, description, parent_id, sort_order)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING tenant_id, id, name, slug, description, parent_id, sort_order, created_at, updated_at
|
||||
"#,
|
||||
)
|
||||
.bind(tenant_id)
|
||||
.bind(name)
|
||||
.bind(slug)
|
||||
.bind(description)
|
||||
.bind(parent_id)
|
||||
.bind(sort_order)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
Ok(column)
|
||||
}
|
||||
|
||||
pub async fn get_column(pool: &PgPool, tenant_id: Uuid, id: Uuid) -> Result<Column, AppError> {
|
||||
let column = sqlx::query_as::<_, Column>(
|
||||
r#"
|
||||
SELECT tenant_id, id, name, slug, description, parent_id, sort_order, created_at, updated_at
|
||||
FROM cms_columns
|
||||
WHERE tenant_id = $1 AND id = $2
|
||||
"#,
|
||||
)
|
||||
.bind(tenant_id)
|
||||
.bind(id)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
Ok(column)
|
||||
}
|
||||
|
||||
pub async fn update_column(
|
||||
pool: &PgPool,
|
||||
tenant_id: Uuid,
|
||||
id: Uuid,
|
||||
name: Option<String>,
|
||||
slug: Option<String>,
|
||||
description: Option<Option<String>>,
|
||||
parent_id: Option<Option<Uuid>>,
|
||||
sort_order: Option<i32>,
|
||||
) -> Result<Column, AppError> {
|
||||
let column = sqlx::query_as::<_, Column>(
|
||||
r#"
|
||||
UPDATE cms_columns
|
||||
SET
|
||||
name = COALESCE($3, name),
|
||||
slug = COALESCE($4, slug),
|
||||
description = COALESCE($5, description),
|
||||
parent_id = COALESCE($6, parent_id),
|
||||
sort_order = COALESCE($7, sort_order),
|
||||
updated_at = now()
|
||||
WHERE tenant_id = $1 AND id = $2
|
||||
RETURNING tenant_id, id, name, slug, description, parent_id, sort_order, created_at, updated_at
|
||||
"#,
|
||||
)
|
||||
.bind(tenant_id)
|
||||
.bind(id)
|
||||
.bind(name)
|
||||
.bind(slug)
|
||||
.bind(description)
|
||||
.bind(parent_id)
|
||||
.bind(sort_order)
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
Ok(column)
|
||||
}
|
||||
|
||||
pub async fn delete_column(pool: &PgPool, tenant_id: Uuid, id: Uuid) -> Result<(), AppError> {
|
||||
let res = sqlx::query(
|
||||
r#"
|
||||
DELETE FROM cms_columns
|
||||
WHERE tenant_id = $1 AND id = $2
|
||||
"#,
|
||||
)
|
||||
.bind(tenant_id)
|
||||
.bind(id)
|
||||
.execute(pool)
|
||||
.await?;
|
||||
|
||||
if res.rows_affected() == 0 {
|
||||
return Err(AppError::NotFound("column:not_found".into()));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ListColumnsQuery {
|
||||
pub page: u32,
|
||||
pub page_size: u32,
|
||||
pub search: Option<String>,
|
||||
pub parent_id: Option<Uuid>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, serde::Serialize, utoipa::ToSchema)]
|
||||
pub struct Paged<T> {
|
||||
pub items: Vec<T>,
|
||||
pub page: u32,
|
||||
pub page_size: u32,
|
||||
pub total: i64,
|
||||
}
|
||||
|
||||
pub async fn list_columns(
|
||||
pool: &PgPool,
|
||||
tenant_id: Uuid,
|
||||
q: ListColumnsQuery,
|
||||
) -> Result<Paged<Column>, AppError> {
|
||||
let page = q.page.max(1);
|
||||
let page_size = q.page_size.clamp(1, 200);
|
||||
let offset = ((page - 1) * page_size) as i64;
|
||||
let limit = page_size as i64;
|
||||
|
||||
let like = q.search.map(|s| format!("%{}%", s));
|
||||
|
||||
let total: i64 = sqlx::query_scalar(
|
||||
r#"
|
||||
SELECT COUNT(*)
|
||||
FROM cms_columns
|
||||
WHERE tenant_id = $1
|
||||
AND ($2::uuid IS NULL OR parent_id = $2)
|
||||
AND ($3::text IS NULL OR name ILIKE $3 OR slug ILIKE $3)
|
||||
"#,
|
||||
)
|
||||
.bind(tenant_id)
|
||||
.bind(q.parent_id)
|
||||
.bind(like.as_deref())
|
||||
.fetch_one(pool)
|
||||
.await?;
|
||||
|
||||
let items = sqlx::query_as::<_, Column>(
|
||||
r#"
|
||||
SELECT tenant_id, id, name, slug, description, parent_id, sort_order, created_at, updated_at
|
||||
FROM cms_columns
|
||||
WHERE tenant_id = $1
|
||||
AND ($2::uuid IS NULL OR parent_id = $2)
|
||||
AND ($3::text IS NULL OR name ILIKE $3 OR slug ILIKE $3)
|
||||
ORDER BY sort_order ASC, updated_at DESC
|
||||
OFFSET $4
|
||||
LIMIT $5
|
||||
"#,
|
||||
)
|
||||
.bind(tenant_id)
|
||||
.bind(q.parent_id)
|
||||
.bind(like.as_deref())
|
||||
.bind(offset)
|
||||
.bind(limit)
|
||||
.fetch_all(pool)
|
||||
.await?;
|
||||
|
||||
Ok(Paged {
|
||||
items,
|
||||
page,
|
||||
page_size,
|
||||
total,
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user