generic factory

This commit is contained in:
Julian Krauser 2025-04-12 13:02:43 +02:00
parent d28e029e33
commit 5e1708e505
12 changed files with 118 additions and 16 deletions

11
package-lock.json generated
View file

@ -20,6 +20,7 @@
"@types/express": "^4.17.17",
"@types/node": "^16.18.41",
"ts-node": "10.7.0",
"ts-transformer-keys": "^0.4.4",
"typescript": "^4.5.2"
}
},
@ -3039,6 +3040,16 @@
}
}
},
"node_modules/ts-transformer-keys": {
"version": "0.4.4",
"resolved": "https://registry.npmjs.org/ts-transformer-keys/-/ts-transformer-keys-0.4.4.tgz",
"integrity": "sha512-LrqgvaFvar01/5mbunRyeLTSIkqoC2xfcpL/90aDY6vR07DGyH+UaYGdIEsUudnlAw2Sr0pxFgdZvE0QIyI4qA==",
"dev": true,
"license": "MIT",
"peerDependencies": {
"typescript": ">=2.4.1"
}
},
"node_modules/tslib": {
"version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",

View file

@ -23,6 +23,7 @@
"@types/express": "^4.17.17",
"@types/node": "^16.18.41",
"ts-node": "10.7.0",
"ts-transformer-keys": "^0.4.4",
"typescript": "^4.5.2"
}
}

View file

@ -1,19 +1,26 @@
import { Request, Response } from "express";
import GenericService from "../services/GenericService";
import BaseEntity from "../entities/baseEntity";
import GenericFactory from "../factories/GenericFactory";
import { GenericViewModel } from "../viewmodels/GenericModel";
export default class GenericController<Service extends GenericService<Repository>, Repository extends BaseEntity> {
constructor(protected readonly service: Service) {}
export default class GenericController<
Service extends GenericService<Repository>,
Factory extends GenericFactory<Repository, ViewModel>,
Repository extends BaseEntity,
ViewModel extends GenericViewModel
> {
constructor(protected readonly service: Service, protected readonly factory: Factory) {}
async getAll(req: Request, res: Response): Promise<void> {
let data: Array<Repository> = await this.service.getAll();
res.json(data);
res.json(this.factory.mapArray(data));
}
async getById(req: Request, res: Response): Promise<void> {
let id: number = parseInt(req.params.id);
let id: string = req.params.id;
let data: Repository = await this.service.getById(id);
res.json(data);
res.json(this.factory.mapSingle(data));
}
async create(req: Request, res: Response): Promise<void> {
@ -27,7 +34,7 @@ export default class GenericController<Service extends GenericService<Repository
}
async delete(req: Request, res: Response): Promise<void> {
let id: number = parseInt(req.params.id);
let id: string = req.params.id;
await this.service.delete(id);
res.sendStatus(204);
}

View file

@ -2,10 +2,12 @@ import { Request, Response } from "express";
import User from "../entities/user";
import UserService from "../services/userService";
import GenericController from "./GenericController";
import { UserViewModel } from "../viewmodels/userModel";
import UserFactory from "../factories/userFactory";
export default class UserController extends GenericController<UserService, User> {
export default class UserController extends GenericController<UserService, UserFactory, User, UserViewModel> {
constructor() {
super(new UserService());
super(new UserService(), new UserFactory());
}
// overwrite defined generic controller function

View file

@ -1,6 +1,6 @@
import { Entity, PrimaryGeneratedColumn } from "typeorm";
import { PrimaryColumn } from "typeorm";
export default abstract class BaseEntity {
@PrimaryGeneratedColumn("increment")
id: number;
@PrimaryColumn({ generated: "uuid" })
id: string;
}

View file

@ -0,0 +1,25 @@
import { keys } from "ts-transformer-keys";
import BaseEntity from "../entities/baseEntity";
import { GenericViewModel } from "../viewmodels/GenericModel";
export default interface GenericFactory<Repository extends BaseEntity, ViewModel extends GenericViewModel> {
mapSingle(row: Repository): ViewModel;
mapArray(rows: Repository[]): ViewModel[];
}
// export default class GenericFactory<Repository extends BaseEntity> {
// constructor() {}
// mapSingle<T extends GenericViewModel>(row: Repository): T {
// let keysOfT = keys<T>();
// return keysOfT.reduce((acc, key) => {
// acc[key] = (row as any)?.[key];
// return acc;
// }, {} as T);
// }
// mapArray<T extends GenericViewModel>(rows: Repository[]): T[] {
// return rows.map((r) => this.mapSingle<T>(r));
// }
// }

View file

@ -0,0 +1,20 @@
import User from "../entities/user";
import { UserViewModel } from "../viewmodels/userModel";
import GenericFactory from "./GenericFactory";
export default class UserFactory implements GenericFactory<User, UserViewModel> {
mapSingle(row: User): UserViewModel {
return {
id: row.id,
firstname: row.firstname,
};
}
mapArray(rows: User[]): UserViewModel[] {
return rows.map((r) => this.mapSingle(r));
}
mapWithX(row: User): Array<{ id: string }> {
return [];
}
}

View file

@ -2,11 +2,15 @@ import express from "express";
import GenericController from "../controller/GenericController";
import GenericService from "../services/GenericService";
import BaseEntity from "../entities/baseEntity";
import { GenericViewModel } from "../viewmodels/GenericModel";
import GenericFactory from "../factories/GenericFactory";
export default class GenericRouter<
Controller extends GenericController<Service, Repository>,
Controller extends GenericController<Service, Factory, Repository, GenericViewModel>,
Service extends GenericService<Repository>,
Repository extends BaseEntity
Factory extends GenericFactory<Repository, ViewModel>,
Repository extends BaseEntity,
ViewModel extends GenericViewModel
> {
public router = express.Router({ mergeParams: true });
constructor(protected controller: Controller) {

View file

@ -1,9 +1,11 @@
import UserController from "../controller/userController";
import User from "../entities/user";
import UserFactory from "../factories/userFactory";
import UserService from "../services/userService";
import { UserViewModel } from "../viewmodels/userModel";
import GenericRouter from "./GenericRouter";
export default class UserRouter extends GenericRouter<UserController, UserService, User> {
export default class UserRouter extends GenericRouter<UserController, UserService, UserFactory, User, UserViewModel> {
constructor() {
super(new UserController());
// extend generic routes by specific routes

View file

@ -10,7 +10,7 @@ export default class GenericService<Repository extends BaseEntity> {
return await dataSource.getRepository(this.entity).createQueryBuilder().getMany();
}
async getById(rowId: number): Promise<Repository> {
async getById(rowId: string): Promise<Repository> {
return await dataSource.getRepository(this.entity).createQueryBuilder().where({ id: rowId }).getOneOrFail();
}
@ -24,7 +24,7 @@ export default class GenericService<Repository extends BaseEntity> {
return await dataSource.createQueryBuilder().update(this.entity).set(value).execute();
}
async delete(rowId: number): Promise<DeleteResult> {
async delete(rowId: string): Promise<DeleteResult> {
return await dataSource.createQueryBuilder().delete().from(this.entity).where({ id: rowId }).execute();
}
}

View file

@ -0,0 +1,13 @@
import BaseEntity from "../entities/baseEntity";
interface GenericViewModel extends BaseEntity {
id: string;
}
interface GenericCreateModel {}
interface GenericUpdateModel extends BaseEntity {
id: string;
}
export { GenericViewModel, GenericCreateModel, GenericUpdateModel };

View file

@ -0,0 +1,17 @@
import { GenericCreateModel, GenericUpdateModel, GenericViewModel } from "./GenericModel";
interface UserViewModel extends GenericViewModel {
id: string;
firstname: string;
}
interface UserCreateModel extends GenericCreateModel {
firstname: string;
}
interface UserUpdateModel extends GenericUpdateModel {
id: string;
firstname: string;
}
export { UserViewModel, UserCreateModel, UserUpdateModel };