@arianaprojects/prisma-nestjs-crud-generator
Version:
code generator from Prisma schema
562 lines (514 loc) • 18 kB
text/typescript
import { ReqNamesType } from './../interfaces';
import { DMMF } from '@prisma/generator-helper/dist/dmmf';
import { apiResponseInterface, functionFixConfig, generalConfig, ReqNames, ReqType } from '../interfaces';
import { classGenerator, constructorGenerator, decoratorGenerator, functionGenerator, functionPromiseGenerator, parameterGenerator, parameterPrivateGenerator } from '../templates';
import Model from './Model';
import fs from 'fs';
import { fixedConfig, UserDecoratorParam, UserParam, UserParamService } from './const';
import { prettierFormatFormat, tsTypes } from '../util';
export default class CRUD {
parent: Model;
config: generalConfig;
controller: string;
service: string;
idGenerator: boolean = false;
constructor(parent: Model) {
this.parent = parent;
this.config = this.configParser(this.parent.option.configPath);
// console.log('here', this.parent.model.fields);
this.generate();
}
private generate() {
// if id not automatically
let conBody: string[] = [];
let serBody: string[] = [];
conBody.push(this.controllerClassConstructor());
serBody.push(this.serviceClassConstructor());
if (this.config.access && !this.config.accessBlackList.includes(this.parent.namePascal)) {
serBody.push(
functionPromiseGenerator(
'hasAccess',
`${UserParamService}, ${this.parent.replace('query: FIND_DTO')}`,
'Boolean',
this.parent.replace(`
const ret = await this.prismaService.NAME_CAMEL.findMany({
where: { ...query, ...this.hasAccessData(user),
...this.isNotDeletedData(), },
});
return ret.length > 0;
`),
),
);
serBody.push(
functionGenerator(
'hasAccessData',
`${UserParamService}`,
`Access${this.parent.namePascal}Dto`,
`
return {
userId:user.id
};
`,
),
);
}
serBody.push(
functionGenerator(
'isNotDeletedData',
``,
`Deleted${this.parent.namePascal}Dto`,
`
return {
deletedAt:null
};
`,
),
);
serBody.push(
functionGenerator(
'pseudonymisationData',
``,
`Pseudonymisation${this.parent.namePascal}Dto`,
`
return {
};
`,
),
);
this.parent.idsNoDefault.map((id) => {
serBody.push(
functionGenerator(
`${id.name}Gen`,
``,
tsTypes(id.type),
`// TODO
return null`,
),
);
});
const keys = Object.keys(fixedConfig.functions);
keys.map((f, i) => {
const d = this.config && this.config.functions && this.config.functions[f] && this.config.functions[f].disable;
if (!(this.config && this.config.functions && this.config.functions[f] && this.config.functions[f].disable)) {
if (i == 12) {
conBody.push('\n\n//\t------------------ ADMIN -------------------\n');
serBody.push('\n\n//\t------------------ ADMIN -------------------\n');
}
const c = fixedConfig.functions[f];
// controller
conBody.push(this.controllerFunction(ReqNames[f], c, true, true, true));
// service
serBody.push(this.serviceFunction(ReqNames[f], c));
serBody.push('\n');
}
});
this.controller = prettierFormatFormat(this.controllerGenerator(conBody.join('\n')));
this.service = prettierFormatFormat(this.serviceGenerator(serBody.join('\n')));
}
private configParser(path?: string): generalConfig {
if (!!path) return JSON.parse(fs.readFileSync(process.cwd() + '/' + path, 'utf-8')) as generalConfig;
return null;
}
private functionControllerDecorator(type: ReqType, conf: functionFixConfig, name: string) {
let res: string[] = [];
let p: string[] = [conf.fixedPath];
if (conf.param)
this.parent.idFields.map((id) => {
if (this.parent.idFields.length > 1) p.push(`${id.name}/:${id.name}`);
else p.push(`:${id.name}`);
});
res.push(decoratorGenerator(String(type), p.join('/')));
if (this.config && this.config.functions && this.config.functions[name] && this.config.functions[name].additionalDecorator) res.push(this.config.functions[name].additionalDecorator.join('\n'));
return res.join('\n');
}
private apiOperationDecorator(name: ReqNames, conf: functionFixConfig) {
let res: string[] = [];
res.push('@ApiOperation({');
if (this.config && this.config.functions && this.config.functions[name] && !!this.config.functions[name].summary) res.push(`summary:"${this.parent.replace(this.config.functions[name].summary)}",`);
if (this.config && this.config.functions && this.config.functions[name] && !!this.config.functions[name].description) res.push(`description:"${this.parent.replace(this.config.functions[name].description)}",`);
res.push(`summary:"${this.parent.replace(conf.info)}",`);
res.push('})');
return res.join('\n');
}
private allApiResponseDecorators(conf: functionFixConfig) {
return conf.responses.map((r) => this.apiResponseDecorator(r, conf)).join('\n');
}
private apiResponseDecorator(option: apiResponseInterface, conf: functionFixConfig) {
let res: string[] = [];
res.push('@ApiResponse({');
res.push(`status:${this.parent.replace(option.status)},`);
if (option.description) res.push(`description:"${this.parent.replace(option.description)}",`);
if (option.type) res.push(`type:${this.parent.replace(option.type)},`);
res.push('})');
return res.join('\n');
}
private apiRequestDecorator(option: functionFixConfig) {
let res: string[] = [];
// // ApiQuery
// if (option.query) {
// res.push('@ApiQuery({');
// res.push('type:' + this.parent.replace(option.query));
// res.push('})');
// }
// // ApiParam
// if (option.param) {
// res.push('@ApiParam({');
// if (option.bodyArray) res.push('isArray:true');
// res.push('type:' + this.parent.replace(option.param));
// res.push('})');
// }
// // Header
// if (option.header) {
// res.push('@ApiHeader({');
// res.push('type:' + this.parent.replace(option.header));
// res.push('})');
// }
// ApiBody
if (option.body) {
res.push('@ApiBody({');
if (option.bodyArray) res.push('isArray:true,');
res.push('type:' + this.parent.replace(option.body));
res.push('})');
}
return res.join('\n');
}
private paramController(option: functionFixConfig, access: boolean = false) {
let res: string[] = [];
if (access && !option.admin) {
res.push(UserDecoratorParam);
res.push(',');
}
// ApiQuery
if (option.query) {
res.push('@Query() query: ');
res.push(this.parent.replace(option.query));
res.push(',');
}
// ApiParam
if (option.param) {
res.push('@Param() param: ');
res.push(this.parent.replace(option.param));
if (option.paramArray) res.push('[]');
res.push(',');
}
// Header
if (option.header) {
res.push('@Header() header: ');
res.push(this.parent.replace(option.header));
res.push(',');
}
// ApiBody
if (option.body) {
res.push('@Body() body: ');
res.push(this.parent.replace(option.body));
if (option.bodyArray) res.push('[]');
res.push(',');
}
return res.join(' ');
}
private paramControllerToService(option: functionFixConfig, access: boolean = false) {
let res: string[] = [];
if (access && !option.admin) {
res.push(UserParam);
res.push(',');
}
// ApiQuery
if (option.query) {
res.push('query');
res.push(',');
}
// ApiParam
if (option.param) {
res.push('param');
res.push(',');
}
// Header
if (option.header) {
res.push('header');
res.push(',');
}
// ApiBody
if (option.body) {
res.push('body ');
res.push(',');
}
// console.log(access, !option.admin, res);
return res.join(' ');
}
private paramService(option: functionFixConfig, access: boolean = false) {
let res: string[] = [];
if (access && !option.admin) {
res.push(UserParamService);
res.push(',');
}
// ApiQuery
if (option.query) {
res.push(parameterGenerator('query', this.parent.replace(option.query)));
res.push(',');
}
// ApiParam
if (option.param) {
res.push(parameterGenerator('param', this.parent.replace(option.param)));
if (option.paramArray) res.push('[]');
res.push(',');
}
// Header
if (option.header) {
res.push(parameterGenerator('header', this.parent.replace(option.header)));
res.push(',');
}
// ApiBody
if (option.body) {
res.push(parameterGenerator('body ', this.parent.replace(option.body)));
if (option.bodyArray) res.push('[]');
res.push(',');
}
return res.join(' ');
}
private serviceClassDecorator() {
let res: string[] = [];
res.push('@Injectable()');
return res.join('\n');
}
private controllerClassDecorator() {
let res: string[] = [];
res.push(``);
res.push(``);
res.push('@ApiBearerAuth()');
res.push(``);
return res.join('\n');
}
private controllerFunctionComment(name: ReqNames) {
let res: string[] = ['\n'];
res.push('/********************************************************************');
res.push('* ' + ReqNames[name]);
res.push(' ********************************************************************/');
return res.join('\n');
}
private controllerFunctionBody(name: ReqNames, conf: functionFixConfig) {
let res: string[] = [];
const ENTITY = conf.responses.filter((r) => r.type == 'ENTITY').length >= 1;
const ENTITYArray = conf.responses.filter((r) => r.type == '[ENTITY]').length >= 1;
if (ENTITY || ENTITYArray) res.push(`return plainToInstance(${this.parent.namePascal}, (await this.${this.parent.nameCamel}Service.${name}(${this.paramControllerToService(conf, this.config.access)})))`);
else res.push(`return await this.${this.parent.nameCamel}Service.${name}(${this.paramControllerToService(conf, this.config.access)})`);
return res.join('\n');
}
private controllerFunction(name: ReqNames, conf: functionFixConfig, apiOperator: boolean, apiReq: boolean, apiResp: boolean) {
let res: string[] = [];
const optionalConf = this.config && this.config.functions && this.config.functions[name];
res.push(this.controllerFunctionComment(name));
res.push(this.functionControllerDecorator(ReqType[ReqNamesType[name]], conf, name)); // TODO param
if (apiOperator) res.push(this.apiOperationDecorator(name, conf));
if (apiResp) res.push(this.allApiResponseDecorators(conf));
if (apiReq) res.push(this.apiRequestDecorator(conf));
res.push(functionPromiseGenerator(ReqNames[name], this.paramController(conf, this.config.access), this.parent.replace(conf.resp), this.parent.replace(this.controllerFunctionBody(name, conf))));
return res.join('\n');
}
private serviceFunction(name: ReqNames, conf: functionFixConfig) {
let res: string[] = [];
res.push(functionPromiseGenerator(ReqNames[name], this.parent.replace(this.paramService(conf, this.config.access)), this.parent.replace(conf.resp), this.parent.replace(this.serviceFunctionBody(conf, name))));
return res.join('\n\n');
}
private serviceFunctionBody(conf: functionFixConfig, name: ReqNames) {
let res: string[] = [];
const service = this.config.access && !this.config.accessBlackList.includes(this.parent.namePascal) ? conf.serviceAccess : conf.service;
// console.log(this.parent.namePascal, service);
let fix = service;
if (this.parent.idsNoDefault.length > 0) {
if (fix.includes('createMany') && conf.bodyArray) {
fix = service.replace(
'...b ',
`
${this.parent.idsNoDefault
.map((id) => {
return `${id.name}:this.${id.name}Gen()`;
})
.join(`,`)}
, ...b `,
);
// console.log(fix);
} else if (fix.includes('create') && !conf.bodyArray) {
fix = service.replace(
'...body',
`
${this.parent.idsNoDefault
.map((id) => {
return `${id.name}:this.${id.name}Gen()`;
})
.join(`,`)}
, ...body
`,
);
// console.log(fix);
}
}
res.push(fix);
return res.join('\n');
}
private controllerClassConstructor() {
let res: string[] = [];
// console.log('sad');
res.push(constructorGenerator(parameterPrivateGenerator(this.parent.nameCamel + 'Service', this.parent.namePascal + 'Service'), ''));
return res.join('\n');
}
private serviceClassConstructor() {
let res: string[] = [];
res.push(constructorGenerator(parameterPrivateGenerator('prismaService', 'PrismaService'), ''));
return res.join('\n');
}
private controllerImport() {
let res: string[] = [];
if (this.config.additionalImport) {
this.config.additionalImport.map((i) => {
res.push(i);
});
}
res.push(
`import {
${this.parent.namePascal}
} from './${this.parent.nameCamel}.entity';`,
);
res.push(
`import {
Find${this.parent.namePascal}Dto,
Create${this.parent.namePascal}Dto,
Update${this.parent.namePascal}Dto,
Connect${this.parent.namePascal}Dto,
Find${this.parent.namePascal}AdminDto,
Create${this.parent.namePascal}AdminDto,
Update${this.parent.namePascal}AdminDto,
Connect${this.parent.namePascal}AdminDto,
Access${this.parent.namePascal}Dto,
Deleted${this.parent.namePascal}Dto,
Pseudonymisation${this.parent.namePascal}Dto
} from './${this.parent.nameCamel}.dto';`,
);
res.push(
`import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,Query,
NotFoundException,
Param,
Post,
Patch,
Put, UnauthorizedException,
ForbiddenException,
ConflictException,
Req,Injectable
} from '@nestjs/common';
import {
ApiBearerAuth,
ApiBody,
ApiConflictResponse,
ApiConsumes,
ApiCreatedResponse,
ApiNotFoundResponse,
ApiOkResponse,
ApiOperation,
ApiParam,
ApiQuery,
ApiResponse,
ApiTags,
ApiUnauthorizedResponse,
} from '@nestjs/swagger';`,
"import { Prisma } from '@prisma/client';",
);
res.push(`import { UserGeneralDto } from 'src/shared/dtos/user.dto';`);
res.push(`import { plainToInstance } from 'class-transformer';`);
res.push(`import { User as UserDecorator } from 'src/shared/decorators/user.decorator'; `);
res.push(
`import {
${this.parent.namePascal}Service
} from './${this.parent.nameCamel}.service';`,
);
return res.join('\n');
}
private serviceImport() {
let res: string[] = [];
if (this.config.additionalImport) {
this.config.additionalImport.map((i) => {
res.push(i);
});
}
res.push(
`import {
${this.parent.namePascal}
} from './${this.parent.nameCamel}.entity';`,
);
res.push(`import { plainToInstance } from 'class-transformer';`);
res.push(`import { PrismaService } from 'src/shared/services/prisma.service';`);
res.push(`import { UserGeneralDto } from 'src/shared/dtos/user.dto';`);
res.push(`import { User as UserDecorator } from 'src/shared/decorators/user.decorator'; `);
res.push(
`import {
Find${this.parent.namePascal}Dto,
Create${this.parent.namePascal}Dto,
Update${this.parent.namePascal}Dto,
Connect${this.parent.namePascal}Dto,
Find${this.parent.namePascal}AdminDto,
Create${this.parent.namePascal}AdminDto,
Update${this.parent.namePascal}AdminDto,
Connect${this.parent.namePascal}AdminDto,
Access${this.parent.namePascal}Dto,
Deleted${this.parent.namePascal}Dto,
Pseudonymisation${this.parent.namePascal}Dto
} from './${this.parent.nameCamel}.dto';`,
);
res.push(
`import {
Body,
Controller,
Delete,
Get,
HttpCode,
HttpStatus,Query,
NotFoundException,
Param,
Post,
Patch,
Put, UnauthorizedException,
ForbiddenException,
ConflictException,
Req,Injectable
} from '@nestjs/common';
import {
ApiBearerAuth,
ApiBody,
ApiConflictResponse,
ApiConsumes,
ApiCreatedResponse,
ApiNotFoundResponse,
ApiOkResponse,
ApiOperation,
ApiParam,
ApiQuery,
ApiResponse,
ApiTags,
ApiUnauthorizedResponse,
} from '@nestjs/swagger';`,
"import { Prisma } from '@prisma/client';",
);
let prismaImport = [];
this.parent.enumFields.map((f) => {
prismaImport.push(` ${f.type},`);
});
res.push('import { ' + prismaImport.join('\n') + "} from '@prisma/client'");
return res.join('\n');
}
private controllerGenerator(body: string) {
let res: string[] = [];
res.push(this.controllerImport());
res.push(classGenerator(this.parent.namePascal + 'Controller', body, this.controllerClassDecorator()));
return res.join('\n');
}
private serviceGenerator(body: string) {
let res: string[] = [];
res.push(this.serviceImport());
res.push(classGenerator(this.parent.namePascal + 'Service', body, this.serviceClassDecorator()));
return res.join('\n');
}
}