☰
@typeorm/codemod 实战指南:TypeORM v0.3 自动迁移到 v1.0 的完整方案
2026/10/10 5:31:12 网站建设 项目流程
  • 后端
  • 数据库
  • ORM

【免费下载链接】typeorm

TypeScript & JavaScript ORM for Node.js — supports PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, Oracle, and more.

项目地址:https://gitcode.com/GitHub_Trending/ty/typeorm
点击查看免费下载

@typeorm/codemod是 TypeORM 官方仓库中随 v1.0 发布的自动化代码迁移工具,它基于 jscodeshift 的 AST 重写能力,把 v0.3.x 到 v1.0 之间的大部分破坏性变更(Connection→DataSource、find 选项语法、驱动与依赖升级等)自动应用到你的源码和package.json上。阅读本文后,你将掌握该工具的全部 CLI 用法、36 个 v1 转换规则的内部实现原理、TODO 人工审查流程,以及如何在大型代码库中安全地执行一次可回滚的版本升级。

为什么需要自动化迁移:v0.3 → v1.0 的破坏性变更

TypeORM v1.0 对公共 API 做了大规模重构:核心概念从Connection更名为DataSource,connect()/close()变为initialize()/destroy(),Repository.exist()更名为exists(),findByIds/findOneById/getCustomRepository等 API 被移除,驱动选项与 find 选项语法也有多处调整。手工迁移这些变更不仅枯燥,而且极易遗漏。

官方在 升级指南 中直接推荐使用@typeorm/codemod完成大部分迁移:它会原地更新你的代码,处理导入重命名、API 替换、find 选项语法、依赖升级等,并把无法自动化的变更以TODO注释形式留给你人工处理。

快速上手:一行命令完成大部分迁移

@typeorm/codemod的 CLI 约定为@typeorm/codemod <version> [options] <paths...>。目前仓库只注册了一个版本迁移目标v1(描述为 "Migrate from v0.3.x to v1.0",见 transforms/index.ts),因此基本用法是:

# 运行全部 v1 转换规则(原地修改) npx @typeorm/codemod v1 src/ # 预演模式:只显示将要发生的修改,不写入任何文件 npx @typeorm/codemod v1 --dry src/ # 只运行某一个转换规则 npx @typeorm/codemod v1 --transform connection-to-datasource src/ # 按 glob 模式排除文件(可重复指定) npx @typeorm/codemod v1 --ignore '**/generated*' --ignore '**/e2e/**' src/ # 控制并行 worker 进程数 npx @typeorm/codemod v1 --workers 4 src/ # 列出该版本下所有可用的转换规则 npx @typeorm/codemod v1 --list

CLI 入口位于 index.ts:不带参数或带--help/-h时打印用法说明;带--version/-v时打印已安装的@typeorm/codemod版本号(当前仓库为 1.0.3,见 package.json);其余情况进入参数解析与执行流程。未指定版本、指定未知版本、或未提供任何路径时,会报错并退出。

运行环境前提

  • Node.js 20 以上(package.json 的engines字段与依赖配置中的minNodeVersion: "20.0.0"均指向该要求,这也是 TypeORM v1 的运行时下限);
  • 迁移前建议先提交当前代码(git commit),因为 codemod 是原地改写,git diff是你核对每一处变更的依据。

CLI 选项全参考

README 中给出的选项表对应 parse-args.ts 的实现,完整内容如下:

选项短选项说明
--dry-d预演模式,显示变更但不写入文件
--help-h显示帮助信息
--ignore <pattern>-i追加的排除 glob 模式,可重复;与默认排除规则合并
--list-l列出当前版本可用的转换规则
--transform <name>-t仅运行指定的单个转换规则
--version-v打印已安装的@typeorm/codemod版本
--workers <num>-wworker 进程数,默认值为 CPU 核数减 1

参数解析的细节

从 parse-args.ts 可以看到几个值得注意的行为:

  • 位置参数中的第一个非选项参数被解释为version,其余作为待处理路径(paths);
  • --workers必须是正整数,否则直接报错退出;
  • --ignore支持多次出现,内部累积成数组;
  • --transform等带值选项如果缺值(下一个参数以-开头或不存在),会输出Error: <flag> requires a value并退出。

永远排除.d.ts文件

**/*.d.ts是硬编码的默认排除项(DEFAULT_IGNORE_PATTERNS,见 run-transforms.ts)。原因是.d.ts环境类型声明描述的是使用者依赖的类型形状,改写其中的标识符会静默破坏已发布的类型。用户提供的--ignore模式通过buildIgnorePatterns叠加在默认规则之后,两者同时生效。

transform 体系:36 个 v1 转换规则

@typeorm/codemod的转换规则以 "版本" 分组。当前唯一的v1分组定义在 transforms/v1/index.ts,其中导出了一个有序的 36 个 transform 数组。

顺序为什么重要

该文件的注释明确说明了排序的约束:connection-to-datasource必须最先运行,这样后续 transform 看到的是DataSource而不是Connection;datasourceName必须在globalFunctions之前运行,这样在createConnection导入被剥离之前,还能先改写createConnection({ name })的参数。这说明迁移规则之间存在依赖关系,不能随意调整顺序。

36 个规则一览

按源码顺序,它们覆盖了 v1 破坏性变更的方方面面:

  • 连接与数据源:connection-to-datasource(Connection→DataSource)、datasource-name(createConnection({ name })参数改写)、connection-manager、connection-options-reader;
  • 全局函数与容器:global-functions(createConnection/getConnection等全局函数)、use-container(IoCuseContainer移除);
  • Repository API:repository-find-by-ids、repository-find-one-by-id(移除的findByIds/findOneById)、repository-exist(exist()→exists())、repository-abstract;
  • QueryBuilder:query-builder-print-sql、query-builder-native-parameters、query-builder-where-expression、query-builder-on-conflict、query-builder-or-update、query-builder-replace-property-names;
  • find 选项:find-options-join、find-options-lock-modes、find-options-string-select、find-options-string-relations;
  • 列选项:column-readonly、column-width-zerofill、column-unsigned-numeric;
  • 驱动与数据源选项:datasource-mysql-connector、datasource-sqlite-options、datasource-sqlite-type、datasource-mongodb、datasource-mssql、datasource-sap、datasource-expo;
  • MongoDB:mongodb-stats、mongodb-types;
  • 其他:migrations-get-all、query-runner-loaded-tables-views、relation-count、file-logger。

运行npx @typeorm/codemod v1 --list会输出全部规则名称与描述;其中标记为(*)的规则在运行后需要人工复核(实现见 list-transforms.ts)。

以 connection-to-datasource 为例:AST 重写的典型思路

connection-to-datasource.ts 是规模最大也最典型的规则,其处理层次可以概括为:

  1. 文件级作用域闸门:文件里没有任何typeorm(或typeorm/...)导入/再导出时直接跳过,避免误伤其他库中同名标识符(如 mongoose 的Connection);
  2. 类型重命名:Connection→DataSource、ConnectionOptions→DataSourceOptions、BaseConnectionOptions→BaseDataSourceOptions,同时改写导入说明符、类型引用(TSTypeReference)、类型查询(TSTypeQuery)与new表达式,并处理Connection as Foo这类别名导入和 CJSrequire("typeorm")解构;
  3. 驱动特定选项类型:MysqlConnectionOptions这类深层类型会被重写为Extract<DataSourceOptions, { type: "mysql" | "mariadb" }>内联表达式(MySQL 选项同时覆盖mariadb,所以生成联合字面量),避免用户依赖typeorm/driver/...深层导入路径;
  4. 方法重命名:只在接收者被识别为 DataSource 实例时,把.connect()→.initialize()、.close()→.destroy()。接收者识别来自带类型标注的变量、函数参数、类属性、构造器参数属性(private readonly x: DataSource)、getter 返回类型,以及访问链推断(如dataSource.manager推导为EntityManager、dataSource.getRepository()推导为Repository);
  5. 属性重命名:.connection→.dataSource,覆盖QueryRunner、EntityManager、各类Repository、各类QueryBuilder、EntityMetadata以及BaseEvent/InsertEvent等订阅者事件类型;ColumnMetadata、IndexMetadata则特殊处理为.entityMetadata.dataSource(v1 中它们的.connectiongetter 被整体移除);
  6. 再导出与去重:export * from "typeorm/..."的深层路径同步改写,并对重命名后产生的重复 import 去重。

测试夹具可以直观印证这些行为,例如 connection-to-datasource-class-members.input.ts 展示了this.tenantConnection.connect()→this.tenantConnection.initialize()、getter 返回类型参与接收者识别,同时保证"未标注类型、与 TypeORM 无关的类属性"不被误改。

转换的两种结果:改写源码 或 留下 TODO

每个 transform 要么直接改写源码,要么在无法自动化处插入 TODO 注释。例如 query-builder-print-sql 的输出夹具 中,.printSql()调用原样保留,但在其上插入了:

// TODO(typeorm-v1): `printSql()` was removed — use `getSql()` or `getQueryAndParameters()` to inspect SQL

TODO 前缀统一为TODO(typeorm-v1):,由 todo.ts 集中定义。该模块还保证了幂等性:再次运行时如果同一节点已有相同 TODO 注释,不会重复插入;同时会把注释插在// prettier-ignore指令之前,避免破坏该指令。

运行机制:基于 jscodeshift 的流水线与统计

执行入口在 run.ts,一次运行的完整链路为:

  1. resolveTransforms解析出要运行的 transform 文件路径(resolve.ts):指定--transform时只解析单个文件,否则解析整个 version 的index文件;
  2. runTransforms逐规则调用 jscodeshift Runner 处理所有路径;
  3. runDependencies扫描并升级package.json;
  4. printSummary输出统计汇总,printGuide提示格式化建议;
  5. 任一环节出现错误(transform 解析错误或依赖升级错误)都会把process.exitCode置为 1,便于 CI 感知失败。

runTransforms:AST 转换的执行细节

run-transforms.ts 直接调用jscodeshift/src/Runner,关键配置包括:

  • 文件扩展名:ts,tsx,js,jsx;解析器:tsx(可同时处理 TS 与 TSX 语法);
  • ignorePattern为默认规则与用户--ignore的合并结果;
  • cpus仅在用户显式传入--workers时设置,否则交给 jscodeshift 默认(README 所述默认值为 CPU 核数减 1);
  • 通过拦截process.stdout.write解析 jscodeshift 输出的Processing N files、ERR、OKK、NOC、SKIP行,驱动进度 spinner(含剩余时间 ETA 估算),并把无法分类的 worker 输出缓冲起来、在运行结束后打印,避免警告与堆栈被吞掉;
  • 每个 transform 结束后输出一行摘要,如✔ Changed 12 out of 40 files (3.2s)。

transformer 管道:规则如何在单文件内串联

单个 transform 文件本质上是导出{ name, description, fn }的模块。transformer.ts中的transformer(transforms)工厂把这些规则串成一条管道:按顺序对同一个文件的源码依次应用每个规则的fn,任一规则返回了字符串就累计hasChanges,最后只把有变更的文件写回。同时通过api.stats记录每个规则实际命中了多少个文件(applied:<name>),供汇总输出展示。

输出汇总的内容

print-summary.ts 最终打印:

  • Statistics:处理文件总数、被转换文件数、跳过文件数、解析错误数、耗时;
  • Transforms applied:按命中文件数降序排列的规则命中统计;
  • Parse errors:解析失败的文件与错误信息(按文件排序);
  • Files requiring manual review:所有被插入 TODO 注释的文件,按规则分组;
  • Dependency changes:package.json的变更、警告与错误(重复项按(N times)聚合)。

运行后需要人工处理的 TODO

README 明确提示:部分 transform 会在代码中留下TODO注释,标记需要人工修改的位置;codemod 完成后会列出所有需要人工审查的文件(对应printTodos的 "Files requiring manual review" 分组列表)。

这些 TODO 是迁移流程的"安全阀"——凡涉及业务逻辑判断、无法通过类型/上下文推断的变更,工具都不会替你拍板,而是明确标注出来。处理建议:

  1. 先用git diff通读 codemod 的全部改动;
  2. 逐个搜索TODO(typeorm-v1):,按注释给出的替代 API 手工修改;
  3. 重新运行类型检查与测试。

依赖升级:package.json 的自动处理

除了改写源码,@typeorm/codemod还会自动扫描项目中的package.json并做依赖升级。查找逻辑见 find-package-json.ts:递归搜索给定路径下的所有package.json(排除node_modules),搜索根为当前工作目录与用户传入路径的并集。

三类依赖处理策略

依赖规则配置在 dependencies/v1.ts,按四类处理:

包替换(replacements)——旧包被新包取代:

旧包新包目标版本
mysqlmysql2^3.22.0
sqlite3better-sqlite3^12.9.0

版本升级(upgrades)——版本低于最低要求时自动提升到目标版本(实现在 upgrade.ts 中通过semver.minVersion比较,非标准版本号如file:/link:/git 依赖会报错要求手动处理):

包名最低版本升级目标
typeorm^1.0.0^1.0.0
@nestjs/typeorm^11.0.1^11.0.1
mongodb^7.0.0^7.1.1
mssql^12.0.0^12.3.0
mysql2^3.15.3^3.22.0
ioredis^5.0.4^5.10.1
redis^5.0.0^5.12.1
expo^52.0.0^55.0.0
@google-cloud/spanner^8.0.0^8.6.0
better-sqlite3^12.0.0^12.9.0
typeorm-aurora-data-api-driver^3.0.0^3.0.2

不兼容包(incompatible)——检测到即报错(Errors),并附上迁移建议,包括typeorm-seeding(使用被移除的ConnectionAPI)、pg-mem(使用被移除的getConnectionManager())、typeorm-naming-strategies(依赖内部路径并覆盖已移除接口方法)、typeorm-typedi-extensions与typeorm-routing-controllers-extensions(IoCuseContainer移除)、mock-typeorm与@opentelemetry/instrumentation-typeorm等。

警告(warnings)——检测到即提示,不阻断:如dotenv(v1 不再自动加载.env,需在DataSource中显式配置)、typeorm-transactional(仍使用已弃用的.connection属性)、以及 peer dependency 尚未支持 v1 的nestjs-typeorm-paginate、typeorm-encrypted、typeorm-fixtures-cli等。

Node 版本检查:若engines.node低于20.0.0,会产生警告提示更新。

写回package.json时会保留原有的缩进风格(2 空格或 4 空格自动探测),且在--dry模式下不做任何写入。

运行后的收尾:格式化与 git diff 审查

格式化

codemod 基于 AST 重写,可能引入细微的格式差异(多余括号、引号风格变化等)。README 与printGuide都建议迁移后运行项目自身的格式化器恢复代码风格:

npx @typeorm/codemod v1 src/ npx prettier --write src/ # 或:npx eslint --fix src/

Scoping 限制:没有类型信号的代码可能不会被转换

README 的 "Scoping" 一节对转换边界做了诚实说明:重命名属性或方法的 transform(如.connection→.dataSource)依赖类型标注来识别 TypeORM 实例;同时,它们也能识别"初始器是已知访问链"的未标注类字段(如private manager = this.dataSource.manager,见resolveAccessorChainType对dataSource.manager/getRepository()/createQueryRunner()等访问链的推导)。但完全没有类型信号的代码可能无法被自动转换——例如纯 JS 中未标注类型且初始器无法追溯的变量。因此运行结束后务必逐行检查git diff,对遗漏处手工修补。

验证与测试

仓库为每个 transform 都配备了输入/输出夹具测试,位于 test/transforms/v1/fixtures 下,可直接作为迁移效果的"预期行为说明书"。几个值得阅读的示例:

  • connection-to-datasource-class-members.input.ts:类属性、getter 返回类型、构造器参数属性的接收者识别,以及对无关类的保护;
  • connection-to-datasource-chained-access.output.ts:链式访问this.entityManager.connection→this.entityManager.dataSource,以及事件解构const { queryRunner } = event后的属性改写;
  • repository-exist-typed.input.ts:userRepo.exist()→userRepo.exists(),同时保证文件系统中同名.exist()方法、Redis 风格缓存客户端的.exist()不被误改;
  • query-builder-print-sql.output.ts:TODO 注释的插入位置与措辞。

这些夹具也提醒我们:codemod 的核心设计原则是"只在有充分把握时改写,拿不准就留 TODO",这正是它适合大规模代码库的原因。

延伸阅读

  • 升级指南:Upgrading from 0.3 to 1.0:v1 全部破坏性变更的权威说明,是人工处理 TODO 时的主要参考;
  • v1 release notes:v1.0 的发布说明与路线图;
  • run-transforms.ts:jscodeshift Runner 调用与进度/错误捕获的实现;
  • dependencies/v1.ts:依赖替换、升级、不兼容检测的完整规则表。
  • 后端
  • 数据库
  • ORM

【免费下载链接】typeorm

TypeScript & JavaScript ORM for Node.js — supports PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, Oracle, and more.

项目地址:https://gitcode.com/GitHub_Trending/ty/typeorm
点击查看免费下载

相关推荐

上一篇:800+ 免费API接口速查指南:无需认证的API与选型清单
下一篇:个人博客评论系统集成:gh_mirrors/v41/v4中Disqus与Commento对比

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询