Skip to content

Commit

Permalink
merge dev to main (v2.11.3) (#1963)
Browse files Browse the repository at this point in the history
  • Loading branch information
ymc9 authored Jan 14, 2025
2 parents ba80eda + 506cf99 commit b220213
Show file tree
Hide file tree
Showing 23 changed files with 287 additions and 23 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "zenstack-monorepo",
"version": "2.11.2",
"version": "2.11.3",
"description": "",
"scripts": {
"build": "pnpm -r --filter=\"!./packages/ide/*\" build",
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/jetbrains/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ plugins {
}

group = "dev.zenstack"
version = "2.11.2"
version = "2.11.3"

repositories {
mavenCentral()
Expand Down
2 changes: 1 addition & 1 deletion packages/ide/jetbrains/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "jetbrains",
"version": "2.11.2",
"version": "2.11.3",
"displayName": "ZenStack JetBrains IDE Plugin",
"description": "ZenStack JetBrains IDE plugin",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/language/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/language",
"version": "2.11.2",
"version": "2.11.3",
"displayName": "ZenStack modeling language compiler",
"description": "ZenStack modeling language compiler",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/misc/redwood/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/redwood",
"displayName": "ZenStack RedwoodJS Integration",
"version": "2.11.2",
"version": "2.11.3",
"description": "CLI and runtime for integrating ZenStack with RedwoodJS projects.",
"repository": {
"type": "git",
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/openapi/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/openapi",
"displayName": "ZenStack Plugin and Runtime for OpenAPI",
"version": "2.11.2",
"version": "2.11.3",
"description": "ZenStack plugin and runtime supporting OpenAPI",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/swr/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/swr",
"displayName": "ZenStack plugin for generating SWR hooks",
"version": "2.11.2",
"version": "2.11.3",
"description": "ZenStack plugin for generating SWR hooks",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/tanstack-query/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/tanstack-query",
"displayName": "ZenStack plugin for generating tanstack-query hooks",
"version": "2.11.2",
"version": "2.11.3",
"description": "ZenStack plugin for generating tanstack-query hooks",
"main": "index.js",
"exports": {
Expand Down
2 changes: 1 addition & 1 deletion packages/plugins/trpc/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/trpc",
"displayName": "ZenStack plugin for tRPC",
"version": "2.11.2",
"version": "2.11.3",
"description": "ZenStack plugin for tRPC",
"main": "index.js",
"repository": {
Expand Down
2 changes: 1 addition & 1 deletion packages/runtime/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "@zenstackhq/runtime",
"displayName": "ZenStack Runtime Library",
"version": "2.11.2",
"version": "2.11.3",
"description": "Runtime of ZenStack for both client-side and server-side environments.",
"repository": {
"type": "git",
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/src/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,5 +77,6 @@ export const ACTIONS_WITH_WRITE_PAYLOAD = [
'createManyAndReturn',
'update',
'updateMany',
'updateManyAndReturn',
'upsert',
];
1 change: 1 addition & 0 deletions packages/runtime/src/cross/nested-write-visitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,7 @@ export class NestedWriteVisitor {
break;

case 'updateMany':
case 'updateManyAndReturn':
for (const item of this.enumerateReverse(data)) {
const newContext = pushNewContext(field, model, item.where);
let callbackResult: any;
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/src/cross/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const PrismaWriteActions = [
'connectOrCreate',
'update',
'updateMany',
'updateManyAndReturn',
'upsert',
'connect',
'disconnect',
Expand Down
81 changes: 73 additions & 8 deletions packages/runtime/src/enhancements/node/policy/handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -511,7 +511,7 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
});
}

// throw read-back error if any of create result read-back fails
// throw read-back error if any of the create result read-back fails
const error = result.find((r) => !!r.error)?.error;
if (error) {
throw error;
Expand Down Expand Up @@ -1268,6 +1268,14 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
}

updateMany(args: any) {
return this.doUpdateMany(args, 'updateMany');
}

updateManyAndReturn(args: any): Promise<unknown[]> {
return this.doUpdateMany(args, 'updateManyAndReturn');
}

private doUpdateMany(args: any, action: 'updateMany' | 'updateManyAndReturn'): Promise<any> {
if (!args) {
throw prismaClientValidationError(this.prisma, this.prismaModule, 'query argument is required');
}
Expand All @@ -1279,9 +1287,10 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
);
}

return createDeferredPromise(() => {
return createDeferredPromise(async () => {
this.policyUtils.tryReject(this.prisma, this.model, 'update');

const origArgs = args;
args = this.policyUtils.safeClone(args);
this.policyUtils.injectAuthGuardAsWhere(this.prisma, args, this.model, 'update');

Expand All @@ -1302,13 +1311,37 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
if (this.shouldLogQuery) {
this.logger.info(`[policy] \`updateMany\` ${this.model}: ${formatObject(args)}`);
}
return this.modelClient.updateMany(args);
if (action === 'updateMany') {
return this.modelClient.updateMany(args);
} else {
// make sure only id fields are returned so we can directly use the result
// for read-back check
const updatedArg = {
...args,
select: this.policyUtils.makeIdSelection(this.model),
include: undefined,
};
const updated = await this.modelClient.updateManyAndReturn(updatedArg);
// process read-back
const result = await Promise.all(
updated.map((item) =>
this.policyUtils.readBack(this.prisma, this.model, 'update', origArgs, item)
)
);
// throw read-back error if any of create result read-back fails
const error = result.find((r) => !!r.error)?.error;
if (error) {
throw error;
} else {
return result.map((r) => r.result);
}
}
}

// collect post-update checks
const postWriteChecks: PostWriteCheckRecord[] = [];

return this.queryUtils.transaction(this.prisma, async (tx) => {
const result = await this.queryUtils.transaction(this.prisma, async (tx) => {
// collect pre-update values
let select = this.policyUtils.makeIdSelection(this.model);
const preValueSelect = this.policyUtils.getPreValueSelect(this.model);
Expand Down Expand Up @@ -1352,13 +1385,45 @@ export class PolicyProxyHandler<DbClient extends DbClientContract> implements Pr
if (this.shouldLogQuery) {
this.logger.info(`[policy] \`updateMany\` in tx for ${this.model}: ${formatObject(args)}`);
}
const result = await tx[this.model].updateMany(args);

// run post-write checks
await this.runPostWriteChecks(postWriteChecks, tx);
if (action === 'updateMany') {
const result = await tx[this.model].updateMany(args);
// run post-write checks
await this.runPostWriteChecks(postWriteChecks, tx);
return result;
} else {
// make sure only id fields are returned so we can directly use the result
// for read-back check
const updatedArg = {
...args,
select: this.policyUtils.makeIdSelection(this.model),
include: undefined,
};
const result = await tx[this.model].updateManyAndReturn(updatedArg);
// run post-write checks
await this.runPostWriteChecks(postWriteChecks, tx);
return result;
}
});

if (action === 'updateMany') {
// no further processing needed
return result;
});
} else {
// process read-back
const readBackResult = await Promise.all(
(result as unknown[]).map((item) =>
this.policyUtils.readBack(this.prisma, this.model, 'update', origArgs, item)
)
);
// throw read-back error if any of the update result read-back fails
const error = readBackResult.find((r) => !!r.error)?.error;
if (error) {
throw error;
} else {
return readBackResult.map((r) => r.result);
}
}
});
}

Expand Down
6 changes: 6 additions & 0 deletions packages/runtime/src/enhancements/node/proxy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ export interface PrismaProxyHandler {

updateMany(args: any): Promise<BatchResult>;

updateManyAndReturn(args: any): Promise<unknown[]>;

upsert(args: any): Promise<unknown>;

delete(args: any): Promise<unknown>;
Expand Down Expand Up @@ -132,6 +134,10 @@ export class DefaultPrismaProxyHandler implements PrismaProxyHandler {
return this.deferred<{ count: number }>('updateMany', args, false);
}

updateManyAndReturn(args: any) {
return this.deferred<unknown[]>('updateManyAndReturn', args);
}

upsert(args: any) {
return this.deferred('upsert', args);
}
Expand Down
1 change: 1 addition & 0 deletions packages/runtime/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export interface DbOperations {
createManyAndReturn(args: unknown): Promise<unknown[]>;
update(args: unknown): Promise<any>;
updateMany(args: unknown): Promise<{ count: number }>;
updateManyAndReturn(args: unknown): Promise<unknown[]>;
upsert(args: unknown): Promise<any>;
delete(args: unknown): Promise<any>;
deleteMany(args?: unknown): Promise<{ count: number }>;
Expand Down
2 changes: 1 addition & 1 deletion packages/schema/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publisher": "zenstack",
"displayName": "ZenStack Language Tools",
"description": "FullStack enhancement for Prisma ORM: seamless integration from database to UI",
"version": "2.11.2",
"version": "2.11.3",
"author": {
"name": "ZenStack Team"
},
Expand Down
27 changes: 26 additions & 1 deletion packages/schema/src/plugins/prisma/schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import {
} from '@zenstackhq/language/ast';
import { getIdFields } from '@zenstackhq/sdk';
import { getPrismaVersion } from '@zenstackhq/sdk/prisma';
import { match } from 'ts-pattern';
import { match, P } from 'ts-pattern';

import { DELEGATE_AUX_RELATION_PREFIX, PRISMA_MINIMUM_VERSION } from '@zenstackhq/runtime';
import {
Expand Down Expand Up @@ -869,9 +869,34 @@ export class PrismaSchemaGenerator {
const docs = [...field.comments, ...this.getCustomAttributesAsComments(field)];
const result = model.addField(field.name, type, attributes, docs, addToFront);

if (this.mode === 'logical') {
if (field.attributes.some((attr) => isDefaultWithAuth(attr))) {
// field has `@default` with `auth()`, turn it into a dummy default value, and the
// real default value setting is handled outside Prisma
this.setDummyDefault(result, field);
}
}

return result;
}

private setDummyDefault(result: ModelField, field: DataModelField) {
const dummyDefaultValue = match(field.type.type)
.with('String', () => new AttributeArgValue('String', ''))
.with(P.union('Int', 'BigInt', 'Float', 'Decimal'), () => new AttributeArgValue('Number', '0'))
.with('Boolean', () => new AttributeArgValue('Boolean', 'false'))
.with('DateTime', () => new AttributeArgValue('FunctionCall', new PrismaFunctionCall('now')))
.with('Json', () => new AttributeArgValue('String', '{}'))
.with('Bytes', () => new AttributeArgValue('String', ''))
.otherwise(() => {
throw new PluginError(name, `Unsupported field type with default value: ${field.type.type}`);
});

result.attributes.push(
new PrismaFieldAttribute('@default', [new PrismaAttributeArg(undefined, dummyDefaultValue)])
);
}

private ensureSupportingTypeDefFields(zmodel: Model) {
const dsProvider = getDataSourceProvider(zmodel);
if (dsProvider && !PROVIDERS_SUPPORTING_TYPEDEF_FIELDS.includes(dsProvider)) {
Expand Down
2 changes: 1 addition & 1 deletion packages/sdk/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/sdk",
"version": "2.11.2",
"version": "2.11.3",
"description": "ZenStack plugin development SDK",
"main": "index.js",
"scripts": {
Expand Down
2 changes: 1 addition & 1 deletion packages/server/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/server",
"version": "2.11.2",
"version": "2.11.3",
"displayName": "ZenStack Server-side Adapters",
"description": "ZenStack server-side adapters",
"homepage": "https://zenstack.dev",
Expand Down
2 changes: 1 addition & 1 deletion packages/testtools/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@zenstackhq/testtools",
"version": "2.11.2",
"version": "2.11.3",
"description": "ZenStack Test Tools",
"main": "index.js",
"private": true,
Expand Down
Loading

0 comments on commit b220213

Please sign in to comment.