数据库工具
八大 TypeScript ORM、查询构建器和数据库库:评估类型安全
简介
评估 TypeScript ORM 开箱即用的类型安全级别可能很耗时。本文简要评估了在2022 年 11 大 Node.js ORM、查询构建器和数据库库中考虑的库的类型安全。
虽然本文中考虑的所有库都为其 API 提供了 TypeScript 绑定,但它们实际提供的类型安全级别却大相径庭。有些库,例如 Waterline,可以无错误地编译,但随后随意传递 any
类型,跳过任何类型检查。相反,其他库,例如 Prisma,对于更改返回数据形状的部分查询等高级功能具有完全的类型安全。
本文将探讨以下内容
- 来源:库的类型定义是官方内置的,还是来源于 DefinitelyTyped @types 仓库?
- 记录创建:模型是否类型安全,以及是否可以以类型安全的方式创建记录?
- 记录获取:获取数据时,即使对于部分模型和关系,对象是否也类型安全?
本文假定读者对 TypeScript 和类型安全有一定了解。要了解更多信息,请查阅官方 TypeScript 文档。本文还将假定读者对 ORM 和查询构建器有一定了解。要了解有关这些数据库工具的更多信息,请参阅 Prisma 的数据指南中的比较 SQL、查询构建器和 ORM。
注意:本文最初发布于 2020 年 10 月 2 日。最近更新于 2022 年 2 月 15 日。
Prisma
评估总结
- 类型定义:内置
- 记录创建:类型安全
- 记录获取:类型安全
概述
Prisma 与大多数 ORM 不同之处在于,模型并非在类中定义,而是在 Prisma Schema 中定义,后者是 Prisma 工具包使用的主要配置和数据模型定义文件。在 Prisma Schema 中,你可以定义数据源(例如 PostgreSQL 数据库)以及模型(例如 users
和 posts
)及其之间的关系。使用此 Schema,Prisma 会生成一个类型安全的 Client,它公开了一个创建-读取-更新-删除 (CRUD) API,然后你就可以使用它来查询数据库。这个 Prisma Client 作为功能丰富的查询构建器,可以在你的 Node.js 应用程序中使用,以返回纯 JavaScript 对象,而不是模型类的实例。
什么是 Prisma?
Prisma 是一个较新的 ORM,经历了多次迭代和重新设计。其独特的、以 Schema 为中心的架构与使用类定义模型的典型 ORM 形成对比。它允许开发人员获得类型安全的一些好处,即使在 JavaScript Node.js 应用程序中也是如此。要深入了解 Prisma 的类型安全,请参阅使用 Prisma 的零成本类型安全进行高效开发。
如果您想了解更多关于我们为什么认为 Prisma 是一个很好的选择,请查看我们的为什么选择 Prisma?页面。
类型定义:内置
Prisma Client 的类型定义在生成客户端时自动生成。Prisma Schema 中定义的模型(例如 User
和 Post
)会自动作为类型导出到生成的 index.d.ts
文件中,从而在查询数据时轻松实现完全的类型安全。
记录创建:类型安全
使用 Prisma 创建新记录时,如果尝试添加模型中未定义的属性,将导致类型错误。模型属性会自动补全。此外,嵌套写入也具有类型安全性。嵌套写入使用关系将数据插入到多个表中。这意味着在使用相同的 prisma.user.create()
调用创建 User
和嵌套的 Post
时,Post
模型字段也会进行类型检查和自动补全,从而保证嵌套记录的有效性。
记录获取:类型安全
从数据库获取记录时,返回对象是完全类型化的,即使对于关系查询也是如此。例如,当从数据库中获取所有用户并包含帖子关系以额外获取用户的所有帖子时,类型被推断为 (User & {posts: Post[];})[]
。此外,在使用 include
添加获取的关系时,自动补全也有效,这样你就无法查询不存在的关系,这是本文中许多库所缺乏的功能。
为了进一步展示 Prisma 内置的类型安全级别,考虑一个部分查询,其中只查询某些属性,从而更改返回对象的类型
const usersWithPartialPosts = await prisma.user.findMany({include: {posts: {select: {title: true,published: true,},},},})
在此查询中,返回所有用户,但 posts
关系模型中只选择了 title
和 published
字段。usersWithPartialPosts
然后被类型化为
(User & {posts: {title: string;published: boolean;}[];})[]
这意味着尝试访问未选择的 post
字段(例如 content
)将失败。Prisma 是本文中唯一能够实现这种粒度类型安全的类似 ORM 的库。
类型安全:强
Prisma 独特的设计,即生成一个编码数据模型的本地 CRUD 客户端,使其能够在 TypeScript ORM 中实现无与伦比的类型安全级别。使用 Prisma 操作和查询数据库中的数据时,你将获得准确的嵌套关系查询类型以及修改返回模型形状的部分查询类型。
Sequelize
评估总结
- 类型定义:内置
- 记录创建:非类型安全
- 记录获取:非类型安全
概述
什么是 Sequelize
Sequelize 是一个成熟的、基于 Promise 的 Node.js ORM,支持 PostgreSQL、MySQL、MariaDB、SQLite 和 Microsoft SQL Server。它遵循传统的 ORM ActiveRecord 模式,通过扩展基础 Model
类来定义模型。然后使用类方法执行 SELECT
和 INSERT
等操作。关系也使用 hasMany()
和 belongsTo()
等类方法定义。它在 JavaScript 社区中非常流行,并且已经存在很长时间了。然而,该项目最近停滞不前,似乎不再像以前那样活跃。
有关 Prisma 和 Sequelize 的更详细比较,请参阅我们的Sequelize 比较页面。
类型定义:内置
截至 v5 版本(撰写本文时,Sequelize 为 v6.16.1),Sequelize 包含内置类型定义。在此之前,类型定义可通过 @types
获取。Sequelize 最初设计为 JavaScript ORM,TypeScript 支持是在近年才添加的。
记录创建:非类型安全
开箱即用,Sequelize 不会为模型属性提供严格的类型检查。要实现这一点,开发人员必须编写大量的样板代码,包括 interfaces
、类以及任何关系的 CRUD 方法定义。对于具有多个复杂数据模型的系统,这很快就会变得繁琐和笨重。当使用添加到模型的 mixin 或使用嵌套模型创建记录时,再次由开发人员提供类型定义。
Sequelize 还允许您在不检查属性类型的情况下定义模型。使用这种方法,您可以快速开始使用 Sequelize 和 TypeScript,但在处理数据时会失去所有类型安全性。
记录获取:非类型安全
鉴于 Sequelize 允许对模型属性进行严格和宽松的类型检查,编译器只有在开发人员提供了所有必要的类型定义时,才能正确地进行类型检查查询。此外,当使用 include
获取关联时,返回类型不包含有关获取数据的嵌套形状的信息,并且为了正确地无错误编译,开发人员必须使用 !
非空断言和 rejectOnEmpty
参数来覆盖编译器。
类型安全:弱
截至 v5 版本,Sequelize 提供了内置类型定义,但要在处理模型和记录时获得任何真正的类型安全,开发人员有责任编写接口并完整定义关联和类的类型。开箱即用时,提供的类型安全不多。
TypeORM
评估总结
- 类型定义:内置
- 记录创建:类型安全
- 记录获取:部分类型安全
概述
什么是 TypeORM?
TypeORM 是一个受 Hibernate 启发的 JavaScript 和 TypeScript ORM,可在 Node.js、Web 浏览器和 Cordova 等多个平台上运行。它在构建时考虑了 TypeScript 和类型安全,并支持两种主要的 ORM 架构模式:数据映射器 (Data Mapper) 和活跃记录 (Active Record),为开发人员提供了两者之间的选择灵活性。它还包括一个查询构建器,并支持许多流行的数据库。
有关 Prisma 和 TypeORM 的更详细比较,请参阅我们的TypeORM 比较页面。
类型定义:内置
TypeORM 是一个 TypeScript 优先的 ORM,明确为 TypeScript 使用而设计。类型内置于库中,并在定义模型时利用 TypeScript 的装饰器等特性。
记录创建:类型安全
在 TypeORM 中,模型是使用 Entity
类定义的。你用 @Entity()
装饰器装饰一个模型类(例如 User
),并用 @PrimaryGeneratedColumn()
和 @Column
等列装饰器装饰其属性(例如 id
和 name
)。如果你使用 DataMapper 模式,那么通过创建现在类型安全的模型类的新实例并设置其属性来定义记录。记录是使用模型特定的 Repository
对象保存的,该对象也已类型化。
嵌套写入通过创建相关类(例如 User
的 Post
)的实例,然后保存 User
和 Post
对象来完成。使用 cascade
功能,这可以通过一次 save
调用完成。TypeORM 开箱即用提供了模型类型安全。
使用查询构建器,模型属性也进行类型检查
await conn.createQueryBuilder().insert().into(User).values([{ firstName: 'Timber', lastName: 'Saw' },{ firstName: 'Phantom', lastName: 'Lancer' },]).execute()
如果 User
类没有 firstName
字段,编译器将发出错误。
当在查询构建器中使用关系时,类型安全性会失效,因为以下代码不会发出编译器错误
await conn.createQueryBuilder().relation(User, 'postsssss').of(user).add(post)
即使没有有效的 postssss
关系。
记录获取:部分类型安全
从数据库中获取记录可以通过多种方式完成。使用类型化、模型特定的 Repository
对象,开发人员调用存储库上的方法,例如 userRepo.find()
,其中返回类型被正确推断为 User[]
。
当包含 userRepo.find({relations: ["posts"]});
等关系时,返回类型仍被推断为 User[]
,并且编译器不了解包含的关系。开发人员需要以防御性方式访问 user.posts
属性。
使用内置查询构建器,以下查询的类型为 User
const firstUser = await conn.getRepository(User).createQueryBuilder('user').where('user.id = :id', { id: 1 }).getOne()
而在以下查询中
const user = await conn.manager.findOne(User, 1)user.photos = await getConnection().createQueryBuilder().relation(User, 'photos').of(user) // you can use just post id as well.loadMany()
user.photos
的类型是 Photo[]
。
类型安全:强
TypeORM 是一个 TypeScript ORM,其模型具有良好的类型安全。其查询构建器也具有良好的类型安全级别。关系的类型安全性较不严格,开发人员需自行编写防御性代码以应对此限制。
Bookshelf.js
评估总结
- 类型定义:@types
- 记录创建:非类型安全
- 记录获取:非类型安全
概述
什么是 Bookshelf.js?
Bookshelf.js 是一个基于 Knex.js 查询构建器库构建的 Node.js ORM。它受数据映射器 ORM 模式启发,提供了一个精简的接口用于建模和数据交互。Bookshelf.js 提供了标准的数据建模、查询和操作工具集。由于它构建于 Knex.js 查询构建器之上,如果您发现其接口受限,随时可以回退到编写更复杂的查询。它不像本文中考虑的其他一些工具那样活跃,但已经存在很长时间,并且拥有一批核心用户,他们更喜欢其精简的风格。
类型定义:@types
Bookshelf.js 的类型定义可以在 TypeScript 类型定义的 Definitely Typed 仓库中找到。它们不是内置于库中的。
记录创建:非类型安全
Bookshelf.js 模型通过扩展 bookshelf.Model
类或使用模型和表名调用 bookshelf.model()
来创建。表和 Schema 必须事先创建,并且不在这些模型中定义。例如,在创建对应表名为 users
的 User
模型后,要设置 name
属性,开发人员将调用 user.set('name', 'Joe')
。如果 users
表中不存在 name
列,则此调用将在运行时失败。因此,Bookshelf 中的模型创建开箱即用时并非类型安全。大多数传递的对象类型都是 any
。
记录获取:非类型安全
鉴于上述情况,从数据库中获取记录同样不具备类型安全性也就不足为奇了。当使用 const user = await User.where({'name': 'Joe'}).fetch();
获取 user
记录时,结果类型是 any
。在 fetch()
中使用 withRelated
包含关系并不会改变这一点。where()
子句中的查询参数不进行类型检查,如果您包含数据库中不存在的列,命令将通过编译但在运行时失败。
类型安全:弱
尽管 Bookshelf.js 确实有 @types
类型定义,但这些仅提供了编译 TypeScript 代码而不报错的最低要求。如果您正在寻找一个具有强大 TypeScript 支持的基于 Knex.js 的 ORM 类似库,那么 Objection.js 和 MikroORM 都提供了全面的类型安全,并且得到了更好的支持和维护。
Objection.js
评估总结
- 类型定义:内置
- 记录创建:类型安全
- 记录获取:部分类型安全
概述
什么是 Objection.js?
Objection.js 自称更像是一个“关系型查询构建器”而不是 ORM。与 Bookshelf.js 类似,它建立在强大的 Knex.js 查询构建器库之上,因此在灵活的查询构建器之上构建了类似 ORM 的功能,你可以随时回退到该构建器。Objection.js 似乎比 Bookshelf.js 更积极地维护和更好地文档化,根据谁在生产环境中使用 Objection.js?,许多 Objection.js 开发人员以前使用 Bookshelf.js。
类型定义:内置
Objection.js 提供了内置的 TypeScript 支持。与 Bookshelf.js 类似,Objection.js 最初是一个 JavaScript 库,随着 TypeScript 的普及和采用,后来添加了类型定义。然而,与 Bookshelf.js 不同,Objection.js 在处理模型和查询时提供了彻底的类型安全。
记录创建:类型安全
Objection.js 中的模型通过扩展 Model
类来定义。例如,在一个 User
模型中,开发人员定义不可空和可选属性,例如 name!
和 age?
,并提供一个必需的 tableName
属性。开发人员还可以为模型验证提供可选的 JSON Schema。到其他模型的关系,例如 HasMany
,也在模型类中定义。
创建新记录时,User.query().insert()
方法是类型安全的。模型属性会自动补全,尝试添加模型类中未定义的属性将导致编译错误。
为关系创建新记录时,例如为 User
创建一个新的 Post
,开发人员使用 user.$relatedQuery('posts').insert()
调用。这也是类型安全的,尽管你可以用不存在的模型或关系替换 posts
,但链式 insert
调用随后将抛出编译器错误。insert()
命令中的模型属性会自动补全,并且包含未定义的 Post
属性将导致编译器错误。
嵌套写入也可以使用 insertGraph()
操作完成
const user = await User.query().insertGraph({firstName: 'Sylvester',lastName: 'Stallone',posts: [{title: 'My first post',},],})
此操作也具有类型安全性,并且嵌套模型的属性会自动补全。
记录获取:部分类型安全
从数据库获取记录时,查询和返回对象是类型化的。当使用 relatedQuery
获取关系时,关系的返回类型也会正确推断。在以下示例中,posts 的返回类型是 Post[]
const posts = await User.relatedQuery('posts').for(1).orderBy('title')console.log(posts[0].name)
如果输入一个不存在的模型或关系而不是 'posts'
,编译器将不会发出任何错误,直到你尝试访问模型属性。此时编译器将抛出 Property does not exist
错误。
使用急切加载和 withGraphFetched()
方法(同时加载关系数据),上面的代码片段将如下所示
const userWithPosts = await User.query().findById(1).withGraphFetched('posts');console.log(userWithPosts.posts![0].title);
在这种情况下,userWithPosts
的类型被推断为 User
。除非包含非空断言,否则在尝试访问帖子的 title
属性时,编译器会发出 Object is possibly undefined
错误。
如果输入一个不存在的模型或关系而不是 'posts'
,编译器将不会发出任何错误。例如,根据编译器,以下代码将是有效的
const userWithPosts = await User.query().findById(1).withGraphFetched('postssss')
类型安全:强
与 MikroORM 和 Bookshelf.js 一样,Objection.js 是一个围绕 Knex.js 查询构建器构建的类 ORM 库。它的 TypeScript 支持和类型安全比 Bookshelf.js 强得多,与 MikroORM 相当。对于寻求精简、极简且具有强大 TypeScript 类型定义的类 ORM 库的开发者来说,它是一个不错的选择。
MikroORM
评估总结
- 类型定义:内置
- 记录创建:类型安全
- 记录获取:类型安全
概述
什么是 MikroORM?
MikroORM 是一个较新的 TypeScript ORM,它也支持原生 JavaScript。它是一个快速增长的项目,在 GitHub 上非常活跃,并得到其开发者的强力支持。受 Doctrine(一个 PHP ORM)的影响,它是一个受数据映射器(Data Mapper)、身份映射(Identity Map)和工作单元(Unit of Work)概念影响的 ORM。它的一些功能包括自动事务处理、多数据库支持、内置的基于 Knex.js 的查询构建器,以及模式和实体生成器。
类型定义:内置
作为一款 TypeScript 优先的 ORM,MikroORM 内置了其自身广泛的类型定义。
记录创建:类型安全
使用 MikroORM 定义模型涉及扩展一个 BaseEntity
类,在该类中声明、类型化模型的属性,并使用 @Property
和关系装饰器进行装饰。定义这些类后,可以通过创建这些模型类的实例以类型安全的方式创建记录。模型字段经过类型检查并支持自动补全。通过关系链接的模型可以使用 persistAndFlush()
在同一事务中持久化。例如
const user = new User('Dave Johnson', 'dave@johns.on')user.age = 14const post1 = new Post("Dave's First Post", user)const post2 = new Post("Dave's Second Post", user)// Persist the post, author will be automatically cascade persistedawait DI.em.persistAndFlush([post1, post2])
在这里,Post
模型在其构造函数中需要一个 title
和 User
,如果未提供这些,记录创建将失败。您可以使用其属性访问帖子的作者对象,例如 post1.author.title
。
记录获取:类型安全
MikroORM 在从数据库获取记录时也提供了强大的类型安全。可以使用实体仓库(EntityRepositories)或实体管理器(EntityManager)获取记录。
当使用给定模型的仓库(例如 userRepository
)获取记录时,返回对象是类型化的,并且您不能基于模型中未定义的属性进行查询。此外,包含关系将导致对象的类型反映加载了哪些关系。例如,对于链接到 Post
和 Item
模型的 User
模型,以下命令
const UserWithPosts = await DI.userRepository.findOne(1, ['posts'])
产生此类型
const UserWithPosts: (User & {posts: LoadedCollection<Post, Post>;items: Collection<Item, unknown>;}) | null
在这里,我们看到帖子已加载而项目未加载。一个限制是,在 findOne
关系数组中,可以附加对应于不存在关系的其他字符串(例如将“postsss”附加到数组),而不会从编译器输出任何错误。此外,即使关系未被显式填充,也可以访问它们而不会从编译器出现任何错误。
在使用 EntityManager
的 find()
或 findOne()
函数时,也适用类似级别的类型安全,如下例所示
const userWithPosts = await DI.em.findOne(User, { email: 'dave@johns.on' }, ['posts'])
类型再次被推断为
const user: (User & {posts: LoadedCollection<Post, Post>;items: Collection<Item, unknown>;}) | null
类型安全:强
MikroORM 是一个功能强大的 ORM,它还集成了灵活的 Knex.js 查询构建器。Knex.js 的结果可以使用 EntityManager.map()
映射到模型,这是一个独特而强大的功能。它在处理模型和查询结果时提供了强大的类型安全。
Waterline
评估总结
- 类型定义:@types
- 记录创建:非类型安全
- 记录获取:非类型安全
概述
什么是 Waterline?
Waterline 是 Sails Node.js 框架中使用的默认 ORM。其设计的一部分是允许您使用“一次编写,随处使用”的数据操作代码,以便您可以编写代码来查询或操作您的数据,无论这些数据位于 MySQL、PostgreSQL、MongoDB 还是其他数据库中。
类型定义:@types
Waterline 的类型定义可以在 TypeScript 类型定义的 Definitely Typed 仓库中找到。它们不是库的内置部分。
记录创建:非类型安全
使用 Waterline,模型是使用 Waterline.Collection.extend()
定义的。指定表名,并声明模型的属性,如 id
和 name
及其类型。然后将模型添加到 Waterline 实例中,该实例用于创建记录。Waterline 中的记录创建不是类型安全的,您可以在新记录中设置模型中未定义的属性。此外,返回类型为 any
,这在使用 Waterline 时经常被传递。
记录获取:非类型安全
当使用 Waterline 实例和给定模型从数据库获取记录时,任何属性,即使是不存在的属性,都可以插入到 find()
方法中,而不会触发任何编译器错误。该方法的返回类型为 any
。使用 Waterline 和 @types
类型定义查询数据通常不是类型安全的。
类型安全:弱
Waterline 的模型不是类型安全的,数据操作和创建操作也同样不是类型安全的。Waterline 主要是一个 JavaScript 库,其类型定义仅为 TypeScript 代码的编译提供了最低限度的支持。
Typegoose 和 Mongoose
评估总结
- 类型定义:@types
- 记录创建:类型安全
- 记录获取:非类型安全
概述
什么是 Mongoose?
Mongoose 是一个流行且维护良好的 Node.js 数据建模工具,用于 MongoDB。它允许您使用模式(schemas)对数据进行建模,并包含内置的类型转换(type casting)、验证(validation)、查询构建(query building)和业务逻辑钩子(business logic hooks)。如果您正在将 MongoDB 数据库与 Node.js 结合使用,并希望使用类似 ORM 的工具来将对象映射到数据库文档(即 ODM),Mongoose 是一个稳妥的选择:它是一个流行、成熟且持续活跃维护的项目。
将强大的 TypeScript 类型与 Mongoose 结合使用主要有两种方法。一种是使用来自 @types
仓库的类型并为您的模型编写自定义接口。另一种是结合 @types
中的类型使用 Typegoose。Typegoose 允许您使用类定义 Mongoose 模型。本文将探讨 Typegoose。
有关 Prisma 和 Mongoose 的更集中比较,您可以查看我们的Mongoose 比较页面。
类型定义:@types
要使用 Typegoose,您首先需要安装 Mongoose 及其 @types
类型定义。这些可以在 Definitely Typed 仓库中找到。它们不是库的内置部分。
记录创建:类型安全
要使用 Typegoose 创建模型,您需要定义模型类(例如 User
)及其属性(例如 name
和 age
)。属性使用 @prop()
装饰器进行装饰,以指定额外信息,例如属性是否为必需以及它们如何与其他模型关联。
一旦定义了模型,就可以使用 Mongoose Model
对象以类型安全的方式创建记录。模型属性会进行自动补全,并且尝试添加未定义的属性将导致编译器错误。返回对象类型与定义的模型类(DocumentType<User>
)相对应,其属性可以以类型安全的方式访问。这种类型安全也扩展到嵌套模型(例如,保存带有嵌套 Post
对象的 User
)。
记录获取:非类型安全
当使用 Model.find()
从数据库查询记录时,过滤属性不会进行类型检查,并且可以在不触发任何编译器错误的情况下添加未定义的属性。这将导致 Mongoose 尝试转换(cast)过滤器。如果转换失败,将在运行时抛出 CastError
。
当在模型上使用 .populate()
来填充对其他文档的引用时,任何内容都可以输入到 .populate()
方法中,而不会出现编译器错误,因此此操作同样不是类型安全的。
来自 find()
或 findOne()
命令的返回类型根据用于查询数据库的模型正确地类型化了。
类型安全:中等
Typegoose 利用类和装饰器帮助您快速构建 Mongoose 模型。创建记录时,参数会进行类型检查,但在查询时,开发者需要自行构建额外的保护措施。它是开始使用类型安全的 TypeScript 和 MongoDB 的绝佳起点。
简要考虑
本文重点关注 Prisma 数据指南中2022 年排名前 11 位的 Node.js ORM、查询构建器和数据库库中提及的最流行 ORM 的类型安全。在使用 TypeScript、Node.js 和数据库时,您可能还需要考虑其他库。
Knex.js
Knex.js 是一个 Node.js 查询构建器(不是 ORM),支持多种数据库,并包含事务支持、连接池和流式接口等功能。它允许您在数据库驱动程序之上工作,避免手动编写 SQL。然而,由于它是一个较低级别的库,因此需要熟悉 SQL 和关系型数据库概念,如连接(joins)和索引(indices)。官方 TypeScript 绑定内置于 knex
NPM 包中。TypeScript 支持是尽力而为的,并且“并非所有使用模式都可以进行类型检查”。Knex 文档还指出,“目前缺乏类型错误并不能保证生成的查询是正确的”。
PgTyped
PgTyped 的目标是让您能够编写原始 SQL,并确保您编写的查询的类型安全。它通过处理 SQL 文件并直接连接到正在运行的 PostgreSQL 数据库,自动为 SQL 查询的参数和结果生成 TypeScript 类型定义。它目前只支持 PostgreSQL。
@slonik/typegen
与 PgTyped 类似的一个包是 Slonik typegen 库,它使用 Slonik PostgreSQL 客户端从原始 SQL 查询生成 TypeScript 接口。要使用 typegen 库,您需要导入它并使用它生成的代理对象来运行查询。运行查询后,typegen 将检查查询结果的字段类型,并为该查询生成一个 TypeScript 接口。后续查询便可以以类型安全的方式执行。
结论
本文简要评估了最受欢迎的 Node.js ORM、数据库工具包和查询构建器的类型安全。本文的库列表来源于 Prisma 数据指南中2022 年排名前 11 位的 Node.js ORM、查询构建器和数据库库,其中这些库的健康状况根据仓库活跃度(repository activity)和开发者支持等标准进行评估。
类型安全并非您选择与数据库交互工具时唯一应考虑的标准。考虑包的编程接口、设计、对数据库功能的支持以及灵活性同样重要。不同的 Node.js 项目可能需要不同的工具。
要了解更多关于查询构建器和 ORM 的信息,请查阅 Prisma 数据指南中的SQL、查询构建器和 ORM 比较,这是一个免费且有用的知识库,可用于学习数据库、数据建模等更多内容。