prisma-next-contract
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChinesePrisma Next — Contract Authoring
Prisma Next — 契约编写
Edit your data contract. Prisma handles the rest.
The data contract is the single source of truth for your data layer. You edit a contract source — (PSL, the canonical surface) or (TypeScript builder) — and the framework derives types, migrations, and runtime configuration from it. The three-step user model:
contract.prismacontract.ts- You edit your data contract.
- The system plans the migrations for you. ()
prisma-next-migrations - If you need data migrations, you edit and execute it. (
migration.ts)prisma-next-migrations
Behind step 1 the agent runs after every contract edit (or installs the Vite plugin so the bundler runs it on save — see ). Emit reads the contract source through the provider the façade picks based on the file extension of in , then writes two artefacts colocated with the source:
prisma-next contract emitprisma-next-buildcontract:prisma-next.config.ts- — the canonical, content-hashed Contract IR. Read by the planner, the runtime, and
contract.json.db verify - — the precise TypeScript types the runtime + lanes propagate when you import
contract.d.tsfrom it.Contract
Both files are emitted artefacts. Edit the source; never the JSON or .
.d.ts编辑你的数据契约,其余工作由Prisma完成。
数据契约是数据层的唯一可信来源。你编辑契约源文件——(PSL,标准交互层)或(TypeScript构建器)——框架会从中派生类型、迁移脚本和运行时配置。三步用户流程:
contract.prismacontract.ts- 编辑你的数据契约
- 系统为你规划迁移方案()
prisma-next-migrations - 如需数据迁移,编辑并执行(
migration.ts)prisma-next-migrations
在步骤1背后,每次编辑契约后代理会运行(或安装Vite插件,让打包器在保存时自动运行——详见)。Emit会根据中字段的文件扩展名,通过外观选择的提供者读取契约源,然后在源文件旁生成两个产物:
prisma-next contract emitprisma-next-buildprisma-next.config.tscontract:- ——标准、带内容哈希的契约IR。供规划器、运行时和
contract.json读取。db verify - ——运行时和lanes在你导入
contract.d.ts时传播的精确TypeScript类型。Contract
这两个文件都是生成产物。请编辑源文件,切勿修改JSON或文件。
.d.tsWhen to Use
适用场景
- User wants to add, change, or remove a model / field / relation.
- User wants to add an index, unique constraint, or enum.
- User wants to use a custom type from an extension (,
pgvector.Vector(length: 1536)).cipherstash.EncryptedString({...}) - User wants to install or configure an extension via in
extensions: [...].prisma-next.config.ts - User is migrating between authoring sources (PSL ↔ TypeScript builder).
- User received ,
PN-CLI-4002, orPN-CLI-4003fromPN-CLI-4011.contract emit - User mentions: schema, fields, models, attributes, prisma schema, PSL, contract.prisma, contract.ts, contract.json, contract.d.ts, contract emit, façade imports, ,
@prisma-next/postgres/config, extensions, extensionPacks, pgvector, cipherstash, postgis, paradedb, validations, callbacks, soft delete, paranoid, scopes. (The last cluster routes to What Prisma Next doesn't do yet below.)@prisma-next/postgres/contract-builder
- 用户想要添加、修改或删除模型/字段/关联关系
- 用户想要添加索引、唯一约束或枚举
- 用户想要使用扩展提供的自定义类型(如、
pgvector.Vector(length: 1536))cipherstash.EncryptedString({...}) - 用户想要通过中的
prisma-next.config.ts安装或配置扩展extensions: [...] - 用户在不同编写源之间迁移(PSL ↔ TypeScript构建器)
- 用户在运行时收到
contract emit、PN-CLI-4002或PN-CLI-4003错误PN-CLI-4011 - 用户提及:schema、字段、模型、属性、prisma schema、PSL、contract.prisma、contract.ts、contract.json、contract.d.ts、contract emit、外观导入、、
@prisma-next/postgres/config、extensions、extensionPacks、pgvector、cipherstash、postgis、paradedb、验证、回调、软删除、偏执模式、作用域。(最后一组内容对应下方「Prisma Next暂不支持的功能」)@prisma-next/postgres/contract-builder
When Not to Use
不适用场景
- User wants to apply a contract change to the DB → .
prisma-next-migrations - User wants to write a query against the contract → .
prisma-next-queries - User wants to wire (runtime entry point, middleware, env config) →
db.ts.prisma-next-runtime - User wants the Vite / bundler integration → .
prisma-next-build - User wants to set up Prisma Next for the first time → .
prisma-next-quickstart - User wants a deeper read of a single structured error envelope → .
prisma-next-debug - User wants to file a missing-feature request → .
prisma-next-feedback
- 用户想要将契约变更应用到数据库 → 使用
prisma-next-migrations - 用户想要针对契约编写查询 → 使用
prisma-next-queries - 用户想要配置(运行时入口、中间件、环境配置)→ 使用
db.tsprisma-next-runtime - 用户想要Vite/打包器集成 → 使用
prisma-next-build - 用户想要首次设置Prisma Next → 使用
prisma-next-quickstart - 用户想要深入阅读单个结构化错误信息 → 使用
prisma-next-debug - 用户想要提交缺失功能请求 → 使用
prisma-next-feedback
Key Concepts
核心概念
-
Thefaçade is the only surface user-authored code imports from. For a Postgres app:
@prisma-next/<target>,@prisma-next/postgres/config,@prisma-next/postgres/contract-builder,@prisma-next/postgres/control. Mongo has the same layout (@prisma-next/postgres/runtime,@prisma-next/mongo/config,@prisma-next/mongo/contract-builder). Each extension publishes its own façade —@prisma-next/mongo/runtime,@prisma-next/extension-pgvector/control,@prisma-next/extension-cipherstash/control,@prisma-next/extension-postgis/control. Never reach into@prisma-next/extension-paradedb/control,@prisma-next/cli/*,@prisma-next/family-*,@prisma-next/target-*,@prisma-next/adapter-*, or@prisma-next/driver-*from user code. The façade bakes the family / target / adapter / driver wiring in. See Common Pitfalls #4.@prisma-next/sql-contract-* -
Contract source. A file the framework reads and lowers to the canonical Contract IR. Two flavours, both first-class:
- (PSL) — schema-flavoured DSL. Canonical for typical apps and brownfield Prisma users. Wired by
contract.prisma— thecontract: './<path>/contract.prisma'façade detects thedefineConfigextension and routes through the PSL provider..prisma - (TypeScript builder) — programmatic authoring with
contract.tsfromdefineContract({...}, ({ field, model, rel, type }) => ({...}))(or@prisma-next/postgres/contract-builder). Wired by@prisma-next/mongo/contract-builder— the façade detects thecontract: './<path>/contract.ts'extension and routes through the TS provider. Use when you need programmatic composition (per-tenant variants, generated fields) or constructs PSL doesn't yet express (e.g. registering a parameterised extension type — see pgvector's contract)..ts
-
. Wires the contract source, the database connection, the migrations directory, and any installed extensions. Use
prisma-next.config.tsfromdefineConfig({...})(or@prisma-next/postgres/config). The four fields the façade accepts:@prisma-next/mongo/config(path string —contractor.prisma),.ts(db),{ connection?: string }(array of control descriptors),extensions(migrations). The output path for{ dir?: string }is auto-derived fromcontract.json(e.g.contract→./src/prisma/contract.prisma)../src/prisma/contract.json -
Emit pipeline.reads
prisma-next contract emit --config <path>?, calls the provider the façade picked, validates the resulting Contract, then atomically writesprisma-next.config.ts+contract.jsoncolocated with the source.contract.d.ts -
Extension namespaces. Extensions contribute namespaced constructors (,
pgvector.Vector(length: 1536)) and helper presets. Install them by adding the descriptor to two places, with two different field names because the surfaces consume two different descriptor types:cipherstash.EncryptedString({equality: true})- In the config façade: — array of control descriptors imported from
extensions: [pgvector]. The façade's underlying field is@prisma-next/extension-<name>/control; the façade renames it toextensionPacks.extensions - In the TS builder's (only when authoring
defineContract):contract.ts— record of pack descriptors imported fromextensionPacks: { pgvector }.@prisma-next/extension-<name>/pack
- In the config façade:
-
Contract space. Every package that emits a contract owns its own contract space — aat package root, a contract source, the colocated emitted artefacts, and a
prisma-next.config.tsdirectory. There are two intentional on-disk layouts, picked by whether the contract space is the consuming application or a contract-space package (an extension, an internal aggregate-root package, etc.):migrations/- Application layout (what you use when building an app). at repo root;
prisma-next.config.ts;src/prisma/contract.{prisma,ts}colocated;src/prisma/contract.{json,d.ts}colocated; migrations undersrc/prisma/db.ts. Themigrations/app/<timestamp>_<slug>/segment is the consuming application's space-id; extension space-ids land in siblingapp/directories that the extension packages manage. This is whatmigrations/<extension-space-id>/uses.examples/prisma-next-democurrently scaffolds something different (prisma-next initat repo root) — that's a defect (TML-2532); the canonical layout is what every command actually expects to see.prisma/... - Contract-space-package layout (what you use when publishing a contract-space package — extensions, internal monorepo packages). at package root;
prisma-next.config.tsdirectly (nosrc/contract.{prisma,ts}subdir);prisma/colocated;src/contract.{json,d.ts}directly undermigrations/<timestamp>_<slug>/(nomigrations/segment — the package is a single space). Documented in<space-id>and ADR 212..cursor/rules/contract-space-package-layout.mdc
Both layouts let'sdefineConfigpath point at the source; the framework derives everything else (emit output, migration root) from there. Pick the layout that matches what you're building and stick with it — don't mix.contract: - Application layout (what you use when building an app).
-
外观是用户代码唯一可导入的交互层。对于Postgres应用:
@prisma-next/<target>、@prisma-next/postgres/config、@prisma-next/postgres/contract-builder、@prisma-next/postgres/control。Mongo有相同的结构(@prisma-next/postgres/runtime、@prisma-next/mongo/config、@prisma-next/mongo/contract-builder)。每个扩展都发布自己的外观——@prisma-next/mongo/runtime、@prisma-next/extension-pgvector/control、@prisma-next/extension-cipherstash/control、@prisma-next/extension-postgis/control。切勿从用户代码中导入@prisma-next/extension-paradedb/control、@prisma-next/cli/*、@prisma-next/family-*、@prisma-next/target-*、@prisma-next/adapter-*或@prisma-next/driver-*。外观已内置了family/target/adapter/driver的配置。详见「常见陷阱」第4条。@prisma-next/sql-contract-* -
契约源文件:框架读取并转换为标准契约IR的文件。有两种形式,均为一等公民:
- (PSL):类Schema的领域特定语言。对典型应用和遗留Prisma用户来说是标准选择。通过
contract.prisma配置——contract: './<path>/contract.prisma'外观会检测defineConfig扩展名并通过PSL提供者处理。.prisma - (TypeScript构建器):使用
contract.ts(或@prisma-next/postgres/contract-builder)中的@prisma-next/mongo/contract-builder进行程序化编写。通过defineContract({...}, ({ field, model, rel, type }) => ({...}))配置——外观会检测contract: './<path>/contract.ts'扩展名并通过TS提供者处理。适用于需要程序化组合(多租户变体、生成字段)或PSL暂不支持的结构(例如注册参数化扩展类型——详见pgvector的契约)。.ts
-
:配置契约源文件、数据库连接、迁移目录和已安装的扩展。使用
prisma-next.config.ts(或@prisma-next/postgres/config)中的@prisma-next/mongo/config。外观接受四个字段:defineConfig({...})(路径字符串——contract或.prisma)、.ts(db)、{ connection?: string }(控制描述符数组)、extensions(migrations)。{ dir?: string }的输出路径会自动从contract.json字段派生(例如contract→./src/prisma/contract.prisma)。./src/prisma/contract.json -
生成流水线:读取
prisma-next contract emit --config <path>?,调用外观选择的提供者,验证生成的契约,然后原子性地在源文件旁写入prisma-next.config.ts+contract.json。contract.d.ts -
扩展命名空间:扩展提供命名空间构造器(、
pgvector.Vector(length: 1536))和辅助预设。需要在两个位置添加描述符,因不同交互层使用不同类型的描述符:cipherstash.EncryptedString({equality: true})- 在配置外观中:——从
extensions: [pgvector]导入的控制描述符数组。外观的底层字段是@prisma-next/extension-<name>/control,外观将其重命名为extensionPacks。extensions - 在TS构建器的中(仅当编写
defineContract时):contract.ts——从extensionPacks: { pgvector }导入的包描述符对象。@prisma-next/extension-<name>/pack
- 在配置外观中:
-
契约空间:每个生成契约的包都拥有自己的契约空间——包根目录下的、契约源文件、旁置的生成产物,以及
prisma-next.config.ts目录。有两种明确的磁盘布局,取决于契约空间是消费应用还是契约空间包(扩展、内部聚合根包等):migrations/- 应用布局(构建应用时使用)。仓库根目录下的;
prisma-next.config.ts;旁置的src/prisma/contract.{prisma,ts};旁置的src/prisma/contract.{json,d.ts};迁移脚本位于src/prisma/db.ts。migrations/app/<timestamp>_<slug>/是消费应用的空间ID;扩展的空间ID位于同级的app/目录,由扩展包管理。migrations/<extension-space-id>/使用的就是这种布局。examples/prisma-next-demo目前生成的结构不同(仓库根目录下的prisma-next init)——这是一个缺陷(TML-2532);所有命令实际期望的是标准布局。prisma/... - 契约空间包布局(发布契约空间包时使用——扩展、内部单体仓库包)。包根目录下的;直接在
prisma-next.config.ts(无src/contract.{prisma,ts}子目录);旁置的prisma/;迁移脚本直接位于src/contract.{json,d.ts}(无migrations/<timestamp>_<slug>/段——包本身就是单个空间)。文档见<space-id>和ADR 212。.cursor/rules/contract-space-package-layout.mdc
两种布局都允许的defineConfig路径指向源文件;框架会从中派生其他所有内容(生成输出、迁移根目录)。选择与你构建内容匹配的布局并坚持使用——不要混合。contract: - 应用布局(构建应用时使用)。仓库根目录下的
Diagnostic codes you route on
需关注的诊断代码
prisma-next contract emitcode| Code | Meaning | Next move |
|---|---|---|
| | Add |
| Source loaded but the Contract IR failed structural validation. | Read |
| The contract uses a namespaced constructor (e.g. | Install the package, import its control descriptor ( |
prisma-next contract emitcode| 代码 | 含义 | 下一步操作 |
|---|---|---|
| | 在 |
| 已加载源文件,但契约IR未通过结构验证 | 查看 |
| 契约使用了命名空间构造器(如 | 安装对应包,导入其控制描述符( |
Workflow — Read the contract source of truth
流程 — 读取契约可信源文件
The concept: every contract change starts by locating the source file. The config is authoritative — read , find the field (a path string under the façade), and open the file it points at. The same field tells you the installed .
prisma-next.config.tscontract:extensions: [...]bash
cat prisma-next.config.tsIf ends in , the source is PSL; if it ends in , the source is the TS builder. If is missing, route to .
contract:.prisma.tsprisma-next.config.tsprisma-next-quickstart核心思路:每次契约变更都从定位源文件开始。配置文件是权威来源——读取,找到字段(外观下的路径字符串),打开它指向的文件。该字段还会告诉你已安装的。
prisma-next.config.tscontract:extensions: [...]bash
cat prisma-next.config.ts如果以结尾,源文件是PSL;如果以结尾,源文件是TS构建器。如果缺失,引导至。
contract:.prisma.tsprisma-next.config.tsprisma-next-quickstartWorkflow — Edit a model / field / relation (PSL)
流程 — 编辑模型/字段/关联关系(PSL)
The concept: PSL models lower to tables (or collections, on Mongo); fields lower to columns; declares the FK side. Add the relation only on the owning side — the framework derives the back-reference automatically.
@relation(...)prisma
model User {
id Int @id @default(autoincrement())
email String @unique
}
model Post {
id Int @id @default(autoincrement())
title String
authorId Int
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
@@unique([title, authorId])
@@index([authorId])
}Then run (or rely on the Vite plugin — see ). Specify cascade behaviour explicitly with / ; the default is .
pnpm prisma-next contract emitprisma-next-buildonDeleteonUpdateRestrictPSL alias surface for repeated types lives in a top-level block:
types {}prisma
types {
Email = String
}
model User {
id Int @id @default(autoincrement())
email Email @unique
}Note: scalar lists (e.g. ) and implicit Prisma-ORM many-to-many (list nav on both sides without a join model) are rejected by the SQL interpreter — use a join model. Composite/embeddable types ( with on a model) are not supported by the SQL contract today.
String[]type Address { ... }address Address核心思路:PSL模型对应表(Mongo中对应集合);字段对应列;声明外键端。仅在拥有端添加关联关系——框架会自动派生反向引用。
@relation(...)prisma
model User {
id Int @id @default(autoincrement())
email String @unique
}
model Post {
id Int @id @default(autoincrement())
title String
authorId Int
author User @relation(fields: [authorId], references: [id], onDelete: Cascade)
@@unique([title, authorId])
@@index([authorId])
}然后运行(或依赖Vite插件——详见)。使用 / 显式指定级联行为;默认是。
pnpm prisma-next contract emitprisma-next-buildonDeleteonUpdateRestrictPSL中重复类型的别名定义在顶层块中:
types {}prisma
types {
Email = String
}
model User {
id Int @id @default(autoincrement())
email Email @unique
}注意:标量列表(如)和隐式Prisma-ORM多对多(两端都有列表导航但无连接模型)会被SQL解释器拒绝——请使用连接模型。组合/可嵌入类型(并在模型中使用)目前不被SQL契约支持。
String[]type Address { ... }address AddressWorkflow — Edit a model / field / relation (TS builder)
流程 — 编辑模型/字段/关联关系(TS构建器)
The concept: same model, different authoring surface. The façade re-exports , , , , plus the / packs as default exports of and . Use the callback overload () to get the higher-level helpers (, , , ).
defineContractfieldmodelrelfamilytarget@prisma-next/postgres/family@prisma-next/postgres/targetdefineContract({...}, ({ field, model, rel, type }) => ({...}))field.text()field.id.uuidv7()field.temporal.createdAt()type.sql.String(35)typescript
import sqlFamily from '@prisma-next/postgres/family';
import { defineContract } from '@prisma-next/postgres/contract-builder';
import postgresPack from '@prisma-next/postgres/target';
export const contract = defineContract(
{
family: sqlFamily,
target: postgresPack,
},
({ field, model }) => ({
models: {
User: model('User', {
fields: {
id: field.id.uuidv7(),
email: field.text().unique(),
createdAt: field.temporal.createdAt(),
},
}).sql({ table: 'app_user' }),
},
}),
);Then . The helpers are only available inside the callback overload; outside the callback only , , exist.
pnpm prisma-next contract emitfield.<scalar>()field.column(...)field.generated(...)field.namedType(...)For Mongo, swap every import for . The Mongo builder also exposes and .
@prisma-next/postgres/*@prisma-next/mongo/*indexvalueObject核心思路:模型逻辑相同,仅编写交互层不同。外观会重新导出、、、,以及/包作为和的默认导出。使用回调重载()获取高级辅助函数(、、、)。
defineContractfieldmodelrelfamilytarget@prisma-next/postgres/family@prisma-next/postgres/targetdefineContract({...}, ({ field, model, rel, type }) => ({...}))field.text()field.id.uuidv7()field.temporal.createdAt()type.sql.String(35)typescript
import sqlFamily from '@prisma-next/postgres/family';
import { defineContract } from '@prisma-next/postgres/contract-builder';
import postgresPack from '@prisma-next/postgres/target';
export const contract = defineContract(
{
family: sqlFamily,
target: postgresPack,
},
({ field, model }) => ({
models: {
User: model('User', {
fields: {
id: field.id.uuidv7(),
email: field.text().unique(),
createdAt: field.temporal.createdAt(),
},
}).sql({ table: 'app_user' }),
},
}),
);然后运行。辅助函数仅在回调重载内可用;回调外仅存在、、。
pnpm prisma-next contract emitfield.<scalar>()field.column(...)field.generated(...)field.namedType(...)对于Mongo,将所有导入替换为。Mongo构建器还提供和。
@prisma-next/postgres/*@prisma-next/mongo/*indexvalueObjectWorkflow — Add an extension-typed scalar (pgvector)
流程 — 添加扩展类型的标量(pgvector)
The concept: an extension contributes a namespace () plus two descriptor flavours — a control descriptor for the config façade and a pack descriptor for the TS builder. Register the control descriptor in (array form). If you're authoring with the TS builder, also register the pack descriptor in (record form). Then reference the namespaced constructor from the contract.
pgvector.*defineConfig.extensionsdefineContract.extensionPacksprisma-next.config.tstypescript
import pgvector from '@prisma-next/extension-pgvector/control';
import { defineConfig } from '@prisma-next/postgres/config';
export default defineConfig({
contract: './src/prisma/contract.prisma',
extensions: [pgvector],
});src/prisma/contract.prismaprisma
model Document {
id Int @id @default(autoincrement())
content String
embedding pgvector.Vector(length: 1536)
}Emit. The named-type lowering puts on the column and the type map in carries the right TS type.
vector(1536)contract.d.tsIf you reference without registering the pack in the config, emit fails with and . The envelope's text says "Add the missing extension descriptors to in prisma-next.config.ts" — that field name matches the façade.
pgvector.*PN-CLI-4011meta.missingExtensionPacks: ['pgvector']fixextensionsFor canonical worked examples covering single and multi-extension setups, read , , and .
examples/multi-extension-monorepo/app/prisma-next.config.tsexamples/cipherstash-integration/prisma-next.config.tsexamples/prisma-next-postgis-demo/prisma-next.config.ts核心思路:扩展提供命名空间()以及两种描述符——配置外观用的控制描述符和TS构建器用的包描述符。在(数组形式)中注册控制描述符。如果使用TS构建器编写,还需在(对象形式)中注册包描述符。然后在契约中引用命名空间构造器。
pgvector.*defineConfig.extensionsdefineContract.extensionPacksprisma-next.config.tstypescript
import pgvector from '@prisma-next/extension-pgvector/control';
import { defineConfig } from '@prisma-next/postgres/config';
export default defineConfig({
contract: './src/prisma/contract.prisma',
extensions: [pgvector],
});src/prisma/contract.prismaprisma
model Document {
id Int @id @default(autoincrement())
content String
embedding pgvector.Vector(length: 1536)
}运行生成命令。命名类型转换会在列上设置,且中的类型映射会携带正确的TS类型。
vector(1536)contract.d.ts如果未在配置中注册包就引用,生成会失败并返回和。错误信息的文本会提示*"在prisma-next.config.ts的中添加缺失的扩展描述符"*——该字段名称与外观一致。
pgvector.*PN-CLI-4011meta.missingExtensionPacks: ['pgvector']fixextensions有关单扩展和多扩展配置的标准示例,请查看、和。
examples/multi-extension-monorepo/app/prisma-next.config.tsexamples/cipherstash-integration/prisma-next.config.tsexamples/prisma-next-postgis-demo/prisma-next.config.tsWorkflow — Polymorphism (@@discriminator
/ @@base
)
@@discriminator@@base流程 — 多态性(@@discriminator
/ @@base
)
@@discriminator@@baseThe concept (SQL targets): one base model declares the discriminator field; each variant model declares its base + discriminator value. The variant chooses STI vs MTI by whether it sets : no means the variant inherits the base's table (single-table inheritance); means the variant gets its own table joined 1:1 by primary key (multi-table inheritance).
@@map(...)@@map@@map("variant_table")prisma
model Task {
id Int @id @default(autoincrement())
title String
type String
@@discriminator(type)
@@map("tasks")
}
// STI variant — shares the `tasks` table.
model Bug {
severity String
@@base(Task, "bug")
}
// MTI variant — joins to `tasks` via PK; carries its own `features` table.
model Feature {
priority Int
@@base(Task, "feature")
@@map("features")
}Verify the polymorphism syntax against the interpreter tests if in doubt: .
packages/2-sql/2-authoring/contract-psl/test/interpreter.polymorphism.test.tsMongo has no schema layer, so polymorphism on Mongo is modelled by an explicit field on the model in the TS builder (see ); / PSL attributes are SQL-only.
discriminator@prisma-next/mongo/contract-builder@@base@@discriminatorQuerying the variants is a runtime concern — see .
prisma-next-queries核心思路(SQL目标):一个基础模型声明鉴别器字段;每个变体模型声明其基础模型+鉴别器值。变体通过**是否设置**选择STI还是MTI:不设置意味着变体继承基础模型的表(单表继承);设置意味着变体拥有自己的表,通过主键1:1关联(多表继承)。
@@map(...)@@map@@map("variant_table")prisma
model Task {
id Int @id @default(autoincrement())
title String
type String
@@discriminator(type)
@@map("tasks")
}
// STI变体——共享`tasks`表
model Bug {
severity String
@@base(Task, "bug")
}
// MTI变体——通过主键关联`tasks`;拥有自己的`features`表
model Feature {
priority Int
@@base(Task, "feature")
@@map("features")
}如有疑问,请对照解释器测试验证多态性语法:。
packages/2-sql/2-authoring/contract-psl/test/interpreter.polymorphism.test.tsMongo没有Schema层,因此Mongo上的多态性通过TS构建器中模型的显式字段建模(详见); / PSL属性仅适用于SQL。
discriminator@prisma-next/mongo/contract-builder@@base@@discriminator查询变体是运行时相关的操作——详见。
prisma-next-queriesWorkflow — Brownfield introspection
流程 — 遗留系统自省
The concept: pull a contract source out of an existing database and continue from there. reads the live schema and writes a file. It stops there — follow it with and (when the schema matches a pinned hash) as separate steps.
prisma-next contract infer --db <url>contract.prismacontract emitdb signbash
pnpm prisma-next contract infer --db $DATABASE_URL --output ./src/prisma/contract.prisma
pnpm prisma-next contract emit核心思路:从现有数据库中提取契约源文件并继续开发。读取实时Schema并写入文件。操作到此为止——后续需分别执行和(当Schema匹配固定哈希时)步骤。
prisma-next contract infer --db <url>contract.prismacontract emitdb signbash
pnpm prisma-next contract infer --db $DATABASE_URL --output ./src/prisma/contract.prisma
pnpm prisma-next contract emitCommon Pitfalls
常见陷阱
- Forgetting to re-emit after an edit. and
contract.jsongo stale; downstream typecheck andcontract.d.tssee the old shape. Re-emit, or install the Vite plugin (migration plan).prisma-next-build - Editing the emitted artefacts. and
contract.jsonare emitted; edits there round-trip away on the next emit. Edit the source.contract.d.ts - Wrong factory/import path for the TS builder. ,
defineContract,field,modelcome fromrel(or@prisma-next/postgres/contract-builder). Outside the callback overload, the available field constructors are@prisma-next/mongo/contract-builder,field.column(...),field.generated(...).field.namedType(...) - Reaching into internal packages from user code. User-authored files (,
prisma-next.config.ts,contract.ts, control clients) import only fromdb.tsand@prisma-next/<target>/<subpath>. Imports from@prisma-next/extension-<name>/<subpath>,@prisma-next/cli/*,@prisma-next/family-*,@prisma-next/target-*,@prisma-next/adapter-*, or@prisma-next/driver-*are framework-internal — the façade composes them for you. If a façade subpath you need is missing for your target, see What Prisma Next doesn't do yet and route to@prisma-next/sql-contract-*(track via TML-2526). The canonical worked examples areprisma-next-feedback,examples/multi-extension-monorepo/app/prisma-next.config.ts, andexamples/cipherstash-integration/prisma-next.config.ts.examples/prisma-next-postgis-demo/prisma-next.config.ts - Confusing (config façade) with
extensions(TS builder). Same packs, two surfaces, two field names:extensionPacks(array of control descriptors fromdefineConfig({ extensions: [pgvector] })) versus@prisma-next/extension-<name>/control(record of pack descriptors fromdefineContract({ extensionPacks: { pgvector } })). The@prisma-next/extension-<name>/packenvelope's fix text refers toPN-CLI-4011— that field name matches the façade.extensions - Renaming a field and expecting the planner to detect it. Prisma Next has no in-contract rename hint; the planner sees a destructive drop+add. Hand-edit after
migration.ts(seemigration plan), or use the keep-then-drop two-migration pattern.prisma-next-migrations
- 编辑后忘记重新生成:和
contract.json会过期;下游类型检查和contract.d.ts会看到旧结构。请重新生成,或安装Vite插件(migration plan)。prisma-next-build - 编辑生成产物:和
contract.json是生成文件;对它们的修改会在下一次生成时被覆盖。请编辑源文件。contract.d.ts - TS构建器使用错误的工厂/导入路径:、
defineContract、field、model来自rel(或@prisma-next/postgres/contract-builder)。回调重载外可用的字段构造器只有@prisma-next/mongo/contract-builder、field.column(...)、field.generated(...)。field.namedType(...) - 从用户代码中导入内部包:用户编写的文件(、
prisma-next.config.ts、contract.ts、控制客户端)只能从db.ts和@prisma-next/<target>/<subpath>导入。从@prisma-next/extension-<name>/<subpath>、@prisma-next/cli/*、@prisma-next/family-*、@prisma-next/target-*、@prisma-next/adapter-*或@prisma-next/driver-*导入属于框架内部操作——外观已为你组合好这些内容。如果你的目标缺少所需的外观子路径,请查看「Prisma Next暂不支持的功能」并引导至@prisma-next/sql-contract-*(跟踪ID:TML-2526)。标准示例见prisma-next-feedback、examples/multi-extension-monorepo/app/prisma-next.config.ts和examples/cipherstash-integration/prisma-next.config.ts。examples/prisma-next-postgis-demo/prisma-next.config.ts - 混淆(配置外观)和
extensions(TS构建器):相同的包,不同的交互层,不同的字段名称:extensionPacks(从defineConfig({ extensions: [pgvector] })导入的控制描述符数组) vs@prisma-next/extension-<name>/control(从defineContract({ extensionPacks: { pgvector } })导入的包描述符对象)。@prisma-next/extension-<name>/pack错误信息的修复文本提到的PN-CLI-4011是外观中的字段名称。extensions - 重命名字段后期望规划器自动检测:Prisma Next没有契约内重命名提示;规划器会将其视为破坏性的删除+添加操作。在后手动编辑
migration plan(详见migration.ts),或使用保留后删除的两步迁移模式。prisma-next-migrations
What Prisma Next doesn't do yet
Prisma Next暂不支持的功能
- Mongo config façade is narrower than Postgres. 's
@prisma-next/mongo/configaccepts onlydefineConfigandcontract; there's nodbfield and noextensionsfield. Track via TML-2526; file additional gaps viamigrations.dir.prisma-next-feedback - SQLite has no or
/configfaçade subpath./contract-builderexposes only@prisma-next/sqlite. There is no façade-shaped way to author SQLite config or TS contracts today. Track via TML-2526; if you hit this, route via/runtime.prisma-next-feedback - In-contract rename hint. No or similar. Use the workarounds in Common Pitfalls #6. To request first-class rename, file via
@@rename(old: ..., new: ...).prisma-next-feedback - Model validations. No declarative surface. Validate in application code (arktype). To request declarative validations in the contract, file via
@validates(...).prisma-next-feedback - Lifecycle callbacks (,
beforeSave, etc.). Not supported. Use middleware (afterCreate) or app code. To request lifecycle callbacks, file viaprisma-next-runtime.prisma-next-feedback - Soft delete / . No built-in soft-delete column. Add a nullable
paranoid: trueand filter explicitly in queries (or in middleware). To request built-in soft delete, file viadeletedAt DateTime?.prisma-next-feedback - Scopes / default filters. No ActiveRecord-style scopes. Compose query helpers yourself. To request scopes, file via .
prisma-next-feedback - Composite / embeddable types on SQL. PSL parses syntax but the SQL interpreter does not lower it to composite types or JSON columns. Use a separate model + relation, or a
type Foo { ... }column with application-side schemas. To request first-class composite types, file viaJson.prisma-next-feedback - Implicit Prisma-ORM many-to-many. List navigation on both sides without an explicit join model is rejected. Author the join model explicitly. To request implicit M2M, file via .
prisma-next-feedback
- Mongo配置外观比Postgres更受限:的
@prisma-next/mongo/config仅接受defineConfig和contract;没有db字段和extensions字段。跟踪ID:TML-2526;如有其他缺失功能,请通过migrations.dir提交。prisma-next-feedback - SQLite没有或
/config外观子路径:/contract-builder仅暴露@prisma-next/sqlite。目前没有外观化的方式编写SQLite配置或TS契约。跟踪ID:TML-2526;如遇到此问题,请引导至/runtime。prisma-next-feedback - 契约内重命名提示:没有或类似功能。请使用「常见陷阱」第6条中的解决方法。如需原生重命名功能,请通过
@@rename(old: ..., new: ...)提交请求。prisma-next-feedback - 模型验证:没有声明式交互层。请在应用代码中验证(如arktype)。如需在契约中添加声明式验证,请通过
@validates(...)提交请求。prisma-next-feedback - 生命周期回调(、
beforeSave等):不支持。请使用中间件(afterCreate)或应用代码。如需生命周期回调,请通过prisma-next-runtime提交请求。prisma-next-feedback - 软删除 / :没有内置软删除列。请添加可空的
paranoid: true并在查询中显式过滤(或在中间件中处理)。如需内置软删除功能,请通过deletedAt DateTime?提交请求。prisma-next-feedback - 作用域 / 默认过滤器:没有ActiveRecord风格的作用域。请自行组合查询辅助函数。如需作用域功能,请通过提交请求。
prisma-next-feedback - SQL上的组合/可嵌入类型:PSL会解析语法,但SQL解释器不会将其转换为组合类型或JSON列。请使用单独的模型+关联关系,或带应用端Schema的
type Foo { ... }列。如需原生组合类型,请通过Json提交请求。prisma-next-feedback - 隐式Prisma-ORM多对多:两端都有列表导航但无显式连接模型会被拒绝。请显式编写连接模型。如需隐式多对多功能,请通过提交请求。
prisma-next-feedback
Reference
参考资料
- Run for the live command surface.
pnpm prisma-next contract --help - PSL feature surface and what the interpreter accepts: .
packages/2-sql/2-authoring/contract-psl/README.md - TS builder surface and the callback-helper vocabulary: .
packages/2-sql/2-authoring/contract-ts/README.md - Layouts (where ,
contract.prisma,contract.json, andcontract.d.tslive):migrations/- App layout (+
src/prisma/...) — whatmigrations/app/...demonstrates; the canonical shape consuming applications use.examples/prisma-next-demo - Contract-space-package layout (directly,
src/contract.{prisma,ts}without a space-id segment) — for extensions and aggregate-root packages, documented inmigrations/<timestamp>_<slug>/and ADR 212..cursor/rules/contract-space-package-layout.mdc
- App layout (
- 运行查看实时命令交互层。
pnpm prisma-next contract --help - PSL功能交互层和解释器支持的内容:。
packages/2-sql/2-authoring/contract-psl/README.md - TS构建器交互层和回调辅助函数词汇:。
packages/2-sql/2-authoring/contract-ts/README.md - 布局(、
contract.prisma、contract.json和contract.d.ts的位置):migrations/- 应用布局(+
src/prisma/...)——migrations/app/...演示的布局;消费应用使用的标准结构。examples/prisma-next-demo - 契约空间包布局(直接在,
src/contract.{prisma,ts}无空间ID段)——适用于扩展和聚合根包,文档见migrations/<timestamp>_<slug>/和ADR 212。.cursor/rules/contract-space-package-layout.mdc
- 应用布局(
Checklist
检查清单
- Read and identified the contract source (path string ending in
prisma-next.config.tsor.prisma) and the installed.ts.extensions: [...] - All user-authored imports resolve to (e.g.
@prisma-next/<target>/<subpath>) or@prisma-next/postgres/config. No imports from@prisma-next/extension-<name>/<subpath>,@prisma-next/cli/*,@prisma-next/family-*,@prisma-next/target-*,@prisma-next/adapter-*, or@prisma-next/driver-*in user files.@prisma-next/sql-contract-* - Edited the contract source (or
contract.prisma), not an emitted artefact.contract.ts - For new extension namespaces: added the package, imported its control descriptor (), added it to
@prisma-next/extension-<name>/controlinextensions: [...](and the matching pack descriptor todefineConfig({...})if using the TS builder).defineContract({extensionPacks: {...}}) - For renames: hand-edited after
migration.ts(or used the keep-then-drop two-migration pattern) — Prisma Next has no rename hint today.migration plan - Ran after the edit (or let the Vite plugin re-emit on save).
pnpm prisma-next contract emit - Confirmed and
contract.jsonupdated next to the source.contract.d.ts - Did not hand-edit /
contract.json.contract.d.ts - Did not confabulate a missing feature (validations, callbacks, soft delete, scopes, in-contract rename hint, composite types) — referred the user to What Prisma Next doesn't do yet + .
prisma-next-feedback
- 已读取并确定契约源文件(以
prisma-next.config.ts或.prisma结尾的路径字符串)和已安装的.ts。extensions: [...] - 所有用户编写的导入都指向(如
@prisma-next/<target>/<subpath>)或@prisma-next/postgres/config。用户文件中没有从@prisma-next/extension-<name>/<subpath>、@prisma-next/cli/*、@prisma-next/family-*、@prisma-next/target-*、@prisma-next/adapter-*或@prisma-next/driver-*导入的内容。@prisma-next/sql-contract-* - 已编辑契约源文件(或
contract.prisma),而非生成产物。contract.ts - 对于新的扩展命名空间:已安装对应包,导入其控制描述符(),添加到
@prisma-next/extension-<name>/control的defineConfig({...})中(如果使用TS构建器,还需将匹配的包描述符添加到extensions: [...])。defineContract({extensionPacks: {...}}) - 对于重命名操作:在后手动编辑
migration plan(或使用保留后删除的两步迁移模式)——Prisma Next目前没有重命名提示。migration.ts - 编辑后已运行(或让Vite插件在保存时自动重新生成)。
pnpm prisma-next contract emit - 已确认和
contract.json在源文件旁更新。contract.d.ts - 未手动编辑/
contract.json。contract.d.ts - 未虚构缺失功能(验证、回调、软删除、作用域、契约内重命名提示、组合类型)——已引导用户查看「Prisma Next暂不支持的功能」+ 。
prisma-next-feedback