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
|
.yarn/install-state.gz
|
||||||
.pnp.*
|
.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