数据库
ShipAny 使用 drizzle-orm 支持多种类型数据库。
配置数据库
以 Supabase 数据库为例,在 ShipAny 配置数据库的流程为:
- 创建数据库
登录 Supabase 控制台,创建数据库
- 查看数据库连接信息
在 Supabase 控制台,进入你创建的数据库,点击上方的 Connect
在弹出来的框中复制数据库连接信息,类似这样的字符串:
postgresql://postgres.defqvdpquwyqqjlmurkg:[YOUR-PASSWORD]@aws-0-ap-southeast-1.pooler.supabase.com:6543/postgres
[YOUR-PASSWORD]
需要替换成你在创建数据库时设置的密码。
- 配置数据库
修改项目配置文件:.env.development
和 .env.production
设置数据库连接信息:
DATABASE_URL="postgresql://postgres.defqvdpquwyqqjlmurkg:******@aws-0-ap-southeast-1.pooler.supabase.com:6543/postgres"
初始化数据库
在配置好 DATABASE_URL
后,在项目根目录下运行以下命令,初始化数据库:
pnpm db:migrate
这个命令会执行 src/db/migrations
目录下的所有迁移文件,创建数据库表。
如果你通过
DATABASE_URL
配置的不是一个新创建的数据库,或者数据库之前已经存在 ShipAny 的库表信息,请不要执行以上命令。而是比较src/db/migrations
目录下所有迁移文件的 sql 内容,手动执行 sql 语句,更新数据库表。
更新数据库
如果在项目创建之处,你使用的是一个新的数据库,且是通过 pnpm db:migrate
命令初始化的数据库,如果后续你拉取了最新的代码,可以继续执行以下命令,更新数据库表:
pnpm db:migrate
这个命令会根据 src/db/migrations
目录下所有迁移文件的 sql 内容,增量更新数据库表。
管理数据库
在项目根目录下执行命令:pnpm db:studio
这个命令会打开一个数据库管理界面,你可以在这里查看、编辑、删除数据库表。
操作数据库
在 src/models
目录下,写数据库操作文件,实现对数据表的增删改查。可参考以下操作 posts 表的示例:
数据表操作语法可参考 drizzle-orm 文档。
import { posts } from "@/db/schema";
import { db } from "@/db";
import { and, desc, eq } from "drizzle-orm";
export enum PostStatus {
Created = "created",
Deleted = "deleted",
Online = "online",
Offline = "offline",
}
export async function insertPost(
data: typeof posts.$inferInsert
): Promise<typeof posts.$inferSelect | undefined> {
const [post] = await db().insert(posts).values(data).returning();
return post;
}
export async function updatePost(
uuid: string,
data: Partial<typeof posts.$inferInsert>
): Promise<typeof posts.$inferSelect | undefined> {
const [post] = await db()
.update(posts)
.set(data)
.where(eq(posts.uuid, uuid))
.returning();
return post;
}
export async function findPostByUuid(
uuid: string
): Promise<typeof posts.$inferSelect | undefined> {
const [post] = await db()
.select()
.from(posts)
.where(eq(posts.uuid, uuid))
.limit(1);
return post;
}
export async function findPostBySlug(
slug: string,
locale: string
): Promise<typeof posts.$inferSelect | undefined> {
const [post] = await db()
.select()
.from(posts)
.where(and(eq(posts.slug, slug), eq(posts.locale, locale)))
.limit(1);
return post;
}
export async function getAllPosts(
page: number = 1,
limit: number = 50
): Promise<(typeof posts.$inferSelect)[] | undefined> {
const offset = (page - 1) * limit;
const data = await db()
.select()
.from(posts)
.orderBy(desc(posts.created_at))
.limit(limit)
.offset(offset);
return data;
}
export async function getPostsByLocale(
locale: string,
page: number = 1,
limit: number = 50
): Promise<(typeof posts.$inferSelect)[] | undefined> {
const offset = (page - 1) * limit;
const data = await db()
.select()
.from(posts)
.where(and(eq(posts.locale, locale), eq(posts.status, PostStatus.Online)))
.orderBy(desc(posts.created_at))
.limit(limit)
.offset(offset);
return data;
}
export async function getPostsTotal(): Promise<number> {
const total = await db().$count(posts);
return total;
}
使用其他类型数据库
如果你使用自建的 Postgres 数据库,或者使用其他兼容 postgres 的云数据库,比如:Neon。配置和连接数据库的步骤跟使用 Supabase 一致,你只需要填写数据库的 DATABASE_URL
即可。
如果你需要使用 MySQL 或者 SQLite 等数据库,可参考以下步骤自定义:
- 使用新的数据库 Schema
修改 src/db/schema.ts
文件,使用新的数据库 Schema。
Schema 中数据表的字段定义,可以参考 drizzle-orm 文档。
- 修改数据库配置
修改 src/db/config.ts
文件,使用新的数据库连接配置。
默认是 Postgres 数据库连接配置,你可以参考 drizzle-orm 文档按需修改。
import "dotenv/config";
import { config } from "dotenv";
import { defineConfig } from "drizzle-kit";
config({ path: ".env" });
config({ path: ".env.development" });
config({ path: ".env.local" });
export default defineConfig({
out: "./src/db/migrations",
schema: "./src/db/schema.ts",
dialect: "postgresql",
dbCredentials: {
url: process.env.DATABASE_URL!,
},
});
- 修改数据库连接实例
根据你使用的数据库类型,修改数据库连接实例。
import { drizzle } from "drizzle-orm/postgres-js";
import postgres from "postgres";
// Detect if running in Cloudflare Workers environment
const isCloudflareWorker =
typeof globalThis !== "undefined" && "Cloudflare" in globalThis;
// Database instance for Node.js environment
let dbInstance: ReturnType<typeof drizzle> | null = null;
export function db() {
const databaseUrl = process.env.DATABASE_URL;
if (!databaseUrl) {
throw new Error("DATABASE_URL is not set");
}
// In Cloudflare Workers, create new connection each time
if (isCloudflareWorker) {
// Workers environment uses minimal configuration
const client = postgres(databaseUrl, {
prepare: false,
max: 1, // Limit to 1 connection in Workers
idle_timeout: 10, // Shorter timeout for Workers
connect_timeout: 5,
});
return drizzle(client);
}
// In Node.js environment, use singleton pattern
if (dbInstance) {
return dbInstance;
}
// Node.js environment with connection pool configuration
const client = postgres(databaseUrl, {
prepare: false,
max: 10, // Maximum connections in pool
idle_timeout: 30, // Idle connection timeout (seconds)
connect_timeout: 10, // Connection timeout (seconds)
});
dbInstance = drizzle({ client });
return dbInstance;
}
- 生成数据库迁移文件
如果你希望后续通过迁移文件更新数据库表。你可以在完成以上三步之后,在项目根目录下执行以下命令生成数据库迁移文件。
pnpm db:generate
在 ShipAny 中配置不同类型的数据库非常简单,只需要完成以上四个步骤的自定义即可。
src/model
下操作数据库的逻辑无需修改。