@effect/sql-pglite 演进全解析:在 Effect 中集成 WASM 版 PostgreSQL(PGlite)客户端
effect/sql-pglite 演进全解析在 Effect 中集成 WASM 版 PostgreSQLPGlite客户端【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code本篇技术指南以effect/sql-pglite包的 CHANGELOG.md 为主线结合该包在 effect-smol 仓库中的源码与测试系统讲解它如何把 PGliteWASM 构建的 PostgreSQL接入 Effect 的 SQL 客户端体系。读完你将掌握该包的核心能力清单Postgres 方言编译、基于 savepoint 的事务、LISTEN/NOTIFY、数据目录导出、迁移器、SQL 错误分类体系、关键 API 演进如valuesUnprepared与UniqueViolation并了解其与 effect 核心包的版本同步机制。一、包的定位从 Changelog 首次发布看设计意图effect/sql-pglite在 Changelog 中的4.0.0-beta.57条目CHANGELOG.md 中的 Minor Changes给出了该包最权威的定位声明新增effect/sql-pglite包封装electric-sql/pglite并配套 Effect SQL 客户端能力Postgres 方言、通过 savepoint 实现的 Effect 托管事务、listen/notify、dumpDataDir/refreshArrayTypes以及一个 Migrator。PGlite 是 PostgreSQL 的 WASM 构建可在浏览器、Node.js 与 Bun 中运行见 README.md。这意味着该包承担了两个关键职责桥接把 PGlite 实例PGliteInterface转化为符合 EffectSqlClient契约的客户端增强在通用 SQL 客户端之上补充 PGlite 特有的操作监听通知、数据目录导出、数组类型刷新。在package.jsonpackage.json中可以看到它仅依赖electric-sql/pglite^0.5.6而effect作为 peerDependency从依赖设计上就决定了“核心逻辑在 effectPGlite 只是接入方”的分层。二、安装与包结构安装命令来自 README.mdnpm install effectrc effect/sql-pgliterc注意安装的是 rc 预发布版本与 Changelog 中4.0.0-rc.*/4.0.0-beta.*的版本命名一致。包的源码结构非常精简src 目录PgliteClient.ts客户端主体包含make/fromClient/layer等构造器与 Layer、SQL 语句编译器、错误分类逻辑PgliteMigrator.ts迁移器复用 effect 的共享迁移加载器index.ts统一出口分别导出PgliteClient与PgliteMigrator两个命名空间。三、核心能力清单与源码印证3.1 两种客户端构建方式托管实例 vs 外部实例从 PgliteClient.ts 的类型定义看PgliteClientConfig分为Create与Live两种形态Create传入 PGlite 构造选项PGliteOptions由make内部创建受 Scope 管理的实例——Effect.acquireRelease创建并在作用域结束时close()带 1000ms 超时生命周期完全由 Effect 托管Live传入调用方已创建好的liveClient此时实例归调用方所有Effect 客户端不会关闭它。对应的两个构造器是make(options)与fromClient(options)配合三个 Layer 工厂使用layer(config?)基于具体配置创建 LayerlayerFrom(acquire)基于任意 acquire Effect 创建 LayerlayerConfig(config)基于 EffectConfig支持从环境变量等读取配置创建 Layer。三者都会同时提供PgliteClient与通用SqlClient两个服务标签Context.make(PgliteClient, client) Context.add(Client.SqlClient, client)因此下游业务代码既可以按需访问 PGlite 特有能力也可以只依赖标准的SqlClient。3.2 Postgres 方言编译器makeCompiler生成符合 PostgreSQL 语法习惯的语句编译器PgliteClient.ts参数占位符使用 PostgreSQL 的$1、$2形式标识符使用双引号转义escape基于Statement.defaultEscape(\)支持onRecordUpdate生成(values ...) AS alias(cols) RETURNING ...形式的批量更新支持 JSON 自定义片段PgJson可选的transformJson会对接入的 JSON 值做名称转换。测试用例Client.test.ts对这些编译行为给出了可直接验证的断言例如const [query, params] sqlINSERT INTO people ${sql.insert({ name: Tim, age: 10 })}.compile() // query INSERT INTO people (name,age) VALUES ($1,$2) // params [Tim, 10]以及in助手、and助手、updateValues生成FROM (values ($1),($2)) AS data(name)等常用片段。3.3 基于 savepoint 的 Effect 托管事务Changelog 明确将“Effect-managed transactions via savepoints”列为核心能力。源码中transactionAcquirer使用Effect.uninterruptibleMask 信号量Semaphore.makeUnsafe(1)保证同一时刻只有一个事务持有连接并把信号量释放注册为当前作用域的 finalizer嵌套事务则通过 savepoint 实现。Transaction.test.ts 覆盖了四类典型场景可作为理解其语义的权威参考事务内提交withTransaction commit插入的数据在提交后可见事务内回滚withTransaction rollbackEffect 失败后整条记录消失嵌套事务成功外层与内层同时提交两条记录都在嵌套事务回滚内层失败只回滚到 savepoint外层记录保留最终只有 1 条并发嵌套事务即使内层并发且部分失败成功分支的数据依然保留。3.4 listen/notify、dumpDataDir 与 refreshArrayTypesPgliteClient接口在标准SqlClient之上扩展了四个 PGlite 专属能力PgliteClient.ts成员签名说明json(_: unknown) Fragment构造 JSON 参数片段配合::jsonb使用listen(channel: string) StreamStreamstring, SqlError订阅频道返回 Effect Streamnotify(channel: string, payload: string) Effectvoid, SqlError发送通知内部执行转义后的NOTIFYpayload 会做单引号转义dumpDataDir(compression?: none \| gzip \| auto) EffectFile \| Blob, SqlError导出整个数据目录refreshArrayTypesEffectvoid, SqlError刷新数组类型注册这些操作统一经过信号量串行化semaphore.withPermit避免与常规查询并发时产生竞争。测试中可以看到典型用法Client.test.ts 演示了listen(ch1, ...)notify(ch1, hello)的配对流程以及创建mood[]枚举数组类型后调用refreshArrayTypes再插入数组值。3.5 迁移器MigratorPgliteMigrator.ts 导出run与layerrun(options)基于当前SqlClient执行待应用的迁移文件返回已应用迁移的[id, name]列表它不需要独立的 PGlite 服务连接由活跃的SqlClient提供layer(options)在 Layer 构建期间执行迁移Layer.effectDiscard(run(options))。迁移器复用 effect 的共享Migrator模块export * from effect/unstable/sql/Migrator并依赖统一的effect_sql_migrations记录表。Migrator.test.ts 验证了迁移按migration_id顺序执行并写入记录表PersistedQueue.test.ts 则展示了迁移器的另一个用途——为PersistedQueue持久化队列自动建表并确保只记录一次迁移。四、SQL 错误分类体系UniqueViolation的引入Changelog4.0.0-beta.65条目记录了一次重要的错误分类增强新增UniqueViolation作为新的 SQL 错误原因。受支持的唯一约束冲突现在归类为UniqueViolation而不再落入更宽泛的ConstraintError。UniqueViolation.constraint保存可用的约束/索引/键标识符当无法取得可靠标识符时回退为unknown。该分类覆盖 PostgreSQL、PGlite、MySQL、MSSQL 以及 SQLite 家族的共享分类逻辑。在 PgliteClient.ts 的classifyError中可以看到完整的映射表它依据 PostgreSQL 的 SQLSTATE 错误码前缀分类SQLSTATE分类结果08xxConnectionError连接错误28xxAuthenticationError认证错误42501AuthorizationError权限错误42xxSqlSyntaxError语法错误23505UniqueViolation唯一约束冲突携带 constraint23xx其余ConstraintError一般完整性约束40P01DeadlockError40001SerializationError55P03LockTimeoutError57014StatementTimeoutError其他UnknownError约束名的提取有精细的兜底逻辑PgliteClient.ts 的pgConstraintFromCause约束缺失、非字符串或全空白时统一回退为unknown有效值会先trim再返回。SqlErrorClassification.test.ts 正是围绕这三点写的测试 users_email_key 会被修剪为users_email_key而缺约束 / 数字约束 / 空白约束均返回unknown23503外键则保持ConstraintError不变。五、关键 API 演进valuesUnprepared与入口调整Changelog 记录了若干影响使用方式的 API 变化4.0.0-beta.86新增Statement.valuesUnprepared用于以数组形式返回未预编译 SQL 语句的行。对应实现在 Statement.ts 中PgliteClient的底层连接通过executeValuesUnprepared内部以rowMode: array查询支撑它返回ReadonlyArrayReadonlyArrayunknown。4.0.0-beta.103移除了显式的./index入口Removed explicit ./index entrypoints。这与 package.json 中的 exports 配置相呼应——./index: null、./*/index: null明确禁用了旧入口导入请使用包根或具体子路径。4.0.0-rc.112更新生产依赖到最新版本由tim-smart提交属于常规的依赖刷新。六、版本节奏与 effect 核心的同步机制通读整个 Changelog 可以发现一个明显规律几乎每个版本的 Patch Changes 都只包含 Updated dependencies 指向effect4.0.0-x.y.z这说明effect/sql-pglite与 effect 核心走的是同版本号、同步发布策略。实际含义是每次 effect 核心更新所有 SQL 包统一跟随升级避免版本矩阵错位该包自身几乎没有独立功能变更——真正的 SQL 客户端基础设施SqlClient、SqlError、Statement、Migrator都沉淀在 effect 核心中本包只做 PGlite 的适配层因此升级时应保持effect与effect/sql-pglite版本一致如均为4.0.0-rc.112这从 package.json 的 peerDependencieseffect: workspace:^也能看出。从源码结构看这种“核心在 effect、适配在 sql/*”的组织方式同样存在于packages/sql/pg、mysql2、sqlite等兄弟包它们共享同一套SqlError分类与valuesUnprepared特性可从各自 CHANGELOG 中看到同名条目。七、使用建议与注意事项综合 Changelog、源码与测试落地使用时有几点值得注意生命周期优先使用layer()/layerConfig()让 Effect 托管 PGlite 实例Scope 结束自动关闭若使用fromClient({ liveClient })包装外部实例务必自行负责关闭客户端不会替你清理。事务语义嵌套事务基于 savepoint内层失败只回滚到 savepoint并发嵌套事务受信号量保护同一连接不会同时跑多个事务。错误处理针对唯一约束冲突直接匹配UniqueViolation并读取constraint字段即可拿到约束名可能为unknown其他完整性错误仍为ConstraintError。版本对齐安装时让effect与effect/sql-pglite保持同版本当前均为4.0.0-rc.112并留意 Changelog 中 Updated dependencies 列出的 effect 版本这是判断兼容性的最快途径。持久化队列等扩展场景PgliteMigrator与PersistedQueue可组合使用迁移器会自动为队列建表并幂等记录迁移见 PersistedQueue.test.ts。八、总结effect/sql-pglite是一个“小而精”的适配包Changelog 中绝大部分条目是跟随 effect 核心的依赖同步仅有的几条独立变更包首发、UniqueViolation分类、valuesUnprepared、入口清理恰好勾勒出它的全部技术边界。结合 PgliteClient.ts、PgliteMigrator.ts 与 test 目录即可在浏览器、Node.js 或 Bun 中用完全符合 Effect 生态惯用法的类型安全方式操作一个嵌入式的、无外部进程依赖的 PostgreSQL 数据库。【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考