
Wasp 数据库完全指南SQLite/PostgreSQL 配置、种子数据与 Prisma Client 定制【免费下载链接】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导读本文以 Waspversion-0.17 文档体系中的数据模型为基础系统讲解 Wasp 框架如何处理数据库从默认的 SQLite、生产级 PostgreSQL 两种后端的选择与连接方式到 SQLite 迁移 PostgreSQL 的完整步骤再到用wasp db seed填充种子数据、通过app.db.prismaSetupFn定制 Prisma Client。读完本文你将掌握在 Wasp 项目中配置数据库、管理连接字符串、编写并运行种子函数以及为 Prisma Client 注入日志与扩展的全部实战技能。数据模型、数据库与 Wasp 的关系在 Wasp 中Entities、Operations 和 Automatic CRUD 共同构成了操作应用数据的高层接口Entities 定义数据形状Operations 封装读写逻辑CRUD 则把常见增删改查自动暴露出来。但无论接口多么友好数据终究要落到某个存储引擎里——这就是数据库层要解决的问题。从源码结构看Wasp 的数据库抽象集中在waspc/src/Wasp/AppSpec/App/Db.hs其中Db记录类型只包含两个可选字段data Db Db { seeds :: Maybe [ExtImport], prismaSetupFn :: Maybe ExtImport }也就是说在 Wasp 的应用规格AppSpec层面数据库相关的声明只有两块种子函数列表seeds与Prisma Client 设置函数prismaSetupFn。而真正的底层交互统一委托给 Prisma——这正是全文反复出现schema.prisma与 Prisma Client 的原因。本文后续的「Seeding the Database」与「Customising the Prisma Client」两节即对应这两个字段的实战用法。支持的数据库后端Wasp 支持多种数据库后端实际由DbSystem枚举PostgreSQL | SQLite见waspc/src/Wasp/AppSpec/App/Db.hs约束下面逐一说明。SQLite零配置的默认后端SQLite 是 Wasp 的默认数据库。新建 Wasp 项目时schema.prisma中默认的datasource就是 SQLitedatasource db { provider sqlite url env(DATABASE_URL) } // ...关于 Wasp 如何使用 Prisma schema 文件可进一步阅读 Prisma schema 文件 一节。使用 SQLite 时DATABASE_URL环境变量由 Wasp 自动设置你完全无需关心连接细节。SQLite 非常适合新项目起步不需要任何安装与配置开箱即用。但要注意它的适用边界——SQLite 只能用于开发阶段。一旦应用要部署到生产环境就必须切换到 PostgreSQL并从此固定使用 PostgreSQL。好在从 SQLite 迁移到 PostgreSQL 的过程相当简单见下文「从 SQLite 迁移到 PostgreSQL」一节。PostgreSQL生产环境的推荐后端PostgreSQL 是最先进的开源数据库之一也是全球最流行的数据库之一经历了 20 多年的持续迭代是久经考验的成熟选择。若要在 Wasp 中使用 PostgreSQL只需把schema.prisma中的provider改为postgresqldatasource db { provider postgresql url env(DATABASE_URL) } // ...作为对照仓库中的示例项目 kitchen-sink 正是采用 PostgreSQL 配置其 schema.prisma 开头即为datasource db { provider postgresql // Wasp requires that the url is set to the DATABASE_URL environment variable. url env(DATABASE_URL) }注意文件中的注释Wasp 要求url必须指向DATABASE_URL环境变量。同时该文件还包含 Wasp 必需的prisma-client-jsgeneratorgenerator client { provider prisma-client-js }与 SQLite 不同使用 PostgreSQL 时你需要保证一个运行中的数据库实例因为wasp start、wasp db migrate-dev等命令都依赖数据库可达。所有受支持的连接方式见下文「连接数据库」一节。连接数据库SQLite无需任何操作使用 SQLite 时你不需要为连接做任何特殊处理Wasp 会自动管理一切。PostgreSQL两种连接方式使用 PostgreSQL 时Wasp 提供两种连接方式按需选择托管体验让 Wasp 为你启动一个开箱即用的开发数据库完全掌控通过数据库 URL 连接到你自行准备的外部数据库。方式一使用 Wasp 提供的开发数据库运行wasp start db即可启动一个默认的 PostgreSQL 开发数据库你的应用会自动连接上去——只要让wasp start db保持在后台运行即可。使用前请确认已安装 Docker且docker命令位于PATH中端口5432未被占用。提示如果你希望用psql、pgAdmin 等外部工具连接该开发数据库连接凭据会在执行wasp db start时打印在控制台最开头留意即可。方式二连接已有数据库如果你想自建开发数据库或连接外部数据库可以通过DATABASE_URL环境变量告诉 Wasp 连接字符串。最直接的方式是把变量写入项目根目录的 .env.server 文件文件不存在则新建DATABASE_URLpostgresql://user:passwordlocalhost:5432/mydb也可以在执行wasp命令时以内联方式设置这一技巧对所有环境变量通用DATABASE_URLmy-db-url wasp ...内联方式非常适合对某个特定数据库执行单次命令例如针对刚创建的 staging 或生产数据库做种子填充DATABASE_URLproduction-db-url wasp db seed myProductionSeed关于种子数据的更多说明见「种子数据Seeding the Database」一节。从 SQLite 迁移到 PostgreSQL要把 Wasp 应用部署到生产环境必须先切换到 PostgreSQL。完整步骤如下修改 provider在schema.prisma中把provider改为postgresqldatasource db { // highlight-next-line provider postgresql url env(DATABASE_URL) } // ...清理旧迁移与旧库删除migrations/目录下的所有旧迁移它们是 SQLite 迁移无法用于 PostgreSQL同时清理 SQLite 数据库文件执行wasp cleanrm -r migrations/ wasp clean启动新数据库确保新的 PostgreSQL 数据库已运行方法见「连接数据库」一节并保持其运行状态因为下一步需要它。生成新初始迁移在另一个终端中运行wasp db migrate-dev应用改动并创建新的初始迁移。完成迁移到此结束。种子数据Seeding the Database数据库种子seeding指用一批初始数据填充数据库的过程最常见的用途有两种把开发数据库调整到便于开发与测试的状态为任意数据库dev、staging或prod初始化其运行所必需的基础数据例如用默认货币填充 Currency 表、用所有可用国家填充 Country 表。编写种子函数你可以在app.db.seeds数组下定义任意数量的种子函数app MyApp { // ... db: { seeds: [ import { devSeedSimple } from src/dbSeeds.js, import { prodSeed } from src/dbSeeds.js ] } }JavaScript 与 TypeScript 项目的写法一致TypeScript 示例同样适用。每个种子函数必须是异步函数接收一个参数prisma——即用于与数据库交互的 Prisma Client 正是这样声明的import { type Db } from wasp.sh/spec; import { setUpPrisma } from ./prisma with { type: ref }; import { devSeedSimple, prodSeed } from ./seeds with { type: ref }; export const db: Db { seeds: [devSeedSimple, prodSeed], prismaSetupFn: setUpPrisma, };种子函数属于服务端代码因此可以导入其他服务端函数——这很方便因为你可能想借助 Action 来执行种子写入。下面是一个导入 Action 的种子函数示例JavaScript 版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: await sanitizeAndSerializeProviderData({ hashedPassword: data.password }), }, }, }, }, }, }) return newUser }TypeScript 版本如下import { createTask } from ./actions.js import type { DbSeedFn } from wasp/server import { sanitizeAndSerializeProviderData } from wasp/server/auth import type { AuthUser } from wasp/auth import type { PrismaClient } from wasp/server 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 } ): PromiseAuthUser { const newUser await prisma.user.create({ data: { auth: { create: { identities: { create: { providerName: username, providerUserId: data.username, providerData: await sanitizeAndSerializeProviderDatausername({ hashedPassword: data.password }), }, }, }, }, }, }) return newUser }Wasp 导出了一个DbSeedFn类型可方便地为种子函数标注类型type DbSeedFn (prisma: PrismaClient) Promisevoid给devSeedSimple标注该类型后TypeScript 会获得两点保障参数prisma的类型为PrismaClient返回值类型为Promisevoid。仓库中 kitchen-sink 的真实实现 seeds.ts 与此一致devSeedSimple创建用户martinsos密码test1234并为其创建初始任务prodSeed则以martinsosProd用户创建面向生产的种子数据并在末尾打印提示日志例如export const devSeedSimple: DbSeedFn async (prismaClient) { const user await createUser(prismaClient, { username: martinsos, password: test1234, }); await createTask( { description: My initial task }, { user, entities: { Task: prismaClient.task } }, ); console.log(Did simple dev seed!); };运行种子函数运行wasp db seed后Wasp 会询问你要执行哪个种子函数前提是你定义了不止一个也可以用wasp db seed seed-name直接指定wasp db seed devSeedSimple关于这两个命令的完整说明见下文「API 参考」。提示通常你会希望在wasp db reset之后立即执行wasp db seed——清空数据库后正好需要重新填充初始数据。种子脚本的底层机制从源码看wasp db seed最终生成并运行一个种子脚本。Wasp 的服务端模板 dbSeed.ts 展示了其运行原理所有在app.db.seeds中声明的种子函数被收集到一个seeds对象中脚本通过环境变量WASP_DB_SEED_NAME定义于waspc/src/Wasp/Generator/ServerGenerator/Db/Seed.hs读取要执行的种子函数名然后以wasp/server导出的共享prisma实例调用之结束后统一$disconnectconst seeds { devSeedSimple, prodSeed, } async function main() { const nameOfSeedToRun process.env.WASP_DB_SEED_NAME if (nameOfSeedToRun) { console.log(Running seed: ${nameOfSeedToRun}) } else { console.error(Name of the seed to run not specified!) } await (seeds[nameOfSeedToRun] satisfies DbSeedFn)(prisma) }而wasp db seed seed-name命令正是把seed-name以该环境变量的形式注入后执行脚本见waspc/src/Wasp/Generator/DbGenerator/Jobs.hs中(dbSeedNameEnvVarName, seedName)的传递。这解释了为什么种子函数名必须与import表达式中的标识符一致。定制 Prisma ClientWasp 通过 Prisma Client 与数据库交互。如需定制客户端在app.db.prismaSetupFn字段中定义一个返回 Prisma Client 实例的函数即可。这允许你配置 日志 或 客户端扩展 等功能。在main.wasp中声明app MyApp { title: My app, // ... db: { prismaSetupFn: import { setUpPrisma } from src/prisma } }对应的src/prisma.js实现JavaScriptimport { PrismaClient } from prisma/client export const setUpPrisma () { const prisma new PrismaClient({ log: [query], }).$extends({ query: { task: { async findMany({ args, query }) { args.where { ...args.where, description: { not: { contains: hidden by setUpPrisma } }, } return query(args) }, }, }, }) return prisma }TypeScript 实现src/prisma.ts与上述逻辑一致先开启log: [query]查询日志再通过$extends为task模型的findMany注入过滤条件——任何描述中包含hidden by setUpPrisma的任务都不会被查出这展示了如何在查询层统一做横切改造。仓库中 kitchen-sink 的 prisma.ts 更进一步同时演示了result扩展为所有模型注入一个计算字段_extraField用来验证 Prisma 类型能够贯穿整个 RPC 调用栈export const setUpPrisma () { const prisma new PrismaClient({ // Log SQL queries if needed // log: [query], }).$extends({ query: { task: { async findMany({ args, query }) { args.where { ...args.where, description: { not: { contains: hidden by setUpPrisma } }, }; return query(args); }, }, }, result: { $allModels: { _extraField: { needs: {}, compute() { return Some string! as const; }, }, }, }, }); return prisma; };可以看到prismaSetupFn的职责边界很清晰接收配置、返回一个配置好的 Prisma Client 实例后续所有数据库访问都经由该实例完成。因此它也是接入日志、软删除、多租户过滤、审计字段等通用能力的统一入口。API 参考app.db是一个字典包含以下字段所有字段均为可选app MyApp { title: My app, // ... db: { seeds: [ import devSeed from src/dbSeeds ], prismaSetupFn: import { setUpPrisma } from src/prisma } }JavaScript 与 TypeScript 写法相同。seeds: [ExtImport]定义种子函数供wasp db seed命令用初始数据填充数据库。详见「种子数据Seeding the Database」一节。prismaSetupFn: ExtImport定义设置 Prisma Client 的函数Wasp 期望它返回一个 Prisma Client 实例。可用于配置 日志 或 客户端扩展import { PrismaClient } from prisma/client export const setUpPrisma () { const prisma new PrismaClient({ log: [query, info, warn, error], }) return prisma }与waspc/src/Wasp/AppSpec/App/Db.hs中Db记录的两个可选字段一一对应两字段在 AppSpec 层均为ExtImport外部导入引用。种子数据库的 CLI 命令wasp db seed如果只定义了一个种子函数直接运行它如果定义了多个则以交互方式让你选择。wasp db seed seed-name直接运行指定名称的种子函数。该名称即app.db.seeds列表中import表达式所用的标识符。例如对于如下定义的devSeedSimpleapp MyApp { // ... db: { seeds: [ // ... import { devSeedSimple } from src/dbSeeds.js, ] } }运行命令wasp db seed devSeedSimple小结后端选择开发期用零配置的 SQLite默认生产环境切换到 PostgreSQL 并固定下来两者都只需修改schema.prisma的provider。连接方式SQLite 全自动PostgreSQL 可用wasp start db启动托管开发库或用DATABASE_URL写入.env.server或内联连接自建/外部数据库。迁移路径改 provider → 删除旧迁移并wasp clean→ 启动新库 →wasp db migrate-dev生成新初始迁移。种子数据在app.db.seeds声明任意数量的异步种子函数用wasp db seed [name]执行种子脚本通过WASP_DB_SEED_NAME环境变量定位目标函数。定制客户端在app.db.prismaSetupFn返回自定义 Prisma Client可开启日志、注入查询扩展与结果扩展。配合 Entities、Operations 与 Automatic CRUD这套数据库能力构成了 Wasp 完整的数据链路既提供了 SQLite 到 PostgreSQL 的平滑升级路径也保留了通过种子与 Prisma 扩展深度定制数据库行为的自由度。【免费下载链接】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),仅供参考