跳到内容
Lenso
简体中文
Esc
导航打开⌘J预览
本页内容

PostgreSQL Kit

为有状态 Plugin 的自有 PostgreSQL schema 建立显式生命周期。

lenso-postgres-kit 是一个 Plugin 自有 PostgreSQL schema 的生命周期 kit。它不是 共享 State Plugin、通用 SQL Capability、repository abstraction 或 ORM。数据模型、 query、transaction 边界、备份与保留策略以及专用数据库 role 仍由所属 Plugin 定义。

定义并安装 schema

把 SQL 放在所属 Plugin 的 migrations/ 目录中;Rust 只保留显式版本、名称和文件 顺序:

orders-module/
├── migrations/
│   ├── 001_create_orders.sql
│   └── 002_add_order_status.sql
└── src/lib.rs
CREATE TABLE orders (
    id bigint PRIMARY KEY,
    total_cents bigint NOT NULL
);
use lenso_postgres_kit::{
    Migration, OwnedPostgres, SchemaOperator, SchemaPlan, sql_migrations,
};

const MIGRATIONS: &[Migration] = sql_migrations![
    (1, "create-orders", "migrations/001_create_orders.sql"),
    (2, "add-order-status", "migrations/002_add_order_status.sql"),
];

async fn install(database_url: &str) -> Result<(), Box<dyn std::error::Error>> {
    let plan = SchemaPlan::new("orders_module", MIGRATIONS)?;
    SchemaOperator::connect(database_url, plan.clone()).await?.setup().await?;
    Ok(())
}

async fn prepare(database_url: &str) -> Result<OwnedPostgres, Box<dyn std::error::Error>> {
    let plan = SchemaPlan::new("orders_module", MIGRATIONS)?;
    // 运行时 prepare 只验证精确 schema,绝不自动 migration。
    Ok(OwnedPostgres::prepare(database_url, plan).await?)
}

路径相对于所属 crate 的 Cargo.tomlsql_migrations! 使用 include_str! 在编译期 嵌入 SQL:文件缺失会直接编译失败,文件变化会触发重编译;运行时不会扫描目录。 版本和名称仍然显式,因此顺序、连续版本校验和 checksum 漂移检测保持确定。

install 必须作为显式安装或部署操作执行,不能放在 Plugin prepare 中。 OwnedPostgres::prepare 成功后,通过 postgres.pool() 使用普通 SQLx query 与 transaction。pool 会把自有 schema 选为 search_path

显式升级

追加新的 SQL 文件和声明项,不要修改已经应用的文件。新的 Plugin generation 会先返回 PostgresKitError::UpgradeRequired;停止所属 Plugin,执行 operator action,再 prepare 新 generation:

let plan = SchemaPlan::new("orders_module", MIGRATIONS)?;
let outcome = SchemaOperator::connect(database_url, plan)
    .await?
    .upgrade()
    .await?;
println!("{outcome:?}");

Setup 与 upgrade 使用 advisory lock 和一个原子 migration transaction。私有 ledger 记录 version、name 与 checksum。

失败 含义
SetupRequired managed schema 尚未安装。
UpgradeRequired 当前链接的 Plugin 有待执行 migration。
UnmanagedSchema schema 存在但没有 kit ledger;不会自动接管。
HistoryDiverged 已应用的 name、version 或 SQL checksum 被改动。
SchemaAhead 数据库版本比当前 Plugin generation 更新。
OwnershipMismatch 当前数据库 role 不是 schema owner。

setup 是幂等的:首次返回 Created,之后返回 AlreadyCurrent。失败时 schema 与 ledger 一起回滚。

在 PostgreSQL 中强制隔离

search_path 只是 query 便利,不是安全边界。每个 Plugin 应使用专用、非 superuser role,只拥有自己的 schema,并通过数据库 grant 限制权限。共享同一个物理 cluster 不代表可以直接访问其他 Plugin 的 table。

跨 Plugin workflow 使用 Capability call 与应用层协调,不使用共享 SQL transaction。 数据库 URL 通过 Secrets Plugin 解析,绝不写进 Resolved App Plan。

验证 kit

cargo fmt --all -- --check
cargo clippy --locked --all-targets --all-features -- -D warnings
cargo test --locked --all-features
LENSO_POSTGRES_TEST_URL=postgres://... \
  cargo test --locked --test postgres_acceptance -- --ignored

最后更新于 2026年9月6日

这个页面有帮助吗?