Skip to content

Commit

Permalink
fix(delegate): several generation issues (#1417)
Browse files Browse the repository at this point in the history
  • Loading branch information
ymc9 authored May 8, 2024
1 parent 00250ea commit 153dd4f
Show file tree
Hide file tree
Showing 4 changed files with 110 additions and 41 deletions.
87 changes: 46 additions & 41 deletions packages/schema/src/plugins/enhancer/enhance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,54 +214,59 @@ export function enhance(prisma: any, context?: EnhancementContext<${authTypePara

// calculate a relative output path to output the logical prisma client into enhancer's output dir
const prismaClientOutDir = path.join(path.relative(zmodelDir, this.outDir), LOGICAL_CLIENT_GENERATION_PATH);
try {
await prismaGenerator.generate({
provider: '@internal', // doesn't matter
schemaPath: this.options.schemaPath,
output: logicalPrismaFile,
overrideClientGenerationPath: prismaClientOutDir,
mode: 'logical',
});
await prismaGenerator.generate({
provider: '@internal', // doesn't matter
schemaPath: this.options.schemaPath,
output: logicalPrismaFile,
overrideClientGenerationPath: prismaClientOutDir,
mode: 'logical',
});

// generate the prisma client
// generate the prisma client

// only run prisma client generator for the logical schema
const prismaClientGeneratorName = this.getPrismaClientGeneratorName(this.model);
let generateCmd = `prisma generate --schema "${logicalPrismaFile}" --generator=${prismaClientGeneratorName}`;
// only run prisma client generator for the logical schema
const prismaClientGeneratorName = this.getPrismaClientGeneratorName(this.model);
let generateCmd = `prisma generate --schema "${logicalPrismaFile}" --generator=${prismaClientGeneratorName}`;

const prismaVersion = getPrismaVersion();
if (!prismaVersion || semver.gte(prismaVersion, '5.2.0')) {
// add --no-engine to reduce generation size if the prisma version supports
generateCmd += ' --no-engine';
}
const prismaVersion = getPrismaVersion();
if (!prismaVersion || semver.gte(prismaVersion, '5.2.0')) {
// add --no-engine to reduce generation size if the prisma version supports
generateCmd += ' --no-engine';
}

try {
// run 'prisma generate'
await execPackage(generateCmd, { stdio: 'ignore' });
} catch {
await trackPrismaSchemaError(logicalPrismaFile);
try {
// run 'prisma generate'
await execPackage(generateCmd, { stdio: 'ignore' });
// run 'prisma generate' again with output to the console
await execPackage(generateCmd);
} catch {
await trackPrismaSchemaError(logicalPrismaFile);
try {
// run 'prisma generate' again with output to the console
await execPackage(generateCmd);
} catch {
// noop
}
throw new PluginError(name, `Failed to run "prisma generate" on logical schema: ${logicalPrismaFile}`);
// noop
}
throw new PluginError(name, `Failed to run "prisma generate" on logical schema: ${logicalPrismaFile}`);
}

// make a bunch of typing fixes to the generated prisma client
await this.processClientTypes(path.join(this.outDir, LOGICAL_CLIENT_GENERATION_PATH));

// make a bunch of typing fixes to the generated prisma client
await this.processClientTypes(path.join(this.outDir, LOGICAL_CLIENT_GENERATION_PATH));
const dmmf = await getDMMF({ datamodel: fs.readFileSync(logicalPrismaFile, { encoding: 'utf-8' }) });

return {
prismaSchema: logicalPrismaFile,
// load the dmmf of the logical prisma schema
dmmf: await getDMMF({ datamodel: fs.readFileSync(logicalPrismaFile, { encoding: 'utf-8' }) }),
};
} finally {
try {
// clean up temp schema
if (fs.existsSync(logicalPrismaFile)) {
fs.rmSync(logicalPrismaFile);
}
} catch {
// ignore errors
}

return {
prismaSchema: logicalPrismaFile,
// load the dmmf of the logical prisma schema
dmmf,
};
}

private getPrismaClientGeneratorName(model: Model) {
Expand All @@ -287,12 +292,12 @@ export function enhance(prisma: any, context?: EnhancementContext<${authTypePara
this.model.declarations
.filter((d): d is DataModel => isDelegateModel(d))
.forEach((dm) => {
delegateInfo.push([
dm,
this.model.declarations.filter(
(d): d is DataModel => isDataModel(d) && d.superTypes.some((s) => s.ref === dm)
),
]);
const concreteModels = this.model.declarations.filter(
(d): d is DataModel => isDataModel(d) && d.superTypes.some((s) => s.ref === dm)
);
if (concreteModels.length > 0) {
delegateInfo.push([dm, concreteModels]);
}
});

// transform index.d.ts and save it into a new file (better perf than in-line editing)
Expand Down
5 changes: 5 additions & 0 deletions packages/schema/src/plugins/prisma/schema-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,11 @@ export class PrismaSchemaGenerator {
// for the given model, find relation fields of delegate model type, find all concrete models
// of the delegate model and generate an auxiliary opposite relation field to each of them
decl.fields.forEach((f) => {
// don't process fields inherited from a delegate model
if (f.$inheritedFrom && isDelegateModel(f.$inheritedFrom)) {
return;
}

const fieldType = f.type.reference?.ref;
if (!isDataModel(fieldType)) {
return;
Expand Down
22 changes: 22 additions & 0 deletions tests/regression/tests/issue-1415.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import { loadSchema } from '@zenstackhq/testtools';

describe('issue 1415', () => {
it('regression', async () => {
await loadSchema(
`
model User {
id String @id @default(cuid())
prices Price[]
}
model Price {
id String @id @default(cuid())
owner User @relation(fields: [ownerId], references: [id])
ownerId String @default(auth().id)
priceType String
@@delegate(priceType)
}
`
);
});
});
37 changes: 37 additions & 0 deletions tests/regression/tests/issue-1416.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { loadSchema } from '@zenstackhq/testtools';

describe('issue 1416', () => {
it('regression', async () => {
await loadSchema(
`
model User {
id String @id @default(cuid())
role String
}
model Price {
id String @id @default(nanoid(6))
entity Entity? @relation(fields: [entityId], references: [id])
entityId String?
priceType String
@@delegate(priceType)
}
model MyPrice extends Price {
foo String
}
model Entity {
id String @id @default(nanoid(6))
price Price[]
type String
@@delegate(type)
}
model MyEntity extends Entity {
foo String
}
`
);
});
});

0 comments on commit 153dd4f

Please sign in to comment.