Drizzle
Drizzle 是一个现代化的、类型安全的 TypeScript ORM,专为 Node.js 设计。它提供了简洁易用的 API,支持 PostgreSQL、MySQL 和 SQLite 等数据库,具备强大的查询构建器、事务处理和数据库迁移功能,同时保持轻量级和无外部依赖的特点,非常适合需要高性能和类型安全的数据库操作场景。
@gqloom/drizzle
提供了 GQLoom 与 Drizzle 的集成:
- 使用 Drizzle Table 作为丝线使用;
- 使用解析器工厂从 Drizzle 快速生成 CRUD 操作。
安装
使用丝线
只需要使用 drizzleSilk
包裹 Drizzle Table,我们就可以轻松地将它们作为丝线使用。
让我们在解析器中使用它们,同时我们使用 useSelectedColumns()
函数以得知当前 GraphQL 查询需要选取哪些列:
如上面的代码所示,我们可以直接在 resolver
里使用 drizzleSilk
包裹的 Drizzle Table。
在这里我们使用了 users
作为 resolver.of
的父类型,并在 resolver 中定义了 user
、users
两个查询和一个名为 posts
的字段。其中:
user
的返回类型是users.$nullable()
,表示user
可能为空;users
的返回类型是users.$list()
,表示users
将返回一个users
的列表;posts
字段的返回类型是posts.$list()
,在posts
字段中,我们在load
方法中使用了userList
参数,TypeScript 将帮助我们推断其类型,load
方法是对DataLoader
的封装,允许我们快速定义一个DataLoader
方法,并使用它来批量获取posts
。
我们还使用 useSelectedColumns()
函数来知道当前 GraphQL 查询需要选取哪些列。这个函数需要启用上下文。
对于无法使用 useSelectedColumns()
函数的运行时,我们也可以使用 getSelectedColumns()
函数来获取当前查询需要选取的列。
派生字段
为数据库表添加派生字段非常简单,但需要注意使用 field().derivedFrom()
方法声明所依赖的列,以便 useSelectedColumns
方法能正确地选取这些列:
隐藏字段
有时候我们并不想把数据库表格的所有字段都暴露给客户端。
考虑我们有一张包含密码字段的 users
表,其中 password
字段是加密后的密码,我们不希望把它暴露给客户端:
我们可以在解析器中使用 field.hidden
来隐藏 password
字段:
解析器工厂
gqloom/drizzle
提供了解析器工厂 DrizzleResolverFactory
,用于从 Drizzle 轻松地生成 CRUD 解析器,同时支持自定参数和添加中间件。
关系字段
在 Drizzle Table 中,我们可以轻松地创建关系,使用解析器工厂的 relationField
方法可以为关系创建对应的 GraphQL 字段。
查询
Drizzle 解析器工厂预置了一些常用的查询:
selectArrayQuery
: 根据条件查找对应表的多条记录selectSingleQuery
: 根据条件查找对应表的一条记录countQuery
: 根据条件统计对应表的记录数量
我们可以在解析器内使用来自解析器工厂的查询:
变更
Drizzle 解析器工厂预置了一些常用的变更:
insertArrayMutation
: 插入多条记录insertSingleMutation
: 插入一条记录updateMutation
: 更新记录deleteMutation
: 删除记录
我们可以在解析器内使用来自解析器工厂的变更:
自定义输入
解析器工厂预置的查询和变更支持自定义输入,你可以通过 input
选项来定义输入类型:
在上面的代码中,我们使用 valibot
来定义输入类型, v.object({ id: v.number() })
定义了输入对象的类型,v.transform(({ id }) => ({ where: eq(users.id, id) }))
将输入参数转换为 Drizzle 的查询参数。
添加中间件
解析器工厂预置的查询、变更和字段支持添加中间件,你可以通过 middlewares
选项来定义中间件:
在上面的代码中,我们使用 middlewares
选项来定义中间件,async (next) => { ... }
定义了一个中间件,useAuthedUser()
是一个自定义的函数,用于获取当前登录的用户,如果用户未登录,则抛出一个错误,否则调用 next()
继续执行。
完整解析器
我们可以用解析器工厂直接创建一个完整的 Resolver:
有两个用于创建 Resolver 的函数:
usersResolverFactory.queriesResolver()
: 创建一个只包含查询、关系字段的 Resolver。usersResolverFactory.resolver()
: 创建一个包含所有查询、变更和关系字段的 Resolver。
自定义类型映射
为了适应更多的 Drizzle 类型,我们可以拓展 GQLoom 为其添加更多的类型映射。
首先我们使用 DrizzleWeaver.config
来定义类型映射的配置。这里我们导入来自 graphql-scalars 的 GraphQLDateTime
和 GraphQLJSONObject
,当遇到 date
和 json
类型时,我们将其映射到对应的 GraphQL 标量。
在编织 GraphQL Schema 时传入配置到 weave 函数中:
默认类型映射
下表列出了 GQLoom 中 Drizzle dataType
与 GraphQL 类型之间的默认映射关系:
Drizzle dataType | GraphQL 类型 |
---|---|
boolean | GraphQLBoolean |
number | GraphQLFloat |
json | GraphQLString |
date | GraphQLString |
bigint | GraphQLString |
string | GraphQLString |
buffer | GraphQLList |
array | GraphQLList |