免费获取学习方案
ARTICLE DETAIL

资讯详情

深耕编程基础知识与建站技术分享的一线实战洞察。

Knex 升级完全指南:从 0.14 到 2.x 的破坏性变更梳理与迁移实战

Knex 升级完全指南:从 0.14 到 2.x 的破坏性变更梳理与迁移实战 Knex 升级完全指南从 0.14 到 2.x 的破坏性变更梳理与迁移实战【免费下载链接】knexA query builder for PostgreSQL, MySQL, CockroachDB, SQL Server, SQLite3 and Oracle, designed to be flexible, portable, and fun to use.项目地址: https://gitcode.com/gh_mirrors/kn/knex导读UPGRADING.md 是 knex 官方维护的版本迁移手册记录了从 0.14.x 到 2.0.x 各主要版本引入的破坏性变更breaking changes涵盖 Node.js 版本要求、TypeScript 类型系统重构、数据库驱动切换、事务与查询行为变化、CLI 参数调整等方方面面。本文将沿该手册的时间线逐版本拆解每一处变更的背景、影响范围与具体迁移代码并结合当前仓库knex 3.3.0的源码实现进行佐证帮助正在升级或计划升级 knex 的开发者一次性理清所有断点、避免踩坑。升级到 2.0.0sqlite3 驱动的回归切换knex 1.0 时代由于sqlite3一度缺乏维护官方将默认 SQLite 驱动切换到了vscode/sqlite3。随着sqlite3项目重新恢复活跃维护knex 2.0.0 起改回使用sqlite3。如果此前你的package.json依赖的是vscode/sqlite3需要做如下替换{ dependencies: { sqlite3: ^5.0.11 } }当前仓库的 package.json 中devDependencies已恢复使用sqlite3: ^5.0.11同时在peerDependenciesMeta中声明为可选依赖且 lib/constants.js 的客户端别名表CLIENT_ALIASES仍保留sqlite→sqlite3的映射说明client: sqlite3与历史写法client: sqlite均可继续使用。此外knex 3.x 还额外支持better-sqlite3方言见 lib/dialects/index.js。升级到 1.0.0Node 版本下限与驱动回退Node.js 12 以下不再支持knex 1.0.0 起要求Node.js ≥ 12。当前仓库 package.json 中engines字段已进一步声明为node: 16而 README.md 也明确写着 Node.js versions 16 are supported。升级前请先确认运行环境node -v驱动依赖从 sqlite3 换回 vscode/sqlite3与 2.0 的方向相反1.0 时代因为sqlite3维护停滞官方要求把依赖从sqlite3替换为vscode/sqlite3。如果你的项目正好处于这个历史版本请执行npm uninstall sqlite3 npm install vscode/sqlite3RETURNING 操作返回值统一为对象RETURNING操作PostgreSQL、SQLite3 等支持RETURNING子句的数据库现在始终返回一个带列名的对象而不是数组或其他形态。以 lib/dialects/sqlite3/query/sqlite-querycompiler.js 的实现为例插入语句会编译出returning col形式的 SQL 片段而 lib/dialects/sqlite3/index.js 会根据是否存在returning决定使用all还是run方法驱动底层驱动。因此迁移时如果此前依赖返回值的数组形态需要改为按对象键访问const rows await knex(users).insert({ name: Tim }, [id, name]); // 现在 rows 是 [{ id: 1, name: Tim }] 这类对象数组Migrator 返回迁移对象列表knex.migrate.latest()等迁移命令的返回值由原先的简单列表变为迁移对象列表。当前源码中 lib/migrations/migrate/migration-list-resolver.js 通过listCompleted(tableName, schemaName, trxOrKnex)查询knex_migrations表并将每行映射为对象返回lib/migrations/migrate/Migrator.js 内对迁移文件也统一以{ file, directory }之类的对象形态处理。升级后建议按对象属性消费返回值const migrations await knex.migrate.latest(); // migrations[0].file 等字段升级到 0.95.0TypeScript 类型导出体系的彻底重构这是 UPGRADING.md 中篇幅最大、对 TypeScript 用户影响最深远的一处变更。0.95.0 起knex 的默认导出与命名导出的职责被彻底拆分明确区分了「实例化函数」「类型命名空间」「knex 对象类型」三者import { knex } from knex; // 这是一个函数调用它来实例化 knex import { Knex } from knex; // 这是一个命名空间同时也是 knex 对象的类型 import KnexTimeoutError Knex.KnexTimeoutError; // 来自 Knex 命名空间的类 const config: Knex.Config {}; // 来自 Knex 命名空间的类型 const knexInstance: Knex knex(config);旧写法与新写法对照如果你之前的代码是这样的把默认导入当命名空间用import knex from knex; const config: knex.Config {}; // 旧类型来自默认导出的命名空间 const knexInstance knex(config);请改为import { knex, Knex } from knex; const config: Knex.Config {}; const knexInstance knex(config);直接导入的类型改为从 Knex 命名空间取此前你可能直接从knex模块导入Config、QueryBuilder等类型import { QueryBuilder } from knex; const qb: QueryBuilder knex(table).select(*);现在应统一通过Knex命名空间访问import { Knex } from knex; const qb: Knex.QueryBuilder knex(table).select(*);当前仓库的 types/index.d.ts 文件头部即声明TypeScript Version: 4.1并在其中以namespace Knex组织全部类型如Knex.Config、Knex.QueryBuilder、Knex.KnexTimeoutError等与文档描述一致。同时 knex.js 的运行时导出保留了对knex.knex、knex.default的挂载knex.mjs 则提供export { knex }与默认导出以满足 CJS/ESM 两种模块体系下多种导入语法const knex require(knex)、import { knex } from knex、import knex from knex等。JavaScript 用户的 IDE 自动补全提示若使用纯 JavaScript非 TypeScript类型重构可能导致 IDE 自动补全失效。文档给出的可用写法是const knex require(knex).knex({ //connection parameters });ESM 下同样可用import { knex } from knex; const kn knex({ //connection parameters });在 JSDoc 中为函数参数标注 knex 实例类型时可写成/** * param {import(knex).Knex} db */ function up(db) { // Your code }QueryBuilder 增强模块扩充语法变更如果你通过declare module为QueryBuilder增加自定义方法例如分页插件旧写法是直接挂在interface QueryBuilder上declare module knex { interface QueryBuilder { paginateTResult any[]( params: IPaginateParams ): KnexQBany, IWithPaginationTResult; } }必须改为嵌套在namespace Knex内部declare module knex { namespace Knex { interface QueryBuilder { paginateTResult any[]( params: IPaginateParams ): KnexQBany, IWithPaginationTResult; } } }这与types/index.d.ts中类型全部收纳于Knex命名空间的布局保持一致——模块扩充的目标必须落在该命名空间的成员上才能被解析到。同时注意使用 knex 类型现在要求 TypeScript 4.1当前仓库的tsd与tstyche类型测试也基于较新的 TypeScript 版本运行见 package.json。升级到 0.95.0MSSQL 驱动重写mssql → tedious0.95.0 为了解决长期存在的连接池、错误处理与性能问题MSSQL 方言被完全重写新实现不再经由mssql包而是直接使用tedious驱动。因此如果你的应用使用 MSSQL 数据库需要把依赖从mssql替换为tediousnpm uninstall mssql npm install tedious当前仓库的 package.json 中devDependencies使用tedious: ^18.2.1并在peerDependenciesMeta中把tedious声明为可选依赖package.jsonbrowser字段里也将tedious指向false以兼容非 Node 环境打包。lib/dialects/mssql 目录下的index.js、transaction.js、mssql-formatter.js等即重写后的实现。重写后连接串解析中 MSSQL 的主机名会被映射为server字段而非host见下文连接 URL 解析一节。升级到 0.95.0事务回滚不再触发 Promise 拒绝0.95.0 起对于带有处理函数handler的事务执行回滚不再自动触发 Promise rejection。若你希望保留旧行为回滚即拒绝需要显式传入doNotRejectOnRollback: falseawait knex.transaction( async (trx) { const ids await trx(catalogues).insert({ name: Old Books }, id); }, { doNotRejectOnRollback: false } );从源码可以确认该默认值的变化lib/execution/transaction.js 中Transaction构造默认doNotRejectOnRollback: truelib/knex-builder/make-knex.js 在创建事务时若用户未显式指定也会补上true嵌套事务savepoint场景同样如此lib/execution/transaction.js。具体执行时lib/execution/transaction.js 的逻辑是若状态为失败且doNotRejectOnRollback为真、且 SQL 匹配ROLLBACK开头的语句则走_resolver()正常完成而非_rejecter()。MySQL/MariaDB 方言也有对应的 lib/dialects/mysql/transaction.js、lib/dialects/mariadb/transaction.js、lib/dialects/mssql/transaction.js 等实现分支。升级到 0.95.0连接 URL 解析切换到 WHATWG URL 标准此前 knex 使用 Node.js 旧的url.parselegacy URL API解析连接串0.95.0 起改用WHATWG URL标准。当前实现位于 lib/knex-builder/internal/parse-connection.js先用new URL(str)解析若解析失败或 Windows 盘符场景则回退为把字符串当作 SQLite 文件名处理{ client: sqlite3, connection: { filename: str } }否则根据协议选择对应方言PostgreSQL 系postgres/postgresql走pg-connection-string解析其余方言从 URL 对象提取hostname、port、username、password、pathname作为 database并把查询字符串参数写入 connection 对象其中mysql:、mariadb:、mssql:协议的查询参数还会尝试JSON.parse。对用户的影响如果连接串中的密码、用户名含有 URL 中非常规字符非字母、数字、点、短横线需要遵循 WHATWG URL 的百分号编码percent-encoding规则例如将编码为%40源码中正是通过decodeURIComponent还原用户名与密码lib/knex-builder/internal/parse-connection.js。典型写法postgresql://user:p%40sswordlocalhost:5432/mydb升级到 0.95.0全局静态 Knex.raw 被移除require(knex).raw()不再可用——全局静态Knex.raw已移除请改用实例方法knex.rawconst knex require(knex)({ client: postgres }); const sql knex.raw(select * from users where id ?, [1]); // ✅从源码看knex 实例上的raw由 lib/knex-builder/make-knex.js 在实例化时挂载内部转发到client.raw而模块级别的导出对象lib/knex-builder/Knex.js只保留knex.Client、knex.KnexTimeoutError、knex.KnexPool以及QueryBuilder/SchemaBuilder/ViewBuilder/ColumnBuilder/TableBuilder.extend等静态工具不再提供raw。KnexTimeoutError的定义与timeout工具在 lib/util/timeout.js 中。升级到 0.95.0CLI 不再直接支持 v8 flagsknex CLI 不再接受 v8 引擎参数。如需传递这类 flag改用环境变量NODE_OPTIONSNODE_OPTIONS--max-old-space-size1536 npm run knex这样 Node 进程本身会在启动时读取NODE_OPTIONS中的 V8 选项而 knex CLI 只需保持普通参数解析即可CLI 入口为 bin/cli.js 所对应的knexbin 命令见 package.json。升级到 0.95.0自定义 Client 必须改为 class所有方言客户端从可 new 的函数改为 ES class。如果你有自定义 client需要按新语法迁移const Client require(knex); const { inherits } require(util); // 旧写法函数 原型链继承 function CustomClient(config) { Client.call(this, config); // construction logic } inherits(CustomClient, Client); CustomClient.prototype.methodOverride function () { // logic }; // 新写法class 继承 class CustomClient extends Client { // node 12 driverName abcd; constructor(config) { super(config); this.driverName abcd; // 错误做法在构造器里赋值不会生效 // construction logic } methodOverride() { // logic } } // 替代方案在原型上声明 driverName CustomClient.prototype.driverName abcd;注意文档强调driverName需要在类字段class field或原型上声明因为在构造器中super()之前、以及实例化过程中的驱动初始化逻辑依赖该字段已就位——若在constructor内才赋值会不工作。基类Client在 lib/client.js 中即通过读取this.dialect/this.driverName来决定是否初始化驱动与连接池例如if (this.driverName config.connection) this.initializeDriver()这解释了为何该字段必须预置在原型层面。升级到 0.95.0内部文件与命名的大规模重构0.95.0 做了大规模的内部重构与重命名多数方言专属的 compiler/builder 文件以方言名为前缀且部分文件被移动。例如当前仓库中可以看到lib/dialects/postgres/query/pg-querycompiler.js、lib/dialects/mysql/schema/mysql-columncompiler.js、lib/dialects/mssql/mssql-formatter.js、lib/dialects/cockroachdb/crdb-querycompiler.js等命名模式与文档描述完全吻合。如果你此前直接从 knex 库文件相对路径引入过内部模块升级后需要同步调整引用路径建议不要依赖未公开的内部路径。升级到 0.95.0first 与 pluck 禁止在同一查询中同时链式调用过去.first()与.pluck()同时链式使用时只有最后链上的一个生效0.95.0 起这种行为会直接抛错。从 lib/query/querybuilder.js 与 lib/query/querybuilder.js 的实现可以看到first()和pluck()都会检查this._method——一旦当前查询方法不是select就抛出Cannot chain .first() on ... query/Cannot chain .pluck() on ... query。请检查代码中是否误用// ❌ 0.95.0 会抛错 await knex(users).pluck(id).first(); // ✅ 分别使用 await knex(users).pluck(id); await knex(users).first();升级到 0.95.0空查询不再静默执行执行结果为空查询的操作例如向空数组插入现在会在所有数据库驱动上抛错而不是静默返回空结果// ❌ 0.95.0 抛错 await knex(users).insert([]); // ✅ 显式处理空数据 if (rows.length) { await knex(users).insert(rows); }这是 knex 有意收紧行为、避免看起来成功实则无事发生的边界情况。更早版本的升级要点0.21 / 0.19 / 0.180.21.0不再支持 Node.js 10。0.19.0向连接池配置传入未知属性现在会抛错beforeDestroy池配置项被移除需要类似功能请改用 tarn.js 的事件处理器。当前仓库连接池相关配置选项白名单见 lib/constants.jsPOOL_CONFIG_OPTIONS含maxWaitingClients、testOnBorrow、fifo、priorityRange、autostart、evictionRunIntervalMillis、numTestsPerRun、softIdleTimeoutMillis、Promise未知键会被拒绝。0.18.0不再支持 Node.js 8knex 改用原生 Promise 取代 bluebird——Knex.Promise被移除迁移与种子脚本不再注入 Promise 参数请移除对 bluebird 特有 API 的依赖使用 TypeScript 时需在compilerOptions.lib中加入es6否则.catch()、.then()可能报方法不存在的类型错误。0.17 至 0.14 的历史变更0.17.0TypeScript 泛型支持knex 的 TypeScript 绑定引入了泛型支持少数边界情况下可能使已有的 TS 构建报错需要按新的泛型签名调整调用代码。0.16.0MSSQL 版本下限与 datetime/timestamp 参数MSSQL数据库版本低于 2008 不再支持。PostgreSQL/MySQLtable.datetime与table.timestamp建议改用选项对象传参而非位置参数参见 schema 相关文档。Node 6存在重复事件监听器导致的MaxListenersExceededWarning问题复用单个 knex 实例多次执行迁移/种子时可能触发建议尽快升级到 Node.js 80.17.0 起完全移除 Node 6 支持。0.15.0MSSQL 存储过程与 MariaDB 方言MSSQL对以QUOTED_IDENTIFIER OFF创建的存储过程所操作的表创建唯一索引会失败。可用如下查询找出所有受影响的存储过程SELECT name OBJECT_NAME([object_id]), uses_quoted_identifier FROM sys.sql_modules WHERE uses_quoted_identifier 0;已知的唯一解决方案是用QUOTED_IDENTIFIER ON重新创建所有存储过程。mariadb方言不再支持请改用mysql或mysql2方言注意这是历史版本结论当前仓库的 lib/dialects/index.js 中mariadb已作为受支持方言重新回归。0.14.4迁移记录表不再支持 schema.table 写法在迁移配置的tableName中内联 schema 前缀已失效以下写法不再合法await knex.migrate.latest({ directory: src/services/orders/database/migrations, tableName: orders.orders_migrations, });从 0.14.5 开始应使用独立的schemaName参数await knex.migrate.latest({ directory: src/services/orders/database/migrations, tableName: orders_migrations, schemaName: orders, });源码侧 lib/migrations/migrate/migrator-configuration-merger.js 中迁移配置的默认值为tableName: knex_migrations、schemaName: nulllib/migrations/migrate/Migrator.js 内所有对迁移表的读写含锁表getLockTableName都通过getTable(knex, tableName, schemaName)将 schema 前缀拼装到最终表名上如orders.knex_migrations由此实现表名与 schema 的彻底解耦。结语升级路径速查目标版本核心动作2.0vscode/sqlite3→sqlite31.0Node ≥ 12当前版本要求 ≥ 16sqlite3→vscode/sqlite3历史过渡RETURNING返回对象迁移返回对象列表0.95TS 类型改走Knex命名空间TS ≥ 4.1MSSQL 换tedious事务回滚默认不 reject连接串用 WHATWG URL 编码移除全局Knex.rawCLI v8 flags 改NODE_OPTIONSClient 改 classfirst/pluck禁链式空查询抛错0.21/0.19/0.18Node 下限逐版上移原生 Promise 替代 bluebird连接池配置白名单化0.14.4迁移记录表用schemaName参数代替tableName: schema.table升级时建议按上述表格逐项对照你的代码库先跑一遍类型检查tsc定位 TS 相关断点再针对RETURNING、事务回滚、first/pluck、空查询插入等运行时行为变更编写回归用例最后用官方 CLInpx knex migrate:latest验证迁移链路。更多运行时行为细节可继续阅读仓库内的 docs/guide 系列文档与 UPGRADING.md 原文件。【免费下载链接】knexA query builder for PostgreSQL, MySQL, CockroachDB, SQL Server, SQLite3 and Oracle, designed to be flexible, portable, and fun to use.项目地址: https://gitcode.com/gh_mirrors/kn/knex创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表