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
12 changes: 11 additions & 1 deletion .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
},
{
"label": "Build all - watch",
"command": "pnpm watch",
"command": "turbo watch build",
"type": "shell",
"group": {
"kind": "build"
Expand All @@ -28,6 +28,16 @@
"id": "server-process"
}
},
{
"label": "Lint all",
"command": "pnpm lint",
"type": "shell",
"icon": {
"color": "terminal.ansiYellow",
"id": "server-process"
},
"problemMatcher": []
},
{
"label": "Test all",
"command": "pnpm test",
Expand Down
2 changes: 0 additions & 2 deletions NEW-FEATURES.md

This file was deleted.

16 changes: 10 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -280,16 +280,20 @@ You can use a plugin to achieve the following goals:

#### 1. ORM query interception

ORM query interception allows you to intercept the high-level ORM API calls.
ORM query interception allows you to intercept the high-level ORM API calls. The interceptor's configuration is compatible with Prisma's [query client extension](https://www.prisma.io/docs/orm/prisma-client/client-extensions/query).

```ts
client.$use({
id: 'cost-logger',
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`);
return result;
onQuery: {
$allModels: {
$allOperations: async ({ model, operation, args, query }) => {
const start = Date.now();
const result = await query(args);
console.log(`[cost] ${model} ${operation} took ${Date.now() - start}ms`);
return result;
},
},
},
});
```
Expand Down
6 changes: 4 additions & 2 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,11 @@
- [x] Count
- [x] Aggregate
- [x] Group by
- [ ] Raw queries
- [ ] Extensions
- [x] Query builder API
- [x] Computed fields
- [ ] Prisma client extension
- [x] Prisma client extension
- [ ] Misc
- [x] JSDoc for CRUD methods
- [x] Cache validation schemas
Expand All @@ -66,7 +67,8 @@
- [ ] Error system
- [x] Custom table name
- [x] Custom field name
- [ ] Implement changesets
- [ ] Strict undefined checks
- [ ] Benchmark
- [ ] Polymorphism
- [ ] Validation
- [ ] Access Policy
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zenstack-v3",
"version": "3.0.0-alpha.4",
"version": "3.0.0-alpha.5",
"description": "ZenStack",
"packageManager": "pnpm@10.12.1",
"scripts": {
Expand Down
5 changes: 3 additions & 2 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publisher": "zenstack",
"displayName": "ZenStack CLI",
"description": "FullStack database toolkit with built-in access control and automatic API generation.",
"version": "3.0.0-alpha.4",
"version": "3.0.0-alpha.5",
"type": "module",
"author": {
"name": "ZenStack Team"
Expand All @@ -22,20 +22,21 @@
},
"scripts": {
"build": "tsup-node",
"watch": "tsup-node --watch",
"lint": "eslint src --ext ts",
"test": "vitest run",
"pack": "pnpm pack"
},
"dependencies": {
"@zenstackhq/language": "workspace:*",
"@zenstackhq/sdk": "workspace:*",
"@zenstackhq/common-helpers": "workspace:*",
"async-exit-hook": "^2.0.1",
"colors": "1.4.0",
"commander": "^8.3.0",
"langium": "catalog:",
"ora": "^5.4.1",
"package-manager-detector": "^1.3.0",
"tiny-invariant": "^1.3.3",
"ts-pattern": "catalog:"
},
"peerDependencies": {
Expand Down
5 changes: 2 additions & 3 deletions packages/cli/src/actions/generate.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import { invariant } from '@zenstackhq/common-helpers';
import { isPlugin, LiteralExpr, type Model } from '@zenstackhq/language/ast';
import type { CliGenerator } from '@zenstackhq/runtime/client';
import { PrismaSchemaGenerator, TsSchemaGenerator } from '@zenstackhq/sdk';
import { PrismaSchemaGenerator, TsSchemaGenerator, type CliGenerator } from '@zenstackhq/sdk';
import colors from 'colors';
import fs from 'node:fs';
import path from 'node:path';
import invariant from 'tiny-invariant';
import { getSchemaFile, loadSchemaDocument } from './action-utils';

type Options = {
Expand Down
4 changes: 4 additions & 0 deletions packages/common-helpers/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;
34 changes: 34 additions & 0 deletions packages/common-helpers/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@zenstackhq/common-helpers",
"version": "3.0.0-alpha.5",
"description": "ZenStack Common Helpers",
"type": "module",
"scripts": {
"build": "tsup-node",
"watch": "tsup-node --watch",
"lint": "eslint src --ext ts",
"pack": "pnpm pack"
},
"keywords": [],
"author": "ZenStack Team",
"license": "MIT",
"files": [
"dist"
],
"exports": {
".": {
"import": {
"types": "./dist/index.d.ts",
"default": "./dist/index.js"
},
"require": {
"types": "./dist/index.d.cts",
"default": "./dist/index.cjs"
}
}
},
"devDependencies": {
"@zenstackhq/typescript-config": "workspace:*",
"@zenstackhq/eslint-config": "workspace:*"
}
}
6 changes: 6 additions & 0 deletions packages/common-helpers/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export * from './is-plain-object';
export * from './lower-case-first';
export * from './param-case';
export * from './sleep';
export * from './tiny-invariant';
export * from './upper-case-first';
23 changes: 23 additions & 0 deletions packages/common-helpers/src/is-plain-object.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
function isObject(o: unknown) {
return Object.prototype.toString.call(o) === '[object Object]';
}

export function isPlainObject(o: unknown) {
if (isObject(o) === false) return false;

// If has modified constructor
const ctor = (o as { constructor: unknown }).constructor;
if (ctor === undefined) return true;

// If has modified prototype
const prot = (ctor as { prototype: unknown }).prototype;
if (isObject(prot) === false) return false;

// If constructor does not have an Object-specific method
if (Object.prototype.hasOwnProperty.call(prot, 'isPrototypeOf') === false) {
return false;
}

// Most likely a plain Object
return true;
}
3 changes: 3 additions & 0 deletions packages/common-helpers/src/lower-case-first.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function lowerCaseFirst(input: string) {
return input.charAt(0).toLowerCase() + input.slice(1);
}
18 changes: 18 additions & 0 deletions packages/common-helpers/src/param-case.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
const DEFAULT_SPLIT_REGEXP_1 = /([a-z0-9])([A-Z])/g;
const DEFAULT_SPLIT_REGEXP_2 = /([A-Z])([A-Z][a-z])/g;
const DEFAULT_STRIP_REGEXP = /[^A-Z0-9]+/gi;

export function paramCase(input: string) {
const result = input
.replace(DEFAULT_SPLIT_REGEXP_1, "$1\0$2")
.replace(DEFAULT_SPLIT_REGEXP_2, "$1\0$2")
.replace(DEFAULT_STRIP_REGEXP, "\0");

let start = 0;
let end = result.length;

while (result.charAt(start) === "\0") start++;
while (result.charAt(end - 1) === "\0") end--;

return result.slice(start, end).split("\0").map((str) => str.toLowerCase()).join("-");
}
5 changes: 5 additions & 0 deletions packages/common-helpers/src/sleep.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function sleep(timeout: number) {
return new Promise<void>((resolve) => {
setTimeout(() => resolve(), timeout);
});
}
14 changes: 14 additions & 0 deletions packages/common-helpers/src/tiny-invariant.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
const isProduction = process.env['NODE_ENV'] === 'production';
const prefix = 'Invariant failed';

export function invariant(condition: unknown, message?: string): asserts condition {
if (condition) {
return;
}

if (isProduction) {
throw new Error(prefix);
}

throw new Error(message ? `${prefix}: ${message}` : prefix);
}
3 changes: 3 additions & 0 deletions packages/common-helpers/src/upper-case-first.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export function upperCaseFirst(input: string) {
return input.charAt(0).toUpperCase() + input.slice(1);
}
7 changes: 7 additions & 0 deletions packages/common-helpers/tsconfig.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"extends": "@zenstackhq/typescript-config/base.json",
"compilerOptions": {
"outDir": "dist"
},
"include": ["src/**/*.ts"]
}
13 changes: 13 additions & 0 deletions packages/common-helpers/tsup.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { defineConfig } from 'tsup';

export default defineConfig({
entry: {
index: 'src/index.ts',
},
outDir: 'dist',
splitting: false,
sourcemap: true,
clean: true,
dts: true,
format: ['cjs', 'esm'],
});
2 changes: 1 addition & 1 deletion packages/create-zenstack/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "create-zenstack",
"version": "3.0.0-alpha.4",
"version": "3.0.0-alpha.5",
"description": "Create a new ZenStack project",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/eslint-config/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/eslint-config",
"version": "3.0.0-alpha.4",
"version": "3.0.0-alpha.5",
"type": "module",
"private": true,
"license": "MIT"
Expand Down
2 changes: 1 addition & 1 deletion packages/language/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/language",
"description": "ZenStack ZModel language specification",
"version": "3.0.0-alpha.4",
"version": "3.0.0-alpha.5",
"license": "MIT",
"author": "ZenStack Team",
"files": [
Expand Down
6 changes: 3 additions & 3 deletions packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
{
"name": "@zenstackhq/runtime",
"version": "3.0.0-alpha.4",
"version": "3.0.0-alpha.5",
"description": "ZenStack Runtime",
"type": "module",
"scripts": {
"build": "tsup-node",
"watch": "tsup-node --watch",
"lint": "eslint src --ext ts",
"test": "vitest run && pnpm test:generate && pnpm test:typecheck",
"test:generate": "tsx test/typing/generate.ts",
Expand Down Expand Up @@ -64,13 +65,12 @@
}
},
"dependencies": {
"@zenstackhq/common-helpers": "workspace:*",
"@paralleldrive/cuid2": "^2.2.2",
"decimal.js": "^10.4.3",
"is-plain-object": "^5.0.0",
"json-stable-stringify": "^1.3.0",
"kysely": "catalog:",
"nanoid": "^5.0.9",
"tiny-invariant": "^1.3.3",
"ts-pattern": "catalog:",
"ulid": "^3.0.0",
"utility-types": "^3.11.0",
Expand Down
Loading