use async_trait::async_trait; use picloud_orchestrator_core::{ResolverError, ScriptResolver}; use picloud_shared::{Script, ScriptId}; use sqlx::PgPool; #[derive(Debug, thiserror::Error)] pub enum ScriptRepositoryError { #[error("database error: {0}")] Db(#[from] sqlx::Error), #[error("not found: {0}")] NotFound(ScriptId), } /// CRUD over the `scripts` table. #[async_trait] pub trait ScriptRepository: Send + Sync { async fn get(&self, id: ScriptId) -> Result, ScriptRepositoryError>; async fn list(&self) -> Result, ScriptRepositoryError>; async fn create(&self, script: &Script) -> Result<(), ScriptRepositoryError>; async fn update(&self, script: &Script) -> Result<(), ScriptRepositoryError>; async fn delete(&self, id: ScriptId) -> Result<(), ScriptRepositoryError>; } pub struct PostgresScriptRepository { pool: PgPool, } impl PostgresScriptRepository { #[must_use] pub fn new(pool: PgPool) -> Self { Self { pool } } } // Real query bodies land alongside the first migration. Stubbing the trait // impl so the workspace compiles and the seam is visible. #[async_trait] impl ScriptRepository for PostgresScriptRepository { async fn get(&self, _id: ScriptId) -> Result, ScriptRepositoryError> { let _ = &self.pool; Ok(None) } async fn list(&self) -> Result, ScriptRepositoryError> { Ok(Vec::new()) } async fn create(&self, _script: &Script) -> Result<(), ScriptRepositoryError> { Ok(()) } async fn update(&self, _script: &Script) -> Result<(), ScriptRepositoryError> { Ok(()) } async fn delete(&self, _id: ScriptId) -> Result<(), ScriptRepositoryError> { Ok(()) } } /// Adapts a `ScriptRepository` into the `ScriptResolver` trait the /// orchestrator depends on, so we don't pull the manager into the /// orchestrator's dependency graph. pub struct RepoResolver { repo: R, } impl RepoResolver { pub fn new(repo: R) -> Self { Self { repo } } } #[async_trait] impl ScriptResolver for RepoResolver { async fn resolve(&self, id: ScriptId) -> Result, ResolverError> { self.repo .get(id) .await .map_err(|e| ResolverError::Backend(e.to_string())) } }