发现于 #5704 批次 0 的迁移工作(把 datasource-autoconnect.test.ts 换到 sqlite :memory: 时核对连接池行为),与该 PR 无关,单独记录。
事实
createDefaultDatasourceDriverFactory 的 postgres / mysql 臂都把 buildSqlPool(spec) 传给 SqlDriver,而 sqlite 臂走 resolveSqliteDriver(...),完全不传 pool:
packages/services/service-datasource/src/default-datasource-driver-factory.ts — sqlite 分支只传 filename / dev / schemaMode / autoMigrate。
packages/services/service-datasource/src/sqlite-driver-fallback.ts — ResolveSqliteDriverOptions 根本没有 pool 字段,buildNative() 构造 SqlDriver 时也没有。
sqlite-wasm 臂同理(SqliteWasmDriver 也不接 pool)。
实测(worktree,service-datasource dist,通过工厂真实构造)
sqlite + pool{min:3,max:9} config.pool = {"createTimeoutMillis":15000} live pool = {"min":1,"max":1}
postgres + pool{min:3,max:9} config.pool = {"min":3,"max":9,"createTimeoutMillis":15000} live pool = {"min":3,"max":9}
sqlite 拿到的是 knex sqlite dialect 自己的默认值,声明的 {min:3,max:9} 没有到达任何地方,也没有任何提示。
现网标本:examples/app-crm 的 CrmDatasource 声明了 pool: { min: 1, max: 5 }(examples/app-crm/src/datasources/crm.datasource.ts),实际得到 {min:1,max:1}。
为什么值得记一笔
这正是 #4410 那一轮在清的「声明了但没人读」的形状 —— datasource.pool 是 strict schema 上的可授权键,pg/mysql 认它、sqlite 不认,差异既没文档也没告警。
但修法不是简单接上去(所以这里不带方案)
对 filename: ':memory:' 的 sqlite,照着 max 大于 1 接上去反而是错的:knex 的 better-sqlite3 每取一条连接就 new Database(':memory:'),即开出一个互相看不见的空库,写进 A 读不到 B。knex 自己的 sqlite dialect 默认 {min:1,max:1} 就是为了躲这个坑。
所以三条路各有代价,需要裁决而不是猜:
- A. 接上去:对文件型 sqlite 正确,对
:memory: 引入静默数据丢失 —— 除非同时对 :memory: 强制 {min:1,max:1}。
- B. 显式拒绝:sqlite datasource 声明
pool 时在 authoring / publish 校验里报错并说明「sqlite 连接池由驱动决定」,契约优先,作者立刻知道。同时要把 app-crm 的声明删掉。
- C. 从 sqlite 的配置契约里移除
pool:走 ADR-0049 enforce-or-remove。
倾向 B 或 C(取决于 pool 是否按驱动分契约),但这是公开契约形状问题,留给维护者定。
复现脚本(在 packages/services/service-datasource/ 下,先 build):
const { createDefaultDatasourceDriverFactory } = await import('./dist/index.js');
const f = createDefaultDatasourceDriverFactory();
const h = await f.create({ name: 'ds', driver: 'sqlite', config: { filename: ':memory:' }, pool: { min: 3, max: 9 } });
console.log(h.driver.knex.client.config.pool, h.driver.knex.client.pool.min, h.driver.knex.client.pool.max);
发现于 #5704 批次 0 的迁移工作(把
datasource-autoconnect.test.ts换到 sqlite:memory:时核对连接池行为),与该 PR 无关,单独记录。事实
createDefaultDatasourceDriverFactory的postgres/mysql臂都把buildSqlPool(spec)传给SqlDriver,而sqlite臂走resolveSqliteDriver(...),完全不传 pool:packages/services/service-datasource/src/default-datasource-driver-factory.ts— sqlite 分支只传filename/dev/schemaMode/autoMigrate。packages/services/service-datasource/src/sqlite-driver-fallback.ts—ResolveSqliteDriverOptions根本没有 pool 字段,buildNative()构造SqlDriver时也没有。sqlite-wasm臂同理(SqliteWasmDriver也不接 pool)。实测(worktree,service-datasource dist,通过工厂真实构造)
sqlite 拿到的是 knex sqlite dialect 自己的默认值,声明的
{min:3,max:9}没有到达任何地方,也没有任何提示。现网标本:
examples/app-crm的CrmDatasource声明了pool: { min: 1, max: 5 }(examples/app-crm/src/datasources/crm.datasource.ts),实际得到{min:1,max:1}。为什么值得记一笔
这正是 #4410 那一轮在清的「声明了但没人读」的形状 ——
datasource.pool是 strict schema 上的可授权键,pg/mysql 认它、sqlite 不认,差异既没文档也没告警。但修法不是简单接上去(所以这里不带方案)
对
filename: ':memory:'的 sqlite,照着max大于 1 接上去反而是错的:knex 的 better-sqlite3 每取一条连接就new Database(':memory:'),即开出一个互相看不见的空库,写进 A 读不到 B。knex 自己的 sqlite dialect 默认{min:1,max:1}就是为了躲这个坑。所以三条路各有代价,需要裁决而不是猜:
:memory:引入静默数据丢失 —— 除非同时对:memory:强制{min:1,max:1}。pool时在 authoring / publish 校验里报错并说明「sqlite 连接池由驱动决定」,契约优先,作者立刻知道。同时要把 app-crm 的声明删掉。pool:走 ADR-0049 enforce-or-remove。倾向 B 或 C(取决于
pool是否按驱动分契约),但这是公开契约形状问题,留给维护者定。复现脚本(在
packages/services/service-datasource/下,先 build):