Skip to content

Commit c3d7697

Browse files
committed
feat(generators): create new app :with-mongo
1 parent cbb30cf commit c3d7697

File tree

7 files changed

+306
-0
lines changed

7 files changed

+306
-0
lines changed

generators/with-mongo/index.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
const Generator = require('yeoman-generator');
2+
const chalk = require('chalk');
3+
const yosay = require('yosay');
4+
const changeCase = require('change-case');
5+
const pluralize = require('pluralize');
6+
7+
const pkg = require('../../package.json');
8+
9+
module.exports = class extends Generator {
10+
async prompting() {
11+
this.log(yosay(`Welcome to the ${chalk.red(pkg.name)} generator!`));
12+
13+
const prompts = [
14+
{
15+
type: 'input',
16+
name: 'compName',
17+
message: 'Name of the new component (singular)?',
18+
default: 'thing',
19+
},
20+
];
21+
22+
return this.prompt(prompts).then((props) => {
23+
const compNameParamCase = changeCase.paramCase(props.compName);
24+
const compNamePascalCase = changeCase.pascalCase(props.compName);
25+
26+
this.props = {
27+
...props,
28+
compNameParamCase,
29+
compNamePascalCase,
30+
compNameParamCasePlural: pluralize(compNameParamCase),
31+
};
32+
});
33+
}
34+
35+
writing() {
36+
this.fs.copyTpl(
37+
[this.templatePath('**/*'), this.templatePath('**/.*')],
38+
this.destinationPath('src/components'),
39+
this.props,
40+
);
41+
}
42+
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
const ENTITY = '<%= compNameParamCase %>';
2+
const RESOURCE = '<%= compNameParamCasePlural %>';
3+
4+
export { ENTITY, RESOURCE };
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
import { Request, Response, NextFunction } from 'express';
2+
import { StatusCodes } from 'http-status-codes';
3+
import { HttpError } from '@boringcodes/utils/error';
4+
5+
import { <%= compNamePascalCase %> } from './types';
6+
import { ENTITY } from './constants';
7+
import repository from './repository';
8+
9+
interface MyRequest extends Request {
10+
readonly [ENTITY]: Required<<%= compNamePascalCase %>>;
11+
}
12+
13+
const getById = async (
14+
req: Request,
15+
_: Response,
16+
next: NextFunction,
17+
): Promise<void> => {
18+
try {
19+
const { id = '' } = req.params;
20+
if (id === '') {
21+
throw new HttpError(StatusCodes.BAD_REQUEST, 'Invalid resource Id');
22+
}
23+
24+
try {
25+
// get object by id
26+
const object = await repository.get(id);
27+
Object.assign(req, { [ENTITY]: object });
28+
29+
next();
30+
} catch (err) {
31+
throw new HttpError(StatusCodes.NOT_FOUND, 'Resource not found');
32+
}
33+
} catch (err) {
34+
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
35+
}
36+
};
37+
38+
const list = async (
39+
_: Request,
40+
res: Response,
41+
next: NextFunction,
42+
): Promise<void> => {
43+
try {
44+
// list objects
45+
const objects = await repository.list();
46+
47+
res.send(objects);
48+
} catch (err) {
49+
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
50+
}
51+
};
52+
53+
const create = async (
54+
req: Request,
55+
res: Response,
56+
next: NextFunction,
57+
): Promise<void> => {
58+
try {
59+
// create object
60+
const object = await repository.create(req.body);
61+
62+
res.send(object);
63+
} catch (err) {
64+
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
65+
}
66+
};
67+
68+
const get = (req: Request, res: Response, next: NextFunction): void => {
69+
try {
70+
// get object
71+
res.send((req as MyRequest)[ENTITY]);
72+
} catch (err) {
73+
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
74+
}
75+
};
76+
77+
const updatePartial = async (
78+
req: Request,
79+
res: Response,
80+
next: NextFunction,
81+
): Promise<void> => {
82+
try {
83+
console.log((req as MyRequest)[ENTITY]);
84+
// update partial object
85+
const object = await repository.updatePartial(
86+
(req as MyRequest)[ENTITY].id,
87+
req.body,
88+
);
89+
90+
res.send(object);
91+
} catch (err) {
92+
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
93+
}
94+
};
95+
96+
const update = async (
97+
req: Request,
98+
res: Response,
99+
next: NextFunction,
100+
): Promise<void> => {
101+
try {
102+
// update object
103+
const object = await repository.update(
104+
(req as MyRequest)[ENTITY].id,
105+
req.body,
106+
);
107+
108+
res.send(object);
109+
} catch (err) {
110+
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
111+
}
112+
};
113+
114+
const del = async (
115+
req: Request,
116+
res: Response,
117+
next: NextFunction,
118+
): Promise<void> => {
119+
try {
120+
// delete object
121+
const object = await repository.del((req as MyRequest)[ENTITY].id);
122+
123+
res.send(object);
124+
} catch (err) {
125+
next(new HttpError(err.code ?? StatusCodes.INTERNAL_SERVER_ERROR, err));
126+
}
127+
};
128+
129+
export default { getById, list, create, get, updatePartial, update, del };
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { Router } from 'express';
2+
3+
import { RouteOptions } from '../types';
4+
import { RESOURCE } from './constants';
5+
import controller from './controller';
6+
7+
const path = `/${RESOURCE}`;
8+
9+
const routes = (_: RouteOptions): Router => {
10+
const router = Router();
11+
12+
router.param('id', controller.getById);
13+
14+
router.route('/').get(controller.list).post(controller.create);
15+
16+
router
17+
.route('/:id')
18+
.get(controller.get)
19+
.patch(controller.updatePartial)
20+
.put(controller.update)
21+
.delete(controller.del);
22+
23+
return router;
24+
};
25+
26+
export default { path, routes };
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import mongoose, {
2+
Schema,
3+
Document as MongooseDocument,
4+
Model as MongooseModel,
5+
} from 'mongoose';
6+
7+
import { <%= compNamePascalCase %> } from './types';
8+
import { ENTITY } from './constants';
9+
10+
interface Document extends MongooseDocument, Omit<<%= compNamePascalCase %>, 'id'> {}
11+
interface Model extends MongooseModel<Document> {}
12+
13+
const schema = new Schema<Document>({
14+
name: String,
15+
});
16+
17+
export default mongoose.model<Document, Model>(ENTITY, schema);
18+
export { Model, Document };
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
import { MyError } from '@boringcodes/utils/error';
2+
3+
import { <%= compNamePascalCase %> } from './types';
4+
import Model, { Document } from './model';
5+
6+
const transform = (document: Document): <%= compNamePascalCase %> => {
7+
const { _id, ...restObject } = document.toObject({
8+
virtuals: true,
9+
versionKey: false,
10+
});
11+
12+
return restObject;
13+
};
14+
15+
const list = async (): Promise<<%= compNamePascalCase %>[]> => {
16+
// list documents
17+
const documents = await Model.find();
18+
19+
return documents.map(transform);
20+
};
21+
22+
const create = async (object: Omit<<%= compNamePascalCase %>, 'id'>): Promise<<%= compNamePascalCase %>> => {
23+
// create document
24+
const document = new Model(object);
25+
await document.save();
26+
27+
return transform(document);
28+
};
29+
30+
const get = async (id: string): Promise<<%= compNamePascalCase %>> => {
31+
// get document
32+
const document = await Model.findById(id).exec();
33+
if (document === null) {
34+
throw new MyError('Document not found');
35+
}
36+
37+
return transform(document);
38+
};
39+
40+
const updatePartial = async (id: string, object: <%= compNamePascalCase %>): Promise<<%= compNamePascalCase %>> => {
41+
// get document
42+
const document = await Model.findById(id).exec();
43+
if (document === null) {
44+
throw new MyError('Document not found');
45+
}
46+
47+
// update partial document
48+
document.set(object);
49+
await document.save();
50+
51+
return transform(document);
52+
};
53+
54+
const update = async (id: string, object: <%= compNamePascalCase %>): Promise<<%= compNamePascalCase %>> => {
55+
// get document
56+
const document = await Model.findById(id).exec();
57+
if (document === null) {
58+
throw new MyError('Document not found');
59+
}
60+
61+
// update document
62+
document.overwrite(object);
63+
await document.save();
64+
65+
return transform(document);
66+
};
67+
68+
const del = async (id: string): Promise<<%= compNamePascalCase %>> => {
69+
// get document
70+
const document = await Model.findById(id).exec();
71+
if (document === null) {
72+
throw new MyError('Document not found');
73+
}
74+
75+
// delete document
76+
await Model.deleteOne({ _id: id }).exec();
77+
78+
return transform(document);
79+
};
80+
81+
export default { list, create, get, updatePartial, update, del };
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
interface <%= compNamePascalCase %> {
2+
readonly id?: string;
3+
readonly name?: string;
4+
}
5+
6+
export { <%= compNamePascalCase %> };

0 commit comments

Comments
 (0)