Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .eslintignore

This file was deleted.

22 changes: 0 additions & 22 deletions .eslintrc.json

This file was deleted.

6 changes: 6 additions & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
{
"tabWidth": 4,
"useTabs": false,
"printWidth": 120,
"singleQuote": true
}
4 changes: 2 additions & 2 deletions NEW-FEATURES.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
- Cross-field comparison (for read and mutations)
- Computed fields
- Cross-field comparison (for read and mutations)
- Computed fields
32 changes: 15 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,13 @@

ZenStack is a TypeScript database toolkit for developing full-stack or backend Node.js/Bun applications. It provides a unified data modeling and access solution with the following features:

- A modern schema-first ORM that's compatible with [Prisma](https://github.com/prisma/prisma)'s schema and API
- Versatile data access APIs: high-level (Prisma-style) ORM queries + low-level ([Kysely](https://github.com/kysely-org/kysely)) query builder
- Built-in access control and data validation
- Advanced data modeling patterns like [polymorphism](https://zenstack.dev/blog/polymorphism)
- Designed for extensibility and flexibility: plugins, life-cycle hooks, etc.
- Automatic CRUD web APIs with adapters for popular frameworks
- Automatic [TanStack Query](https://github.com/TanStack/query) hooks for easy CRUD from the frontend
- A modern schema-first ORM that's compatible with [Prisma](https://github.com/prisma/prisma)'s schema and API
- Versatile data access APIs: high-level (Prisma-style) ORM queries + low-level ([Kysely](https://github.com/kysely-org/kysely)) query builder
- Built-in access control and data validation
- Advanced data modeling patterns like [polymorphism](https://zenstack.dev/blog/polymorphism)
- Designed for extensibility and flexibility: plugins, life-cycle hooks, etc.
- Automatic CRUD web APIs with adapters for popular frameworks
- Automatic [TanStack Query](https://github.com/TanStack/query) hooks for easy CRUD from the frontend

# What's new with V3

Expand Down Expand Up @@ -83,10 +83,10 @@ Then create a `zenstack` folder and a `schema.zmodel` file in it.

ZenStack uses a DSL named ZModel to model different aspects of database:

- Tables and fields
- Validation rules (coming soon)
- Access control policies (coming soon)
- ...
- Tables and fields
- Validation rules (coming soon)
- Access control policies (coming soon)
- ...

ZModel is a super set of [Prisma Schema Language](https://www.prisma.io/docs/orm/prisma-schema/overview), i.e., every valid Prisma schema is a valid ZModel.

Expand Down Expand Up @@ -288,9 +288,7 @@ client.$use({
async onQuery({ model, operation, proceed, queryArgs }) {
const start = Date.now();
const result = await proceed(queryArgs);
console.log(
`[cost] ${model} ${operation} took ${Date.now() - start}ms`
);
console.log(`[cost] ${model} ${operation} took ${Date.now() - start}ms`);
return result;
},
});
Expand Down Expand Up @@ -365,19 +363,19 @@ client.$use({

ZenStack v3 delegates database schema migration to Prisma. The CLI provides Prisma CLI wrappers for managing migrations.

- Sync schema to dev database and create a migration record:
- Sync schema to dev database and create a migration record:

```bash
npx zenstack migrate dev
```

- Deploy new migrations:
- Deploy new migrations:

```bash
npx zenstack migrate deploy
```

- Reset dev database
- Reset dev database

```bash
npx zenstack migrate reset
Expand Down
156 changes: 78 additions & 78 deletions TODO.md
Original file line number Diff line number Diff line change
@@ -1,80 +1,80 @@
## V3 Alpha Todo

- [ ] Infra
- [ ] Dependency injection
- [ ] CLI
- [x] generate
- [x] migrate
- [x] info
- [x] init
- [ ] ORM
- [x] Create
- [x] Input validation
- [x] Simple create
- [x] Nested create
- [x] Relation connection
- [x] Create many
- [x] ID generation
- [x] CreateManyAndReturn
- [x] Find
- [x] Input validation
- [x] Field selection
- [x] Omit
- [x] Counting relation
- [x] Pagination
- [x] Skip and limit
- [x] Cursor
- [x] Filtering
- [x] Unique fields
- [x] Scalar fields
- [x] Relation fields
- [x] Sort
- [x] Scalar fields
- [x] Relation fields
- [x] Relation inclusion
- [x] Filtering
- [x] Sorting
- [x] Pagination
- [x] Distinct
- [ ] JSON filtering
- [x] Update
- [x] Input validation
- [x] Top-level
- [x] Nested to-many
- [x] Nested to-one
- [x] Incremental update for numeric fields
- [x] Array update
- [x] Upsert
- [ ] Implement with "on conflict"
- [x] Delete
- [x] Aggregation
- [x] Count
- [x] Aggregate
- [x] Group by
- [ ] Extensions
- [x] Query builder API
- [x] Computed fields
- [ ] Prisma client extension
- [ ] Misc
- [x] JSDoc for CRUD methods
- [x] Cache validation schemas
- [x] Compound ID
- [ ] Cross field comparison
- [x] Many-to-many relation
- [ ] Empty AND/OR/NOT behavior
- [?] Logging
- [ ] Error system
- [x] Custom table name
- [x] Custom field name
- [ ] Implement changesets
- [ ] Polymorphism
- [ ] Validation
- [ ] Access Policy
- [ ] Short-circuit pre-create check for scalar-field only policies
- [ ] Inject "replace into"
- [ ] Inject "on conflict do update"
- [x] Migration
- [ ] Databases
- [x] SQLite
- [x] PostgreSQL
- [ ] Multi-schema
- [ ] Infra
- [ ] Dependency injection
- [ ] CLI
- [x] generate
- [x] migrate
- [x] info
- [x] init
- [ ] ORM
- [x] Create
- [x] Input validation
- [x] Simple create
- [x] Nested create
- [x] Relation connection
- [x] Create many
- [x] ID generation
- [x] CreateManyAndReturn
- [x] Find
- [x] Input validation
- [x] Field selection
- [x] Omit
- [x] Counting relation
- [x] Pagination
- [x] Skip and limit
- [x] Cursor
- [x] Filtering
- [x] Unique fields
- [x] Scalar fields
- [x] Relation fields
- [x] Sort
- [x] Scalar fields
- [x] Relation fields
- [x] Relation inclusion
- [x] Filtering
- [x] Sorting
- [x] Pagination
- [x] Distinct
- [ ] JSON filtering
- [x] Update
- [x] Input validation
- [x] Top-level
- [x] Nested to-many
- [x] Nested to-one
- [x] Incremental update for numeric fields
- [x] Array update
- [x] Upsert
- [ ] Implement with "on conflict"
- [x] Delete
- [x] Aggregation
- [x] Count
- [x] Aggregate
- [x] Group by
- [ ] Extensions
- [x] Query builder API
- [x] Computed fields
- [ ] Prisma client extension
- [ ] Misc
- [x] JSDoc for CRUD methods
- [x] Cache validation schemas
- [x] Compound ID
- [ ] Cross field comparison
- [x] Many-to-many relation
- [ ] Empty AND/OR/NOT behavior
- [?] Logging
- [ ] Error system
- [x] Custom table name
- [x] Custom field name
- [ ] Implement changesets
- [ ] Polymorphism
- [ ] Validation
- [ ] Access Policy
- [ ] Short-circuit pre-create check for scalar-field only policies
- [ ] Inject "replace into"
- [ ] Inject "on conflict do update"
- [x] Migration
- [ ] Databases
- [x] SQLite
- [x] PostgreSQL
- [ ] Multi-schema
8 changes: 5 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"watch": "turbo run watch build",
"lint": "turbo run lint",
"test": "turbo run test",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"publish-all": "pnpm --filter \"./packages/**\" -r publish --tag next",
"publish-preview": "pnpm --filter \"./packages/**\" -r publish --tag next --force --registry https://preview.registry.zenstack.dev/",
"unpublish-preview": "pnpm --filter \"./packages/**\" -r --shell-mode exec -- npm unpublish -f --registry https://preview.registry.zenstack.dev/ \"\\$PNPM_PACKAGE_NAME\""
Expand All @@ -16,16 +17,17 @@
"author": "",
"license": "MIT",
"devDependencies": {
"@eslint/js": "^9.29.0",
"@swc/core": "^1.12.5",
"@types/node": "^20.17.24",
"@typescript-eslint/eslint-plugin": "~7.3.1",
"@typescript-eslint/parser": "~7.3.1",
"eslint": "~8.57.1",
"eslint": "~9.29.0",
"npm-run-all": "^4.1.5",
"prettier": "^3.5.3",
"tsup": "^8.5.0",
"tsx": "^4.20.3",
"turbo": "^2.5.4",
"typescript": "catalog:",
"typescript-eslint": "^8.34.1",
"vitest": "^3.2.4"
},
"pnpm": {
Expand Down
4 changes: 4 additions & 0 deletions packages/cli/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import config from '@zenstackhq/eslint-config/base.js';

/** @type {import("eslint").Linter.Config} */
export default config;
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
"@zenstackhq/runtime": "workspace:*",
"@zenstackhq/testtools": "workspace:*",
"@zenstackhq/typescript-config": "workspace:*",
"@zenstackhq/eslint-config": "workspace:*",
"better-sqlite3": "^11.8.1",
"tmp": "^0.2.3"
}
Expand Down
8 changes: 2 additions & 6 deletions packages/cli/src/actions/action-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export function getSchemaFile(file?: string) {
return './schema.zmodel';
} else {
throw new CliError(
'Schema file not found in default locations ("./zenstack/schema.zmodel" or "./schema.zmodel").'
'Schema file not found in default locations ("./zenstack/schema.zmodel" or "./schema.zmodel").',
);
}
}
Expand All @@ -35,11 +35,7 @@ export async function loadSchemaDocument(schemaFile: string) {
}

export function handleSubProcessError(err: unknown) {
if (
err instanceof Error &&
'status' in err &&
typeof err.status === 'number'
) {
if (err instanceof Error && 'status' in err && typeof err.status === 'number') {
process.exit(err.status);
} else {
process.exit(1);
Expand Down
5 changes: 1 addition & 4 deletions packages/cli/src/actions/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@ export async function run(command: string, options: CommonOptions) {
silent: true,
});

const prismaSchemaFile = path.join(
path.dirname(schemaFile),
'schema.prisma'
);
const prismaSchemaFile = path.join(path.dirname(schemaFile), 'schema.prisma');

switch (command) {
case 'push':
Expand Down
11 changes: 2 additions & 9 deletions packages/cli/src/actions/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,18 +48,11 @@ const client = new ZenStackClient(schema, {
}
}

async function runPlugins(
model: Model,
outputPath: string,
tsSchemaFile: string
) {
async function runPlugins(model: Model, outputPath: string, tsSchemaFile: string) {
const plugins = model.declarations.filter(isPlugin);
for (const plugin of plugins) {
const providerField = plugin.fields.find((f) => f.name === 'provider');
invariant(
providerField,
`Plugin ${plugin.name} does not have a provider field`
);
invariant(providerField, `Plugin ${plugin.name} does not have a provider field`);
const provider = (providerField.value as LiteralExpr).value as string;
let useProvider = provider;
if (useProvider.startsWith('@core/')) {
Expand Down
Loading