Drizzle ORM:轻量级数据库工具
在上一章中,我们探究了 Cloudflare D1 如何作为一款高性能、低本钱的边缘数据库办理方案,彻底改变了我们对数据库架构的认知.
但一般来说,我们很少在项目里裸写sql,以是我们需要一个能简化操作和开辟的ORM工具,但市面上绝大多数的ORM对于这种ServerLess数据库的适配很差,需要办理各种依赖问题。 那么在尝试了一圈后,发现Drizzle是最好的搭配方案,选择它最焦点的理由是:它没有三方依赖、且对ServerLess这个场景非常友好。 [Drizzle地点](https://orm.drizzle.team/),建议看文档,中文只是阅读起来快一点,精简一点。
Schema:数据模子定义
Schema 是 Drizzle ORM 的基础,它定义了数据库表的结构和关系。
根本表定义
以下是一个简朴的表定义示例:- import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
- // 定义用户表
- export const users = sqliteTable('users', {
- id: integer('id').primaryKey(),
- name: text('name').notNull(),
- email: text('email').notNull().unique(),
- createdAt: integer('created_at', { mode: 'timestamp' }).notNull().defaultNow()
- })
复制代码 Schema 组织方式
Drizzle 允许你机动组织 Schema 文件,可以选择单文件或多文件方式:
单文件方式
得当小型项目,将所有表定义放在一个 schema.ts 文件中:- // src/db/schema.ts
- import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'
- export const users = sqliteTable('users', {
- /* 列定义 */
- })
- export const posts = sqliteTable('posts', {
- /* 列定义 */
- })
复制代码 多文件方式
对于大型项目,可以将表定义分散到多个文件中:- 📦 src
- └ 📂 db
- └ 📂 schema
- ├ 📜 users.ts
- ├ 📜 posts.ts
- └ 📜 comments.ts
复制代码 命名约定转换
TypeScript 通常利用驼峰命名法(camelCase),而数据库常用蛇形命名法(snake_case)。Drizzle 提供了自动转换功能:- // schema.ts
- export const users = sqliteTable('users', {
- id: integer('id'),
- firstName: text('first_name') // 显式指定数据库列名
- })
- // 或使用自动转换
- const db = drizzle(sqlite, {
- schema: { users },
- // 自动将 camelCase 转换为 snake_case
- casing: 'snake_case'
- })
复制代码 关系定义
Drizzle 支持定义表之间的关系:- export const posts = sqliteTable('posts', {
- id: integer('id').primaryKey(),
- title: text('title').notNull(),
- content: text('content'),
- userId: integer('user_id').references(() => users.id)
- })
复制代码 复用列定义
对于常见的列模式(如时间戳字段),可以创建可复用的定义:- // 通用时间戳字段
- const timestamps = {
- createdAt: integer('created_at', { mode: 'timestamp' }).notNull().defaultNow(),
- updatedAt: integer('updated_at', { mode: 'timestamp' })
- }
- // 在多个表中复用
- export const users = sqliteTable('users', {
- id: integer('id').primaryKey(),
- // ...其他字段
- ...timestamps
- })
复制代码 通过这种方式定义 Schema,Drizzle 不仅提供了类型安全的数据访问,还能自动生成迁移脚本,大大简化了数据库管理工作。
数据库连接
Drizzle ORM 通过数据库驱动执行 SQL 查询。
数据库驱动就是指的一个中心层,负责将查询哀求发送到数据库并处理处罚返回的结果。Drizzle 支持多种数据库驱动,使其可以或许与各种数据库系统无缝集成。
根本连接方式
- import { drizzle } from 'drizzle-orm/node-postgres'
- import { users } from './schema'
- // 创建数据库连接
- const db = drizzle(process.env.DATABASE_URL)
- // 使用连接执行查询
- const usersCount = await db.$count(users)
复制代码 Drizzle 的工作流程如下:
- 你的查询(如 db.$count(users))被转换为 SQL 语句(SELECT COUNT(*) FROM users)
- SQL 语句通过数据库驱动发送到数据库
- 数据库返回结果,驱动将其转换为 JavaScript 对象
- Drizzle 将结果返回给你的应用
访问底层驱动
如果需要,你可以直接访问底层数据库驱动:- import { drizzle } from 'drizzle-orm/node-postgres'
- const db = drizzle(process.env.DATABASE_URL)
- const pool = db.$client // 访问底层 node-postgres 驱动
复制代码 ServerLess 环境支持
Drizzle 原生支持各种边缘计算和 ServerLess 环境,这也是它与 Cloudflare D1 完善配合的缘故原由:- // Neon 数据库(ServerLess PostgreSQL)
- import { drizzle } from 'drizzle-orm/neon-http'
- const db = drizzle(process.env.DATABASE_URL)
- // Cloudflare D1
- import { drizzle } from 'drizzle-orm/d1'
- export default {
- async fetch(request, env) {
- const db = drizzle(env.DB)
- // 使用 db 执行查询
- }
- }
复制代码 特定运行时支持
Drizzle 还支持特定运行时的数据库驱动:- // Bun SQLite
- import { drizzle } from 'drizzle-orm/bun-sqlite'
- const db = drizzle() // 创建内存数据库
- // 或
- const db = drizzle('./sqlite.db') // 连接文件数据库
复制代码 连接 URL 格式
数据库连接 URL 通常依照以下格式:- postgresql://username:password@hostname/database_name
复制代码 例如:- postgresql://alex:AbC123dEf@ep-cool-darkness-123456.us-east-2.aws.neon.tech/dbname
复制代码 其中:
- username: 数据库用户名
- password: 数据库暗码
- hostname: 数据库服务器地点
- database_name: 数据库名称
通过这种简朴的连接方式,Drizzle 让你可以或许快速开始利用数据库,而不必担心复杂的配置和设置。
数据库查询
Drizzle 提供了两种主要的查询方式:SQL 风格语法和关系式 API。这两种方式各有优势,可以根据不同场景选择利用。
SQL 风格查询
Drizzle 的焦点理念是"如果你懂 SQL,你就懂 Drizzle"。与其他 ORM 不同,Drizzle 不会抽象掉 SQL,而是拥抱它,提供类似 SQL 的 API:- // 查询示例
- const result = await db.select().from(posts).leftJoin(comments, eq(posts.id, comments.postId)).where(eq(posts.id, 10))
- // 生成的 SQL
- // SELECT *
- // FROM posts
- // LEFT JOIN comments ON posts.id = comments.post_id
- // WHERE posts.id = 10
复制代码 根本 CRUD 操作
- // 查询所有用户
- const allUsers = await db.select().from(users)
-
- // 查询特定字段
- const userNames = await db.select({ id: users.id, name: users.name }).from(users)
-
- // 条件查询
- import { eq, like } from 'drizzle-orm'
- const filteredUsers = await db.select().from(users).where(eq(users.email, 'test@example.com'))
复制代码- // 插入单条记录
- await db.insert(users).values({
- name: '张三',
- email: 'zhangsan@example.com'
- })
- // 插入多条记录
- await db.insert(users).values([
- { name: '李四', email: 'lisi@example.com' },
- { name: '王五', email: 'wangwu@example.com' }
- ])
复制代码- // 更新记录
- await db.update(users).set({ name: '张三丰' }).where(eq(users.id, 1))
复制代码- // 删除记录
- await db.delete(users).where(eq(users.id, 1))
复制代码 关系式查询 API
对于需要获取嵌套关系数据的场景,Drizzle 提供了更简洁的关系式 API:- // 获取用户及其所有文章
- const usersWithPosts = await db.query.users.findMany({
- with: {
- posts: true
- }
- })
- // 结果格式
- // [
- // { id: 1, name: '张三', posts: [{ id: 1, title: '文章1' }, ...] },
- // ...
- // ]
复制代码 这种方式特别得当获取嵌套数据,Drizzle 会自动处理处罚关联和数据映射,同时保证只生成一条 SQL 查询,避免 N+1 查扣问题。
高级查询技巧
Drizzle 支持查询组合和分区,让你可以或许构建复杂而机动的查询:
- // 动态构建查询条件
- function getProductsBy({ name, category, maxPrice }) {
- const filters = []
- if (name) filters.push(like(products.name, `%${name}%`))
- if (category) filters.push(eq(products.category, category))
- if (maxPrice) filters.push(lte(products.price, maxPrice))
- return db
- .select()
- .from(products)
- .where(filters.length ? and(...filters) : undefined)
- }
复制代码- // 使用子查询
- const subquery = db.select().from(staff).leftJoin(users, eq(staff.userId, users.id)).as('staff_users')
- const result = await db.select().from(tickets).leftJoin(subquery, eq(subquery.staff_users.userId, tickets.assignedTo))
复制代码 通过这些机动的查询方式,Drizzle 既保持了 SQL 的强大表达本领,又提供了更简洁的 API 来处理处罚常见的数据访问模式,让数据库操作变得既直观又高效。
数据库迁移
数据库迁移是开辟过程中的重要环节,Drizzle 通过 Drizzle Kit 工具提供了完整的迁移办理方案。
Drizzle Kit 简介
Drizzle Kit 是一个命令行工具,用于管理 SQL 数据库迁移:- npm install -D drizzle-kit
复制代码 Drizzle Kit 提供了多种命令来满意不同的迁移需求:
命令功能形貌generate根据 Schema 生成 SQL 迁移文件migrate应用生成的 SQL 迁移文件到数据库push直接将 Schema 变动推送到数据库pull从数据库拉取 Schema 并转换为 Drizzle Schemastudio启动 Drizzle Studio 用于可视化数据库管理check查抄生成的迁移文件是否存在冲突up升级之前生成的迁移快照配置 Drizzle Kit
Drizzle Kit 通过 drizzle.config.ts 文件举行配置:- // drizzle.config.ts
- import { defineConfig } from 'drizzle-kit'
- export default defineConfig({
- dialect: 'postgresql', // 数据库类型
- schema: './src/db/schema.ts', // Schema 文件路径
- out: './drizzle', // 迁移文件输出目录
- dbCredentials: {
- // 数据库连接信息(用于 migrate、push、pull 等命令)
- url: 'postgresql://user:password@host:port/dbname'
- }
- })
复制代码 主要配置项包括:
- dialect: 数据库类型('postgresql'、'mysql'、'sqlite' 等)
- schema: Schema 文件路径,支持 glob 模式匹配多个文件
- out: 迁移文件输出目录,默认为 './drizzle'
- dbCredentials: 数据库连接信息
- migrations: 迁移相关配置,如迁移记录表名称
迁移工作流
1. 生成迁移文件 (generate)
当你修改 Schema 后,可以生成迁移文件:这将在 out 目录中生成 SQL 迁移文件,包含从当前数据库状态到新 Schema 的所有必要更改。
你可以通过 --name 参数指定迁移文件的名称:- npx drizzle-kit generate --name=init
复制代码 这将生成类似 0000_init.sql 的文件。
对于需要自定义 SQL 操作(如数据填充)的场景,可以生成空缺迁移文件:- npx drizzle-kit generate --custom --name=seed-users
复制代码 然后在生成的文件中添加自定义 SQL:- -- ./drizzle/0001_seed-users.sql
- INSERT INTO "users" ("name") VALUES('张三');
- INSERT INTO "users" ("name") VALUES('李四');
复制代码 2. 应用迁移 (migrate)
生成迁移文件后,可以将其应用到数据库:Drizzle Kit 会在数据库中创建一个名为 __drizzle_migrations 的表,用于记录已应用的迁移。你可以自定义这个表:- // drizzle.config.ts
- export default defineConfig({
- // ...其他配置
- migrations: {
- table: 'my_migrations', // 默认为 __drizzle_migrations
- schema: 'public' // PostgreSQL 专用,默认为 drizzle
- }
- })
复制代码 3. 直接推送 Schema (push)
在开辟环境中,可以直接将 Schema 变动推送到数据库,跳过生成迁移文件的步骤:这个命令会分析当前数据库状态和 Schema 文件的差别,并直接应用变动,得当快速迭代的开辟阶段。
4. 从数据库拉取 Schema (pull)
如果你有一个现有的数据库,可以从中拉取 Schema 并转换为 Drizzle Schema:这对于将现有项目迁移到 Drizzle 特别有用。
多环境配置
对于有多个环境(开辟、测试、生产)的项目,可以创建多个配置文件:- 📦 项目根目录
- ├ 📜 drizzle-dev.config.ts
- ├ 📜 drizzle-prod.config.ts
复制代码 利用时指定配置文件:- npx drizzle-kit push --config=drizzle-dev.config.ts
复制代码 Drizzle Studio
Drizzle Kit 还提供了一个可视化工具 Drizzle Studio,用于欣赏和管理数据库:这将启动一个本地服务器,通过欣赏器界面可以查看表结构、数据记录,并执行根本的 CRUD 操作。
完整迁移流程示例
以下是一个完整的迁移流程示例:
- // src/schema.ts
- import { pgTable, serial, text } from 'drizzle-orm/pg-core'
- export const users = pgTable('users', {
- id: serial('id').primaryKey(),
- name: text('name').notNull()
- })
复制代码- // drizzle.config.ts
- import { defineConfig } from 'drizzle-kit'
- export default defineConfig({
- dialect: 'postgresql',
- schema: './src/schema.ts',
- dbCredentials: {
- url: 'postgresql://user:password@host:port/dbname'
- }
- })
复制代码- npx drizzle-kit generate --name=init
复制代码 完整配置示例
以下是一个包含所有可用选项的扩展配置示例:- import { defineConfig } from 'drizzle-kit'
- export default defineConfig({
- out: './drizzle', // 迁移文件输出目录
- dialect: 'postgresql', // 数据库类型
- schema: './src/schema.ts', // Schema 文件路径
- driver: 'pglite', // 特定数据库驱动
- dbCredentials: {
- // 数据库连接信息
- url: './database/'
- },
- extensionsFilters: ['postgis'], // 忽略特定扩展的表
- schemaFilter: 'public', // 要管理的 schema
- tablesFilter: '*', // 要管理的表
- introspect: {
- // pull 命令的配置
- casing: 'camel' // 列名命名风格
- },
- migrations: {
- // 迁移记录配置
- prefix: 'timestamp', // 迁移文件前缀
- table: '__drizzle_migrations__', // 迁移记录表名
- schema: 'public' // 迁移记录表所在 schema
- },
- entities: {
- // 实体管理配置
- roles: {
- // 角色管理
- provider: '', // 数据库提供商
- exclude: [], // 排除的角色
- include: [] // 包含的角色
- }
- },
- breakpoints: true, // 是否在 SQL 中添加断点
- strict: true, // push 命令是否需要确认
- verbose: true // 是否打印详细日志
- })
复制代码 多配置文件支持
对于管理多个数据库或环境的项目,可以创建多个配置文件:- 📦 项目根目录
- ├ 📜 drizzle-dev.config.ts
- ├ 📜 drizzle-prod.config.ts
复制代码 利用时指定配置文件:- npx drizzle-kit generate --config=drizzle-dev.config.ts
复制代码 主要配置项详解
- dialect:数据库类型
- 可选值:postgresql、mysql、sqlite、turso、singlestore
- 适用命令:generate、migrate、push、pull、check、up
- schema:Schema 文件路径
- 类型:string | string[](支持 glob 模式)
- 适用命令:generate、push
- 示例:'./src/schema.ts' 或 './src/schema/*.ts'
- out:迁移文件输出目录
- 类型:string
- 默认值:'drizzle'
- 适用命令:generate、migrate、push、pull、check、up
- dbCredentials:数据库连接信息
- 类型:URL 字符串或连接参数对象
- 适用命令:migrate、push、pull
- 示例:
- dbCredentials: {
- url: 'postgresql://user:password@host:port/db'
- }
- // 或
- dbCredentials: {
- host: 'host',
- port: 5432,
- user: 'user',
- password: 'password',
- database: 'dbname',
- ssl: true
- }
复制代码
- migrations:迁移记录配置
- 类型:{ table: string, schema: string }
- 默认值:{ table: '__drizzle_migrations', schema: 'drizzle' }
- 适用命令:migrate
- tablesFilter:表过滤器
- 类型:string | string[]
- 适用命令:generate、push、pull
- 示例:['users', 'posts', 'project1_*']
- schemaFilter:Schema 过滤器
- 类型:string[]
- 默认值:['public']
- 适用命令:generate、push、pull
- extensionsFilters:扩展过滤器
- 类型:string[]
- 默认值:[]
- 适用命令:push、pull
- 示例:['postgis'](忽略 PostGIS 扩展创建的表)
- entities.roles:角色管理配置
- 类型:boolean | { provider: string, include: string[], exclude: string[] }
- 默认值:false
- 适用命令:push、pull、generate
- 示例:
- entities: {
- roles: {
- provider: 'supabase', // 使用 Supabase 预定义角色
- exclude: ['admin'] // 排除 admin 角色
- }
- }
复制代码
- strict:严格模式
- 2. 类型:`boolean`
-
- 3. 默认值:`false`
-
- 4. 适用命令:`push`
-
- 5. 作用:执行 `push` 命令时是否需要确认 SQL 语句
复制代码- 2. 类型:`boolean`
-
- 3. 默认值:`true`
-
- 4. 适用命令:`generate`、`pull`
-
- 5. 作用:是否打印详细的 SQL 语句
复制代码- 2. 类型:`boolean`
-
- 3. 默认值:`true`
-
- 4. 适用命令:`generate`、`pull`
-
- 5. 作用:是否在生成的 SQL 中添加 `--> statement-breakpoint` 断点(对于不支持在一个事务中执行多个 DDL 语句的数据库如 MySQL 和 SQLite 很重要)
复制代码 结束
讲这个的主要目标是为了给各人普及一下外洋批量应用的基础套件的知识,接待更多的相识下。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |