@tsed/prisma
Version:
Generate Ts.ED JsonSchema based on Prisma models
209 lines (183 loc) • 5.27 kB
text/typescript
import path from "node:path";
import {DMMF} from "@prisma/generator-helper";
import {toMap} from "@tsed/core";
import {camelCase, pascalCase} from "change-case";
import pluralize from "pluralize";
import {ClassDeclaration, Project, Scope} from "ts-morph";
import {DmmfModel} from "../domain/DmmfModel.js";
import {generateOutputsBarrelFile} from "./generateOutputsBarrelFile.js";
import {resolveExtension} from "./resolveExtension.js";
interface MethodOptions {
repository: ClassDeclaration;
name: string;
model: string;
returnType?: string | undefined;
hasQuestionToken?: boolean;
isAsync?: boolean;
}
function addDelegatedMethod({name, hasQuestionToken, repository, model, returnType, isAsync = true}: MethodOptions) {
const method = repository.addMethod({
name: name,
isAsync,
returnType: returnType ? `Promise<${returnType}>` : undefined,
parameters: [
{
name: "args",
type: `Prisma.${model}${pascalCase(name)}Args`,
hasQuestionToken
}
]
});
if (returnType) {
method.setBodyText(`const obj = await this.collection.${name}(args);
return this.deserialize<${returnType}>(obj);`);
} else {
method.setBodyText(`return this.collection.${name}(args)`);
}
}
export function generateRepositories(dmmf: DMMF.Document, project: Project, baseDirPath: string) {
const modelsMap = toMap<string, DMMF.Model>(dmmf.datamodel.models as any, "name");
const models = DmmfModel.getModels(dmmf, modelsMap);
const repoDirPath = path.resolve(baseDirPath, "repositories");
const repoDirectory = project.createDirectory(repoDirPath);
const repositoriesIndex = repoDirectory.createSourceFile(`index.ts`, undefined, {overwrite: true});
const exportedModels = models.map((model) => {
const name = pascalCase(`${pluralize(model.name)}Repository`);
const modelName = model.toString();
const sourceFile = repoDirectory.createSourceFile(`${name}.ts`, undefined, {overwrite: true});
sourceFile.addImportDeclarations([
{
moduleSpecifier: "@tsed/core",
namedImports: ["isArray"]
},
{
moduleSpecifier: "@tsed/json-mapper",
namedImports: ["deserialize"]
},
{
moduleSpecifier: "@tsed/di",
namedImports: ["Injectable", "Inject"]
},
{
moduleSpecifier: resolveExtension("../services/PrismaService"),
namedImports: ["PrismaService"]
},
{
moduleSpecifier: resolveExtension("../client/index"),
namedImports: ["Prisma", model.name]
},
{
moduleSpecifier: resolveExtension("../models/index"),
namedImports: [model.toString()]
}
]);
const repository = sourceFile.addClass({
name,
isExported: true,
decorators: [
{
name: "Injectable",
arguments: []
}
]
});
repository.addProperty({
name: "prisma",
type: "PrismaService",
scope: Scope.Protected,
decorators: [
{
name: "Inject",
arguments: []
}
]
});
repository
.addGetAccessor({
name: "collection"
})
.setBodyText(`return this.prisma.${camelCase(model.name)}`);
repository
.addGetAccessor({
name: "groupBy"
})
.setBodyText(`return this.collection.groupBy.bind(this.collection)`);
repository
.addMethod({
name: "deserialize",
scope: Scope.Protected,
returnType: "T",
parameters: [
{
name: "obj",
type: `null | ${model.name} | ${model.name}[]`
}
],
typeParameters: ["T"]
})
.setBodyText(`return deserialize<T>(obj, {type: ${modelName}, collectionType: isArray(obj) ? Array : undefined})`);
addDelegatedMethod({
repository,
name: "findUnique",
model: model.name,
returnType: `${modelName} | null`
});
addDelegatedMethod({
repository,
name: "findFirst",
model: model.name,
returnType: `${modelName} | null`
});
addDelegatedMethod({
repository,
name: "findMany",
model: model.name,
returnType: `${modelName}[]`,
hasQuestionToken: true
});
addDelegatedMethod({
repository,
name: "create",
model: model.name,
returnType: `${modelName}`
});
addDelegatedMethod({
repository,
name: "update",
model: model.name,
returnType: `${modelName}`
});
addDelegatedMethod({
repository,
name: "upsert",
model: model.name,
returnType: `${modelName}`
});
addDelegatedMethod({
repository,
name: "delete",
model: model.name,
returnType: `${modelName}`
});
addDelegatedMethod({
repository,
name: "deleteMany",
model: model.name,
isAsync: false
});
addDelegatedMethod({
repository,
name: "updateMany",
model: model.name,
isAsync: false
});
addDelegatedMethod({
repository,
name: "aggregate",
model: pascalCase(model.name),
isAsync: false
});
return name;
});
generateOutputsBarrelFile(repositoriesIndex, exportedModels);
}