Drizzle 与 Turso
本教程演示了如何将 Drizzle ORM 与 Turso 结合使用。
- 您应该已经安装了 Drizzle ORM 和 Drizzle Kit。您可以通过运行以下命令来完成此操作:
npm i drizzle-orm
npm i -D drizzle-kit
- 您应该已安装
dotenv
包来管理环境变量。在此处了解有关此包的更多信息 这里
npm i dotenv
- 您应该已安装
@libsql/client
包。在此处了解有关此包的更多信息 这里。
npm i @libsql/client
- 您应该已安装 Turso CLI。请查看 文档 以获取更多信息
Turso 是一个基于 libSQL(SQLite 的开放贡献分支)构建的与 SQLite 兼容的数据库。它支持每个组织扩展到数十万个数据库,并支持复制到任何位置(包括您自己的服务器),以实现微秒级延迟访问。您可以在此处了解有关 Turso 概念的更多信息 这里。
Drizzle ORM 原生支持 libSQL 驱动程序,我们支持 SQL 方言以及特定于方言的驱动程序和语法,并镜像了大多数流行的类 SQLite all
、 get
、 values
和 run
查询方法的语法。
请查看 官方文档 以设置 Turso 数据库。
设置 Turso 和 Drizzle ORM
注册或登录 Turso
注册
turso auth signup
登录
turso auth login
创建新数据库
通过运行 turso db create <DATABASE_NAME>
命令创建新数据库
turso db create drizzle-turso-db
要查看数据库信息,请运行以下命令
turso db show drizzle-turso-db
创建身份验证令牌
要为您的数据库创建身份验证令牌,请运行以下命令
turso db tokens create drizzle-turso-db
在此处了解有关此命令及其选项的更多信息 文档。
更新环境变量
使用连接 URL 和身份验证令牌更新您的 .env
或 .env.local
文件。
TURSO_CONNECTION_URL=
TURSO_AUTH_TOKEN=
将 Drizzle ORM 连接到您的数据库
在 src/db
目录中创建 index.ts
文件并设置数据库配置
import { config } from 'dotenv';
import { drizzle } from 'drizzle-orm/libsql';
config({ path: '.env' }); // or .env.local
export const db = drizzle({ connection: {
url: process.env.TURSO_CONNECTION_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
}});
创建表
在 src/db
目录中创建 schema.ts
文件并声明您的表
import { sql } from 'drizzle-orm';
import { integer, sqliteTable, text } from 'drizzle-orm/sqlite-core';
export const usersTable = sqliteTable('users', {
id: integer('id').primaryKey(),
name: text('name').notNull(),
age: integer('age').notNull(),
email: text('email').unique().notNull(),
});
export const postsTable = sqliteTable('posts', {
id: integer('id').primaryKey(),
title: text('title').notNull(),
content: text('content').notNull(),
userId: integer('user_id')
.notNull()
.references(() => usersTable.id, { onDelete: 'cascade' }),
createdAt: text('created_at')
.default(sql`(CURRENT_TIMESTAMP)`)
.notNull(),
updatedAt: integer('updated_at', { mode: 'timestamp' }).$onUpdate(() => new Date()),
});
export type InsertUser = typeof usersTable.$inferInsert;
export type SelectUser = typeof usersTable.$inferSelect;
export type InsertPost = typeof postsTable.$inferInsert;
export type SelectPost = typeof postsTable.$inferSelect;
设置 Drizzle 配置文件
Drizzle config - 由 Drizzle Kit 使用的配置文件,包含有关你的数据库连接、迁移文件夹和 schema 文件的所有信息。
在项目的根目录中创建 drizzle.config.ts
文件并添加以下内容
import { config } from 'dotenv';
import { defineConfig } from 'drizzle-kit';
config({ path: '.env' });
export default defineConfig({
schema: './src/db/schema.ts',
out: './migrations',
dialect: 'turso',
dbCredentials: {
url: process.env.TURSO_CONNECTION_URL!,
authToken: process.env.TURSO_AUTH_TOKEN!,
},
});
应用更改到数据库
您可以使用 drizzle-kit generate
命令生成迁移,然后使用 drizzle-kit migrate
命令运行它们。
生成迁移
npx drizzle-kit generate
这些迁移存储在 migrations
目录中,正如您在 drizzle.config.ts
中指定的那样。此目录将包含更新数据库 Schema 所需的 SQL 文件,以及一个用于在不同迁移阶段存储 Schema 快照的 meta
文件夹。
生成迁移示例
CREATE TABLE `posts` (
`id` integer PRIMARY KEY NOT NULL,
`title` text NOT NULL,
`content` text NOT NULL,
`user_id` integer NOT NULL,
`created_at` text DEFAULT (CURRENT_TIMESTAMP) NOT NULL,
`updated_at` integer,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `users` (
`id` integer PRIMARY KEY NOT NULL,
`name` text NOT NULL,
`age` integer NOT NULL,
`email` text NOT NULL
);
--> statement-breakpoint
CREATE UNIQUE INDEX `users_email_unique` ON `users` (`email`);
运行迁移
npx drizzle-kit migrate
或者,您可以使用 Drizzle kit push 命令 将更改直接推送到数据库
npx drizzle-kit push
基本文件结构
这是项目的基础文件结构。在 src/db
目录中,我们有与数据库相关的文件,包括 index.ts
中的连接和 schema.ts
中的 Schema 定义。
📦 <project root>
├ 📂 src
│ ├ 📂 db
│ │ ├ 📜 index.ts
│ │ └ 📜 schema.ts
├ 📂 migrations
│ ├ 📂 meta
│ │ ├ 📜 _journal.json
│ │ └ 📜 0000_snapshot.json
│ └ 📜 0000_watery_spencer_smythe.sql
├ 📜 .env
├ 📜 drizzle.config.ts
├ 📜 package.json
└ 📜 tsconfig.json
查询示例
例如,我们创建 src/db/queries
文件夹,并为每个操作分别创建文件:insert、select、update、delete。
插入数据
在此处了解有关 insert 查询的更多信息 文档。
import { db } from '../index';
import { InsertPost, InsertUser, postsTable, usersTable } from '../schema';
export async function createUser(data: InsertUser) {
await db.insert(usersTable).values(data);
}
export async function createPost(data: InsertPost) {
await db.insert(postsTable).values(data);
}
选择数据
在此处了解有关 select 查询的更多信息 文档。
import { asc, count, eq, getTableColumns, gt, sql } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, postsTable, usersTable } from '../schema';
export async function getUserById(id: SelectUser['id']): Promise<
Array<{
id: number;
name: string;
age: number;
email: string;
}>
> {
return db.select().from(usersTable).where(eq(usersTable.id, id));
}
export async function getUsersWithPostsCount(
page = 1,
pageSize = 5,
): Promise<
Array<{
postsCount: number;
id: number;
name: string;
age: number;
email: string;
}>
> {
return db
.select({
...getTableColumns(usersTable),
postsCount: count(postsTable.id),
})
.from(usersTable)
.leftJoin(postsTable, eq(usersTable.id, postsTable.userId))
.groupBy(usersTable.id)
.orderBy(asc(usersTable.id))
.limit(pageSize)
.offset((page - 1) * pageSize);
}
export async function getPostsForLast24Hours(
page = 1,
pageSize = 5,
): Promise<
Array<{
id: number;
title: string;
}>
> {
return db
.select({
id: postsTable.id,
title: postsTable.title,
})
.from(postsTable)
.where(gt(postsTable.createdAt, sql`(datetime('now','-24 hour'))`))
.orderBy(asc(postsTable.title), asc(postsTable.id))
.limit(pageSize)
.offset((page - 1) * pageSize);
}
或者,您可以使用 关系查询语法。
更新数据
在此处了解有关 update 查询的更多信息 文档。
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectPost, postsTable } from '../schema';
export async function updatePost(id: SelectPost['id'], data: Partial<Omit<SelectPost, 'id'>>) {
await db.update(postsTable).set(data).where(eq(postsTable.id, id));
}
删除数据
在此处了解有关 delete 查询的更多信息 文档。
import { eq } from 'drizzle-orm';
import { db } from '../index';
import { SelectUser, usersTable } from '../schema';
export async function deleteUser(id: SelectUser['id']) {
await db.delete(usersTable).where(eq(usersTable.id, id));
}