- Clone the repo
pnpm install
from the rootpnpm build
from the root
cd samples/blog
pnpm generate
pnpm db:migrate
pnpm dev
- ZModel is located in zenstack/schema.zmodel.
- When you run
zenstack generate
, a TypeScript version of the schema is generated to zenstack/schema.ts. - A Prisma schema zenstack/schema.prisma is also generated. It's used for generating and running database migrations, and you can also use it for other purposes as needed.
- You can create a database client with the TypeScript schema like:
import { createClient } from '@zenstackhq/runtime'; import { schema } from './zenstack/schema'; const db = createClient(schema);
- Run
zenstack migrate dev
to generate and apply database migrations. It internally callsprisma migrate dev
. Same forzenstack migrate deploy
. - ZenStack v3 doesn't generate into "node_modules" anymore. The generated TypeScript schema file can be checked in to source control, and you decide how to build or bundle it with your application.
- The TS schema will also serve as the foundation of inferring types of other artifacts, e.g., zod schemas, frontend hooks, etc.
Replicating PrismaClient's CRUD API is around 80% done, including typing and runtime. Database access is entirely through Kysely. At runtime there's no Prisma dependency.
Not supported yet:
$transaction
$extends
You can use the $expr
key to invoke Kysely expression builder in your where
clause. The expression built will be merged with other filter conditions and evaluated as a whole.
For example:
db.user.findMany({
where: {
role: 'USER',
// `eb` is Kysely expression builder, fully typed
$expr: (eb) => eb('email', 'like', '%@zenstack.dev'),
},
});
You can define computed fields in ZModel using the @computed
attribute. E.g.:
model User {
...
/// Domain of the email address
emailDomain String @computed
}
When calling createClient
, you need to provide implementation for the computed field, using Kysely expression builder. During query, the computed field will be evaluated on the database server side and returned as part of the result.
E.g.:
import { createClient } from '@zenstackhq/runtime';
const db = createClient({
computedFields: {
User: {
emailDomain: (eb) =>
// build SQL expression: substr(email, instr(email, '@') + 1)
eb.fn('substr', [
eb.ref('email'),
eb(eb.fn('instr', [eb.ref('email'), eb.val('@')]), '+', 1),
]),
},
},
});
You can also filter and sort on computed fields.
db.user.findMany({
where: {
emailDomain: 'zenstack.dev',
},
});