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
13 changes: 4 additions & 9 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,7 @@
"request": "launch",
"skipFiles": ["<node_internals>/**"],
"type": "node",
"args": [
"generate",
"--schema",
"${workspaceFolder}/samples/blog/zenstack/schema.zmodel"
]
"args": ["generate", "--schema", "${workspaceFolder}/samples/blog/zenstack/schema.zmodel"]
},
{
"name": "Debug with TSX",
Expand Down Expand Up @@ -44,15 +40,14 @@

// Ignore all dependencies (optional)
"${workspaceFolder}/node_modules/**"
]
],
"cwd": "${fileDirname}"
},
{
"name": "Run Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}/packages/ide/vscode"
],
"args": ["--extensionDevelopmentPath=${workspaceFolder}/packages/ide/vscode"],
"sourceMaps": true,
"outFiles": ["${workspaceFolder}/packages/ide/vscode/dist/**/*.js"]
},
Expand Down
59 changes: 31 additions & 28 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -289,15 +289,11 @@ ORM query interception allows you to intercept the high-level ORM API calls. The
```ts
db.$use({
id: 'cost-logger',
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;
},
},
onQuery: async ({ model, operation, args, proceed }) => {
const start = Date.now();
const result = await proceed(args);
console.log(`[cost] ${model} ${operation} took ${Date.now() - start}ms`);
return result;
},
});
```
Expand Down Expand Up @@ -333,11 +329,14 @@ Another popular interception use case is, instead of intercepting calls, "listen
```ts
db.$use({
id: 'mutation-hook-plugin',
beforeEntityMutation({ model, action }) {
console.log(`Before ${model} ${action}`);
},
afterEntityMutation({ model, action }) {
console.log(`After ${model} ${action}`);
onEntityMutation: {
beforeEntityMutation({ model, action }) {
console.log(`Before ${model} ${action}`);
},

afterEntityMutation({ model, action }) {
console.log(`After ${model} ${action}`);
},
},
});
```
Expand All @@ -347,20 +346,24 @@ You can provide an extra `mutationInterceptionFilter` to control what to interce
```ts
db.$use({
id: 'mutation-hook-plugin',
mutationInterceptionFilter: ({ model }) => {
return {
intercept: model === 'User',
// load entities affected before the mutation (defaults to false)
loadBeforeMutationEntities: true,
// load entities affected after the mutation (defaults to false)
loadAfterMutationEntities: true,
};
},
beforeEntityMutation({ model, action, entities }) {
console.log(`Before ${model} ${action}: ${entities}`);
},
afterEntityMutation({ model, action, afterMutationEntities }) {
console.log(`After ${model} ${action}: ${afterMutationEntities}`);
onEntityMutation: {
mutationInterceptionFilter: ({ model }) => {
return {
intercept: model === 'User',
// load entities affected before the mutation (defaults to false)
loadBeforeMutationEntities: true,
// load entities affected after the mutation (defaults to false)
loadAfterMutationEntities: true,
};
},

beforeEntityMutation({ model, action, entities }) {
console.log(`Before ${model} ${action}: ${entities}`);
},

afterEntityMutation({ model, action, afterMutationEntities }) {
console.log(`After ${model} ${action}: ${afterMutationEntities}`);
},
},
});
```
Expand Down
1 change: 1 addition & 0 deletions TODO.md
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
- [ ] Short-circuit pre-create check for scalar-field only policies
- [ ] Inject "replace into"
- [ ] Inject "on conflict do update"
- [ ] Inject "insert into select from"
- [x] Migration
- [ ] Databases
- [x] SQLite
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.23",
"version": "3.0.0-alpha.24",
"description": "ZenStack",
"packageManager": "[email protected]",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion 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.23",
"version": "3.0.0-alpha.24",
"type": "module",
"author": {
"name": "ZenStack Team"
Expand Down
2 changes: 1 addition & 1 deletion packages/common-helpers/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/common-helpers",
"version": "3.0.0-alpha.23",
"version": "3.0.0-alpha.24",
"description": "ZenStack Common Helpers",
"type": "module",
"scripts": {
Expand Down
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.23",
"version": "3.0.0-alpha.24",
"description": "Create a new ZenStack project",
"type": "module",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/dialects/sql.js/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/kysely-sql-js",
"version": "3.0.0-alpha.23",
"version": "3.0.0-alpha.24",
"description": "Kysely dialect for sql.js",
"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.23",
"version": "3.0.0-alpha.24",
"type": "module",
"private": true,
"license": "MIT"
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/vscode/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "zenstack",
"publisher": "zenstack",
"version": "3.0.0-alpha.23",
"version": "3.0.0-alpha.24",
"displayName": "ZenStack Language Tools",
"description": "VSCode extension for ZenStack ZModel language",
"private": true,
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.23",
"version": "3.0.0-alpha.24",
"license": "MIT",
"author": "ZenStack Team",
"files": [
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/runtime",
"version": "3.0.0-alpha.23",
"version": "3.0.0-alpha.24",
"description": "ZenStack Runtime",
"type": "module",
"scripts": {
Expand Down
43 changes: 16 additions & 27 deletions packages/runtime/src/client/client-impl.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { invariant, lowerCaseFirst } from '@zenstackhq/common-helpers';
import { invariant } from '@zenstackhq/common-helpers';
import type { QueryExecutor } from 'kysely';
import {
CompiledQuery,
Expand Down Expand Up @@ -358,9 +358,9 @@ function createModelCrudHandler<Schema extends SchemaDef, Model extends GetModel
throwIfNoResult = false,
) => {
return createZenStackPromise(async (txClient?: ClientContract<Schema>) => {
let proceed = async (_args?: unknown) => {
let proceed = async (_args: unknown) => {
const _handler = txClient ? handler.withClient(txClient) : handler;
const r = await _handler.handle(operation, _args ?? args);
const r = await _handler.handle(operation, _args);
if (!r && throwIfNoResult) {
throw new NotFoundError(model);
}
Expand All @@ -376,30 +376,19 @@ function createModelCrudHandler<Schema extends SchemaDef, Model extends GetModel
// apply plugins
const plugins = [...(client.$options.plugins ?? [])];
for (const plugin of plugins) {
if (plugin.onQuery && typeof plugin.onQuery === 'object') {
// for each model key or "$allModels"
for (const [_model, modelHooks] of Object.entries<any>(plugin.onQuery)) {
if (_model === lowerCaseFirst(model) || _model === '$allModels') {
if (modelHooks && typeof modelHooks === 'object') {
// for each operation key or "$allOperations"
for (const [op, opHooks] of Object.entries(modelHooks)) {
if (op === operation || op === '$allOperations') {
if (typeof opHooks === 'function') {
const _proceed = proceed;
proceed = () =>
opHooks({
client,
model,
operation,
args,
query: _proceed,
}) as Promise<unknown>;
}
}
}
}
}
}
const onQuery = plugin.onQuery;
if (onQuery) {
const _proceed = proceed;
proceed = (_args: unknown) =>
onQuery({
client,
model,
operation,
// reflect the latest override if provided
args: _args,
// ensure inner overrides are propagated to the previous proceed
proceed: (nextArgs: unknown) => _proceed(nextArgs),
}) as Promise<unknown>;
}
}

Expand Down
Loading