Skip to content

fix: $containerIndex is not updated after merging imported declarations #1221

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 2 commits into from
Apr 9, 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
4 changes: 2 additions & 2 deletions packages/plugins/trpc/tests/projects/t3-trpc-v10/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
"start": "next start"
},
"dependencies": {
"@prisma/client": "^5.6.0",
"@prisma/client": "5.12.0",
"@t3-oss/env-nextjs": "^0.7.1",
"@tanstack/react-query": "^4.36.1",
"@trpc/client": "^10.43.6",
Expand All @@ -35,7 +35,7 @@
"@typescript-eslint/parser": "^6.11.0",
"eslint": "^8.54.0",
"eslint-config-next": "^14.0.4",
"prisma": "^5.6.0",
"prisma": "5.12.0",
"typescript": "^5.1.6"
},
"ct3aMetadata": {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export default function createRouter<Config extends BaseConfig>(router: RouterFa

aggregate: procedure.input($Schema.PostInputSchema.aggregate).query(({ ctx, input }) => checkRead(db(ctx).post.aggregate(input as any))),

createMany: procedure.input($Schema.PostInputSchema.createMany).mutation(async ({ ctx, input }) => checkMutate(db(ctx).post.createMany(input as any))),

create: procedure.input($Schema.PostInputSchema.create).mutation(async ({ ctx, input }) => checkMutate(db(ctx).post.create(input as any))),

deleteMany: procedure.input($Schema.PostInputSchema.deleteMany).mutation(async ({ ctx, input }) => checkMutate(db(ctx).post.deleteMany(input as any))),
Expand Down Expand Up @@ -60,6 +62,20 @@ export interface ClientType<AppRouter extends AnyRouter, Context = AppRouter['_d
TRPCClientErrorLike<AppRouter>
>;

};
createMany: {

useMutation: <T extends Prisma.PostCreateManyArgs>(opts?: UseTRPCMutationOptions<
Prisma.PostCreateManyArgs,
TRPCClientErrorLike<AppRouter>,
Prisma.BatchPayload,
Context
>,) =>
Omit<UseTRPCMutationResult<Prisma.BatchPayload, TRPCClientErrorLike<AppRouter>, Prisma.SelectSubset<T, Prisma.PostCreateManyArgs>, Context>, 'mutateAsync'> & {
mutateAsync:
<T extends Prisma.PostCreateManyArgs>(variables: T, opts?: UseTRPCMutationOptions<T, TRPCClientErrorLike<AppRouter>, Prisma.BatchPayload, Context>) => Promise<Prisma.BatchPayload>
};

};
create: {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ export default function createRouter<Config extends BaseConfig>(router: RouterFa

aggregate: procedure.input($Schema.UserInputSchema.aggregate).query(({ ctx, input }) => checkRead(db(ctx).user.aggregate(input as any))),

createMany: procedure.input($Schema.UserInputSchema.createMany).mutation(async ({ ctx, input }) => checkMutate(db(ctx).user.createMany(input as any))),

create: procedure.input($Schema.UserInputSchema.create).mutation(async ({ ctx, input }) => checkMutate(db(ctx).user.create(input as any))),

deleteMany: procedure.input($Schema.UserInputSchema.deleteMany).mutation(async ({ ctx, input }) => checkMutate(db(ctx).user.deleteMany(input as any))),
Expand Down Expand Up @@ -60,6 +62,20 @@ export interface ClientType<AppRouter extends AnyRouter, Context = AppRouter['_d
TRPCClientErrorLike<AppRouter>
>;

};
createMany: {

useMutation: <T extends Prisma.UserCreateManyArgs>(opts?: UseTRPCMutationOptions<
Prisma.UserCreateManyArgs,
TRPCClientErrorLike<AppRouter>,
Prisma.BatchPayload,
Context
>,) =>
Omit<UseTRPCMutationResult<Prisma.BatchPayload, TRPCClientErrorLike<AppRouter>, Prisma.SelectSubset<T, Prisma.UserCreateManyArgs>, Context>, 'mutateAsync'> & {
mutateAsync:
<T extends Prisma.UserCreateManyArgs>(variables: T, opts?: UseTRPCMutationOptions<T, TRPCClientErrorLike<AppRouter>, Prisma.BatchPayload, Context>) => Promise<Prisma.BatchPayload>
};

};
create: {

Expand Down
13 changes: 4 additions & 9 deletions packages/schema/src/cli/cli-util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { getDataModels, getLiteral, hasAttribute } from '@zenstackhq/sdk';
import colors from 'colors';
import fs from 'fs';
import getLatestVersion from 'get-latest-version';
import { AstNode, getDocument, LangiumDocument, LangiumDocuments, Mutable } from 'langium';
import { getDocument, LangiumDocument, LangiumDocuments, linkContentToContainer } from 'langium';
import { NodeFileSystem } from 'langium/node';
import path from 'path';
import semver from 'semver';
Expand Down Expand Up @@ -153,19 +153,14 @@ export function mergeImportsDeclarations(documents: LangiumDocuments, model: Mod
const importedModels = resolveTransitiveImports(documents, model);

const importedDeclarations = importedModels.flatMap((m) => m.declarations);

importedDeclarations.forEach((d) => {
const mutable = d as Mutable<AstNode>;
// Plugins might use $container to access the model
// need to make sure it is always resolved to the main model
mutable.$container = model;
});

model.declarations.push(...importedDeclarations);

// remove import directives
model.imports = [];

// fix $containerIndex
linkContentToContainer(model);

return importedModels;
}

Expand Down
6 changes: 4 additions & 2 deletions packages/schema/src/utils/ast-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
getContainerOfType,
getDocument,
LangiumDocuments,
linkContentToContainer,
Linker,
Mutable,
Reference,
Expand Down Expand Up @@ -72,6 +73,9 @@ export function mergeBaseModel(model: Model, linker: Linker) {
.filter((attr) => attr.decl.$refText !== '@@map')
.map((attr) => cloneAst(attr, dataModel, buildReference))
.concat(dataModel.attributes);

// fix $containerIndex
linkContentToContainer(dataModel);
}

dataModel.$baseMerged = true;
Expand All @@ -89,8 +93,6 @@ function cloneAst<T extends InheritableNode>(
): Mutable<T> {
const clone = copyAstNode(node, buildReference) as Mutable<T>;
clone.$container = newContainer;
clone.$containerProperty = node.$containerProperty;
clone.$containerIndex = node.$containerIndex;
clone.$inheritedFrom = node.$inheritedFrom ?? getContainerOfType(node, isDataModel);
return clone;
}
Expand Down
92 changes: 92 additions & 0 deletions tests/integration/tests/regression/issue-1210.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
import { FILE_SPLITTER, loadSchema } from '@zenstackhq/testtools';

describe('issue 1210', () => {
it('regression', async () => {
await loadSchema(
`schema.zmodel
import "./user"
import "./tokens"

generator client {
provider = "prisma-client-js"
binaryTargets = ["native"]
previewFeatures = ["postgresqlExtensions"]
}

datasource db {
provider = "postgresql"
extensions = [citext]

url = env("DATABASE_URL")
}

plugin zod {
provider = '@core/zod'
}

${FILE_SPLITTER}base.zmodel
abstract model Base {
id String @id @default(uuid())
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
deletedAt DateTime? @omit

@@deny('read', deletedAt != null)
@@deny('delete', true)
}

${FILE_SPLITTER}tokens.zmodel
import "base"
import "user"

model Session extends Base {
expiresAt DateTime
userId String
user User @relation(references: [id], fields: [userId], onDelete: Cascade)
}

${FILE_SPLITTER}user.zmodel
import "base"
import "tokens"
enum UserRole {
USER
ADMIN
}

model User extends Base {
email String @unique @db.Citext @email @trim @lower
role UserRole @default(USER) @deny('read,update', auth().role != ADMIN)

sessions Session[]
posts Post[]

@@allow('read,create', auth() == this)
@@allow('all', auth().role == ADMIN)
}

abstract model UserEntity extends Base {
userId String
user User @relation(fields: [userId], references: [id])

@@allow('create', userId == auth().id)
@@allow('update', userId == auth().id && future().userId == auth().id)

@@allow('all', auth().role == ADMIN)
}

abstract model PrivateUserEntity extends UserEntity {
@@allow('read', userId == auth().id)
}

abstract model PublicUserEntity extends UserEntity {
@@allow('read', true)
}

model Post extends PublicUserEntity {
title String
}
`,
{ addPrelude: false, pushDb: false }
);
});
});