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
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ ZenStack is a TypeScript database toolkit for developing full-stack or backend N
- Automatic CRUD web APIs with adapters for popular frameworks (coming soon)
- Automatic [TanStack Query](https://github.com/TanStack/query) hooks for easy CRUD from the frontend (coming soon)

# What's new with V3
# What's New in V3

ZenStack V3 is a major rewrite of [V2](https://github.com/zenstackhq/zenstack). The biggest change is V3 doesn't have a runtime dependency to Prisma anymore. Instead of working as a big wrapper of Prisma as in V2, V3 made a bold move and implemented the entire ORM engine using [Kysely](https://github.com/kysely-org/kysely), while keeping the query API fully compatible with Prisma.

Expand All @@ -49,7 +49,7 @@ Even without using advanced features, ZenStack offers the following benefits as

> Although ZenStack v3's ORM runtime doesn't depend on Prisma anymore (specifically, `@prisma/client`), it still relies on Prisma to handle database migration. See [database migration](https://zenstack.dev/docs/3.x/orm/migration) for more details.

# Quick start
# Quick Start

- [ORM](./samples/orm): A simple example demonstrating ZenStack ORM usage.
- [Next.js + TanStack Query](./samples/next.js): A full-stack sample demonstrating using TanStack Query to consume ZenStack's automatic CRUD services in a Next.js app.
Expand All @@ -72,7 +72,7 @@ Or, if you have an existing project, use the CLI to initialize it:
npx @zenstackhq/cli@next init
```

### 3. Manual setup
### 3. Setting up manually

Alternatively, you can set it up manually:

Expand Down
6 changes: 4 additions & 2 deletions packages/language/res/stdlib.zmodel
Original file line number Diff line number Diff line change
Expand Up @@ -382,12 +382,14 @@ attribute @map(_ name: String) @@@prisma
attribute @@map(_ name: String) @@@prisma

/**
* Exclude a field from the Prisma Client (for example, a field that you do not want Prisma users to update).
* Exclude a field from the ORM Client (for example, a field that you do not want Prisma users to update).
* The field is still recognized by database schema migrations.
*/
attribute @ignore() @@@prisma

/**
* Exclude a model from the Prisma Client (for example, a model that you do not want Prisma users to update).
* Exclude a model from the ORM Client (for example, a model that you do not want Prisma users to update).
* The model is still recognized by database schema migrations.
*/
attribute @@ignore() @@@prisma

Expand Down
6 changes: 3 additions & 3 deletions packages/orm/src/client/client-impl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ import { FindOperationHandler } from './crud/operations/find';
import { GroupByOperationHandler } from './crud/operations/group-by';
import { UpdateOperationHandler } from './crud/operations/update';
import { InputValidator } from './crud/validator';
import { NotFoundError, QueryError } from './errors';
import { createConfigError, createNotFoundError } from './errors';
import { ZenStackDriver } from './executor/zenstack-driver';
import { ZenStackQueryExecutor } from './executor/zenstack-query-executor';
import * as BuiltinFunctions from './functions';
Expand Down Expand Up @@ -223,7 +223,7 @@ export class ClientImpl<Schema extends SchemaDef> {

private async handleProc(name: string, args: unknown[]) {
if (!('procedures' in this.$options) || !this.$options || typeof this.$options.procedures !== 'object') {
throw new QueryError('Procedures are not configured for the client.');
throw createConfigError('Procedures are not configured for the client.');
}

const procOptions = this.$options.procedures as ProceduresOptions<
Expand Down Expand Up @@ -389,7 +389,7 @@ function createModelCrudHandler<Schema extends SchemaDef, Model extends GetModel
const _handler = txClient ? handler.withClient(txClient) : handler;
const r = await _handler.handle(operation, _args);
if (!r && throwIfNoResult) {
throw new NotFoundError(model);
throw createNotFoundError(model);
}
let result: unknown;
if (r && postProcess) {
Expand Down
18 changes: 9 additions & 9 deletions packages/orm/src/client/crud/dialects/base-dialect.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import type {
SortOrder,
StringFilter,
} from '../../crud-types';
import { InternalError, QueryError } from '../../errors';
import { createConfigError, createInvalidInputError, createNotSupportedError } from '../../errors';
import type { ClientOptions } from '../../options';
import {
aggregate,
Expand Down Expand Up @@ -95,7 +95,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
if (this.supportsDistinctOn) {
result = result.distinctOn(distinct.map((f) => this.eb.ref(`${modelAlias}.${f}`)));
} else {
throw new QueryError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
throw createNotSupportedError(`"distinct" is not supported by "${this.schema.provider.type}" provider`);
}
}

Expand Down Expand Up @@ -482,7 +482,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
}

default: {
throw new InternalError(`Invalid array filter key: ${key}`);
throw createInvalidInputError(`Invalid array filter key: ${key}`);
}
}
}
Expand Down Expand Up @@ -510,10 +510,10 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
.with('Bytes', () => this.buildBytesFilter(fieldRef, payload))
// TODO: JSON filters
.with('Json', () => {
throw new InternalError('JSON filters are not supported yet');
throw createNotSupportedError('JSON filters are not supported yet');
})
.with('Unsupported', () => {
throw new QueryError(`Unsupported field cannot be used in filters`);
throw createInvalidInputError(`Unsupported field cannot be used in filters`);
})
.exhaustive()
);
Expand Down Expand Up @@ -589,7 +589,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
})
.otherwise(() => {
if (throwIfInvalid) {
throw new QueryError(`Invalid filter key: ${op}`);
throw createInvalidInputError(`Invalid filter key: ${op}`);
} else {
return undefined;
}
Expand Down Expand Up @@ -642,7 +642,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
: this.eb(fieldRef, 'like', sql.val(`%${value}`)),
)
.otherwise(() => {
throw new QueryError(`Invalid string filter key: ${key}`);
throw createInvalidInputError(`Invalid string filter key: ${key}`);
});

if (condition) {
Expand Down Expand Up @@ -815,7 +815,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
if (fieldDef.array) {
// order by to-many relation
if (typeof value !== 'object') {
throw new QueryError(`invalid orderBy value for field "${field}"`);
throw createInvalidInputError(`invalid orderBy value for field "${field}"`);
}
if ('_count' in value) {
invariant(
Expand Down Expand Up @@ -1084,7 +1084,7 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
computer = computedFields?.[fieldDef.originModel ?? model]?.[field];
}
if (!computer) {
throw new QueryError(`Computed field "${field}" implementation not provided for model "${model}"`);
throw createConfigError(`Computed field "${field}" implementation not provided for model "${model}"`);
}
return computer(this.eb, { modelAlias });
}
Expand Down
4 changes: 2 additions & 2 deletions packages/orm/src/client/crud/dialects/postgresql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import { match } from 'ts-pattern';
import type { BuiltinType, FieldDef, GetModels, SchemaDef } from '../../../schema';
import { DELEGATE_JOINED_FIELD_PREFIX } from '../../constants';
import type { FindArgs } from '../../crud-types';
import { QueryError } from '../../errors';
import type { ClientOptions } from '../../options';
import {
buildJoinPairs,
Expand All @@ -24,6 +23,7 @@ import {
requireModel,
} from '../../query-utils';
import { BaseCrudDialect } from './base-dialect';
import { createInternalError } from '../../errors';

export class PostgresCrudDialect<Schema extends SchemaDef> extends BaseCrudDialect<Schema> {
constructor(schema: Schema, options: ClientOptions<Schema>) {
Expand Down Expand Up @@ -438,7 +438,7 @@ export class PostgresCrudDialect<Schema extends SchemaDef> extends BaseCrudDiale
override getFieldSqlType(fieldDef: FieldDef) {
// TODO: respect `@db.x` attributes
if (fieldDef.relation) {
throw new QueryError('Cannot get SQL type of a relation field');
throw createInternalError('Cannot get SQL type of a relation field');
}

let result: string;
Expand Down
8 changes: 4 additions & 4 deletions packages/orm/src/client/crud/dialects/sqlite.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { match } from 'ts-pattern';
import type { BuiltinType, FieldDef, GetModels, SchemaDef } from '../../../schema';
import { DELEGATE_JOINED_FIELD_PREFIX } from '../../constants';
import type { FindArgs } from '../../crud-types';
import { QueryError } from '../../errors';
import { createInternalError } from '../../errors';
import {
getDelegateDescendantModels,
getManyToManyRelation,
Expand Down Expand Up @@ -121,7 +121,7 @@ export class SqliteCrudDialect<Schema extends SchemaDef> extends BaseCrudDialect
try {
return JSON.parse(value);
} catch (e) {
throw new QueryError('Invalid JSON returned', e);
throw createInternalError('Invalid JSON returned', undefined, { cause: e });
}
}
return value;
Expand Down Expand Up @@ -376,10 +376,10 @@ export class SqliteCrudDialect<Schema extends SchemaDef> extends BaseCrudDialect
override getFieldSqlType(fieldDef: FieldDef) {
// TODO: respect `@db.x` attributes
if (fieldDef.relation) {
throw new QueryError('Cannot get SQL type of a relation field');
throw createInternalError('Cannot get SQL type of a relation field');
}
if (fieldDef.array) {
throw new QueryError('SQLite does not support scalar list type');
throw createInternalError('SQLite does not support scalar list type');
}

if (this.schema.enums?.[fieldDef.type]) {
Expand Down
Loading