Skip to content

Commit 5f3669e

Browse files
authored
fix: support for custom prisma client output path (#514)
1 parent 3b07a1e commit 5f3669e

File tree

17 files changed

+270
-100
lines changed

17 files changed

+270
-100
lines changed

packages/plugins/react/src/generator/react-query.ts

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { DMMF } from '@prisma/generator-helper';
2-
import { PluginOptions, createProject, getDataModels, saveProject } from '@zenstackhq/sdk';
2+
import { PluginOptions, createProject, getDataModels, getPrismaClientImportSpec, saveProject } from '@zenstackhq/sdk';
33
import { DataModel, Model } from '@zenstackhq/sdk/ast';
44
import { requireOption, resolvePath } from '@zenstackhq/sdk/utils';
55
import { paramCase } from 'change-case';
@@ -147,14 +147,18 @@ function generateMutationHook(
147147

148148
function generateModelHooks(project: Project, outDir: string, model: DataModel, mapping: DMMF.ModelMapping) {
149149
const fileName = paramCase(model.name);
150-
const sf = project.createSourceFile(path.join(outDir, `${fileName}.ts`), undefined, { overwrite: true });
150+
151+
const hooksFile = path.resolve(outDir, `${fileName}.ts`);
152+
const sf = project.createSourceFile(hooksFile, undefined, { overwrite: true });
151153

152154
sf.addStatements('/* eslint-disable */');
153155

156+
const prismaImport = getPrismaClientImportSpec(model.$container, path.dirname(hooksFile));
157+
154158
sf.addImportDeclaration({
155159
namedImports: ['Prisma', model.name],
156160
isTypeOnly: true,
157-
moduleSpecifier: '@prisma/client',
161+
moduleSpecifier: prismaImport,
158162
});
159163
sf.addStatements([
160164
`import { useContext } from 'react';`,

packages/plugins/react/src/generator/swr.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
PluginOptions,
55
createProject,
66
getDataModels,
7+
getPrismaClientImportSpec,
78
requireOption,
89
resolvePath,
910
saveProject,
@@ -56,10 +57,11 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel,
5657

5758
sf.addStatements('/* eslint-disable */');
5859

60+
const prismaImport = getPrismaClientImportSpec(model.$container, outDir);
5961
sf.addImportDeclaration({
6062
namedImports: ['Prisma', model.name],
6163
isTypeOnly: true,
62-
moduleSpecifier: '@prisma/client',
64+
moduleSpecifier: prismaImport,
6365
});
6466
sf.addStatements([
6567
`import { useContext } from 'react';`,

packages/plugins/swr/src/generator.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
PluginOptions,
55
createProject,
66
getDataModels,
7+
getPrismaClientImportSpec,
78
requireOption,
89
resolvePath,
910
saveProject,
@@ -59,10 +60,11 @@ function generateModelHooks(project: Project, outDir: string, model: DataModel,
5960

6061
sf.addStatements('/* eslint-disable */');
6162

63+
const prismaImport = getPrismaClientImportSpec(model.$container, outDir);
6264
sf.addImportDeclaration({
6365
namedImports: ['Prisma', model.name],
6466
isTypeOnly: true,
65-
moduleSpecifier: '@prisma/client',
67+
moduleSpecifier: prismaImport,
6668
});
6769
sf.addStatements([
6870
`import { useContext } from 'react';`,

packages/plugins/tanstack-query/src/generator.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
PluginOptions,
55
createProject,
66
getDataModels,
7+
getPrismaClientImportSpec,
78
requireOption,
89
resolvePath,
910
saveProject,
@@ -218,10 +219,11 @@ function generateModelHooks(
218219

219220
sf.addStatements('/* eslint-disable */');
220221

222+
const prismaImport = getPrismaClientImportSpec(model.$container, outDir);
221223
sf.addImportDeclaration({
222224
namedImports: ['Prisma', model.name],
223225
isTypeOnly: true,
224-
moduleSpecifier: '@prisma/client',
226+
moduleSpecifier: prismaImport,
225227
});
226228
sf.addStatements(makeBaseImports(target));
227229

packages/plugins/trpc/src/generator.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import {
44
PluginError,
55
PluginOptions,
66
RUNTIME_PACKAGE,
7+
getPrismaClientImportSpec,
78
requireOption,
89
resolvePath,
910
saveProject,
@@ -53,7 +54,7 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.
5354
const hiddenModels: string[] = [];
5455
resolveModelsComments(models, hiddenModels);
5556

56-
createAppRouter(outDir, modelOperations, hiddenModels, generateModelActions, generateClientHelpers);
57+
createAppRouter(outDir, modelOperations, hiddenModels, generateModelActions, generateClientHelpers, model);
5758
createHelper(outDir);
5859

5960
await saveProject(project);
@@ -64,22 +65,25 @@ function createAppRouter(
6465
modelOperations: DMMF.ModelMapping[],
6566
hiddenModels: string[],
6667
generateModelActions: string[] | undefined,
67-
generateClientHelpers: string[] | undefined
68+
generateClientHelpers: string[] | undefined,
69+
zmodel: Model
6870
) {
69-
const appRouter = project.createSourceFile(path.resolve(outDir, 'routers', `index.ts`), undefined, {
71+
const indexFile = path.resolve(outDir, 'routers', `index.ts`);
72+
const appRouter = project.createSourceFile(indexFile, undefined, {
7073
overwrite: true,
7174
});
7275

7376
appRouter.addStatements('/* eslint-disable */');
7477

78+
const prismaImport = getPrismaClientImportSpec(zmodel, path.dirname(indexFile));
7579
appRouter.addImportDeclarations([
7680
{
7781
namedImports: ['AnyRootConfig'],
7882
moduleSpecifier: '@trpc/server',
7983
},
8084
{
8185
namedImports: ['PrismaClient'],
82-
moduleSpecifier: '@prisma/client',
86+
moduleSpecifier: prismaImport,
8387
},
8488
{
8589
namedImports: ['createRouterFactory', 'AnyRouter'],
@@ -133,7 +137,8 @@ function createAppRouter(
133137
operations,
134138
outDir,
135139
generateModelActions,
136-
generateClientHelpers
140+
generateClientHelpers,
141+
zmodel
137142
);
138143

139144
appRouter.addImportDeclaration({
@@ -201,7 +206,8 @@ function generateModelCreateRouter(
201206
operations: Record<string, string | undefined | null>,
202207
outputDir: string,
203208
generateModelActions: string[] | undefined,
204-
generateClientHelpers: string[] | undefined
209+
generateClientHelpers: string[] | undefined,
210+
zmodel: Model
205211
) {
206212
const modelRouter = project.createSourceFile(path.resolve(outputDir, 'routers', `${model}.router.ts`), undefined, {
207213
overwrite: true,
@@ -219,7 +225,7 @@ function generateModelCreateRouter(
219225
generateRouterSchemaImports(modelRouter, model);
220226
generateHelperImport(modelRouter);
221227
if (generateClientHelpers) {
222-
generateRouterTypingImports(modelRouter);
228+
generateRouterTypingImports(modelRouter, zmodel);
223229
}
224230

225231
const createRouterFunc = modelRouter.addFunction({

packages/plugins/trpc/src/helpers.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
import { DMMF } from '@prisma/generator-helper';
2-
import { PluginError } from '@zenstackhq/sdk';
2+
import { PluginError, getPrismaClientImportSpec } from '@zenstackhq/sdk';
33
import { CodeBlockWriter, SourceFile } from 'ts-morph';
44
import { upperCaseFirst } from 'upper-case-first';
55
import { name } from '.';
66
import { uncapitalizeFirstLetter } from './utils/uncapitalizeFirstLetter';
7+
import { Model } from '@zenstackhq/sdk/ast';
78

89
export function generateProcedure(
910
writer: CodeBlockWriter,
@@ -226,9 +227,11 @@ export function generateRouterTyping(writer: CodeBlockWriter, opType: string, mo
226227
});
227228
}
228229

229-
export function generateRouterTypingImports(sourceFile: SourceFile) {
230+
export function generateRouterTypingImports(sourceFile: SourceFile, model: Model) {
231+
const importingDir = sourceFile.getDirectoryPath();
232+
const prismaImport = getPrismaClientImportSpec(model, importingDir);
230233
sourceFile.addStatements([
231-
`import type { Prisma } from '@prisma/client';`,
234+
`import type { Prisma } from '${prismaImport}';`,
232235
`import type { UseTRPCMutationOptions, UseTRPCMutationResult, UseTRPCQueryOptions, UseTRPCQueryResult, UseTRPCInfiniteQueryOptions, UseTRPCInfiniteQueryResult } from '@trpc/react-query/shared';`,
233236
`import type { TRPCClientErrorLike } from '@trpc/client';`,
234237
`import type { AnyRouter } from '@trpc/server';`,

packages/plugins/trpc/src/zod/generator.ts

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,11 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.
2626
const outputObjectTypes = prismaClientDmmf.schema.outputObjectTypes.prisma;
2727
const models: DMMF.Model[] = prismaClientDmmf.datamodel.models;
2828

29-
await generateEnumSchemas(prismaClientDmmf.schema.enumTypes.prisma, prismaClientDmmf.schema.enumTypes.model ?? []);
29+
await generateEnumSchemas(
30+
prismaClientDmmf.schema.enumTypes.prisma,
31+
prismaClientDmmf.schema.enumTypes.model ?? [],
32+
model
33+
);
3034

3135
const dataSource = model.declarations.find((d): d is DataSource => isDataSource(d));
3236

@@ -43,8 +47,8 @@ export async function generate(model: Model, options: PluginOptions, dmmf: DMMF.
4347

4448
const aggregateOperationSupport = resolveAggregateOperationSupport(inputObjectTypes);
4549

46-
await generateObjectSchemas(inputObjectTypes, output);
47-
await generateModelSchemas(models, modelOperations, aggregateOperationSupport);
50+
await generateObjectSchemas(inputObjectTypes, output, model);
51+
await generateModelSchemas(models, modelOperations, aggregateOperationSupport, model);
4852
}
4953

5054
async function handleGeneratorOutputValue(output: string) {
@@ -56,22 +60,27 @@ async function handleGeneratorOutputValue(output: string) {
5660
Transformer.setOutputPath(output);
5761
}
5862

59-
async function generateEnumSchemas(prismaSchemaEnum: DMMF.SchemaEnum[], modelSchemaEnum: DMMF.SchemaEnum[]) {
63+
async function generateEnumSchemas(
64+
prismaSchemaEnum: DMMF.SchemaEnum[],
65+
modelSchemaEnum: DMMF.SchemaEnum[],
66+
zmodel: Model
67+
) {
6068
const enumTypes = [...prismaSchemaEnum, ...modelSchemaEnum];
6169
const enumNames = enumTypes.map((enumItem) => enumItem.name);
6270
Transformer.enumNames = enumNames ?? [];
6371
const transformer = new Transformer({
6472
enumTypes,
73+
zmodel,
6574
});
6675
await transformer.generateEnumSchemas();
6776
}
6877

69-
async function generateObjectSchemas(inputObjectTypes: DMMF.InputType[], output: string) {
78+
async function generateObjectSchemas(inputObjectTypes: DMMF.InputType[], output: string, zmodel: Model) {
7079
const moduleNames: string[] = [];
7180
for (let i = 0; i < inputObjectTypes.length; i += 1) {
7281
const fields = inputObjectTypes[i]?.fields;
7382
const name = inputObjectTypes[i]?.name;
74-
const transformer = new Transformer({ name, fields });
83+
const transformer = new Transformer({ name, fields, zmodel });
7584
const moduleName = await transformer.generateObjectSchema();
7685
moduleNames.push(moduleName);
7786
}
@@ -84,12 +93,14 @@ async function generateObjectSchemas(inputObjectTypes: DMMF.InputType[], output:
8493
async function generateModelSchemas(
8594
models: DMMF.Model[],
8695
modelOperations: DMMF.ModelMapping[],
87-
aggregateOperationSupport: AggregateOperationSupport
96+
aggregateOperationSupport: AggregateOperationSupport,
97+
zmodel: Model
8898
) {
8999
const transformer = new Transformer({
90100
models,
91101
modelOperations,
92102
aggregateOperationSupport,
103+
zmodel,
93104
});
94105
await transformer.generateModelSchemas();
95106
}

packages/plugins/trpc/src/zod/transformer.ts

Lines changed: 6 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
/* eslint-disable @typescript-eslint/ban-ts-comment */
22
import type { DMMF as PrismaDMMF } from '@prisma/generator-helper';
3-
import { AUXILIARY_FIELDS } from '@zenstackhq/sdk';
3+
import { AUXILIARY_FIELDS, getPrismaClientImportSpec } from '@zenstackhq/sdk';
4+
import { Model } from '@zenstackhq/sdk/ast';
45
import { checkModelHasModelRelation, findModelByName, isAggregateInputType } from '@zenstackhq/sdk/dmmf-helpers';
56
import indentString from '@zenstackhq/sdk/utils';
67
import path from 'path';
@@ -21,8 +22,7 @@ export default class Transformer {
2122
static provider: string;
2223
private static outputPath = './generated';
2324
private hasJson = false;
24-
private static prismaClientOutputPath = '@prisma/client';
25-
private static isCustomPrismaClientOutputPath = false;
25+
private zmodel: Model;
2626

2727
constructor(params: TransformerParams) {
2828
this.name = params.name ?? '';
@@ -31,6 +31,7 @@ export default class Transformer {
3131
this.modelOperations = params.modelOperations ?? [];
3232
this.aggregateOperationSupport = params.aggregateOperationSupport ?? {};
3333
this.enumTypes = params.enumTypes ?? [];
34+
this.zmodel = params.zmodel;
3435
}
3536

3637
static setOutputPath(outPath: string) {
@@ -41,11 +42,6 @@ export default class Transformer {
4142
return this.outputPath;
4243
}
4344

44-
static setPrismaClientOutputPath(prismaClientCustomPath: string) {
45-
this.prismaClientOutputPath = prismaClientCustomPath;
46-
this.isCustomPrismaClientOutputPath = prismaClientCustomPath !== '@prisma/client';
47-
}
48-
4945
async generateEnumSchemas() {
5046
for (const enumType of this.enumTypes) {
5147
const { name, values } = enumType;
@@ -268,27 +264,8 @@ export default class Transformer {
268264
}
269265

270266
generateImportPrismaStatement() {
271-
let prismaClientImportPath: string;
272-
if (Transformer.isCustomPrismaClientOutputPath) {
273-
/**
274-
* If a custom location was designated for the prisma client, we need to figure out the
275-
* relative path from {outputPath}/schemas/objects to {prismaClientCustomPath}
276-
*/
277-
const fromPath = path.join(Transformer.outputPath, 'schemas', 'objects');
278-
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
279-
const toPath = Transformer.prismaClientOutputPath!;
280-
const relativePathFromOutputToPrismaClient = path
281-
.relative(fromPath, toPath)
282-
.split(path.sep)
283-
.join(path.posix.sep);
284-
prismaClientImportPath = relativePathFromOutputToPrismaClient;
285-
} else {
286-
/**
287-
* If the default output path for prisma client (@prisma/client) is being used, we can import from it directly
288-
* without having to resolve a relative path
289-
*/
290-
prismaClientImportPath = Transformer.prismaClientOutputPath;
291-
}
267+
const importingFrom = path.resolve(Transformer.outputPath, 'schemas', 'objects');
268+
const prismaClientImportPath = getPrismaClientImportSpec(this.zmodel, importingFrom);
292269
return `import type { Prisma } from '${prismaClientImportPath}';\n\n`;
293270
}
294271

packages/plugins/trpc/src/zod/types.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { DMMF as PrismaDMMF } from '@prisma/generator-helper';
2+
import { Model } from '@zenstackhq/sdk/ast';
23

34
export type TransformerParams = {
45
enumTypes?: PrismaDMMF.SchemaEnum[];
@@ -9,6 +10,7 @@ export type TransformerParams = {
910
aggregateOperationSupport?: AggregateOperationSupport;
1011
isDefaultPrismaClientOutput?: boolean;
1112
prismaClientOutputPath?: string;
13+
zmodel: Model;
1214
};
1315

1416
export type AggregateOperationSupport = {

packages/schema/src/plugins/access-policy/policy-guard-generator.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import {
2121
emitProject,
2222
getDataModels,
2323
getLiteral,
24+
getPrismaClientImportSpec,
2425
GUARD_FIELD_NAME,
2526
PluginError,
2627
PluginOptions,
@@ -63,10 +64,11 @@ export default class PolicyGenerator {
6364
});
6465

6566
// import enums
67+
const prismaImport = getPrismaClientImportSpec(model, output);
6668
for (const e of model.declarations.filter((d) => isEnum(d))) {
6769
sf.addImportDeclaration({
6870
namedImports: [{ name: e.name }],
69-
moduleSpecifier: '@prisma/client',
71+
moduleSpecifier: prismaImport,
7072
});
7173
}
7274

0 commit comments

Comments
 (0)