Connect Postgres with Drizzle ORM

设置 Drizzle ORM 连接 Postgres 为例

前言

单纯通过 SQL 与关系数据库直接沟通,可能会带来开发效率与安全性的问题,因此挑选合适的 ORM 多一层抽象是常见的选择,而 Drizzle ORM🔗 是我最常使用也是接触 ORM 的起点。它在 TypeScript 生态中有出色支持,虽然相对新颖,但社区活跃,值得一试。

为什么选择 Drizzle ORM?

主因是相较于其他 ORM 如 Prisma🔗 可能造成抽象泄漏🔗的问题,Drizzle 提供了两种形式的 API 与数据库互动:

  • Query🔗:高度的抽象方便使用
  • SQL like🔗:最少量的抽象 Query Builder,如果你懂 SQL 你就懂 Drizzle

既保留了传统 ORM 易用的操作界面,也提供更接近底层运作的互动方式,某方面来说降低了学习成本也更避免技术上的锁定,身为新手也能站在适当的抽象程度上学习。

听说过吓人的故事像是 Prisma 容易产出低效的语句: Migration Lesson: Don’t Use Prisma | Prime Reacts🔗,但由于抽象层过多,当需要处理底层问题时就显得困难,进而影响系统的扩展性与性能。Drizzle 官方有对应的 Benchmark🔗或许能参考看看。

更多好处像是:TypeScript 支持、无任何依赖、完全支持 Serverless、支持多种数据库(如 PostgreSQL、MySQL、SQLite)与云端供应商(如 Neon、PlanetScale 等),更多能参考官方文档:Why Drizzle🔗

Drizzle 与 Postgres

依赖安装

假设有一个 TS 专案需要与 Postgres 沟通,先把会用到的依赖都安装上:

Terminal window
pnpm add drizzle-orm pg
pnpm add -D drizzle-kit tsx @types/pg dotenv

文件结构

官方推荐文件结构🔗如下,在 index.ts 中会使用 Drizzle 与数据库进行互动,但在这之前有许多概念与设置需要提前准备。

📦 <project root>
├ 📂 drizzle
├ 📂 src
│ ├ 📂 db
│ │ └ 📜 schema.ts
│ └ 📜 index.ts
├ 📜 .env
├ 📜 drizzle.config.ts
├ 📜 package.json
└ 📜 tsconfig.json

连接数据库

其中 .env 添加数据库的连接网址🔗,通常是以下的格式,具体如何启动 Postgres 服务器于本地可以参考:初学 Docker 并轻松构建 Postgres

postgresql://alex:[email protected]/dbname
└──┘ └───────┘ └─────────────────────────────────────────────┘ └────┘
ʌ ʌ ʌ ʌ
role -│ │ │- hostname │- database
│- password
DATABASE_URL=

index.ts 使用 drizzle 选择对应的 Postgres 驱动🔗 进行连接即可。接着执行该文件: pnpm tsx src/index.ts 便能连接上数据库。

index.ts
import 'dotenv/config';
import { drizzle } from 'drizzle-orm/node-postgres';
const db = drizzle(process.env.DATABASE_URL!);
console.log(db)

具体来说通过 node-postgres 驱动与数据库进行沟通,可以参考官方说明:Database connection with Drizzle🔗

Database First 与 Code First

将 Drizzle ORM 连接上 Postgres 后有两种风格的开发策略可以选择处理数据库与代码之间的映射关系:

  • Database First
  • Code First

这两种方法的差异在于「先定义数据库结构」还是「先撰写程序模型」,各有优缺点,适用于不同的场景。

Database First

先设计并建立好数据库,然后由 ORM 工具依据数据库结构产生对应的模型代码,适合用于:

  • 有现成数据库或既有系统需要整合

  • 数据库由第三方设计与维护

  • 想保持数据库设计的严谨性与一致性

  • 优点

    • 与现有数据库整合容易
    • 数据库结构清晰、可由工具产生 ER 图
    • 较容易与其他非 ORM 应用共享数据库
  • 缺点

    • 每次数据库更改都需手动更新模型(或重新产生)
    • 程序开发较依赖数据库调整的速度

Code First

先写好模型代码,然后由 ORM 工具依据代码自动建立或同步数据库结构。 适合情境:

  • 新项目、从零开始

  • 开发团队主导数据结构设计

  • 敏捷开发,需求快速变动

  • 优点

    • 开发流程集中在代码,版本控制方便
    • 更容易做自动化迁移(migrations)
    • 不需先建数据库,即可专注于业务逻辑开发
  • 缺点

    • 若数据库由多人共享,结构变更需谨慎管理。
    • 较不适合整合已有数据库。

Drizzle Kit 进行 Database Migration

Terminal window
# Drizzle kit 指令范例
pnpm drizzle-kit generate
pnpm drizzle-kit migrate
pnpm drizzle-kit push
pnpm drizzle-kit pull
pnpm drizzle-kit check
pnpm drizzle-kit up
pnpm drizzle-kit studio

Drizzle migrations fundamentals🔗 列出不同情境下如何通过 drizzle-kit🔗 工具进行同步。举例以 Code First 开发策略为例,先建立「模型代码」再同步到数据库。

定义数据库数据表及字段设计

src/db/schema.ts
import { integer, pgTable, varchar } from "drizzle-orm/pg-core";
export const usersTable = pgTable("users", {
id: integer().primaryKey().generatedAlwaysAsIdentity(),
name: varchar({ length: 255 }).notNull(),
age: integer().notNull(),
email: varchar({ length: 255 }).notNull().unique(),
});

Drizzle Kit 设置

设置 drizzle.config.tsDrizzle Kit🔗 了解 Migration 前所需的数据。

drizzle.config.ts
import 'dotenv/config';
import { defineConfig } from 'drizzle-kit';
export default defineConfig({
out: './drizzle',
schema: './src/db/schema.ts',
dialect: 'postgresql',
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});

进行 Migration

Terminal window
# drizzle-kit push 将架构和后续架构变更直接推送到数据库,同时省略 SQL 文件生成。
pnpm drizzle-kit push

观察数据库变动

Drizzle Studio🔗 是一项还在测试中的数据库预览工具。

Terminal window
pnpm drizzle-kit studio
Warning Drizzle Studio is currently in Beta. If you find anything that is not working as expected or should be improved, feel free to create an issue on GitHub: https://github.com/drizzle-team/drizzle-kit-mirror/issues/new or write to us on Discord: https://discord.gg/WcRKz2FFxN
Drizzle Studio is up and running on https://local.drizzle.studio

总结

Drizzle ORM 是一个轻量、现代、并拥有良好 TypeScript 体验的 ORM 工具。无论你是喜欢高度抽象的操作方式,还是希望保有接近 SQL 的灵活性,它都能提供弹性的开发体验。

当你熟悉了基本的连接与迁移流程后,接下来只需专注于 query 与 schema 的设计,相信对熟悉 SQL 的开发者来说会非常上手。

延伸阅读