Skip to content

Commit cd0c415

Browse files
mhodgsonymc9
andauthored
chore: Improve performance for prisma-client generation (#2177)
Co-authored-by: Yiming <[email protected]> Co-authored-by: ymc9 <[email protected]>
1 parent dc4eb4e commit cd0c415

File tree

2 files changed

+49
-12
lines changed

2 files changed

+49
-12
lines changed

packages/schema/src/plugins/enhancer/enhance/index.ts

Lines changed: 48 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ import {
2626
type Model,
2727
} from '@zenstackhq/sdk/ast';
2828
import { getDMMF, getPrismaClientImportSpec, getPrismaVersion, type DMMF } from '@zenstackhq/sdk/prisma';
29-
import { upperCaseFirst } from '@zenstackhq/runtime/local-helpers';
29+
import { invariant, upperCaseFirst } from '@zenstackhq/runtime/local-helpers';
3030
import fs from 'fs';
3131
import path from 'path';
3232
import semver from 'semver';
@@ -40,6 +40,7 @@ import {
4040
SyntaxKind,
4141
TypeAliasDeclaration,
4242
VariableStatement,
43+
type StatementStructures,
4344
} from 'ts-morph';
4445
import { name } from '..';
4546
import { getConcreteModels, getDiscriminatorField } from '../../../utils/ast-utils';
@@ -503,16 +504,13 @@ export type Enhanced<Client> =
503504
for (const d of this.model.declarations.filter(isDataModel)) {
504505
const fileName = `${prismaClientDir}/models/${d.name}.ts`;
505506
const sf = project.addSourceFileAtPath(fileName);
506-
const sfNew = project.createSourceFile(`${prismaClientDir}/models/${d.name}-fixed.ts`, undefined, {
507-
overwrite: true,
508-
});
509507

510508
const syntaxList = sf.getChildren()[0];
511509
if (!Node.isSyntaxList(syntaxList)) {
512510
throw new PluginError(name, `Unexpected syntax list structure in ${fileName}`);
513511
}
514512

515-
sfNew.addStatements('import $Types = runtime.Types;');
513+
const statements: (string | StatementStructures)[] = ['import $Types = runtime.Types;'];
516514

517515
// Add import for json-types if this model has JSON type fields
518516
const modelWithJsonFields = this.modelsWithJsonTypeFields.find((m) => m.name === d.name);
@@ -525,23 +523,35 @@ export type Enhanced<Client> =
525523
const typeNames = [...new Set(jsonFieldTypes.map((field) => field.type.reference!.$refText))];
526524

527525
if (typeNames.length > 0) {
528-
sfNew.addStatements(`import type { ${typeNames.join(', ')} } from "../../json-types";`);
526+
statements.push(`import type { ${typeNames.join(', ')} } from "../../json-types";`);
529527
}
530528
}
531529

532530
syntaxList.getChildren().forEach((node) => {
533531
if (Node.isInterfaceDeclaration(node)) {
534-
sfNew.addInterface(this.transformInterface(node, delegateInfo));
532+
statements.push(this.transformInterface(node, delegateInfo));
535533
} else if (Node.isTypeAliasDeclaration(node)) {
536-
sfNew.addTypeAlias(this.transformTypeAlias(node, delegateInfo));
534+
statements.push(this.transformTypeAlias(node, delegateInfo));
537535
} else {
538-
sfNew.addStatements(node.getText());
536+
statements.push(node.getText());
539537
}
540538
});
541539

542-
await sfNew.move(sf.getFilePath(), { overwrite: true });
540+
const structure = sf.getStructure();
541+
structure.statements = statements;
542+
543+
const sfNew = project.createSourceFile(`${prismaClientDir}/models/${d.name}-fixed.ts`, structure, {
544+
overwrite: true,
545+
});
543546
await sfNew.save();
544547
}
548+
549+
for (const d of this.model.declarations.filter(isDataModel)) {
550+
const fixedFileName = `${prismaClientDir}/models/${d.name}-fixed.ts`;
551+
const fileName = `${prismaClientDir}/models/${d.name}.ts`;
552+
553+
fs.renameSync(fixedFileName, fileName);
554+
}
545555
}
546556

547557
private transformPrismaTypes(sf: SourceFile, sfNew: SourceFile, delegateInfo: DelegateInfo) {
@@ -641,6 +651,27 @@ export type Enhanced<Client> =
641651
return structure;
642652
}
643653

654+
private transformVariableStatementProps(variable: VariableStatement) {
655+
const structure = variable.getStructure();
656+
657+
// remove `delegate_aux_*` fields from the variable's initializer
658+
const auxFields = this.findAuxProps(variable);
659+
if (auxFields.length > 0) {
660+
structure.declarations.forEach((variable) => {
661+
if (variable.initializer) {
662+
let source = variable.initializer;
663+
auxFields.forEach((f) => {
664+
invariant(typeof source === 'string');
665+
source = this.removeFromSource(source, f.getText());
666+
});
667+
variable.initializer = source;
668+
}
669+
});
670+
}
671+
672+
return structure;
673+
}
674+
644675
private transformInterface(iface: InterfaceDeclaration, delegateInfo: DelegateInfo) {
645676
const structure = iface.getStructure();
646677

@@ -958,6 +989,12 @@ export type Enhanced<Client> =
958989
.filter((n) => n.getName().includes(DELEGATE_AUX_RELATION_PREFIX));
959990
}
960991

992+
private findAuxProps(node: Node) {
993+
return node
994+
.getDescendantsOfKind(SyntaxKind.PropertyAssignment)
995+
.filter((n) => n.getName().includes(DELEGATE_AUX_RELATION_PREFIX));
996+
}
997+
961998
private saveSourceFile(sf: SourceFile) {
962999
if (this.options.preserveTsFiles) {
9631000
saveSourceFile(sf);
@@ -974,7 +1011,7 @@ export type Enhanced<Client> =
9741011
}
9751012

9761013
private trimEmptyLines(source: string): string {
977-
return source.replace(/^\s*[\r\n]/gm, '');
1014+
return source.replace(/^\s*,?[\r\n]/gm, '');
9781015
}
9791016

9801017
private get isNewPrismaClientGenerator() {

tests/integration/tests/cli/generate.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ model Post {
4545
// set up project
4646
fs.writeFileSync('package.json', JSON.stringify({ name: 'my app', version: '1.0.0' }));
4747
createNpmrc();
48-
installPackage('prisma @prisma/client zod');
48+
installPackage('prisma @prisma/client zod@3');
4949
installPackage(path.join(__dirname, '../../../../packages/runtime/dist'));
5050

5151
// set up schema

0 commit comments

Comments
 (0)