alaz-db 1.0.0

Long-term memory for AI coding agents
Documentation
use alaz_core::models::VaultSecret;
use alaz_core::{AlazError, Result};
use sqlx::PgPool;

pub struct VaultRepo;

impl VaultRepo {
    pub async fn store(
        pool: &PgPool,
        owner_id: &str,
        name: &str,
        encrypted_value: &[u8],
        nonce: &[u8],
        description: Option<&str>,
    ) -> Result<VaultSecret> {
        let id = cuid2::create_id();

        let row = sqlx::query_as::<_, VaultSecret>(
            r#"
            INSERT INTO vault_secrets (id, owner_id, name, encrypted_value, nonce, description)
            VALUES ($1, $2, $3, $4, $5, $6)
            ON CONFLICT (owner_id, name) DO UPDATE SET
                encrypted_value = EXCLUDED.encrypted_value,
                nonce = EXCLUDED.nonce,
                description = EXCLUDED.description,
                updated_at = now()
            RETURNING id, owner_id, name, encrypted_value, nonce, description, created_at, updated_at
            "#,
        )
        .bind(&id)
        .bind(owner_id)
        .bind(name)
        .bind(encrypted_value)
        .bind(nonce)
        .bind(description)
        .fetch_one(pool)
        .await?;

        Ok(row)
    }

    pub async fn get_by_name(pool: &PgPool, owner_id: &str, name: &str) -> Result<VaultSecret> {
        let row = sqlx::query_as::<_, VaultSecret>(
            r#"
            SELECT id, owner_id, name, encrypted_value, nonce, description, created_at, updated_at
            FROM vault_secrets
            WHERE owner_id = $1 AND name = $2
            "#,
        )
        .bind(owner_id)
        .bind(name)
        .fetch_optional(pool)
        .await?
        .ok_or_else(|| AlazError::NotFound(format!("vault secret '{name}'")))?;

        Ok(row)
    }

    pub async fn list(pool: &PgPool, owner_id: &str) -> Result<Vec<VaultSecret>> {
        let rows = sqlx::query_as::<_, VaultSecret>(
            r#"
            SELECT id, owner_id, name, encrypted_value, nonce, description, created_at, updated_at
            FROM vault_secrets
            WHERE owner_id = $1
            ORDER BY name
            "#,
        )
        .bind(owner_id)
        .fetch_all(pool)
        .await?;

        Ok(rows)
    }

    pub async fn delete(pool: &PgPool, owner_id: &str, name: &str) -> Result<()> {
        let result = sqlx::query("DELETE FROM vault_secrets WHERE owner_id = $1 AND name = $2")
            .bind(owner_id)
            .bind(name)
            .execute(pool)
            .await?;

        if result.rows_affected() == 0 {
            return Err(AlazError::NotFound(format!("vault secret '{name}'")));
        }
        Ok(())
    }
}