zenstack-migrate-from-v2

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Migrating from ZenStack V2 to V3

从ZenStack V2迁移到V3

ZenStack V3 is a major rewrite: the Prisma ORM engine is replaced with ZenStack's own engine built on Kysely, while the ZModel schema stays largely compatible and the query API stays PrismaClient-compatible. Supported databases: PostgreSQL, MySQL, SQLite.
Because V2 was Prisma-based, the migration has two layers: the generic Prisma→ZenStack changes, then the V2-specific deltas below. For general setup/CLI see
zenstack-project-setup
.
ZenStack V3是一次重大重构:Prisma ORM引擎被替换为基于Kysely构建的ZenStack自研引擎,同时ZModel架构保持高度兼容,查询API也与PrismaClient兼容。支持的数据库:PostgreSQL、MySQL、SQLite
由于V2基于Prisma构建,迁移分为两层:首先是通用的Prisma→ZenStack变更,然后是以下V2专属的增量调整。通用配置/CLI相关内容可参考
zenstack-project-setup

Step 1 — Do the Prisma migration first

步骤1 — 先完成Prisma迁移

V2 ran on Prisma, so start with the
zenstack-migrate-from-prisma
skill (swap deps, move the schema to
zenstack/schema.zmodel
, replace the client with
ZenStackClient
, update generate/migrate scripts). Then apply the V2-specific steps below.
V2运行在Prisma之上,因此请先执行**
zenstack-migrate-from-prisma
**技能(替换依赖、将架构文件移至
zenstack/schema.zmodel
、用
ZenStackClient
替换客户端、更新生成/迁移脚本)。然后应用以下V2专属步骤。

Step 2 — Rename ZenStack packages

步骤2 — 重命名ZenStack包

bash
npm uninstall zenstack @zenstackhq/runtime
npm install @zenstackhq/schema @zenstackhq/orm
npm install --save-dev @zenstackhq/cli
V2V3
zenstack
(CLI)
@zenstackhq/cli
@zenstackhq/runtime
@zenstackhq/orm
@zenstackhq/schema
(new)
The CLI command moves from
zenstack <cmd>
to
zen <cmd>
(e.g.
zen generate
).
bash
npm uninstall zenstack @zenstackhq/runtime
npm install @zenstackhq/schema @zenstackhq/orm
npm install --save-dev @zenstackhq/cli
V2V3
zenstack
(CLI)
@zenstackhq/cli
@zenstackhq/runtime
@zenstackhq/orm
@zenstackhq/schema
(新增)
CLI命令从
zenstack <cmd>
改为
zen <cmd>
(例如
zen generate
)。

Step 3 — Access control is now a plugin

步骤3 — 访问控制现在作为插件存在

In V2 access control was built into the runtime (
enhance(prisma)
). In V3 it's an opt-in plugin.
  1. Install it:
    npm install @zenstackhq/plugin-policy
  2. Declare it in the schema:
    zmodel
    plugin policy {
        provider = '@zenstackhq/plugin-policy'
    }
  3. Wrap the client and bind the user per request:
    ts
    import { ZenStackClient } from '@zenstackhq/orm';
    import { PolicyPlugin } from '@zenstackhq/plugin-policy';
    
    export const db = new ZenStackClient(schema, { dialect });
    export const authDb = db.$use(new PolicyPlugin());   // was: enhance(prisma, { user })
    // per request:
    const userDb = authDb.$setAuth(user);                // was: passing { user } to enhance()
See
zenstack-access-control
for the full policy/runtime model.
在V2中,访问控制内置在运行时(
enhance(prisma)
)。V3中它是一个可选插件。
  1. 安装插件:
    npm install @zenstackhq/plugin-policy
  2. 在架构中声明:
    zmodel
    plugin policy {
        provider = '@zenstackhq/plugin-policy'
    }
  3. 包装客户端并在每个请求中绑定用户:
    ts
    import { ZenStackClient } from '@zenstackhq/orm';
    import { PolicyPlugin } from '@zenstackhq/plugin-policy';
    
    export const db = new ZenStackClient(schema, { dialect });
    export const authDb = db.$use(new PolicyPlugin());   // 原写法:enhance(prisma, { user })
    // 每个请求中:
    const userDb = authDb.$setAuth(user);                // 原写法:向enhance()传递{ user }
完整的策略/运行时模型可参考
zenstack-access-control

Step 4 — Post-update policies:
future()
post-update
+
before()

步骤4 — 更新后策略:
future()
post-update
+
before()

V2 expressed post-update conditions with
future()
inside an
update
rule. V3 uses a dedicated
post-update
operation, where bare field references mean the new values and
before()
reads the old ones.
zmodel
// V2
@@deny('update', future().ownerId != ownerId)

// V3
@@deny('post-update', ownerId != before().ownerId)
V2中使用
update
规则内的
future()
表示更新后条件。V3使用专用的
post-update
操作,其中直接的字段引用代表值,
before()
用于读取值。
zmodel
// V2
@@deny('update', future().ownerId != ownerId)

// V3
@@deny('post-update', ownerId != before().ownerId)

Step 5 — Abstract models → types + mixins

步骤5 — 抽象模型 → 类型+混入

V2's
abstract model
+
extends
becomes a
type
applied with
with
(see
zenstack-schema-modeling
).
zmodel
// V2
abstract model Timestamped {
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}
model Post extends Timestamped { title String }

// V3
type Timestamped {
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}
model Post with Timestamped { title String }
(Note:
extends
still exists in V3, but for polymorphism via
@@delegate
, which is a different feature — don't use it as a plain mixin replacement.)
V2的
abstract model
+
extends
变为使用
with
应用的
type
(详见
zenstack-schema-modeling
)。
zmodel
// V2
abstract model Timestamped {
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}
model Post extends Timestamped { title String }

// V3
type Timestamped {
    createdAt DateTime @default(now())
    updatedAt DateTime @updatedAt
}
model Post with Timestamped { title String }
(注意:V3中仍保留
extends
,但用于通过
@@delegate
实现多态,这是一个不同的功能——不要将其用作普通混入的替代方案。)

Step 6 — Server adapters

步骤6 — 服务器适配器

V3 requires you to pass an explicit
apiHandler
(
RPCApiHandler
or
RestApiHandler
), and the client-supplying callback is renamed
getPrisma
getClient
:
ts
// V2
ZenStackMiddleware({ getPrisma: (req) => enhance(prisma, { user: getUser(req) }) });

// V3
ZenStackMiddleware({
    apiHandler: new RPCApiHandler({ schema }),
    getClient: (req) => authDb.$setAuth(getUser(req)),
});
See
zenstack-crud-server
for all frameworks and both API styles.
V3要求传递显式的
apiHandler
RPCApiHandler
RestApiHandler
),并且提供客户端的回调函数从
getPrisma
重命名为
getClient
ts
// V2
ZenStackMiddleware({ getPrisma: (req) => enhance(prisma, { user: getUser(req) }) });

// V3
ZenStackMiddleware({
    apiHandler: new RPCApiHandler({ schema }),
    getClient: (req) => authDb.$setAuth(getUser(req)),
});
所有框架和两种API风格的相关内容可参考
zenstack-crud-server

Step 7 — Client-side hooks (TanStack Query)

步骤7 — 客户端钩子(TanStack Query)

Flat hook names are replaced by hooks grouped under a client that mirrors the ORM:
ts
// V2
import { useFindManyUser } from '~/hooks';
const { data } = useFindManyUser({ where: { ... } });

// V3
import { useClientQueries } from '@zenstackhq/tanstack-query/react';
import { schema } from '~/zenstack/schema';

const client = useClientQueries(schema);
const { data } = client.user.useFindMany({ where: { ... } });
SWR support was dropped in V3. See
zenstack-crud-server
for the full TanStack Query setup.
扁平化的钩子名称被替换为归属于镜像ORM的客户端下的钩子:
ts
// V2
import { useFindManyUser } from '~/hooks';
const { data } = useFindManyUser({ where: { ... } });

// V3
import { useClientQueries } from '@zenstackhq/tanstack-query/react';
import { schema } from '~/zenstack/schema';

const client = useClientQueries(schema);
const { data } = client.user.useFindMany({ where: { ... } });
V3中已移除SWR支持。完整的TanStack Query配置可参考
zenstack-crud-server

Step 8 — Other plugin/utility migrations

步骤8 — 其他插件/工具迁移

  • Zod: now a utility rather than a plugin (see the zod utility docs).
  • OpenAPI: folded into the automatic CRUD API handlers — generate a spec via
    apiHandler.generateSpec()
    (see
    zenstack-crud-server
    ).
  • Custom plugins: the V3 plugin system is revised; consult the current plugin docs.
  • Zod:现在是工具而非插件(详见Zod工具文档)。
  • OpenAPI:整合到自动CRUD API处理器中——通过
    apiHandler.generateSpec()
    生成规范(详见
    zenstack-crud-server
    )。
  • 自定义插件:V3的插件系统已修订,请查阅当前插件文档。

After upgrading

升级完成后

Run
zen generate
, typecheck, and exercise your test suite / app. Confirm access control behaves as expected now that it's an explicit
$use(new PolicyPlugin())
+
$setAuth()
flow rather than V2's implicit
enhance()
.
运行
zen generate
,进行类型检查,并测试你的测试套件/应用。确认访问控制行为符合预期,现在它是显式的
$use(new PolicyPlugin())
+
$setAuth()
流程,而非V2中的隐式
enhance()

Reference docs

参考文档

Full ZenStack documentation for this topic is bundled under
references/
:
  • migrate-v2.md — official "Migrating from ZenStack v2" guide
本主题的完整ZenStack文档打包在
references/
目录下:
  • migrate-v2.md — 官方“从ZenStack v2迁移”指南