generic structure
This commit is contained in:
parent
6133c0a39f
commit
d28e029e33
16 changed files with 3716 additions and 0 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
@ -130,3 +130,4 @@ dist
|
|||
.yarn/install-state.gz
|
||||
.pnp.*
|
||||
|
||||
db.sqlite
|
5
.prettierrc
Normal file
5
.prettierrc
Normal file
|
@ -0,0 +1,5 @@
|
|||
{
|
||||
"trailingComma": "es5",
|
||||
"tabWidth": 2,
|
||||
"printWidth": 120
|
||||
}
|
3478
package-lock.json
generated
Normal file
3478
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
28
package.json
Normal file
28
package.json
Normal file
|
@ -0,0 +1,28 @@
|
|||
{
|
||||
"name": "express-template-structure",
|
||||
"version": "1.0.0",
|
||||
"main": "dist/index.js",
|
||||
"scripts": {
|
||||
"typeorm": "typeorm-ts-node-commonjs",
|
||||
"build": "tsc",
|
||||
"start": "node .",
|
||||
"dev": "npm run build && set NODE_ENV=development && npm run start"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"description": "",
|
||||
"dependencies": {
|
||||
"cors": "^2.8.5",
|
||||
"express": "^5.0.1",
|
||||
"reflect-metadata": "^0.2.2",
|
||||
"sqlite3": "^5.1.7",
|
||||
"typeorm": "^0.3.20"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/cors": "^2.8.14",
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/node": "^16.18.41",
|
||||
"ts-node": "10.7.0",
|
||||
"typescript": "^4.5.2"
|
||||
}
|
||||
}
|
34
src/controller/GenericController.ts
Normal file
34
src/controller/GenericController.ts
Normal file
|
@ -0,0 +1,34 @@
|
|||
import { Request, Response } from "express";
|
||||
import GenericService from "../services/GenericService";
|
||||
import BaseEntity from "../entities/baseEntity";
|
||||
|
||||
export default class GenericController<Service extends GenericService<Repository>, Repository extends BaseEntity> {
|
||||
constructor(protected readonly service: Service) {}
|
||||
|
||||
async getAll(req: Request, res: Response): Promise<void> {
|
||||
let data: Array<Repository> = await this.service.getAll();
|
||||
res.json(data);
|
||||
}
|
||||
|
||||
async getById(req: Request, res: Response): Promise<void> {
|
||||
let id: number = parseInt(req.params.id);
|
||||
let data: Repository = await this.service.getById(id);
|
||||
res.json(data);
|
||||
}
|
||||
|
||||
async create(req: Request, res: Response): Promise<void> {
|
||||
let insert = await this.service.insert(req.body);
|
||||
res.json(insert.identifiers);
|
||||
}
|
||||
|
||||
async update(req: Request, res: Response): Promise<void> {
|
||||
let update = await this.service.insert(req.body);
|
||||
res.json(update.identifiers);
|
||||
}
|
||||
|
||||
async delete(req: Request, res: Response): Promise<void> {
|
||||
let id: number = parseInt(req.params.id);
|
||||
await this.service.delete(id);
|
||||
res.sendStatus(204);
|
||||
}
|
||||
}
|
21
src/controller/userController.ts
Normal file
21
src/controller/userController.ts
Normal file
|
@ -0,0 +1,21 @@
|
|||
import { Request, Response } from "express";
|
||||
import User from "../entities/user";
|
||||
import UserService from "../services/userService";
|
||||
import GenericController from "./GenericController";
|
||||
|
||||
export default class UserController extends GenericController<UserService, User> {
|
||||
constructor() {
|
||||
super(new UserService());
|
||||
}
|
||||
|
||||
// overwrite defined generic controller function
|
||||
async getById(req: Request, res: Response): Promise<void> {
|
||||
res.send("overwritten getById");
|
||||
}
|
||||
|
||||
// extend generic controller by specific function
|
||||
async getUserByFirstname(req: Request, res: Response): Promise<void> {
|
||||
let data: Array<User> = await this.service.getUsersByFirstname(req.params.firstname);
|
||||
res.json(data);
|
||||
}
|
||||
}
|
14
src/data-source.ts
Normal file
14
src/data-source.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import "dotenv/config";
|
||||
import "reflect-metadata";
|
||||
import { DataSource } from "typeorm";
|
||||
import User from "./entities/user";
|
||||
|
||||
const dataSource = new DataSource({
|
||||
type: "sqlite",
|
||||
database: "db.sqlite",
|
||||
synchronize: true,
|
||||
logging: true,
|
||||
entities: [User],
|
||||
});
|
||||
|
||||
export { dataSource };
|
6
src/entities/baseEntity.ts
Normal file
6
src/entities/baseEntity.ts
Normal file
|
@ -0,0 +1,6 @@
|
|||
import { Entity, PrimaryGeneratedColumn } from "typeorm";
|
||||
|
||||
export default abstract class BaseEntity {
|
||||
@PrimaryGeneratedColumn("increment")
|
||||
id: number;
|
||||
}
|
8
src/entities/user.ts
Normal file
8
src/entities/user.ts
Normal file
|
@ -0,0 +1,8 @@
|
|||
import { Column, Entity } from "typeorm";
|
||||
import BaseEntity from "./baseEntity";
|
||||
|
||||
@Entity()
|
||||
export default class User extends BaseEntity {
|
||||
@Column({ type: "varchar", length: 255 })
|
||||
firstname: string;
|
||||
}
|
12
src/index.ts
Normal file
12
src/index.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import "dotenv/config";
|
||||
import express from "express";
|
||||
import { dataSource } from "./data-source";
|
||||
|
||||
dataSource.initialize();
|
||||
|
||||
const app = express();
|
||||
import router from "./routes/index";
|
||||
router(app);
|
||||
app.listen(5000, () => {
|
||||
console.log(`listening on *:5000`);
|
||||
});
|
16
src/routes/GenericRouter.ts
Normal file
16
src/routes/GenericRouter.ts
Normal file
|
@ -0,0 +1,16 @@
|
|||
import express from "express";
|
||||
import GenericController from "../controller/GenericController";
|
||||
import GenericService from "../services/GenericService";
|
||||
import BaseEntity from "../entities/baseEntity";
|
||||
|
||||
export default class GenericRouter<
|
||||
Controller extends GenericController<Service, Repository>,
|
||||
Service extends GenericService<Repository>,
|
||||
Repository extends BaseEntity
|
||||
> {
|
||||
public router = express.Router({ mergeParams: true });
|
||||
constructor(protected controller: Controller) {
|
||||
this.router.get("/", (req, res) => this.controller.getAll(req, res));
|
||||
this.router.get("/:id", (req, res) => this.controller.getById(req, res));
|
||||
}
|
||||
}
|
18
src/routes/index.ts
Normal file
18
src/routes/index.ts
Normal file
|
@ -0,0 +1,18 @@
|
|||
import express from "express";
|
||||
import type { Express } from "express";
|
||||
import cors from "cors";
|
||||
import UserRouter from "./userRouter";
|
||||
|
||||
export default (app: Express) => {
|
||||
app.set("query parser", "extended");
|
||||
app.use(express.json());
|
||||
app.use(
|
||||
express.urlencoded({
|
||||
extended: true,
|
||||
})
|
||||
);
|
||||
app.use(cors());
|
||||
app.options("*path", cors());
|
||||
|
||||
app.use("/user", new UserRouter().router);
|
||||
};
|
12
src/routes/userRouter.ts
Normal file
12
src/routes/userRouter.ts
Normal file
|
@ -0,0 +1,12 @@
|
|||
import UserController from "../controller/userController";
|
||||
import User from "../entities/user";
|
||||
import UserService from "../services/userService";
|
||||
import GenericRouter from "./GenericRouter";
|
||||
|
||||
export default class UserRouter extends GenericRouter<UserController, UserService, User> {
|
||||
constructor() {
|
||||
super(new UserController());
|
||||
// extend generic routes by specific routes
|
||||
this.router.get("/name/:firstname", (req, res) => this.controller.getUserByFirstname(req, res));
|
||||
}
|
||||
}
|
30
src/services/GenericService.ts
Normal file
30
src/services/GenericService.ts
Normal file
|
@ -0,0 +1,30 @@
|
|||
import { DeleteResult, EntityTarget, InsertResult, UpdateResult } from "typeorm";
|
||||
import { dataSource } from "../data-source";
|
||||
import BaseEntity from "../entities/baseEntity";
|
||||
import { QueryDeepPartialEntity } from "typeorm/query-builder/QueryPartialEntity";
|
||||
|
||||
export default class GenericService<Repository extends BaseEntity> {
|
||||
constructor(protected readonly entity: EntityTarget<Repository>) {}
|
||||
|
||||
async getAll(): Promise<Repository[]> {
|
||||
return await dataSource.getRepository(this.entity).createQueryBuilder().getMany();
|
||||
}
|
||||
|
||||
async getById(rowId: number): Promise<Repository> {
|
||||
return await dataSource.getRepository(this.entity).createQueryBuilder().where({ id: rowId }).getOneOrFail();
|
||||
}
|
||||
|
||||
async insert(
|
||||
value: QueryDeepPartialEntity<Repository> | QueryDeepPartialEntity<Repository>[]
|
||||
): Promise<InsertResult> {
|
||||
return await dataSource.createQueryBuilder().insert().into(this.entity).values(value).execute();
|
||||
}
|
||||
|
||||
async update(value: QueryDeepPartialEntity<Repository>): Promise<UpdateResult> {
|
||||
return await dataSource.createQueryBuilder().update(this.entity).set(value).execute();
|
||||
}
|
||||
|
||||
async delete(rowId: number): Promise<DeleteResult> {
|
||||
return await dataSource.createQueryBuilder().delete().from(this.entity).where({ id: rowId }).execute();
|
||||
}
|
||||
}
|
14
src/services/userService.ts
Normal file
14
src/services/userService.ts
Normal file
|
@ -0,0 +1,14 @@
|
|||
import { dataSource } from "../data-source";
|
||||
import User from "../entities/user";
|
||||
import GenericService from "./GenericService";
|
||||
|
||||
export default class UserService extends GenericService<User> {
|
||||
constructor() {
|
||||
super(User);
|
||||
}
|
||||
|
||||
// extend generic service by specific function
|
||||
async getUsersByFirstname(firstname: string): Promise<User[]> {
|
||||
return await dataSource.getRepository(User).createQueryBuilder().where({ firstname }).getMany();
|
||||
}
|
||||
}
|
19
tsconfig.json
Normal file
19
tsconfig.json
Normal file
|
@ -0,0 +1,19 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"emitDecoratorMetadata": true,
|
||||
"experimentalDecorators": true,
|
||||
"module": "commonjs",
|
||||
"esModuleInterop": true,
|
||||
"target": "esnext",
|
||||
"noImplicitAny": true,
|
||||
"skipLibCheck": true,
|
||||
"moduleResolution": "node",
|
||||
"sourceMap": true,
|
||||
"outDir": "dist",
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"*": ["node_modules/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
Loading…
Reference in a new issue