t3code 依赖解析:@effect/sql-sqlite-react-native 4.0 版本演进与 React Native SQLite 集成原理

发布时间:2026/9/15 13:48:04
t3code 依赖解析:@effect/sql-sqlite-react-native 4.0 版本演进与 React Native SQLite 集成原理 t3code 依赖解析effect/sql-sqlite-react-native 4.0 版本演进与 React Native SQLite 集成原理【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code本文基于仓库中 .repos/effect-smol/packages/sql/sqlite-react-native/CHANGELOG.md 与同目录源码系统梳理effect/sql-sqlite-react-native从4.0.0-beta.0到4.0.0-rc.112的版本演进脉络并结合 SqliteClient.ts、SqliteMigrator.ts 与测试用例深入解析它在 React Native 中桥接 SQLite 的底层实现、配置项语义与能力边界。读完本文你将掌握该包的初始化方式、同步/异步执行模型、迁移工具用法以及 4.0 系列关键破坏性变更结构化错误模型、值查询行为、入口导出调整对升级路径的影响。一、版本脉络总览从 beta.0 到 rc.112CHANGELOG 记录了该包完整的预发布历史整体可分为三个阶段阶段版本区间主题v4 启动4.0.0-beta.0随 Effect v4 进入 beta标记 Major Changesbeta 演进期4.0.0-beta.1~4.0.0-beta.107结构化错误模型、值查询能力、导出结构调整等实质性变更rc 冻结期4.0.0-rc.108~4.0.0-rc.112仅同步effect核心依赖版本无本包独立变更从 rc.108 起每个版本的变更内容都只有一条Updated dependencies指向对应的effect4.0.0-rc.*。这说明 rc 阶段包自身 API 已冻结版本号仅跟随 Effect 核心库的发布节奏属于典型的 monorepo 版本联动模式。其中4.0.0-beta.107与4.0.0-beta.103之间的命名切换beta→rc意味着 Effect v4 系列进入了发布候选阶段。包当前版本为4.0.0-rc.112对应 package.json 中的version: 4.0.0-rc.112。二、包的角色把 op-sqlite 桥接进 Effect SQL 生态effect/sql-sqlite-react-native是 Effect SQL 家族在移动端 SQLite 的实现之一与同目录下的sqlite-node、sqlite-wasm、sqlite-bun、d1、libsql、pglite、pg、mysql2、mssql、clickhouse等驱动共同构成 .repos/effect-smol/packages/sql 多数据库支持矩阵。它的底层驱动是 React Native 生态的op-engineering/op-sqlite原生绑定实现从源码注释SqliteClient.ts可以确认其核心职责打开设备端 SQLite 数据库暴露为SqliteClient与通用SqlClient两个服务对访问进行串行化单连接 信号量支持普通查询与基于值的查询value queries默认使用驱动的同步查询 APIAsyncQuery/withAsyncQuery可切换为异步 API不支持流式查询streaming与updateValues。从 package.json 可以看到依赖约束peerDependencies要求op-engineering/op-sqlite 17.1.2 18.0.0即消费方需自行安装 op-sqlite 并在该版本范围内同时要求effect与 monorepo 工作区版本一致workspace:^。三、配置项详解SqliteClientConfig 全字段语义客户端的全部配置集中定义在SqliteClientConfig接口SqliteClient.ts各字段如下字段类型必填语义filenamestring是数据库文件名透传给 op-sqlite 的open({ name })决定落盘文件locationstring否数据库存放位置目录路径不传则使用驱动默认位置encryptionKeystring否数据库加密密钥传入后 op-sqlite 以加密模式打开数据库spanAttributesRecordstring, unknown否附加的追踪 span 属性transformResultNames(str: string) string否查询结果的列名转换函数如 snake_case → camelCasetransformQueryNames(str: string) string否查询中 SQL 标识符的转换函数作用于 SQL 编译阶段从实现看SqliteClient.tsfilename、location、encryptionKey会被原样组装进 op-sqlite 的open选项transformQueryNames会传入Statement.makeCompilerSqlite参与 SQL 语句编译transformResultNames则通过Statement.defaultTransforms(...).array构造结果行转换器。此外无论是否配置spanAttributes客户端都会自动追加[db.system.name, sqlite]这一遥测属性。四、两种初始化方式make 与 Layer包提供了三个入口函数1.SqliteClient.make(config)—— 直接构造 scoped 客户端import { Effect, Layer } from effect import { Reactivity } from effect/unstable/reactivity import { SqliteClient } from effect/sql-sqlite-react-native const program Effect.gen(function*() { const sql yield* SqliteClient.make({ filename: app.db, location: documents // 可选 // encryptionKey: ... // 可选 }) const rows yield* sqlSELECT * FROM users WHERE id ${1}.values return rows }).pipe(Effect.provide(Reactivity.layer))注意make返回的 Effect 需要Scope与Reactivity两个依赖从源码签名Effect.EffectSqliteClient, never, Scope.Scope | Reactivity.Reactivity可见测试用例 Client.test.ts 正是通过.pipe(Effect.provide(Reactivity.layer))完成装配的。数据库连接的关闭由Effect.addFinalizer(() Effect.sync(() db.close()))注册随 Scope 结束自动释放。2.SqliteClient.layer(config)—— 基于普通配置对象构造 Layerconst SqliteLayer SqliteClient.layer({ filename: app.db }) // 提供 SqliteClient 与通用 SqlClient 两个服务3.SqliteClient.layerConfig(config)—— 基于 Effect 的Config值构造 Layer配置可从环境/文件等来源读取import { Config } from effect const SqliteLayer SqliteClient.layerConfig( Config.all({ filename: Config.string(DB_FILENAME), location: Config.option(Config.string(DB_LOCATION)) }) )从源码可见layer与layerConfig构造的上下文同时注册SqliteClient与Client.SqlClient两个 Tag因此业务代码既可以注入具体驱动也可以只依赖通用的 Effect SQL 接口。五、执行模型单连接串行化与同步/异步切换5.1 为什么需要串行化React Native 单线程 JS 环境中多个并发查询共享一个底层连接时容易出现竞态。源码中make通过Semaphore.make(1)创建容量为 1 的信号量普通查询走semaphore.withPermits(1)(...)事务则使用transactionAcquirer配合Scope.addFinalizer在事务结束时释放许可SqliteClient.ts。这意味着所有 SQL 操作被强制排队执行代价是并发度被限制为 1换取移动端数据库访问的确定性。5.2 默认同步可按作用域切异步op-sqlite 同时提供同步 APIexecuteSync/executeRawSync与异步 APIexecute/executeRaw。该包默认走同步 API原因是同步调用能避免额外的 Promise 包装开销但同步执行会阻塞 JS 线程长时间查询可能卡顿 UI。为此包引入了一个 Fiber 级别的 Context 引用AsyncQuery默认false并在run/runValues中通过fiber.getRef(AsyncQuery)动态判断走哪套 APISqliteClient.ts。withAsyncQuery用于在某个作用域内临时开启异步执行const rows yield* SqliteClient.withAsyncQuery( sqlSELECT * FROM large_table.values )测试 Client.test.ts 分别验证了同步与异步两种模式下values与valuesUnprepared均能返回[[1]]形式的数组行。这一设计让开发者可以默认快速、关键路径切异步且切换粒度精确到单个 Effect。六、能力边界明确不支持的 SQL 能力桥接层对不支持的能力做了显式标记这是接入前必须了解的约束流式查询streamingexecuteStream()直接Stream.die(executeStream not implemented)任何尝试流式读取的行为都会抛出缺陷DefectupdateValuesSqliteClient接口中updateValues被声明为never类型类型系统层面直接禁止调用批量 / 原始执行executeValuesUnprepared与executeUnprepared在实现上复用runValues/run并未提供独立的批量执行路径。这些限制源于 op-sqlite 驱动的能力集合接入前应对照业务 SQL 形态评估是否受影响。七、迁移工具SqliteMigrator 的启动期 schema 管理SqliteMigrator.ts 复用 Effect 核心库的Migrator实现提供两个入口SqliteMigrator.run(options)返回按序执行迁移的 Effect产出已执行迁移的[id, name]数组依赖当前SqlClientSqliteMigrator.layer(options)把迁移封装进 Layer 的构造过程Layer.effectDiscard(run(options))在 Layer 构建时完成 schema 升级。迁移必须在与业务相同的filename/location/encryptionKey配置下运行数据库按配置作用域隔离。源码注释还给出了两条移动端特有的实践忠告迁移默认走同步 API会阻塞 JS 线程长迁移集应包裹在SqliteClient.withAsyncQuery中执行移动 App 升级可能被系统挂起或进程被杀迁移必须具备事务意识不能假设每次启动都是全新数据库。八、beta 阶段的关键变更解读升级必读CHANGELOG 中真正影响行为的变更集中在 beta 阶段按时间倒序整理如下。8.1 4.0.0-beta.104值查询返回选中行Return selected rows from synchronous and asynchronous value queries.此前values类查询的返回值行为不一致该变更统一了同步与异步值查询的返回语义确保两种模式都返回选中的行。测试用例中的values/valuesUnprepared断言Client.test.ts即是对此行为的回归验证。8.2 4.0.0-beta.103移除显式 ./index 入口Removed explicit ./index entrypoints.包从export * as SqliteClient from ./SqliteClient改为显式.ts扩展名的模块导出见 index.ts同时 package.json 的 exports 中把./index、./*/index声明为null。这是打包器与解析层面的破坏性调整——依赖effect/sql-sqlite-react-native/index这类深路径导入的代码需要改为直接导入包根路径。8.3 4.0.0-beta.86新增 valuesUnpreparedAddStatement.valuesUnpreparedfor returning unprepared SQL statement rows as arrays.valuesUnprepared允许以数组形式返回未预编译语句的行数据与已预编译语句的values互补。在 React Native 客户端中实现上两者最终都走runValuesexecuteRaw/executeRawSync返回值形如[[1]]仅值、不含列名适用于对吞吐敏感的原始数据读取场景。8.4 4.0.0-beta.65新增 UniqueViolation 错误原因AddUniqueViolationas a new SQL error reason.这是对 4.0.0-beta.37reason-based 结构化错误模型Consolidate the SqlError changes to the new reason-based shape的细化。唯一约束冲突从宽泛的ConstraintError中拆分为独立的UniqueViolation其结构定义在 SqlError.ts新增constraint: string字段保存可获取到的约束/索引/键标识取不到可靠标识时回退为字符串unknown该分类覆盖 PostgreSQL、PGlite、MySQL、MSSQL 以及 SQLite 家族共享的分类逻辑与ConstraintError一样isRetryable为false唯一约束冲突重试无意义。SQLite 场景下由classifySqliteError负责把原生错误映射到UniqueViolationSqlError.ts这为移动端手机号已注册用户名已占用等业务判断提供了类型安全的捕获途径import { Effect } from effect import { SqlError } from effect/unstable/sql/SqlError const createUser sql INSERT INTO users (email) VALUES (${email}) .pipe( Effect.catchTag(UniqueViolation, (err) Effect.fail(邮箱已存在约束: ${err.constraint}) ) )8.5 4.0.0-beta.105 与 4.0.0-beta.0依赖与基线beta.105由 fubhy 提交Update peer dependencies调整了 peer 依赖范围beta.0随 Effect v4 发布4.0.0-beta.0标记为 Major Changesv4 beta是 4.0 系列版本号的起点。8.6 结构性变更ServiceMap 更名4.0.0-beta.44虽然该条目是 effect 核心库的变更Rename theServiceMapmodule toContext但作为同一 monorepo 的联动产物它提醒升级者v4 系列把 DI 容器模块统一到了Context命名下涉及服务注册的代码需同步迁移。类似的跨包结构性变更在 Effect v4 预发布期间频繁出现因此在 rc 阶段之前锁定版本并配套升级是必要的。九、rc 阶段依赖联动而非功能迭代rc.108 ~ rc.112 的五个版本全部只有Updated dependencies指向effect4.0.0-rc.*。结合包 package.json 中effect: workspace:^的声明可以推断这种模式由 Changesets 自动生成每当核心库发版所有依赖它的 SQL 驱动包自动 bump 并生成对应 CHANGELOG 条目。对消费方而言rc 阶段的升级风险很低但建议始终让该包与effect核心保持同一 rc 版本号避免版本错位导致的类型不匹配。十、接入与验证路径如需在本仓库环境下验证该包行为可直接运行其测试# 在仓库根目录pnpm workspace pnpm --filter effect/sql-sqlite-react-native test测试通过 mockop-engineering/op-sqlite模块vi.mock隔离原生依赖覆盖同步/异步值查询与valuesUnprepared的返回语义见 Client.test.ts。接入时建议遵循以下清单安装op-engineering/op-sqlite版本满足17.1.2 18.0.0并完成原生链接用统一的filename/location/encryptionKey构造客户端与迁移层默认保持同步执行对长查询或迁移集使用SqliteClient.withAsyncQuery用catchTag(UniqueViolation, ...)处理唯一约束冲突将写操作放进事务sql.transaction避免部分写入导致的数据不一致升级时保持effect/sql-sqlite-react-native与effect版本号对齐rc 阶段尤其如此。结语effect/sql-sqlite-react-native的 CHANGELOG 完整呈现了一个 Effect v4 SQL 驱动从 beta 到 rc 的演进轨迹以4.0.0-beta.0为起点经历了结构化错误模型reason-based SqlError、UniqueViolation细分、valuesUnprepared与值查询语义统一、入口导出调整等一系列实质性变更最终在 rc 阶段进入依赖联动模式。其源码实现则展示了单连接串行化 默认同步执行 作用域级异步切换这一面向移动端的务实设计。理解这些版本信号与实现约束是正确接入、平稳升级并规避移动端 SQLite 陷阱的前提。【免费下载链接】t3code项目地址: https://gitcode.com/GitHub_Trending/t3/t3code创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考