Wasp 数据库后端实战指南:SQLite / PostgreSQL 的连接、迁移与数据播种
【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp
本篇指南以 Wasp(v0.14 时代文档体系)的数据层为背景,系统讲解 Wasp 项目如何选择数据库后端、如何连接开发数据库、如何从 SQLite 平滑迁移到 PostgreSQL,以及如何使用app.db.seeds编写并执行数据库播种(seeding)函数。读完本文,你将掌握 Wasp 中数据库配置的完整链路——从schema.prisma的provider切换、DATABASE_URL环境变量的注入方式,到wasp db系列命令的实际用法,并理解其底层(AppSpec Db 定义 与 Seed 生成器)是如何工作的。
数据库在 Wasp 数据层中的位置
在 Wasp 中,Entities、Operations 与 Automatic CRUD 共同构成了操作应用数据的高层接口:Entities 定义数据模型,Operations 声明查询与操作,Automatic CRUD 则自动生成常见的增删改查接口。但无论接口多高,数据最终都要落到某个存储介质上——这就是数据库后端要解决的问题。
Wasp 把数据库抽象为两部分:
schema.prisma文件:遵循 Prisma 的 datasource 语法,声明数据库provider和连接url;app.db配置(写在main.wasp中):声明播种函数等数据库相关能力。
两条线索最终都会在编译阶段被 Wasp 读取并生成对应的服务端代码,因此理解二者的关系是掌握 Wasp 数据库用法的前提。
支持的数据库后端
Wasp 在 AppSpec 的 Db 模块中把数据库系统建模为枚举DbSystem = PostgreSQL | SQLite,即官方支持且经过代码路径校验的后端只有两个:SQLite 与 PostgreSQL。下面分别说明。
SQLite:默认的开发数据库
当你通过wasp new创建新项目时,生成器会写出以 SQLite 为默认 provider 的schema.prisma(见 basic 模板 与 minimal 模板):
datasource db { provider = "sqlite" url = env("DATABASE_URL") } // ...使用 SQLite 时,Wasp 会自动为你设置DATABASE_URL环境变量,你不需要准备任何数据库服务、不需要 Docker、不需要安装额外的中间件。这正是它适合快速起步的原因。
但需要注意它的边界:SQLite 只能用于开发阶段。一旦你要把 Wasp 应用部署到生产环境,就必须切换到 PostgreSQL,并且之后保持使用 PostgreSQL(Wasp 不会在生产环境替你管理 SQLite)。好在迁移过程并不复杂,本文后续有专门的迁移章节指导你完成切换。
PostgreSQL:面向生产的选择
PostgreSQL 是一款在开源数据库领域久经考验的成熟产品,适合对稳定性、并发和特性有更高要求的应用。在 Wasp 中使用 PostgreSQL 同样简单,只需把schema.prisma中的 provider 改为"postgresql":
datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ...一旦切换到 PostgreSQL,你必须在开发期间保证有一个数据库实例在运行——Wasp 执行wasp start或wasp db migrate-dev等命令时都需要真实可用的数据库连接。至于如何提供这个连接,请看下一节。
仓库中的示例项目可以印证这一点:例如 ask-the-documents 的 schema.prisma 就是一个真实使用 PostgreSQL 的案例,它还额外启用了pgvector扩展来存储向量字段,这说明schema.prisma中 Prisma 支持的能力(扩展、生成器等)在 Wasp 中都可以正常使用。
连接数据库
使用 SQLite:零配置
如果你使用 SQLite,连接工作完全由 Wasp 接管,无需任何额外操作。DATABASE_URL由 Wasp 在启动时注入,你只需要正常执行wasp start即可。
使用 PostgreSQL:两种连接方式
使用 PostgreSQL 时,Wasp 提供两种连接策略:
- 托管式体验:让 Wasp 帮你启动一个开箱即用的开发数据库;
- 自主控制:你自己准备数据库,通过
DATABASE_URL连接串告诉 Wasp。
方式一:使用 Wasp 提供的开发数据库
执行下面的命令,Wasp 会为你启动一个默认的 PostgreSQL 开发数据库:
wasp start dbWasp 应用会自动连接上它,只需让wasp start db在后台保持运行。使用前请确认:
- 本机已安装 Docker 且
docker命令在PATH中可用(wasp start db正是通过 Docker 拉起 PostgreSQL 容器); - 端口
5432没有被其他进程占用。
提示:如果你希望通过
psql、pgAdmin 等外部工具连接这个开发数据库,运行wasp db start时控制台最开头打印的就是它的连接凭据。
方式二:连接已有的数据库
如果你想自建开发数据库,或连接外部(如远端)数据库,通过DATABASE_URL环境变量告知 Wasp 即可,Wasp 会把它当作连接串直接使用。
最简单的做法是把DATABASE_URL写进项目根目录的 .env.server 文件(该文件不存在则新建):
DATABASE_URL=postgresql://user:password@localhost:5432/mydb也可以在执行wasp命令时以内联方式注入(对所有环境变量均适用):
DATABASE_URL=<my-db-url> wasp ...这个技巧非常适合针对特定数据库执行某条命令。例如对全新的 staging 或 production 数据库做初始化播种:
DATABASE_URL=<production-db-url> wasp db seed myProductionSeed上述命令会把种子数据写入目标生产/预发布数据库——这正是「播种」最常见的生产场景之一,更多细节见播种数据库一节。
从 SQLite 迁移到 PostgreSQL
要把应用带上生产环境,你需要完成 SQLite → PostgreSQL 的切换。Wasp 给出的迁移步骤很直接:
第 1 步:切换 provider
把schema.prisma中的 provider 改为"postgresql":
datasource db { provider = "postgresql" url = env("DATABASE_URL") } // ...第 2 步:清掉旧的迁移与旧数据库
旧迁移文件是面向 SQLite 生成的,无法用于 PostgreSQL,SQLite 数据库文件本身也不再需要。删除迁移目录后,用wasp clean清理生成产物:
rm -r migrations/ wasp clean第 3 步:确保新数据库在运行
参考连接数据库一节,启动 PostgreSQL(可以用wasp start db,也可以自己准备并设置好DATABASE_URL)。让它在后台保持运行,因为下一步需要它。
第 4 步:生成初始迁移
在另一个终端中执行:
wasp db migrate-devWasp 会连接你正在运行的 PostgreSQL,把当前 schema 应用到数据库并生成一份全新的初始迁移。
第 5 步:完成
至此迁移结束。此后项目将一直以 PostgreSQL 为数据库后端,schema.prisma的新改动继续通过wasp db migrate-dev管理。
播种数据库
**数据库播种(database seeding)**指的是向数据库填充初始数据的过程。最常见的两种用途:
- 把开发数据库置入一个方便开发与测试的状态;
- 为任意环境(dev / staging / prod)的数据库初始化其运转所必需的基准数据,例如向 Currency 表填充默认币种、向 Country 表填充全部国家。
编写 Seed 函数
在main.wasp中,你可以在app.db.seeds字段下以数组形式声明任意多个seed 函数:
app MyApp { // ... db: { seeds: [ import { devSeedSimple } from "@src/dbSeeds.js", import { prodSeed } from "@src/dbSeeds.js" ] } }如果你使用的是新版 TypeScript 规范(
main.wasp.ts),同样的声明方式见 kitchen-sink 示例中的 db 配置,它同时展示了seeds与prismaSetupFn两个字段的写法。
每个 seed 函数必须是接收一个参数的 async 函数,该参数prisma是用于操作数据库的 Prisma Client 实例——这个实例与 Wasp 内部使用的完全一致。
由于 seed 函数属于服务端代码,它天然可以导入其他服务端函数。这意味着你可以很方便地「用 Action 来播种」——例如下面的例子,seed 函数同时创建了一个带用户名密码的用户,并调用createTask这个 Action 为用户创建任务:
import { createTask } from './actions.js' import { sanitizeAndSerializeProviderData } from 'wasp/server/auth' export const devSeedSimple = async (prisma) => { const user = await createUser(prisma, { username: 'RiuTheDog', password: 'bark1234', }) await createTask( { description: 'Chase the cat' }, { user, entities: { Task: prisma.task } } ) } async function createUser(prisma, data) { const newUser = await prisma.user.create({ data: { auth: { create: { identities: { create: { providerName: 'username', providerUserId: data.username, providerData: sanitizeAndSerializeProviderData({ hashedPassword: data.password }), }, }, }, }, }, }) return newUser }代码中有两点值得注意:
- 创建用户时直接操作
prisma.user,并在auth.identities中写入providerName: 'username'的身份数据,hashedPassword经过sanitizeAndSerializeProviderData序列化——这与 Wasp 内部创建用户名密码登录身份的实现一致; createTask的第二个参数携带{ user, entities: { Task: prisma.task } },这是 Wasp Action 执行上下文(context)的标准形态,说明 seed 完全可以复用应用中已有的操作逻辑。
TypeScript 版本使用DbSeedFn类型标注 seed 函数:
import { createTask } from './actions.js' import { type DbSeedFn } from 'wasp/server' import { sanitizeAndSerializeProviderData } from 'wasp/server/auth' import { type AuthUser } from 'wasp/auth' import { PrismaClient } from '@prisma/client' export const devSeedSimple: DbSeedFn = async (prisma) => { const user = await createUser(prisma, { username: 'RiuTheDog', password: 'bark1234', }) await createTask( { description: 'Chase the cat', isDone: false }, { user, entities: { Task: prisma.task } } ) }; async function createUser( prisma: PrismaClient, data: { username: string, password: string } ): Promise<AuthUser> { const newUser = await prisma.user.create({ data: { auth: { create: { identities: { create: { providerName: 'username', providerUserId: data.username, providerData: sanitizeAndSerializeProviderData<'username'>({ hashedPassword: data.password }), }, }, }, }, }, }) return newUser }DbSeedFn由 Wasp 导出,其定义如下:
type DbSeedFn = (prisma: PrismaClient) => Promise<void>给devSeedSimple标注该类型后,TypeScript 会得到两重保证:
- seed 函数的参数
prisma类型为PrismaClient; - seed 函数的返回值类型为
Promise<void>。
仓库中的真实范例可以参考 kitchen-sink 的 seeds.ts:它同时导出了devSeedSimple与prodSeed两个 seed 函数,分别向开发库与生产库写入用户名、任务等初始数据,并打印日志确认执行结果——与本文示例模式完全一致。
运行 Seed 函数
运行命令:
wasp db seed如果你定义了多个 seed 函数,Wasp 会以交互方式让你选择运行哪一个;只定义了一个则会直接运行。
也可以直接指定名称执行:
wasp db seed devSeedSimple实用技巧:在
wasp db reset清空数据库之后,紧接着运行wasp db seed把初始数据填回去,是开发中最常见的组合操作。
API 参考:app.db 与种子命令
app.db 配置项
app.db是一个字典,所有字段均为可选:
app MyApp { title: "My app", // ... db: { seeds: [ import devSeed from "@src/dbSeeds.js" ], } }seeds: [ExtImport]定义可用wasp db seed命令执行的 seed 函数列表,用于向数据库填充初始数据。每个元素是一个外部导入(ExtImport),指向@src/下的服务端模块。完整的语义见播种数据库一节。
从源码实现看,AppSpec 的 Db 记录除了seeds外还定义了prismaSetupFn字段——后者用于注入自定义的 Prisma 初始化逻辑(如示例中的setUpPrisma),说明app.db在设计上就是围绕 Prisma 生态的可扩展配置入口。
CLI 命令
wasp db seed:只定义一个 seed 函数时直接运行它;定义多个时以交互方式让你选择。wasp db seed <seed-name>:直接运行指定名称的 seed 函数。该名称就是它在app.db.seeds列表的import表达式中的标识符。例如对如下声明:app MyApp { // ... db: { seeds: [ // ... import { devSeedSimple } from "@src/dbSeeds.js", ] } }运行:
wasp db seed devSeedSimple
源码视角:db 命令与种子生成的底层机制
理解 Wasp 是如何执行这些命令的,有助于排查问题。
db 命令的公共前置流程。在 CLI 的 Db 模块中,所有wasp db ...命令都经由makeDbCommand包装,它依次完成:
- 校验当前目录是 Wasp 项目(
InWaspProject); - 校验 Wasp 规范文件可用(
WaspSpecAvailable); - 执行编译并安装 npm 依赖(
compileWithOptions,即代码生成阶段); - 校验数据库连接已建立(
DbConnectionEstablished)。
这正是文档中「Wasp 需要访问你的数据库才能执行wasp start、wasp db migrate-dev」这一说法的代码依据——任何 db 命令的前提都是「先编译出代码、再连上数据库」。
种子脚本的生成。在代码生成阶段,Seed 生成器读取 AppSpec 中的seeds列表,为服务端生成dbSeed.ts脚本,并把每个 ExtImport 转换为可注入的导入;当存在至少一个 seed 时,它还会在package.json的 Prisma 配置中注册prisma.seed = "npm run db-seed"(getPackageJsonPrismaSeedField),从而让 Prisma 层面的 seed 机制与 Wasp 的 seed 命令打通。此外,它还定义了环境变量名WASP_DB_SEED_NAME(见 Seed.hs)——wasp db seed <name>正是通过向该环境变量写入指定名称,再由生成的脚本据此挑选并执行对应的 seed 函数。
小结
围绕 Wasp 的数据库能力,你需要记住四条主线:
- 默认 SQLite、生产 PostgreSQL:新项目开箱即用 SQLite(零配置、仅限开发),上线前务必切换到 PostgreSQL;
- 连接方式二选一:
wasp start db走 Docker 拉起托管开发库,或通过.env.server/ 命令行内联注入DATABASE_URL连接自建库; - 迁移三步走:改 provider →
rm -r migrations/+wasp clean→ 确保 PG 运行后wasp db migrate-dev; - 播种即服务端函数:在
app.db.seeds中声明任意多个(prisma) => Promise<void>函数(推荐用DbSeedFn标注类型),用wasp db seed [name]执行,可用于初始化 dev / staging / prod 任意环境的基准数据。
把上述操作与 AppSpec Db 定义、Seed 生成器 及 kitchen-sink 示例 对照阅读,你就能在 Wasp 中自如地管理从开发到生产的完整数据链路。
【免费下载链接】waspThe batteries-included full-stack framework for the AI era. Develop JS/TS web apps (React, Node.js, and Prisma) using declarative code that abstracts away complex full-stack features like auth, background jobs, RPC, email sending, end-to-end type safety, single-command deployment, and more.项目地址: https://gitcode.com/GitHub_Trending/wa/wasp
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考