Skip to content

chore: Improve performance for prisma-client generation #2177

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
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
efe65ec
merge dev to main (v2.9.2) (#1882)
ymc9 Nov 22, 2024
f5e4e7c
merge dev to main (v2.9.3) (#1886)
ymc9 Nov 26, 2024
251c699
merge dev to main (v2.9.4) (#1892)
ymc9 Nov 27, 2024
7cc5f00
merge dev to main (v2.10.0) (#1907)
ymc9 Dec 5, 2024
f7f85ea
merge dev to main (v2.10.1) (#1913)
ymc9 Dec 13, 2024
689d013
merge dev to main (v2.10.2) (#1919)
ymc9 Dec 18, 2024
70a81c6
merge dev to main (v2.11.0) (#1943)
ymc9 Jan 7, 2025
4b7d813
merge dev to main (v2.11.1) (#1952)
ymc9 Jan 8, 2025
ba80eda
merge dev to main (v2.11.2) (#1957)
ymc9 Jan 13, 2025
b220213
merge dev to main (v2.11.3) (#1963)
ymc9 Jan 14, 2025
ff393da
merge dev to main (v2.11.4) (#1966)
ymc9 Jan 17, 2025
a1dfdcd
merge dev to main (v2.11.5) (#1973)
ymc9 Jan 29, 2025
584d8af
merge dev to main (v2.11.6) (#1981)
ymc9 Feb 7, 2025
0107e1c
merge dev to main (v2.12.0) (#2013)
ymc9 Feb 25, 2025
8934679
merge dev to main (v2.12.1) (#2026)
ymc9 Mar 4, 2025
d4fb5ab
merge dev to main (v2.12.2) (#2032)
ymc9 Mar 7, 2025
a4acf35
merge dev to main (v2.12.3) (#2043)
ymc9 Mar 13, 2025
8a62f63
merge dev to main (v2.13.0) (#2057)
ymc9 Mar 24, 2025
79197c6
merge dev to main (v2.13.1) (#2068)
ymc9 Apr 4, 2025
c017a40
merge dev to main (v2.13.2) (#2072)
ymc9 Apr 7, 2025
2f69aa8
merge dev to main (v2.13.3) (#2076)
ymc9 Apr 9, 2025
bf9be5c
merge dev to main (v2.14.0) (#2086)
ymc9 Apr 15, 2025
88f8c77
merge dev to main (v2.14.0) (#2091)
ymc9 Apr 15, 2025
3895746
merge dev to main (v2.14.1) (#2110)
ymc9 May 5, 2025
b79a749
merge dev to main (v2.14.2) (#2113)
ymc9 May 8, 2025
53bf340
merge dev to main (v2.15.0) (#2126)
ymc9 May 20, 2025
e835599
merge dev to main (v2.15.0) (#2130)
ymc9 May 21, 2025
d8bc32d
merge dev to main (v2.15.0) (#2132)
ymc9 May 21, 2025
19f4870
merge dev to main (v2.15.1) (#2138)
ymc9 Jun 3, 2025
9596d33
merge dev to main (v2.16.0) (#2156)
ymc9 Jun 21, 2025
b73b3de
merge dev to main (v2.16.1) (#2174)
ymc9 Jul 7, 2025
999fdde
chore: Improve performance for prisma-client generation
mhodgson Jul 8, 2025
3bfa67c
Additional fixes for generated types in Prisma namespace
mhodgson Jul 8, 2025
c882c18
several fixes
ymc9 Jul 14, 2025
6def505
pin test projects to zod3
ymc9 Jul 14, 2025
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
59 changes: 48 additions & 11 deletions packages/schema/src/plugins/enhancer/enhance/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import {
type Model,
} from '@zenstackhq/sdk/ast';
import { getDMMF, getPrismaClientImportSpec, getPrismaVersion, type DMMF } from '@zenstackhq/sdk/prisma';
import { upperCaseFirst } from '@zenstackhq/runtime/local-helpers';
import { invariant, upperCaseFirst } from '@zenstackhq/runtime/local-helpers';
import fs from 'fs';
import path from 'path';
import semver from 'semver';
Expand All @@ -40,6 +40,7 @@ import {
SyntaxKind,
TypeAliasDeclaration,
VariableStatement,
type StatementStructures,
} from 'ts-morph';
import { name } from '..';
import { getConcreteModels, getDiscriminatorField } from '../../../utils/ast-utils';
Expand Down Expand Up @@ -503,16 +504,13 @@ export type Enhanced<Client> =
for (const d of this.model.declarations.filter(isDataModel)) {
const fileName = `${prismaClientDir}/models/${d.name}.ts`;
const sf = project.addSourceFileAtPath(fileName);
const sfNew = project.createSourceFile(`${prismaClientDir}/models/${d.name}-fixed.ts`, undefined, {
overwrite: true,
});

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

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

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

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

syntaxList.getChildren().forEach((node) => {
if (Node.isInterfaceDeclaration(node)) {
sfNew.addInterface(this.transformInterface(node, delegateInfo));
statements.push(this.transformInterface(node, delegateInfo));
} else if (Node.isTypeAliasDeclaration(node)) {
sfNew.addTypeAlias(this.transformTypeAlias(node, delegateInfo));
statements.push(this.transformTypeAlias(node, delegateInfo));
} else {
sfNew.addStatements(node.getText());
statements.push(node.getText());
}
});

await sfNew.move(sf.getFilePath(), { overwrite: true });
const structure = sf.getStructure();
structure.statements = statements;

const sfNew = project.createSourceFile(`${prismaClientDir}/models/${d.name}-fixed.ts`, structure, {
overwrite: true,
});
await sfNew.save();
}

for (const d of this.model.declarations.filter(isDataModel)) {
const fixedFileName = `${prismaClientDir}/models/${d.name}-fixed.ts`;
const fileName = `${prismaClientDir}/models/${d.name}.ts`;

fs.renameSync(fixedFileName, fileName);
}
}

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

private transformVariableStatementProps(variable: VariableStatement) {
const structure = variable.getStructure();

// remove `delegate_aux_*` fields from the variable's initializer
const auxFields = this.findAuxProps(variable);
if (auxFields.length > 0) {
structure.declarations.forEach((variable) => {
if (variable.initializer) {
let source = variable.initializer;
auxFields.forEach((f) => {
invariant(typeof source === 'string');
source = this.removeFromSource(source, f.getText());
});
variable.initializer = source;
}
});
}

return structure;
}

private transformInterface(iface: InterfaceDeclaration, delegateInfo: DelegateInfo) {
const structure = iface.getStructure();

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

private findAuxProps(node: Node) {
return node
.getDescendantsOfKind(SyntaxKind.PropertyAssignment)
.filter((n) => n.getName().includes(DELEGATE_AUX_RELATION_PREFIX));
}

private saveSourceFile(sf: SourceFile) {
if (this.options.preserveTsFiles) {
saveSourceFile(sf);
Expand All @@ -974,7 +1011,7 @@ export type Enhanced<Client> =
}

private trimEmptyLines(source: string): string {
return source.replace(/^\s*[\r\n]/gm, '');
return source.replace(/^\s*,?[\r\n]/gm, '');
}

private get isNewPrismaClientGenerator() {
Expand Down
2 changes: 1 addition & 1 deletion tests/integration/tests/cli/generate.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ model Post {
// set up project
fs.writeFileSync('package.json', JSON.stringify({ name: 'my app', version: '1.0.0' }));
createNpmrc();
installPackage('prisma @prisma/client zod');
installPackage('prisma @prisma/client zod@3');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Test dependency version pinning looks good, but verify necessity.

The explicit pinning to zod@3 ensures test stability and compatibility with the enhanced schema processing logic mentioned in the PR. However, please verify if this version constraint is actually required or if it's possible to support newer zod versions.

Consider running the following to check if the latest zod version would work:


🏁 Script executed:

#!/bin/bash
# Check latest zod version and any breaking changes
curl -s https://api.github.com/repos/colinhacks/zod/releases/latest | jq '.tag_name'

# Check if there are any major version differences that would justify pinning
npm view zod versions --json | jq '.[-10:]'

Length of output: 436


Update test to use the latest Zod major version

Latest stable Zod release is v4.0.5, so pinning to v3 may be unnecessarily restrictive and could prevent us from catching breaking changes or benefiting from fixes in v4. Unless there’s a specific incompatibility with Zod 4, please update the test setup.

• Location: tests/integration/tests/cli/generate.test.ts:48
• Change:

- installPackage('prisma @prisma/client zod@3');
+ installPackage('prisma @prisma/client zod@4');
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
installPackage('prisma @prisma/client zod@3');
installPackage('prisma @prisma/client zod@4');
🤖 Prompt for AI Agents
In tests/integration/tests/cli/generate.test.ts at line 48, the test installs
Zod version 3 which is outdated. Update the installPackage call to use the
latest stable Zod major version 4 instead of pinning to v3, unless there is a
known incompatibility. This will ensure the test uses the current Zod release
and can catch any breaking changes or benefit from fixes.

installPackage(path.join(__dirname, '../../../../packages/runtime/dist'));

// set up schema
Expand Down
Loading