//! `PostgresModuleSource` — the Postgres-backed `ModuleSource` impl. //! //! Mirrors the structure of [`crate::kv_repo::PostgresKvRepo`] / //! [`crate::docs_repo::PostgresDocsRepo`]: thin wrapper around a //! `PgPool` that owns a single statement returning the module by //! `(cx.app_id, name, kind = 'module')`. The resolver lives in //! `executor-core` and consumes this trait through the `Services` //! bundle, so manager-core stays the only crate that touches //! Postgres. use async_trait::async_trait; use chrono::{DateTime, Utc}; use picloud_shared::{ModuleScript, ModuleSource, ModuleSourceError, SdkCallCx}; use sqlx::PgPool; pub struct PostgresModuleSource { pool: PgPool, } impl PostgresModuleSource { #[must_use] pub fn new(pool: PgPool) -> Self { Self { pool } } } #[derive(sqlx::FromRow)] struct ModuleRow { id: uuid::Uuid, app_id: uuid::Uuid, name: String, source: String, updated_at: DateTime, } impl From for ModuleScript { fn from(r: ModuleRow) -> Self { Self { script_id: r.id.into(), app_id: r.app_id.into(), name: r.name, source: r.source, updated_at: r.updated_at, } } } #[async_trait] impl ModuleSource for PostgresModuleSource { async fn lookup( &self, cx: &SdkCallCx, name: &str, ) -> Result, ModuleSourceError> { // The query is the cross-app isolation boundary: app_id comes // from cx (never from the script-passed argument), and the // CHECK constraint `kind IN ('endpoint','module')` plus the // `kind = 'module'` filter together guarantee endpoint scripts // are never importable. The `(app_id, kind)` index from // migration 0015 makes this an index scan returning at most // one row (per-app uniqueness on `name`). let row: Option = sqlx::query_as( "SELECT id, app_id, name, source, updated_at \ FROM scripts \ WHERE app_id = $1 AND kind = 'module' AND name = $2", ) .bind(cx.app_id.into_inner()) .bind(name) .fetch_optional(&self.pool) .await .map_err(|e| ModuleSourceError::Backend(e.to_string()))?; Ok(row.map(Into::into)) } }