Skip to content

Commit dfc175a

Browse files
committed
fix: $containerIndex is not updated after merging imported declarations
1 parent 17c5e5a commit dfc175a

File tree

3 files changed

+100
-11
lines changed

3 files changed

+100
-11
lines changed

packages/schema/src/cli/cli-util.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { getDataModels, getLiteral, hasAttribute } from '@zenstackhq/sdk';
33
import colors from 'colors';
44
import fs from 'fs';
55
import getLatestVersion from 'get-latest-version';
6-
import { AstNode, getDocument, LangiumDocument, LangiumDocuments, Mutable } from 'langium';
6+
import { getDocument, LangiumDocument, LangiumDocuments, linkContentToContainer } from 'langium';
77
import { NodeFileSystem } from 'langium/node';
88
import path from 'path';
99
import semver from 'semver';
@@ -153,19 +153,14 @@ export function mergeImportsDeclarations(documents: LangiumDocuments, model: Mod
153153
const importedModels = resolveTransitiveImports(documents, model);
154154

155155
const importedDeclarations = importedModels.flatMap((m) => m.declarations);
156-
157-
importedDeclarations.forEach((d) => {
158-
const mutable = d as Mutable<AstNode>;
159-
// Plugins might use $container to access the model
160-
// need to make sure it is always resolved to the main model
161-
mutable.$container = model;
162-
});
163-
164156
model.declarations.push(...importedDeclarations);
165157

166158
// remove import directives
167159
model.imports = [];
168160

161+
// fix $containerIndex
162+
linkContentToContainer(model);
163+
169164
return importedModels;
170165
}
171166

packages/schema/src/utils/ast-utils.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import {
2424
getContainerOfType,
2525
getDocument,
2626
LangiumDocuments,
27+
linkContentToContainer,
2728
Linker,
2829
Mutable,
2930
Reference,
@@ -72,6 +73,9 @@ export function mergeBaseModel(model: Model, linker: Linker) {
7273
.filter((attr) => attr.decl.$refText !== '@@map')
7374
.map((attr) => cloneAst(attr, dataModel, buildReference))
7475
.concat(dataModel.attributes);
76+
77+
// fix $containerIndex
78+
linkContentToContainer(dataModel);
7579
}
7680

7781
dataModel.$baseMerged = true;
@@ -89,8 +93,6 @@ function cloneAst<T extends InheritableNode>(
8993
): Mutable<T> {
9094
const clone = copyAstNode(node, buildReference) as Mutable<T>;
9195
clone.$container = newContainer;
92-
clone.$containerProperty = node.$containerProperty;
93-
clone.$containerIndex = node.$containerIndex;
9496
clone.$inheritedFrom = node.$inheritedFrom ?? getContainerOfType(node, isDataModel);
9597
return clone;
9698
}
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
import { FILE_SPLITTER, loadSchema } from '@zenstackhq/testtools';
2+
3+
describe('issue 1210', () => {
4+
it('regression', async () => {
5+
await loadSchema(
6+
`schema.zmodel
7+
import "./user"
8+
import "./tokens"
9+
10+
generator client {
11+
provider = "prisma-client-js"
12+
binaryTargets = ["native"]
13+
previewFeatures = ["postgresqlExtensions"]
14+
}
15+
16+
datasource db {
17+
provider = "postgresql"
18+
extensions = [citext]
19+
20+
url = env("DATABASE_URL")
21+
}
22+
23+
plugin zod {
24+
provider = '@core/zod'
25+
}
26+
27+
${FILE_SPLITTER}base.zmodel
28+
abstract model Base {
29+
id String @id @default(uuid())
30+
createdAt DateTime @default(now())
31+
updatedAt DateTime @updatedAt
32+
deletedAt DateTime? @omit
33+
34+
@@deny('read', deletedAt != null)
35+
@@deny('delete', true)
36+
}
37+
38+
${FILE_SPLITTER}tokens.zmodel
39+
import "base"
40+
import "user"
41+
42+
model Session extends Base {
43+
expiresAt DateTime
44+
userId String
45+
user User @relation(references: [id], fields: [userId], onDelete: Cascade)
46+
}
47+
48+
${FILE_SPLITTER}user.zmodel
49+
import "base"
50+
import "tokens"
51+
enum UserRole {
52+
USER
53+
ADMIN
54+
}
55+
56+
model User extends Base {
57+
email String @unique @db.Citext @email @trim @lower
58+
role UserRole @default(USER) @deny('read,update', auth().role != ADMIN)
59+
60+
sessions Session[]
61+
posts Post[]
62+
63+
@@allow('read,create', auth() == this)
64+
@@allow('all', auth().role == ADMIN)
65+
}
66+
67+
abstract model UserEntity extends Base {
68+
userId String
69+
user User @relation(fields: [userId], references: [id])
70+
71+
@@allow('create', userId == auth().id)
72+
@@allow('update', userId == auth().id && future().userId == auth().id)
73+
74+
@@allow('all', auth().role == ADMIN)
75+
}
76+
77+
abstract model PrivateUserEntity extends UserEntity {
78+
@@allow('read', userId == auth().id)
79+
}
80+
81+
abstract model PublicUserEntity extends UserEntity {
82+
@@allow('read', true)
83+
}
84+
85+
model Post extends PublicUserEntity {
86+
title String
87+
}
88+
`,
89+
{ addPrelude: false, pushDb: false }
90+
);
91+
});
92+
});

0 commit comments

Comments
 (0)