TypeORM 官方 playground 实战指南:用 ESM + sql.js 跑通内存版 SQLite 全流程
后端数据库ORM【免费下载链接】typeormTypeScript JavaScript ORM for Node.js — supports PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, Oracle, and more.项目地址https://gitcode.com/GitHub_Trending/ty/typeorm点击查看免费下载导读本文以仓库中的 playground/README.md 为核心完整拆解 TypeORM 官方自带的 SQLite 演示项目从零初始化一个运行在内存中的 SQLite 数据库基于 sql.js 驱动到定义 User 实体、写入示例数据、查询回显再到优雅关闭连接的全过程。读完本文你将掌握 TypeORM 在纯 ESMECMAScript Modules工程中的配置方式、sqljs驱动的底层工作原理、synchronize自动建表机制以及SqljsEntityManager提供的数据库导入导出能力。一、项目概览一个最小可运行的 TypeORM 演示工程playground是 TypeORM 仓库中的一个独立演示项目其 README 明确描述为TypeORM SQLite Example即一个使用 TypeORM 连接 SQLite 数据库的示例。它的特点是使用ESMECMAScript Modules模块体系采用现代 async/await 异步模式编写业务代码展示数据库连接的完整生命周期管理包括初始化与清理initialize/destroy完整演示TypeScript 装饰器与实体定义的用法。项目使用sql.js作为数据库驱动sql.js会把 SQLite 编译为 WebAssembly从而在 Node.js 甚至浏览器环境中创建一个纯内存数据库无需任何原生native依赖。这也是该示例能够运行在 Stackblitz 这类浏览器在线环境中的根本原因详见 playground/README.md。项目目录结构playground/ ├── src/ │ ├── entity/ │ │ └── User.ts # User 实体定义 │ ├── index.ts # 主应用代码入口 │ └── ormconfig.ts # 数据库配置DataSource 定义 ├── package.json ├── tsconfig.json └── README.md整个项目只有三个核心源文件实体定义、主入口、数据源配置结构极度精简是学习 TypeORM 最小闭环的绝佳样板。二、环境与依赖如何在 monorepo 中运行 playgroundplayground隶属于 TypeORM 的 pnpm workspace。仓库根目录的 pnpm-workspace.yaml 中声明了packages/*与playground两个成员其中playground对typeorm的依赖以workspace:*形式声明见 playground/package.json意味着它直接链接仓库内packages/typeorm的构建产物而非 npm 上的发布版本。查看 playground/package.json 可以看到完整的依赖清单依赖版本作用sql.js^1.13.0纯 JS/WASM 的 SQLite 实现作为 TypeORM 的sqljs驱动后端ts-node^10.9.2在 Node 中直接运行 TypeScripttypeormworkspace:*链接本仓库的 TypeORM 源码构建产物types/node^22.18.6Node.js 类型定义types/sql.js^1.4.9sql.js 类型定义typescript^5.9.2TypeScript 编译器运行步骤如下安装依赖在仓库根目录执行pnpm install或进入playground目录执行npm iREADME 中给出的即为此命令启动应用执行npm start。需要说明的适用前提由于playground通过workspace:*依赖typeorm在 pnpm 工作区中解析typeorm前需要先在仓库根目录执行pnpm run package构建 TypeORM 包pnpm-workspace.yaml 中的注释对此有明确说明。直接在仓库外单独npm i无法获得本地 TypeORM。可用命令一览README 给出了三个命令见 playground/README.md# 启动应用入口src/index.ts npm start # 构建 TypeScript 代码tsc 编译到 dist/ npm run build # 运行 TypeORM CLI按需使用 npm run typeorm其中npm run typeorm映射到typeorm-ts-node-esm -d ./src/ormconfig.ts这是 TypeORM 专为 ESM 场景提供的 CLI 入口。packages/typeorm/src/cli-ts-node-esm.ts 展示了它的实现它会检查环境变量NODE_OPTIONS是否已包含--loader ts-node若没有则通过spawnSync以--loader ts-node/esm --no-warnings重新拉起自身进程从而让 CLI 也能解析 ESM 环境下的 TypeScript 配置文件。三、ESM 工程配置package.json与tsconfig.json的配合playground 是一份纯 ESM 示例因此模块化配置是关键一环。在 playground/package.json 中type: module声明整个包按 ESM 解析.ts源码经 ts-node 转换后以 ESM 方式加载start: node --loader ts-node/esm src/index.ts通过 Node 的--loader ts-node/esm钩子直接运行 TypeScript 源码无需先编译build: tsc使用 TypeScript 编译器输出到dist/。在 playground/tsconfig.json 中配置项值含义targetESNext编译目标为最新 ECMAScriptmodule/moduleResolutionESNext/NodeESM 模块体系stricttrue开启严格类型检查experimentalDecoratorstrue启用装饰器语法实体定义必需emitDecoratorMetadatatrue输出装饰器元数据TypeORM 反射实体属性类型必需rootDir/outDir./src/./dist编译输入输出目录ts-node.esmtrue让 ts-node 在 ESM 模式下工作值得注意的是src/index.ts与src/ormconfig.ts中导入本地模块时使用了.js后缀如import { AppDataSource } from ./ormconfig.js这是 ESM 环境下 TypeScript 的标准做法——源码中的.js导入路径在编译后依然有效同时也能被 ts-node 正确解析。四、数据源配置ormconfig.ts里的sqljs驱动playground/src/ormconfig.ts 是整个示例的心脏完整代码如下import reflect-metadata import { DataSource } from typeorm import { User } from ./entity/User.js export const AppDataSource new DataSource({ type: sqljs, synchronize: true, logging: true, entities: [User], })逐项拆解import reflect-metadataTypeORM 依赖reflect-metadata提供的反射元数据能力来读取装饰器信息必须在导入DataSource前引入type: sqljs指定使用 sql.js 驱动。注意 TypeORM 中 SQLite 相关驱动有三个sqlite原生sqlite3包、better-sqlite3同步 API 原生绑定、sqljsWASM 内存实现。这里选择sqljs意味着不触碰任何原生二进制文件synchronize: true数据源初始化时自动根据实体元数据创建数据库表结构。由于这里没有配置migrations演示项目依靠该选项让User表随初始化自动创建logging: true开启 SQL 日志运行时终端会打印 TypeORM 实际执行的 SQL 语句entities: [User]注册实体类。该配置未设置location因此 sql.js 驱动会创建一个全新的内存数据库下文结合源码说明。从源码看sqljs驱动的连接建立过程packages/typeorm/src/driver/sqljs/SqljsDriver.ts 的createDatabaseConnection()展示了连接建立的策略protected createDatabaseConnection(): Promiseany { if (this.options.location) { return this.load(this.options.location, false) } return this.createDatabaseConnectionWithImport(this.options.database) }也就是说若配置了location驱动会尝试从该文件加载已有数据库文件不存在时不报错首次写操作时才落盘未配置location时直接new sqlite.Database()创建一个全新的空内存数据库与 playground 的行为完全一致。在createDatabaseConnectionWithImport()中驱动创建数据库后还会执行PRAGMA foreign_keys ON启用外键约束——这意味着即使没有显式配置sqljs驱动的连接默认也会开启 SQLite 外键检查。sqljs特有的数据源选项packages/typeorm/src/driver/sqljs/SqljsDataSourceOptions.ts 定义了sqljs驱动的扩展选项playground 虽未使用全部但理解它们有助于将此示例升级为可持久化的应用选项类型说明databaseUint8Array打开连接时导入的数据库二进制内容用于从备份恢复driverany自定义 sql.js 驱动对象默认require(sql.js)sqlJsConfigany初始化 sql.js 时传入的配置autoSaveboolean开启自动保存每次数据库变更后自动写盘或回调autoSaveCallbackFunction替代内部保存逻辑的回调autoSave为true时生效locationstringNode 环境下的文件路径或浏览器环境下的 localStorage 键useLocalForageboolean浏览器环境下改用 localforage 异步读写 indexedDBpoolSizeneversqljs 驱动不支持连接池一个关键约束在 SqljsDriver.ts 的构造函数中开启autoSave时必须同时提供location或autoSaveCallback否则会抛出DriverOptionNotSetError。这与直觉一致——自动保存总需要一个落点文件、localStorage 或回调。五、实体定义User.ts中的装饰器用法playground/src/entity/User.ts 定义了一个最典型的 TypeORM 实体import { Entity, PrimaryGeneratedColumn, Column } from typeorm Entity() export class User { PrimaryGeneratedColumn() id!: number Column() firstName!: string Column() lastName!: string Column() email!: string Column({ default: true }) isActive!: boolean }要点分析Entity()将该类标记为数据库表映射实体表名默认由类名推导此处为userPrimaryGeneratedColumn()声明自增主键。在 sql.js 场景下插入后需要回读主键——SqljsDriver.ts 的createGeneratedMap()正是通过执行SELECT last_insert_rowid()拿到新插入行的自增 id源码注释引用了 sql.js 上游 issue说明这是获取插入 id 的唯一可靠途径Column()映射普通列默认列类型由 TypeScript 设计时类型number/string/boolean推断Column({ default: true })为isActive指定默认值true建表时对应列会带上DEFAULT true约束!非空断言属性通过装饰器元数据赋值TypeScript 的strict模式下用!声明该属性在构造后必然被赋值这是 TypeORM 实体的惯例写法。正是 playground/tsconfig.json 中的experimentalDecorators与emitDecoratorMetadata两个开关才让 TypeORM 能够在运行时读取Column对应属性的类型从而推断出 SQLite 中的列类型。六、主流程index.ts的完整生命周期playground/src/index.ts 演示了 TypeORM 使用中的标准五步流程import { AppDataSource } from ./ormconfig.js import { User } from ./entity/User.js async function main() { try { await AppDataSource.initialize() console.log(Database initialized) // 创建新用户 const user new User() user.firstName John user.lastName Doe user.email johnexample.com // 保存用户 await AppDataSource.manager.save(user) console.log(User saved:, user) // 查询所有用户 const users await AppDataSource.manager.find(User) console.log(All users:, users) await AppDataSource.destroy() } catch (error) { console.error(Error during Data Source initialization:, error) process.exit(1) } } await main()六个关键动作AppDataSource.initialize()建立数据库连接。sqljs驱动在此阶段创建内存数据库因为synchronize: true同时会根据User实体的元数据创建user表实例化实体new User()后逐个为属性赋值id留空由数据库自增生成AppDataSource.manager.save(user)通过 EntityManager 将实体写入数据库。INSERT 执行后 TypeORM 通过last_insert_rowid()回填id因此控制台随后打印的user对象已包含完整主键AppDataSource.manager.find(User)查询该表全部记录并映射回User实例数组AppDataSource.destroy()关闭数据源。在 sql.js 场景下对应驱动disconnect()中的databaseConnection.close()见 SqljsDriver.ts释放内存数据库错误处理初始化或执行失败时打印错误并process.exit(1)保证进程以非零码退出便于 CI 或脚本感知失败。顶层await main()是 ESM 特有的语法package.json中type: module使其合法也是该示例作为 ESM 演示的标志性写法。七、sql.js 内存数据库的特性与适用场景README 特别强调了内存数据库的两点特性见 playground/README.md数据是临时的数据库完全驻留内存进程退出后数据即被清空。因此该示例非常适合测试与开发用途无原生依赖sql.js 以 WASM 实现 SQLite可运行在浏览器等受限环境中如 Stackblitz天然具备跨平台可移植性。若需要持久化应该怎么做README 只演示了内存模式但结合仓库源码可以从 SqljsEntityManager.ts 中看到 sql.js 驱动独有的持久化 API。当数据源使用sqljs驱动时dataSource.manager实际是SqljsEntityManager它额外提供loadDatabase(fileNameOrLocalStorageOrData)从文件Node或 localStorage 键浏览器加载数据库或直接导入Uint8ArraysaveDatabase(fileNameOrLocalStorage?)把当前内存数据库导出并写入文件/localStorage不传参时使用options.locationexportDatabase()导出当前数据库为Uint8Array。仓库测试 packages/typeorm/test/functional/driver/sqljs/save.test.ts 完整验证了这一闭环先repository.save(post)写入数据再dataSource.sqljsManager.saveDatabase(pathToSqlite)落盘随后loadDatabase(pathToSqlite)重新加载并能通过findOneBy({ title: The second title })读回数据。此外locationautoSave组合则提供变更即落盘的持久化模式startup.test.ts 验证了文件不存在时正常启动、首次写操作后自动生成文件。自动保存的触发机制packages/typeorm/src/driver/sqljs/SqljsQueryRunner.ts 揭示了自动保存的内部机制每次执行非 SELECT 语句insert/update/delete 等后查询运行器将内部isDirty标记为true在release()连接归还与commitTransaction()事务提交后时调用flush()进而触发driver.autoSave()autoSave()见 SqljsDriver.ts会判断options.autoSave且当前不在事务中再决定调用autoSaveCallback(export())还是save()事务进行中不会自动保存因为export()会中断当前事务。仓库测试 packages/typeorm/test/functional/driver/sqljs/auto-save.test.ts 对该机制做了双向验证开启autoSave时插入、更新、删除共触发 8 次回调关闭时一次也不触发。八、查询执行与日志sqljs驱动如何跑 SQLplayground 在ormconfig.ts中开启了logging: true运行时会在终端看到 TypeORM 打印的 SQL 与参数。从 SqljsQueryRunner.ts 的query()方法可以看到 sql.js 驱动的执行细节参数校验sql.js 驱动不支持命名占位符:name形式只支持位置参数?传入对象形式参数会抛出NamedPlaceholdersNotSupportedError执行方式databaseConnection.prepare(query)预编译语句随后statement.bind(parameters)绑定参数undefined会被规范化为null最后通过while (statement.step())逐行迭代取出结果——这是 sql.js 的语句执行模型结果统计databaseConnection.getRowsModified()提供受影响行数对应affected慢查询日志若配置了maxQueryExecutionTime执行耗时超过阈值会触发logQuerySlow。仓库测试 packages/typeorm/test/functional/driver/sqljs/query-execution-time.test.ts 用一条 50 万次递归 CTE 的慢查询验证了计时覆盖的是完整执行循环而非仅预编译阶段事件广播执行前后会通过Broadcaster广播BeforeQuery/AfterQuery事件订阅者可以在此挂载查询审计或性能监控。九、延伸阅读playground/README.md本文对应的原始演示文档playground/src/index.ts、playground/src/ormconfig.ts、playground/src/entity/User.ts本文剖析的三个核心源文件packages/typeorm/src/driver/sqljs/SqljsDriver.tssql.js 驱动的连接、加载、保存与自增 id 回填实现packages/typeorm/src/driver/sqljs/SqljsQueryRunner.tssql.js 驱动的查询执行与自动保存触发逻辑packages/typeorm/src/entity-manager/SqljsEntityManager.tssql.js 专属的数据库导入/导出 APIpackages/typeorm/src/driver/sqljs/SqljsDataSourceOptions.tssqljs驱动的全部扩展配置项packages/typeorm/test/functional/driver/sqljs/覆盖启动、加载、保存、自动保存与慢查询计时的完整测试集packages/typeorm/src/cli-ts-node-esm.tstypeorm-ts-node-esmCLI 入口实现。十、总结playground项目虽然代码量极小却浓缩了 TypeORM 在 ESM 工程中的完整最佳实践type: module与 ts-node loader 的模块化配置、experimentalDecoratorsemitDecoratorMetadata的装饰器支撑、DataSource的声明式配置、synchronize自动建表、EntityManager 的增查操作以及initialize/destroy的严谨生命周期管理。同时通过阅读仓库中sqljs驱动的源码与测试可以清晰地看到它在内存数据库表象下的工程细节外键默认开启、事务与自动保存的协调、last_insert_rowid()的主键回填、位置参数而非命名占位符的 SQL 绑定方式以及SqljsEntityManager提供的持久化扩展点。若你的项目需要零依赖、可移植的数据库单元测试、CI 环境、浏览器端演示以本 playground 为起点再按需接入locationautoSave或saveDatabase/loadDatabase即可快速演进为一个可持久化、可迁移的 TypeORM SQLite 应用。赞分享后端数据库ORM【免费下载链接】typeormTypeScript JavaScript ORM for Node.js — supports PostgreSQL, MySQL, MariaDB, SQLite, SQL Server, Oracle, and more.项目地址https://gitcode.com/GitHub_Trending/ty/typeorm点击查看免费下载相关推荐MikroORM 与 sql.js 实战在浏览器与 Node.js 中运行纯内存 SQLiteWASMMikroORM 与 sql.js 实战在浏览器与 Node.js 中运行纯内存 SQLiteWASM 本文围绕 MikroORM 的 mikro or后端camembert-ner常见问题解决指南10个开发者必知的技术要点camembert ner常见问题解决指南10个开发者必知的技术要点 camembert ner是一个基于camemBERT微调的命名实体识别 NER 模型Snowpack 快速上手5 分钟跑通 ESM 无打包前端开发全流程Snowpack 快速上手5 分钟跑通 ESM 无打包前端开发全流程 导读 Snowpack 是一款 ESM 驱动的现代前端构建工具其核心思路是无打包开发前端开发工具前端构建上一篇Pulumi迁移指南从CloudFormation、Terraform迁移到Pulumi下一篇如何快速配置Bagisto多语言支持打造全球化电商平台的完整指南创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考