- 后端
- 数据库
- ORM
【免费下载链接】typeorm
TypeScript & JavaScript ORM for Node.js — supports PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, Oracle, and more.
@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 --listCLI 入口位于 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> | -w | worker 进程数,默认值为 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 是规模最大也最典型的规则,其处理层次可以概括为:
- 文件级作用域闸门:文件里没有任何
typeorm(或typeorm/...)导入/再导出时直接跳过,避免误伤其他库中同名标识符(如 mongoose 的Connection); - 类型重命名:
Connection→DataSource、ConnectionOptions→DataSourceOptions、BaseConnectionOptions→BaseDataSourceOptions,同时改写导入说明符、类型引用(TSTypeReference)、类型查询(TSTypeQuery)与new表达式,并处理Connection as Foo这类别名导入和 CJSrequire("typeorm")解构; - 驱动特定选项类型:
MysqlConnectionOptions这类深层类型会被重写为Extract<DataSourceOptions, { type: "mysql" | "mariadb" }>内联表达式(MySQL 选项同时覆盖mariadb,所以生成联合字面量),避免用户依赖typeorm/driver/...深层导入路径; - 方法重命名:只在接收者被识别为 DataSource 实例时,把
.connect()→.initialize()、.close()→.destroy()。接收者识别来自带类型标注的变量、函数参数、类属性、构造器参数属性(private readonly x: DataSource)、getter 返回类型,以及访问链推断(如dataSource.manager推导为EntityManager、dataSource.getRepository()推导为Repository); - 属性重命名:
.connection→.dataSource,覆盖QueryRunner、EntityManager、各类Repository、各类QueryBuilder、EntityMetadata以及BaseEvent/InsertEvent等订阅者事件类型;ColumnMetadata、IndexMetadata则特殊处理为.entityMetadata.dataSource(v1 中它们的.connectiongetter 被整体移除); - 再导出与去重:
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 SQLTODO 前缀统一为TODO(typeorm-v1):,由 todo.ts 集中定义。该模块还保证了幂等性:再次运行时如果同一节点已有相同 TODO 注释,不会重复插入;同时会把注释插在// prettier-ignore指令之前,避免破坏该指令。
运行机制:基于 jscodeshift 的流水线与统计
执行入口在 run.ts,一次运行的完整链路为:
resolveTransforms解析出要运行的 transform 文件路径(resolve.ts):指定--transform时只解析单个文件,否则解析整个 version 的index文件;runTransforms逐规则调用 jscodeshift Runner 处理所有路径;runDependencies扫描并升级package.json;printSummary输出统计汇总,printGuide提示格式化建议;- 任一环节出现错误(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 是迁移流程的"安全阀"——凡涉及业务逻辑判断、无法通过类型/上下文推断的变更,工具都不会替你拍板,而是明确标注出来。处理建议:
- 先用
git diff通读 codemod 的全部改动; - 逐个搜索
TODO(typeorm-v1):,按注释给出的替代 API 手工修改; - 重新运行类型检查与测试。
依赖升级:package.json 的自动处理
除了改写源码,@typeorm/codemod还会自动扫描项目中的package.json并做依赖升级。查找逻辑见 find-package-json.ts:递归搜索给定路径下的所有package.json(排除node_modules),搜索根为当前工作目录与用户传入路径的并集。
三类依赖处理策略
依赖规则配置在 dependencies/v1.ts,按四类处理:
包替换(replacements)——旧包被新包取代:
| 旧包 | 新包 | 目标版本 |
|---|---|---|
mysql | mysql2 | ^3.22.0 |
sqlite3 | better-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.
相关推荐
散落各处的教案别再孤军奋战:用GraphRAG知识图谱RAG把教育数据串成一张网
散落各处的教案别再孤军奋战:用GraphRAG知识图谱RAG把教育数据串成一张网 教师、教研团队和教育产品团队,把分散在各系统的教案、课件、学生档案交给Grap
人工智能RAG知识图谱数据工程大模型TypeORM 1.0 升级指南:从 0.3.x 迁移的完整 Breaking Changes 清单与实战方案
TypeORM 1.0 升级指南:从 0.3.x 迁移的完整 Breaking Changes 清单与实战方案 本文是一份面向 TypeORM 0.3.x 存量
后端数据库ORMTypeORM迁移生成失败终极指南:从报错到修复的完整解决方案
TypeORM迁移生成失败终极指南:从报错到修复的完整解决方案 TypeORM迁移是数据库版本控制的核心功能,但在实际使用中,迁移生成失败是开发者经常遇到的痛点
后端数据库ORM
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考