diff --git a/package.json b/package.json index ce90997d..f3076315 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "zenstack-v3", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack", "packageManager": "pnpm@10.23.0", "type": "module", diff --git a/packages/auth-adapters/better-auth/package.json b/packages/auth-adapters/better-auth/package.json index ed7c0294..bb7aafef 100644 --- a/packages/auth-adapters/better-auth/package.json +++ b/packages/auth-adapters/better-auth/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/better-auth", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack Better Auth Adapter. This adapter is modified from better-auth's Prisma adapter.", "type": "module", "scripts": { diff --git a/packages/cli/package.json b/packages/cli/package.json index b00c0798..c2356c70 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -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-beta.31", + "version": "3.0.0-beta.32", "type": "module", "author": { "name": "ZenStack Team" diff --git a/packages/cli/src/actions/generate.ts b/packages/cli/src/actions/generate.ts index bd11c622..2c29da5b 100644 --- a/packages/cli/src/actions/generate.ts +++ b/packages/cli/src/actions/generate.ts @@ -36,7 +36,7 @@ export async function run(options: Options) { \`\`\`ts import { ZenStackClient } from '@zenstackhq/orm'; -import { schema } from '${outputPath}/schema'; +import { schema } from '${path.relative('.', outputPath)}/schema'; const client = new ZenStackClient(schema, { dialect: { ... } diff --git a/packages/cli/src/actions/templates.ts b/packages/cli/src/actions/templates.ts index 155e51db..4cd74660 100644 --- a/packages/cli/src/actions/templates.ts +++ b/packages/cli/src/actions/templates.ts @@ -21,7 +21,7 @@ model Post { title String @length(1, 256) content String published Boolean @default(false) - author User @relation(fields: [authorId], references: [id]) + author User @relation(fields: [authorId], references: [id], onDelete: Cascade) authorId String } `; diff --git a/packages/clients/tanstack-query/package.json b/packages/clients/tanstack-query/package.json index 4ed8c06f..401589cf 100644 --- a/packages/clients/tanstack-query/package.json +++ b/packages/clients/tanstack-query/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/tanstack-query", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "TanStack Query Client for consuming ZenStack v3's CRUD service", "main": "index.js", "type": "module", diff --git a/packages/common-helpers/package.json b/packages/common-helpers/package.json index e7616d51..2b3aa8a3 100644 --- a/packages/common-helpers/package.json +++ b/packages/common-helpers/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/common-helpers", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack Common Helpers", "type": "module", "scripts": { diff --git a/packages/config/eslint-config/package.json b/packages/config/eslint-config/package.json index b2eaf81d..43e47152 100644 --- a/packages/config/eslint-config/package.json +++ b/packages/config/eslint-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/eslint-config", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "type": "module", "private": true, "license": "MIT" diff --git a/packages/config/typescript-config/package.json b/packages/config/typescript-config/package.json index 7898557b..a08b125f 100644 --- a/packages/config/typescript-config/package.json +++ b/packages/config/typescript-config/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/typescript-config", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "private": true, "license": "MIT" } diff --git a/packages/config/vitest-config/package.json b/packages/config/vitest-config/package.json index 78d8b455..c3f7ebb3 100644 --- a/packages/config/vitest-config/package.json +++ b/packages/config/vitest-config/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/vitest-config", "type": "module", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "private": true, "license": "MIT", "exports": { diff --git a/packages/create-zenstack/package.json b/packages/create-zenstack/package.json index a30ffadf..1bc4ac61 100644 --- a/packages/create-zenstack/package.json +++ b/packages/create-zenstack/package.json @@ -1,6 +1,6 @@ { "name": "create-zenstack", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "Create a new ZenStack project", "type": "module", "scripts": { diff --git a/packages/ide/vscode/package.json b/packages/ide/vscode/package.json index bfaf079c..dee8389b 100644 --- a/packages/ide/vscode/package.json +++ b/packages/ide/vscode/package.json @@ -1,7 +1,7 @@ { "name": "zenstack-v3", "publisher": "zenstack", - "version": "3.0.14", + "version": "3.0.15", "displayName": "ZenStack V3 Language Tools", "description": "VSCode extension for ZenStack (v3) ZModel language", "private": true, diff --git a/packages/language/package.json b/packages/language/package.json index a0a11793..3b62243c 100644 --- a/packages/language/package.json +++ b/packages/language/package.json @@ -1,7 +1,7 @@ { "name": "@zenstackhq/language", "description": "ZenStack ZModel language specification", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "license": "MIT", "author": "ZenStack Team", "files": [ diff --git a/packages/orm/package.json b/packages/orm/package.json index 948f6f59..083018c1 100644 --- a/packages/orm/package.json +++ b/packages/orm/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/orm", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack ORM", "type": "module", "scripts": { diff --git a/packages/orm/src/client/crud-types.ts b/packages/orm/src/client/crud-types.ts index 9704d173..1fefdc7d 100644 --- a/packages/orm/src/client/crud-types.ts +++ b/packages/orm/src/client/crud-types.ts @@ -139,50 +139,34 @@ type ModelSelectResult< Options extends QueryOptions, > = { [Key in keyof Select as Select[Key] extends false | undefined - ? never - : Key extends keyof Omit - ? Omit[Key] extends true - ? never - : Key - : Key extends '_count' - ? Select[Key] extends SelectCount - ? Key - : never + ? // not selected + never + : Key extends '_count' + ? // select "_count" + Select[Key] extends SelectCount + ? Key + : never + : Key extends keyof Omit + ? Omit[Key] extends true + ? // omit + never + : Key : Key]: Key extends '_count' - ? SelectCountResult + ? // select "_count" result + SelectCountResult : Key extends NonRelationFields - ? MapModelFieldType + ? // scalar field result + MapModelFieldType : Key extends RelationFields - ? Select[Key] extends FindArgs< + ? // relation field result (recurse) + ModelResult< Schema, RelationFieldType, + Select[Key], + Options, + ModelFieldIsOptional, FieldIsArray > - ? 'select' extends keyof Select[Key] - ? ModelResult< - Schema, - RelationFieldType, - Pick, - Options, - ModelFieldIsOptional, - FieldIsArray - > - : ModelResult< - Schema, - RelationFieldType, - Pick, - Options, - ModelFieldIsOptional, - FieldIsArray - > - : DefaultModelResult< - Schema, - RelationFieldType, - Omit, - Options, - ModelFieldIsOptional, - FieldIsArray - > : never; }; @@ -204,40 +188,29 @@ export type ModelResult< Array = false, > = WrapType< Args extends { - select: infer S; - omit?: infer O; - } + select: infer S extends object; + omit?: infer O extends object; + } & Record ? ModelSelectResult : Args extends { - include: infer I; - omit?: infer O; - } - ? DefaultModelResult & { + include: infer I extends object; + omit?: infer O extends object; + } & Record + ? // select all non-omitted scalar fields + DefaultModelResult & { + // recurse for "include" relations [Key in keyof I & RelationFields as I[Key] extends false | undefined ? never - : Key]: I[Key] extends FindArgs< + : Key]: ModelResult< Schema, RelationFieldType, + I[Key], + Options, + ModelFieldIsOptional, FieldIsArray - > - ? ModelResult< - Schema, - RelationFieldType, - I[Key], - Options, - ModelFieldIsOptional, - FieldIsArray - > - : DefaultModelResult< - Schema, - RelationFieldType, - undefined, - Options, - ModelFieldIsOptional, - FieldIsArray - >; + >; } - : Args extends { omit: infer O } + : Args extends { omit: infer O } & Record ? DefaultModelResult : DefaultModelResult, Optional, diff --git a/packages/orm/src/client/query-utils.ts b/packages/orm/src/client/query-utils.ts index adeabd5d..51096722 100644 --- a/packages/orm/src/client/query-utils.ts +++ b/packages/orm/src/client/query-utils.ts @@ -232,18 +232,22 @@ export function getManyToManyRelation(schema: SchemaDef, model: string, field: s if (!fieldDef.array || !fieldDef.relation?.opposite) { return undefined; } + + // in case the m2m relation field is inherited from a delegate base, get the base model + const realModel = fieldDef.originModel ?? model; + const oppositeFieldDef = requireField(schema, fieldDef.type, fieldDef.relation.opposite); if (oppositeFieldDef.array) { // Prisma's convention for many-to-many relation: // - model are sorted alphabetically by name // - join table is named _To, unless an explicit name is provided by `@relation` // - foreign keys are named A and B (based on the order of the model) - const sortedModelNames = [model, fieldDef.type].sort(); + const sortedModelNames = [realModel, fieldDef.type].sort(); let orderedFK: [string, string]; - if (model !== fieldDef.type) { + if (realModel !== fieldDef.type) { // not a self-relation, model name's sort order determines fk order - orderedFK = sortedModelNames[0] === model ? ['A', 'B'] : ['B', 'A']; + orderedFK = sortedModelNames[0] === realModel ? ['A', 'B'] : ['B', 'A']; } else { // for self-relations, since model names are identical, relation field name's // sort order determines fk order @@ -251,7 +255,7 @@ export function getManyToManyRelation(schema: SchemaDef, model: string, field: s orderedFK = sortedFieldNames[0] === field ? ['A', 'B'] : ['B', 'A']; } - const modelIdFields = requireIdFields(schema, model); + const modelIdFields = requireIdFields(schema, realModel); invariant(modelIdFields.length === 1, 'Only single-field ID is supported for many-to-many relation'); const otherIdFields = requireIdFields(schema, fieldDef.type); invariant(otherIdFields.length === 1, 'Only single-field ID is supported for many-to-many relation'); diff --git a/packages/plugins/policy/package.json b/packages/plugins/policy/package.json index 8a2b76e1..a5c8c394 100644 --- a/packages/plugins/policy/package.json +++ b/packages/plugins/policy/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/plugin-policy", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack Policy Plugin", "type": "module", "scripts": { diff --git a/packages/schema/package.json b/packages/schema/package.json index 55cd411b..2ab34409 100644 --- a/packages/schema/package.json +++ b/packages/schema/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/schema", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack Runtime Schema", "type": "module", "scripts": { diff --git a/packages/sdk/package.json b/packages/sdk/package.json index a5ef69c4..7aaada5b 100644 --- a/packages/sdk/package.json +++ b/packages/sdk/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/sdk", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack SDK", "type": "module", "scripts": { diff --git a/packages/server/package.json b/packages/server/package.json index ec3ce79a..068119de 100644 --- a/packages/server/package.json +++ b/packages/server/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/server", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack automatic CRUD API handlers and server adapters", "type": "module", "scripts": { diff --git a/packages/testtools/package.json b/packages/testtools/package.json index 46cb5c85..45d443f3 100644 --- a/packages/testtools/package.json +++ b/packages/testtools/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/testtools", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "ZenStack Test Tools", "type": "module", "scripts": { diff --git a/packages/zod/package.json b/packages/zod/package.json index 99c108da..187046dd 100644 --- a/packages/zod/package.json +++ b/packages/zod/package.json @@ -1,6 +1,6 @@ { "name": "@zenstackhq/zod", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "", "type": "module", "main": "index.js", diff --git a/samples/next.js/package.json b/samples/next.js/package.json index de1d5dcd..71d496ec 100644 --- a/samples/next.js/package.json +++ b/samples/next.js/package.json @@ -1,6 +1,6 @@ { "name": "next.js", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "private": true, "scripts": { "generate": "zen generate --lite", diff --git a/samples/orm/package.json b/samples/orm/package.json index 01035a4b..1aae5022 100644 --- a/samples/orm/package.json +++ b/samples/orm/package.json @@ -1,6 +1,6 @@ { "name": "sample-blog", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "description": "", "main": "index.js", "private": true, diff --git a/tests/e2e/orm/schemas/typing/typecheck.ts b/tests/e2e/orm/schemas/typing/typecheck.ts index 9c6860e3..976c04c8 100644 --- a/tests/e2e/orm/schemas/typing/typecheck.ts +++ b/tests/e2e/orm/schemas/typing/typecheck.ts @@ -167,6 +167,7 @@ async function find() { select: { posts: { where: { title: 'Foo' }, + take: 1, select: { author: { select: { diff --git a/tests/e2e/package.json b/tests/e2e/package.json index 19a99f77..743bcd0c 100644 --- a/tests/e2e/package.json +++ b/tests/e2e/package.json @@ -1,6 +1,6 @@ { "name": "e2e", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "private": true, "type": "module", "scripts": { diff --git a/tests/regression/package.json b/tests/regression/package.json index d750958f..4b99fc7f 100644 --- a/tests/regression/package.json +++ b/tests/regression/package.json @@ -1,12 +1,12 @@ { "name": "regression", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "private": true, "type": "module", "scripts": { - "build": "pnpm run generate", - "generate": "tsx ../../scripts/test-generate.ts ./test", - "test": "pnpm generate && tsc && vitest run" + "build": "pnpm run test:generate", + "test:generate": "tsx ../../scripts/test-generate.ts ./test", + "test": "pnpm test:generate && tsc && vitest run" }, "dependencies": { "@zenstackhq/testtools": "workspace:*", diff --git a/tests/regression/test/issue-503/input.ts b/tests/regression/test/issue-503/input.ts new file mode 100644 index 00000000..e1e5bb0d --- /dev/null +++ b/tests/regression/test/issue-503/input.ts @@ -0,0 +1,70 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { type SchemaType as $Schema } from "./schema"; +import type { FindManyArgs as $FindManyArgs, FindUniqueArgs as $FindUniqueArgs, FindFirstArgs as $FindFirstArgs, CreateArgs as $CreateArgs, CreateManyArgs as $CreateManyArgs, CreateManyAndReturnArgs as $CreateManyAndReturnArgs, UpdateArgs as $UpdateArgs, UpdateManyArgs as $UpdateManyArgs, UpdateManyAndReturnArgs as $UpdateManyAndReturnArgs, UpsertArgs as $UpsertArgs, DeleteArgs as $DeleteArgs, DeleteManyArgs as $DeleteManyArgs, CountArgs as $CountArgs, AggregateArgs as $AggregateArgs, GroupByArgs as $GroupByArgs, WhereInput as $WhereInput, SelectInput as $SelectInput, IncludeInput as $IncludeInput, OmitInput as $OmitInput, QueryOptions as $QueryOptions } from "@zenstackhq/orm"; +import type { SimplifiedPlainResult as $Result, SelectIncludeOmit as $SelectIncludeOmit } from "@zenstackhq/orm"; +export type InternalChatFindManyArgs = $FindManyArgs<$Schema, "InternalChat">; +export type InternalChatFindUniqueArgs = $FindUniqueArgs<$Schema, "InternalChat">; +export type InternalChatFindFirstArgs = $FindFirstArgs<$Schema, "InternalChat">; +export type InternalChatCreateArgs = $CreateArgs<$Schema, "InternalChat">; +export type InternalChatCreateManyArgs = $CreateManyArgs<$Schema, "InternalChat">; +export type InternalChatCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "InternalChat">; +export type InternalChatUpdateArgs = $UpdateArgs<$Schema, "InternalChat">; +export type InternalChatUpdateManyArgs = $UpdateManyArgs<$Schema, "InternalChat">; +export type InternalChatUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "InternalChat">; +export type InternalChatUpsertArgs = $UpsertArgs<$Schema, "InternalChat">; +export type InternalChatDeleteArgs = $DeleteArgs<$Schema, "InternalChat">; +export type InternalChatDeleteManyArgs = $DeleteManyArgs<$Schema, "InternalChat">; +export type InternalChatCountArgs = $CountArgs<$Schema, "InternalChat">; +export type InternalChatAggregateArgs = $AggregateArgs<$Schema, "InternalChat">; +export type InternalChatGroupByArgs = $GroupByArgs<$Schema, "InternalChat">; +export type InternalChatWhereInput = $WhereInput<$Schema, "InternalChat">; +export type InternalChatSelect = $SelectInput<$Schema, "InternalChat">; +export type InternalChatInclude = $IncludeInput<$Schema, "InternalChat">; +export type InternalChatOmit = $OmitInput<$Schema, "InternalChat">; +export type InternalChatGetPayload, Options extends $QueryOptions<$Schema> = $QueryOptions<$Schema>> = $Result<$Schema, "InternalChat", Args, Options>; +export type MessageFindManyArgs = $FindManyArgs<$Schema, "Message">; +export type MessageFindUniqueArgs = $FindUniqueArgs<$Schema, "Message">; +export type MessageFindFirstArgs = $FindFirstArgs<$Schema, "Message">; +export type MessageCreateArgs = $CreateArgs<$Schema, "Message">; +export type MessageCreateManyArgs = $CreateManyArgs<$Schema, "Message">; +export type MessageCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Message">; +export type MessageUpdateArgs = $UpdateArgs<$Schema, "Message">; +export type MessageUpdateManyArgs = $UpdateManyArgs<$Schema, "Message">; +export type MessageUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "Message">; +export type MessageUpsertArgs = $UpsertArgs<$Schema, "Message">; +export type MessageDeleteArgs = $DeleteArgs<$Schema, "Message">; +export type MessageDeleteManyArgs = $DeleteManyArgs<$Schema, "Message">; +export type MessageCountArgs = $CountArgs<$Schema, "Message">; +export type MessageAggregateArgs = $AggregateArgs<$Schema, "Message">; +export type MessageGroupByArgs = $GroupByArgs<$Schema, "Message">; +export type MessageWhereInput = $WhereInput<$Schema, "Message">; +export type MessageSelect = $SelectInput<$Schema, "Message">; +export type MessageInclude = $IncludeInput<$Schema, "Message">; +export type MessageOmit = $OmitInput<$Schema, "Message">; +export type MessageGetPayload, Options extends $QueryOptions<$Schema> = $QueryOptions<$Schema>> = $Result<$Schema, "Message", Args, Options>; +export type MediaFindManyArgs = $FindManyArgs<$Schema, "Media">; +export type MediaFindUniqueArgs = $FindUniqueArgs<$Schema, "Media">; +export type MediaFindFirstArgs = $FindFirstArgs<$Schema, "Media">; +export type MediaCreateArgs = $CreateArgs<$Schema, "Media">; +export type MediaCreateManyArgs = $CreateManyArgs<$Schema, "Media">; +export type MediaCreateManyAndReturnArgs = $CreateManyAndReturnArgs<$Schema, "Media">; +export type MediaUpdateArgs = $UpdateArgs<$Schema, "Media">; +export type MediaUpdateManyArgs = $UpdateManyArgs<$Schema, "Media">; +export type MediaUpdateManyAndReturnArgs = $UpdateManyAndReturnArgs<$Schema, "Media">; +export type MediaUpsertArgs = $UpsertArgs<$Schema, "Media">; +export type MediaDeleteArgs = $DeleteArgs<$Schema, "Media">; +export type MediaDeleteManyArgs = $DeleteManyArgs<$Schema, "Media">; +export type MediaCountArgs = $CountArgs<$Schema, "Media">; +export type MediaAggregateArgs = $AggregateArgs<$Schema, "Media">; +export type MediaGroupByArgs = $GroupByArgs<$Schema, "Media">; +export type MediaWhereInput = $WhereInput<$Schema, "Media">; +export type MediaSelect = $SelectInput<$Schema, "Media">; +export type MediaInclude = $IncludeInput<$Schema, "Media">; +export type MediaOmit = $OmitInput<$Schema, "Media">; +export type MediaGetPayload, Options extends $QueryOptions<$Schema> = $QueryOptions<$Schema>> = $Result<$Schema, "Media", Args, Options>; diff --git a/tests/regression/test/issue-503/models.ts b/tests/regression/test/issue-503/models.ts new file mode 100644 index 00000000..e71f3a61 --- /dev/null +++ b/tests/regression/test/issue-503/models.ts @@ -0,0 +1,12 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { type SchemaType as $Schema } from "./schema"; +import { type ModelResult as $ModelResult } from "@zenstackhq/orm"; +export type InternalChat = $ModelResult<$Schema, "InternalChat">; +export type Message = $ModelResult<$Schema, "Message">; +export type Media = $ModelResult<$Schema, "Media">; diff --git a/tests/regression/test/issue-503/regression.test.ts b/tests/regression/test/issue-503/regression.test.ts new file mode 100644 index 00000000..c31864a7 --- /dev/null +++ b/tests/regression/test/issue-503/regression.test.ts @@ -0,0 +1,31 @@ +import { createTestClient } from '@zenstackhq/testtools'; +import { describe, expect, it } from 'vitest'; +import { schema } from './schema'; + +describe('Regression tests for issues #503', () => { + it('verifies the issue', async () => { + const db = await createTestClient(schema); + const r = await db.internalChat.create({ + data: { + messages: { + create: { + media: { + create: { + type: 'Image', + }, + }, + }, + }, + }, + select: { + messages: { + take: 1, + include: { + media: true, + }, + }, + }, + }); + expect(r.messages[0]?.media).toMatchObject({ type: 'Image' }); + }); +}); diff --git a/tests/regression/test/issue-503/schema.ts b/tests/regression/test/issue-503/schema.ts new file mode 100644 index 00000000..0c857314 --- /dev/null +++ b/tests/regression/test/issue-503/schema.ts @@ -0,0 +1,109 @@ +////////////////////////////////////////////////////////////////////////////////////////////// +// DO NOT MODIFY THIS FILE // +// This file is automatically generated by ZenStack CLI and should not be manually updated. // +////////////////////////////////////////////////////////////////////////////////////////////// + +/* eslint-disable */ + +import { type SchemaDef, ExpressionUtils } from "@zenstackhq/orm/schema"; +export class SchemaType implements SchemaDef { + provider = { + type: "sqlite" + } as const; + models = { + InternalChat: { + name: "InternalChat", + fields: { + id: { + name: "id", + type: "Int", + id: true, + attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("autoincrement") }] }], + default: ExpressionUtils.call("autoincrement") + }, + messages: { + name: "messages", + type: "Message", + array: true, + relation: { opposite: "chat" } + } + }, + idFields: ["id"], + uniqueFields: { + id: { type: "Int" } + } + }, + Message: { + name: "Message", + fields: { + id: { + name: "id", + type: "Int", + id: true, + attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("autoincrement") }] }], + default: ExpressionUtils.call("autoincrement") + }, + chat: { + name: "chat", + type: "InternalChat", + attributes: [{ name: "@relation", args: [{ name: "fields", value: ExpressionUtils.array([ExpressionUtils.field("chatId")]) }, { name: "references", value: ExpressionUtils.array([ExpressionUtils.field("id")]) }] }], + relation: { opposite: "messages", fields: ["chatId"], references: ["id"] } + }, + chatId: { + name: "chatId", + type: "Int", + foreignKeyFor: [ + "chat" + ] + }, + media: { + name: "media", + type: "Media", + optional: true, + attributes: [{ name: "@relation", args: [{ name: "fields", value: ExpressionUtils.array([ExpressionUtils.field("mediaId")]) }, { name: "references", value: ExpressionUtils.array([ExpressionUtils.field("id")]) }] }], + relation: { opposite: "messages", fields: ["mediaId"], references: ["id"] } + }, + mediaId: { + name: "mediaId", + type: "Int", + optional: true, + foreignKeyFor: [ + "media" + ] + } + }, + idFields: ["id"], + uniqueFields: { + id: { type: "Int" } + } + }, + Media: { + name: "Media", + fields: { + id: { + name: "id", + type: "Int", + id: true, + attributes: [{ name: "@id" }, { name: "@default", args: [{ name: "value", value: ExpressionUtils.call("autoincrement") }] }], + default: ExpressionUtils.call("autoincrement") + }, + type: { + name: "type", + type: "String" + }, + messages: { + name: "messages", + type: "Message", + array: true, + relation: { opposite: "media" } + } + }, + idFields: ["id"], + uniqueFields: { + id: { type: "Int" } + } + } + } as const; + plugins = {}; +} +export const schema = new SchemaType(); diff --git a/tests/regression/test/issue-503/schema.zmodel b/tests/regression/test/issue-503/schema.zmodel new file mode 100644 index 00000000..7cbe035d --- /dev/null +++ b/tests/regression/test/issue-503/schema.zmodel @@ -0,0 +1,23 @@ +datasource db { + provider = "sqlite" + url = "file:./dev.db" +} + +model InternalChat { + id Int @id @default(autoincrement()) + messages Message[] +} + +model Message { + id Int @id @default(autoincrement()) + chat InternalChat @relation(fields: [chatId], references: [id]) + chatId Int + media Media? @relation(fields: [mediaId], references: [id]) + mediaId Int? +} + +model Media { + id Int @id @default(autoincrement()) + type String + messages Message[] +} diff --git a/tests/regression/test/issue-505.test.ts b/tests/regression/test/issue-505.test.ts new file mode 100644 index 00000000..da848285 --- /dev/null +++ b/tests/regression/test/issue-505.test.ts @@ -0,0 +1,69 @@ +import { createTestClient } from '@zenstackhq/testtools'; +import { describe, expect, it } from 'vitest'; + +describe('Regression tests for issues 505', () => { + it('verifies the issue', async () => { + const db = await createTestClient( + ` +model Media { + id String @id @default(cuid()) + type String + @@delegate(type) + + messages Message[] +} + +model TelegramPhoto extends Media { + tgFileId String @unique + width Int + height Int +} + +model Message { + id String @id @default(cuid()) + media Media[] + type String + @@delegate(type) +} + +model TelegramMessage extends Message { + tgId BigInt @unique +} +`, + { usePrismaPush: true }, + ); + + const photo = await db.telegramPhoto.create({ + data: { + tgFileId: 'file123', + width: 800, + height: 600, + }, + }); + + const message = await db.telegramMessage.create({ + data: { + tgId: BigInt(1), + media: { + connect: { + id: photo.id, + }, + }, + }, + include: { + media: true, + }, + }); + + expect(message).toMatchObject({ + media: [photo], + }); + + const media = await db.media.findFirst({ + include: { messages: true }, + }); + expect(media).toMatchObject({ + messages: [expect.objectContaining({ tgId: BigInt(1), type: 'TelegramMessage' })], + }); + }); +}); diff --git a/tests/runtimes/bun/package.json b/tests/runtimes/bun/package.json index dc9c1ed6..ded75caf 100644 --- a/tests/runtimes/bun/package.json +++ b/tests/runtimes/bun/package.json @@ -1,6 +1,6 @@ { "name": "bun-e2e", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "private": true, "type": "module", "scripts": { diff --git a/tests/runtimes/edge-runtime/package.json b/tests/runtimes/edge-runtime/package.json index 3b46fddc..6a3004a4 100644 --- a/tests/runtimes/edge-runtime/package.json +++ b/tests/runtimes/edge-runtime/package.json @@ -1,6 +1,6 @@ { "name": "edge-runtime-e2e", - "version": "3.0.0-beta.31", + "version": "3.0.0-beta.32", "private": true, "type": "module", "scripts": {