refactor(data): limit query abstraction to postgres and sqlite

This commit is contained in:
Kayphoon
2026-05-17 15:40:44 +08:00
parent 77640d51a6
commit f29cca72ba
13 changed files with 498 additions and 563 deletions
@@ -1,5 +1,5 @@
use async_trait::async_trait;
use sqlx::{mysql::MySqlRow, MySql, QueryBuilder, Row};
use sqlx::{mysql::MySqlRow, Row};
use super::types::{
CreateManagementTokenRecord, ManagementTokenListQuery, ManagementTokenReadRepository,
@@ -10,7 +10,6 @@ use super::types::{
use crate::driver::mysql::MysqlPool;
use crate::error::SqlResultExt;
use crate::DataLayerError;
use aether_data_query::{push_eq, push_limit, push_limit_offset, push_optional_eq, WhereClause};
#[derive(Debug, Clone)]
pub struct MysqlManagementTokenRepository {
@@ -26,12 +25,8 @@ impl MysqlManagementTokenRepository {
&self,
token_id: &str,
) -> Result<Option<StoredManagementToken>, DataLayerError> {
let mut builder = QueryBuilder::<MySql>::new(TOKEN_COLUMNS);
let mut where_clause = WhereClause::new();
push_eq(&mut builder, &mut where_clause, "id", token_id.to_string());
push_limit(&mut builder, 1);
let row = builder
.build()
let row = sqlx::query(TOKEN_BY_ID_SQL)
.bind(token_id)
.fetch_optional(&self.pool)
.await
.map_sql_err()?;
@@ -39,7 +34,7 @@ impl MysqlManagementTokenRepository {
}
}
const TOKEN_COLUMNS: &str = r#"
const TOKEN_BY_ID_SQL: &str = r#"
SELECT
id,
user_id,
@@ -56,9 +51,11 @@ SELECT
created_at AS created_at_unix_ms,
updated_at AS updated_at_unix_secs
FROM management_tokens
WHERE id = ?
LIMIT 1
"#;
const TOKEN_WITH_USER_COLUMNS: &str = r#"
const LIST_MANAGEMENT_TOKENS_SQL: &str = r#"
SELECT
mt.id,
mt.user_id,
@@ -80,6 +77,69 @@ SELECT
u.role AS user_role
FROM management_tokens mt
JOIN users u ON u.id = mt.user_id
WHERE (? IS NULL OR mt.user_id = ?)
AND (? IS NULL OR mt.is_active = ?)
ORDER BY mt.created_at DESC, mt.id DESC
LIMIT ? OFFSET ?
"#;
const COUNT_MANAGEMENT_TOKENS_SQL: &str = r#"
SELECT COUNT(mt.id) AS total
FROM management_tokens mt
WHERE (? IS NULL OR mt.user_id = ?)
AND (? IS NULL OR mt.is_active = ?)
"#;
const GET_MANAGEMENT_TOKEN_WITH_USER_SQL: &str = r#"
SELECT
mt.id,
mt.user_id,
mt.name,
mt.description,
mt.token_prefix,
mt.allowed_ips,
mt.permissions,
mt.expires_at AS expires_at_unix_secs,
mt.last_used_at AS last_used_at_unix_secs,
mt.last_used_ip,
COALESCE(mt.usage_count, 0) AS usage_count,
mt.is_active,
mt.created_at AS created_at_unix_ms,
mt.updated_at AS updated_at_unix_secs,
u.id AS user_row_id,
u.email AS user_email,
u.username AS user_username,
u.role AS user_role
FROM management_tokens mt
JOIN users u ON u.id = mt.user_id
WHERE mt.id = ?
LIMIT 1
"#;
const GET_MANAGEMENT_TOKEN_WITH_USER_BY_HASH_SQL: &str = r#"
SELECT
mt.id,
mt.user_id,
mt.name,
mt.description,
mt.token_prefix,
mt.allowed_ips,
mt.permissions,
mt.expires_at AS expires_at_unix_secs,
mt.last_used_at AS last_used_at_unix_secs,
mt.last_used_ip,
COALESCE(mt.usage_count, 0) AS usage_count,
mt.is_active,
mt.created_at AS created_at_unix_ms,
mt.updated_at AS updated_at_unix_secs,
u.id AS user_row_id,
u.email AS user_email,
u.username AS user_username,
u.role AS user_role
FROM management_tokens mt
JOIN users u ON u.id = mt.user_id
WHERE mt.token_hash = ?
LIMIT 1
"#;
#[async_trait]
@@ -88,27 +148,23 @@ impl ManagementTokenReadRepository for MysqlManagementTokenRepository {
&self,
query: &ManagementTokenListQuery,
) -> Result<StoredManagementTokenListPage, DataLayerError> {
let mut count_builder =
QueryBuilder::<MySql>::new("SELECT COUNT(mt.id) AS total FROM management_tokens mt");
let mut count_where = WhereClause::new();
apply_management_token_filters(&mut count_builder, &mut count_where, query);
let total = count_builder
.build_query_scalar::<i64>()
let count_row = sqlx::query(COUNT_MANAGEMENT_TOKENS_SQL)
.bind(query.user_id.as_deref())
.bind(query.user_id.as_deref())
.bind(query.is_active)
.bind(query.is_active)
.fetch_one(&self.pool)
.await
.map_sql_err()?;
let total = count_row.try_get::<i64, _>("total").map_sql_err()?;
let mut list_builder = QueryBuilder::<MySql>::new(TOKEN_WITH_USER_COLUMNS);
let mut list_where = WhereClause::new();
apply_management_token_filters(&mut list_builder, &mut list_where, query);
list_builder.push(" ORDER BY mt.created_at DESC, mt.id DESC");
push_limit_offset(
&mut list_builder,
i64::try_from(query.limit).unwrap_or(i64::MAX),
i64::try_from(query.offset).unwrap_or(i64::MAX),
);
let rows = list_builder
.build()
let rows = sqlx::query(LIST_MANAGEMENT_TOKENS_SQL)
.bind(query.user_id.as_deref())
.bind(query.user_id.as_deref())
.bind(query.is_active)
.bind(query.is_active)
.bind(i64::try_from(query.limit).unwrap_or(i64::MAX))
.bind(i64::try_from(query.offset).unwrap_or(i64::MAX))
.fetch_all(&self.pool)
.await
.map_sql_err()?;
@@ -126,17 +182,8 @@ impl ManagementTokenReadRepository for MysqlManagementTokenRepository {
&self,
token_id: &str,
) -> Result<Option<StoredManagementTokenWithUser>, DataLayerError> {
let mut builder = QueryBuilder::<MySql>::new(TOKEN_WITH_USER_COLUMNS);
let mut where_clause = WhereClause::new();
push_eq(
&mut builder,
&mut where_clause,
"mt.id",
token_id.to_string(),
);
push_limit(&mut builder, 1);
let row = builder
.build()
let row = sqlx::query(GET_MANAGEMENT_TOKEN_WITH_USER_SQL)
.bind(token_id)
.fetch_optional(&self.pool)
.await
.map_sql_err()?;
@@ -147,17 +194,8 @@ impl ManagementTokenReadRepository for MysqlManagementTokenRepository {
&self,
token_hash: &str,
) -> Result<Option<StoredManagementTokenWithUser>, DataLayerError> {
let mut builder = QueryBuilder::<MySql>::new(TOKEN_WITH_USER_COLUMNS);
let mut where_clause = WhereClause::new();
push_eq(
&mut builder,
&mut where_clause,
"mt.token_hash",
token_hash.to_string(),
);
push_limit(&mut builder, 1);
let row = builder
.build()
let row = sqlx::query(GET_MANAGEMENT_TOKEN_WITH_USER_BY_HASH_SQL)
.bind(token_hash)
.fetch_optional(&self.pool)
.await
.map_sql_err()?;
@@ -165,15 +203,6 @@ impl ManagementTokenReadRepository for MysqlManagementTokenRepository {
}
}
fn apply_management_token_filters(
builder: &mut QueryBuilder<'_, MySql>,
where_clause: &mut WhereClause,
query: &ManagementTokenListQuery,
) {
push_optional_eq(builder, where_clause, "mt.user_id", query.user_id.clone());
push_optional_eq(builder, where_clause, "mt.is_active", query.is_active);
}
#[async_trait]
impl ManagementTokenWriteRepository for MysqlManagementTokenRepository {
async fn create_management_token(