use crate::domain::error::AppResult; use crate::infrastructure::db::DbPool; use serde::{Deserialize, Serialize}; use sqlx::FromRow; #[derive(Debug, Serialize, Deserialize, FromRow, Clone)] pub struct ApiKeyRecord { pub key_id: String, pub merchant_id: String, pub name: String, pub secret_hash: String, pub scopes: serde_json::Value, pub last_used_at: Option, pub created_at: chrono::NaiveDateTime, } impl ApiKeyRecord { pub async fn find_by_id(pool: &DbPool, key_id: &str) -> AppResult> { let record = sqlx::query_as::<_, Self>("SELECT * FROM api_keys WHERE key_id = $1") .bind(key_id) .fetch_optional(pool) .await?; Ok(record) } pub async fn create(pool: &DbPool, record: &Self) -> AppResult<()> { sqlx::query( "INSERT INTO api_keys (key_id, merchant_id, name, secret_hash, scopes) VALUES ($1, $2, $3, $4, $5)" ) .bind(&record.key_id) .bind(&record.merchant_id) .bind(&record.name) .bind(&record.secret_hash) .bind(&record.scopes) .execute(pool) .await?; Ok(()) } pub async fn delete(pool: &DbPool, key_id: &str, merchant_id: &str) -> AppResult<()> { sqlx::query("DELETE FROM api_keys WHERE key_id = $1 AND merchant_id = $2") .bind(key_id) .bind(merchant_id) .execute(pool) .await?; Ok(()) } pub async fn list_for_merchant(pool: &DbPool, merchant_id: &str) -> AppResult> { let records = sqlx::query_as::<_, Self>( "SELECT * FROM api_keys WHERE merchant_id = $1 ORDER BY created_at DESC", ) .bind(merchant_id) .fetch_all(pool) .await?; Ok(records) } }