Skip to content

Commit

Permalink
feat(generators): create new app :with-postgres-prisma
Browse files Browse the repository at this point in the history
  • Loading branch information
phatpham9 committed Feb 14, 2021
1 parent d7d8098 commit 87952b8
Show file tree
Hide file tree
Showing 7 changed files with 257 additions and 2 deletions.
7 changes: 5 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ $ yo create-service-component:with-postgres

# or :with-postgres-typeorm
$ yo create-service-component:with-postgres-typeorm

# or :with-postgres-prisma
$ yo create-service-component:with-postgres-prisma
```

This scaffolds out:
Expand All @@ -77,8 +80,8 @@ This scaffolds out:
│ │   │   ├── constants.ts
│ │   │   ├── controller.ts
│ │   │   ├── index.ts
│ │   │   ├── model.ts (:with-mongo, :with-postgres or :with-postgres-typeorm)
│ │   │   ├── repository.ts (:with-mongo, :with-postgres or :with-postgres-typeorm)
│ │   │   ├── model.ts (:with-mongo/:with-postgres/:with-postgres-typeorm)
│ │   │   ├── repository.ts (:with-mongo/:with-postgres/:with-postgres-typeorm/:with-postgres-prisma)
│ │   │   ├── types.ts
│ │   └── ...
│ ├── ...
Expand Down
51 changes: 51 additions & 0 deletions generators/with-postgres-prisma/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const Generator = require('yeoman-generator');
const chalk = require('chalk');
const yosay = require('yosay');
const changeCase = require('change-case');
const pluralize = require('pluralize');

const pkg = require('../../package.json');

module.exports = class extends Generator {
async prompting() {
this.log(yosay(`Welcome to the ${chalk.red(pkg.name)} generator!`));

const prompts = [
{
type: 'input',
name: 'compName',
message: 'Name of the new component (singular)?',
default: 'thing',
},
];

return this.prompt(prompts).then((props) => {
const compNameParamCase = changeCase.paramCase(props.compName);
const compNamePascalCase = changeCase.pascalCase(props.compName);
const compNameCamelCase = changeCase.camelCase(props.compName);

this.props = {
// param-case
compNameParamCase,
// param-cases
compNameParamCasePlural: pluralize(compNameParamCase),
// PascalCase
compNamePascalCase,
// PasCalCases
compNamePascalCasePlural: pluralize(compNamePascalCase),
// camelCase
compNameCamelCase,
// camelCases
compNameCamelCasePlural: pluralize(compNameCamelCase),
};
});
}

writing() {
this.fs.copyTpl(
[this.templatePath('**/*'), this.templatePath('**/.*')],
this.destinationPath('src/components'),
this.props,
);
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
const ENTITY = '<%= compNameParamCase %>';
const RESOURCE = '<%= compNameParamCasePlural %>';

export { ENTITY, RESOURCE };
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import { Request, Response, NextFunction } from 'express';
import { StatusCodes } from 'http-status-codes';
import { HttpError } from '@boringcodes/utils/error';

import { <%= compNamePascalCase %> } from './types';
import { ENTITY } from './constants';
import repository from './repository';

interface MyRequest extends Request {
readonly [ENTITY]: Required<<%= compNamePascalCase %>>;
}

const getById = async (
req: Request,
_: Response,
next: NextFunction,
): Promise<void> => {
try {
const { id = '' } = req.params;
if (id === '') {
throw new HttpError(StatusCodes.BAD_REQUEST, 'Invalid resource Id');
}

try {
// get object by id
const object = await repository.get(+id);

// assign object to request for using in the next handlers
Object.assign(req, { [ENTITY]: object });

next();
} catch (err) {
throw new HttpError(StatusCodes.NOT_FOUND, 'Resource not found');
}
} catch (err) {
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
}
};

const list = async (
_: Request,
res: Response,
next: NextFunction,
): Promise<void> => {
try {
// list objects
const objects = await repository.list();

res.send(objects);
} catch (err) {
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
}
};

const create = async (
req: Request,
res: Response,
next: NextFunction,
): Promise<void> => {
try {
// create object
const object = await repository.create(req.body);

res.send(object);
} catch (err) {
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
}
};

const get = (req: Request, res: Response, next: NextFunction): void => {
try {
// get object
res.send((req as MyRequest)[ENTITY]);
} catch (err) {
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
}
};

const update = async (
req: Request,
res: Response,
next: NextFunction,
): Promise<void> => {
try {
// update object
const object = await repository.update(
(req as MyRequest)[ENTITY].id,
req.body,
);

res.send(object);
} catch (err) {
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
}
};

const del = async (
req: Request,
res: Response,
next: NextFunction,
): Promise<void> => {
try {
// delete object
const object = await repository.del((req as MyRequest)[ENTITY].id);

res.send(object);
} catch (err) {
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
}
};

export default { getById, list, create, get, update, del };
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import { Router } from 'express';

import { RouteOptions } from '../types';
import { RESOURCE } from './constants';
import controller from './controller';

const path = `/${RESOURCE}`;

const routes = (_: RouteOptions): Router => {
const router = Router();

router.param('id', controller.getById);

router.route('/').get(controller.list).post(controller.create);

router
.route('/:id')
.get(controller.get)
.patch(controller.update)
.delete(controller.del);

return router;
};

export default { path, routes };
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import { MyError } from '@boringcodes/utils/error';

import postgres from '../../db/postgres';
import { <%= compNamePascalCase %> } from './types';

const list = async (): Promise<<%= compNamePascalCase %>[]> => {
// list documents
return await postgres.<%= compNameCamelCase %>.findMany();
};

const create = async (data: Omit<<%= compNamePascalCase %>, 'id'>): Promise<<%= compNamePascalCase %>> => {
// create document
return await postgres.<%= compNameCamelCase %>.create({ data });
};

const get = async (id: number): Promise<<%= compNamePascalCase %>> => {
// get document
const document = await postgres.<%= compNameCamelCase %>.findUnique({ where: { id } });
if (document === null) {
throw new MyError('Document not found');
}

return document;
};

const update = async (id: number, data: Omit<<%= compNamePascalCase %>, 'id'>): Promise<<%= compNamePascalCase %>> => {
// get document
const document = await postgres.<%= compNameCamelCase %>.findUnique({ where: { id } });
if (document === null) {
throw new MyError('Document not found');
}

// update document
return await postgres.<%= compNameCamelCase %>.update({
data,
where: { id },
});
};

const del = async (id: number): Promise<<%= compNamePascalCase %>> => {
// get document
const document = await postgres.<%= compNameCamelCase %>.findUnique({ where: { id } });
if (document === null) {
throw new MyError('Document not found');
}

// delete document
await postgres.<%= compNameCamelCase %>.delete({ where: { id } });

return document;
};

export default { list, create, get, update, del };
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
interface <%= compNamePascalCase %> {
readonly id: number;
readonly name: string | null;
// TODO: add more props
}

export { <%= compNamePascalCase %> };

0 comments on commit 87952b8

Please sign in to comment.