Skip to content

merge dev to main (v2.2.4) #1527

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jun 20, 2024
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
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.2.3",
"version": "2.2.4",
"description": "",
"scripts": {
"build": "pnpm -r 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.2.3"
version = "2.2.4"

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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"description": "Runtime of ZenStack for both client-side and server-side environments.",
"repository": {
"type": "git",
Expand Down
71 changes: 49 additions & 22 deletions packages/runtime/src/enhancements/delegate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -194,15 +194,13 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {

if (this.injectBaseFieldSelect(model, field, value, args, kind)) {
delete args[kind][field];
} else {
if (fieldInfo && this.isDelegateOrDescendantOfDelegate(fieldInfo.type)) {
let nextValue = value;
if (nextValue === true) {
// make sure the payload is an object
args[kind][field] = nextValue = {};
}
this.injectSelectIncludeHierarchy(fieldInfo.type, nextValue);
} else if (fieldInfo.isDataModel) {
let nextValue = value;
if (nextValue === true) {
// make sure the payload is an object
args[kind][field] = nextValue = {};
}
this.injectSelectIncludeHierarchy(fieldInfo.type, nextValue);
}
}
}
Expand Down Expand Up @@ -392,8 +390,11 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
);
}

// note that we can't call `createMany` directly because it doesn't support
// nested created, which is needed for creating base entities
// `createMany` doesn't support nested create, which is needed for creating entities
// inheriting a delegate base, so we need to convert it to a regular `create` here.
// Note that the main difference is `create` doesn't support `skipDuplicates` as
// `createMany` does.

return this.queryUtils.transaction(this.prisma, async (tx) => {
const r = await Promise.all(
enumerate(args.data).map(async (item) => {
Expand Down Expand Up @@ -425,17 +426,33 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
this.doProcessCreatePayload(model, args);
},

createMany: (model, args, _context) => {
if (args.skipDuplicates) {
throw prismaClientValidationError(
this.prisma,
this.options.prismaModule,
'`createMany` with `skipDuplicates` set to true is not supported for delegated models'
);
}
createMany: (model, args, context) => {
// `createMany` doesn't support nested create, which is needed for creating entities
// inheriting a delegate base, so we need to convert it to a regular `create` here.
// Note that the main difference is `create` doesn't support `skipDuplicates` as
// `createMany` does.

for (const item of enumerate(args?.data)) {
this.doProcessCreatePayload(model, item);
if (this.isDelegateOrDescendantOfDelegate(model)) {
if (args.skipDuplicates) {
throw prismaClientValidationError(
this.prisma,
this.options.prismaModule,
'`createMany` with `skipDuplicates` set to true is not supported for delegated models'
);
}

// convert to regular `create`
let createPayload = context.parent.create ?? [];
if (!Array.isArray(createPayload)) {
createPayload = [createPayload];
}

for (const item of enumerate(args.data)) {
this.doProcessCreatePayload(model, item);
createPayload.push(item);
}
context.parent.create = createPayload;
delete context.parent['createMany'];
}
},
});
Expand All @@ -460,8 +477,8 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
}

// ensure the full nested "create" structure is created for base types
private ensureBaseCreateHierarchy(model: string, result: any) {
let curr = result;
private ensureBaseCreateHierarchy(model: string, args: any) {
let curr = args;
let base = this.getBaseModel(model);
let sub = this.getModelInfo(model);

Expand All @@ -478,6 +495,16 @@ export class DelegateProxyHandler extends DefaultPrismaProxyHandler {
curr[baseRelationName].create[base.discriminator] = sub.name;
}
}

// Look for base id field assignments in the current level, and push
// them down to the base level
for (const idField of getIdFields(this.options.modelMeta, base.name)) {
if (curr[idField.name] !== undefined) {
curr[baseRelationName].create[idField.name] = curr[idField.name];
delete curr[idField.name];
}
}

curr = curr[baseRelationName].create;
sub = base;
base = this.getBaseModel(base.name);
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": "Build scalable web apps with minimum code by defining authorization and validation rules inside the data schema that closer to the database",
"version": "2.2.3",
"version": "2.2.4",
"author": {
"name": "ZenStack Team"
},
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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"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.2.3",
"version": "2.2.4",
"description": "ZenStack Test Tools",
"main": "index.js",
"private": true,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,22 @@ describe('Polymorphism Test', () => {
).resolves.toMatchObject({ count: 2 });
});

it('create concrete with explicit id', async () => {
const { enhance } = await loadSchema(schema, { enhancements: ['delegate'] });
const db = enhance();

await expect(
db.ratedVideo.create({ data: { id: 1, duration: 100, url: 'xyz', rating: 5 } })
).resolves.toMatchObject({
id: 1,
duration: 100,
url: 'xyz',
rating: 5,
assetType: 'Video',
videoType: 'RatedVideo',
});
});

it('read with concrete', async () => {
const { db, user, video } = await setup();

Expand Down
31 changes: 31 additions & 0 deletions tests/regression/tests/issue-1518.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { loadSchema } from '@zenstackhq/testtools';
describe('issue 1518', () => {
it('regression', async () => {
const { enhance } = await loadSchema(
`
model Activity {
id String @id @default(uuid())
title String
type String
@@delegate(type)
@@allow('all', true)
}

model TaskActivity extends Activity {
description String
@@map("task_activity")
@@allow('all', true)
}
`
);

const db = enhance();
await db.taskActivity.create({
data: {
id: '00000000-0000-0000-0000-111111111111',
title: 'Test Activity',
description: 'Description of task',
},
});
});
});
70 changes: 70 additions & 0 deletions tests/regression/tests/issue-1520.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { loadSchema } from '@zenstackhq/testtools';

describe('issue 1520', () => {
it('regression', async () => {
const { enhance } = await loadSchema(
`
model Course {
id Int @id @default(autoincrement())
title String
addedToNotifications AddedToCourseNotification[]
}

model Group {
id Int @id @default(autoincrement())
addedToNotifications AddedToGroupNotification[]
}

model Notification {
id Int @id @default(autoincrement())
createdAt DateTime @default(now())
type String
senderId Int
receiverId Int
@@delegate (type)
}

model AddedToGroupNotification extends Notification {
groupId Int
group Group @relation(fields: [groupId], references: [id], onDelete: Cascade)
}

model AddedToCourseNotification extends Notification {
courseId Int
course Course @relation(fields: [courseId], references: [id], onDelete: Cascade)
}
`,
{ enhancements: ['delegate'] }
);

const db = enhance();
const r = await db.course.create({
data: {
title: 'English classes',
addedToNotifications: {
createMany: {
data: [
{
id: 1,
receiverId: 1,
senderId: 2,
},
],
},
},
},
include: { addedToNotifications: true },
});

expect(r.addedToNotifications).toEqual(
expect.arrayContaining([
expect.objectContaining({
id: 1,
courseId: 1,
receiverId: 1,
senderId: 2,
}),
])
);
});
});
Loading
Loading