diff --git a/components/task/controllers/tasks_controller.ts b/components/task/controllers/tasks_controller.ts index d9a13ba..741c3a1 100644 --- a/components/task/controllers/tasks_controller.ts +++ b/components/task/controllers/tasks_controller.ts @@ -4,33 +4,47 @@ import { StatusCodes } from "http-status-codes"; import { TaskRepository } from "../public/repositories/task_repository"; import { TaskAdapter } from "../adapters/task_adapter"; import { TaskEntity } from "../public/entities/task_entity"; +import { TaskModel } from "../models/task_model"; +import { TaskMapper } from "../public/mappers/task_mapper"; export class TasksController { taskRepository = new TaskRepository(); + constructor() { + this.taskRepository + .setMapper(new TaskMapper()) + .setModel(TaskModel); + } + public addNewTask = async (req: Request, res: Response) => { - const taskEntity = await this.taskRepository.create({ + this.taskRepository.setCreateDto({ name: req.body.name, description: req.body.description }); + const taskEntity = await this.taskRepository.create(); + const json = new TaskAdapter(taskEntity).toJson(); return res.status(StatusCodes.CREATED).json(json); }; public getTasks = async (_req: Request, res: Response) => { - const taskEntities = await this.taskRepository.read({}); - const taskListJson = taskEntities.map((taskEntity: TaskEntity) => new TaskAdapter(taskEntity).toJson()); + this.taskRepository.setReadDto({}); + + const taskEntities = await this.taskRepository.read(); + const taskListJson = taskEntities && taskEntities.map((taskEntity: TaskEntity) => new TaskAdapter(taskEntity).toJson()); return res.status(StatusCodes.OK).json(taskListJson); }; public getTaskWithID = async (req: Request, res: Response) => { - const taskEntities = await this.taskRepository.read({ id: req.params.id }); + this.taskRepository.setReadDto({ id: req.params.id }); + + const taskEntities = await this.taskRepository.read(); let json = {}; - if (taskEntities.length > 0) { + if (taskEntities && taskEntities.length > 0) { json = new TaskAdapter(taskEntities[0]).toJson(); } @@ -38,22 +52,25 @@ export class TasksController { }; public updateTask = async (req: Request, res: Response) => { - const taskEntity = await this.taskRepository.update({ + this.taskRepository.setUpdateDto({ id: req.body.id, name: req.body.name, description: req.body.description }); + const taskEntity = await this.taskRepository.update(); const json = new TaskAdapter(taskEntity).toJson(); return res.status(StatusCodes.OK).json(json); }; public deleteTask = async (req: Request, res: Response) => { - await this.taskRepository.delete({ + this.taskRepository.setDeleteDto({ id: req.body.id }); + await this.taskRepository.delete(); + return res.status(StatusCodes.OK).json({}); }; } diff --git a/components/task/public/repositories/task_repository.ts b/components/task/public/repositories/task_repository.ts index 1fc9d1b..f9336c8 100644 --- a/components/task/public/repositories/task_repository.ts +++ b/components/task/public/repositories/task_repository.ts @@ -1,48 +1,5 @@ -import { TaskEntity } from "../entities/task_entity"; -import { CreateDto } from "../dtos/tasks/create_dto"; -import { ReadDto } from "../dtos/tasks/read_dto"; -import { UpdateDto } from "../dtos/tasks/update_dto"; -import { DeleteDto } from "../dtos/tasks/delete_dto"; -import { ITaskModelDocument, TaskModel } from "../../models/task_model"; -import { TaskMapper } from "../mappers/task_mapper"; +import { FractalRepository } from "../../../../public/repositories/fracatal_repository"; -export class TaskRepository { - async create(dto: CreateDto): Promise { - const task = await TaskModel.create({ - name: dto.name, - description: dto.description - }); - - return new TaskMapper().fromModel(task); - } - - async read(dto: ReadDto): Promise { - if (dto.id) { - const task = await TaskModel.findOne({ id: dto.id }); - - if (task !== undefined && task !== null && task.name) { - return [new TaskEntity(task.name, task.description)]; - } - - return []; - } - // Let us read and map to entity but in future this should be memoized - const tasks = await TaskModel.find({}); - const taskEntities = tasks.map((task: ITaskModelDocument) => new TaskMapper().fromModel(task)); - - return Promise.resolve(taskEntities); - } - - async update(dto: UpdateDto): Promise { - const updatedTask = await TaskModel.update(dto.id as string, { - name: dto.name, - description: dto.description - }); - - return new TaskMapper().fromModel(updatedTask); - } - - delete(dto: DeleteDto): void { - TaskModel.delete(dto.id as string); - }; +export class TaskRepository extends FractalRepository { + // add other methods } diff --git a/components/task/tests/public/respositories/task_respository.spec.ts b/components/task/tests/public/respositories/task_respository.spec.ts index c3b3f07..5281b98 100644 --- a/components/task/tests/public/respositories/task_respository.spec.ts +++ b/components/task/tests/public/respositories/task_respository.spec.ts @@ -4,6 +4,8 @@ import * as sinon from "sinon"; import { DataBaseMock } from "../../../../../tests/support/data_base_mock"; import { taskOne, taskTwo } from "../../factories/tasks/task_data"; import { TaskRepository } from "../../../public/repositories/task_repository"; +import { TaskMapper } from "../../../public/mappers/task_mapper"; +import { TaskModel } from "../../../../task/models/task_model"; describe("Task Repository", () => { const sandbox = sinon.createSandbox(); @@ -13,6 +15,10 @@ describe("Task Repository", () => { before(() => { modelMock = sandbox.stub(); new DataBaseMock(modelMock).setNosqlMock(); + + taskRepository + .setMapper(new TaskMapper()) + .setModel(TaskModel); }); describe("find()", () => { @@ -24,8 +30,9 @@ describe("Task Repository", () => { findOneMock.resolves(taskOne); - const results = await taskRepository.read({ id: taskOne._id }); - const result = results[0]; + taskRepository.setReadDto({ id: taskOne._id }); + const results = await taskRepository.read(); + const result = results && results[0]; expect(result).to.deep.equal({ name: taskOne.name, description: taskOne.description }); // expect(modelMock.calledWith({})).to.be.true; @@ -37,9 +44,10 @@ describe("Task Repository", () => { findMock.resolves([taskOne, taskTwo]); - const results = await taskRepository.read({}); + taskRepository.setReadDto({}); + const results = await taskRepository.read(); - expect(results.length).to.equal(2); + expect(results?.length).to.equal(2); // TODO: this might be flaky // expect(results[0]).to.deep.equal(taskOne); // expect(findMock.calledWith({})).to.be.true; @@ -51,9 +59,12 @@ describe("Task Repository", () => { findOneMock.resolves([]); - const results = await taskRepository.read({ id: "random_id" }); + taskRepository.setReadDto({ id: "random_id" }); + const results = await taskRepository.read(); + + console.log(results) - expect(results.length).to.eq(0); + expect(results?.length).to.eq(0); // expect(modelMock.calledWith({})).to.be.true; }); }); @@ -65,10 +76,11 @@ describe("Task Repository", () => { createMock.resolves(taskOne); - const result = await taskRepository.create({ + taskRepository.setCreateDto({ name: taskOne.name, description: taskOne.description }); + const result = await taskRepository.create(); expect(result).to.deep.equal(taskOne); }); @@ -77,11 +89,13 @@ describe("Task Repository", () => { const updateMock = modelMock.returns(Promise.resolve(taskTwo)); updateMock.resolves(taskTwo); - const result = await taskRepository.update({ + taskRepository.setUpdateDto({ id: taskOne._id, name: taskTwo.name, description: taskTwo.description - }); + }) + + const result = await taskRepository.update(); expect({ name: result.name, @@ -95,10 +109,12 @@ describe("Task Repository", () => { it("should delete a task", async () => { const deleteMock = modelMock.returns(Promise.resolve(undefined)); - deleteMock.resolves(undefined); - const result = await taskRepository.delete({ id: taskOne._id }); + deleteMock.resolves(null); + taskRepository.setDeleteDto({ id: taskOne._id }); + + const result = await taskRepository.delete(); - expect(result).to.equal(undefined); + expect(result).to.equal(null); }); // Tear down diff --git a/public/repositories/fracatal_repository.ts b/public/repositories/fracatal_repository.ts new file mode 100644 index 0000000..1539211 --- /dev/null +++ b/public/repositories/fracatal_repository.ts @@ -0,0 +1,94 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +export class FractalRepository { + private createDto: any; + private readDto: any; + private updateDto: any; + private deleteDto: any; + private mapper: any; + private model: any; + + constructor() { + this.createDto = {}; + this.readDto = {}; + this.updateDto = {}; + this.deleteDto = {}; + this.mapper = {}; + this.model = {}; + } + + setCreateDto(createDto: any): FractalRepository { + this.createDto = createDto; + return this; + } + + setReadDto(readDto: any): FractalRepository { + this.readDto = readDto; + return this; + } + + setUpdateDto(updateDto: any): FractalRepository { + this.updateDto = updateDto; + return this; + } + + setDeleteDto(deleteDto: any): FractalRepository { + this.deleteDto = deleteDto; + return this; + } + + setMapper(mapper: any): FractalRepository { + this.mapper = mapper; + return this; + } + + setModel(model: any): FractalRepository { + this.model = model; + return this; + } + + create = async (): Promise => { + const record = await this.model.create({ ...this.createDto }); + + return this.mapper.fromModel(record); + } + + read = async (): Promise => { + if (this.readDto.id !== undefined) { + const record = await this.model.findOne({ id: this.readDto.id }); + + return record._id || record.id ? [this.mapper.fromModel(record)] : []; + } + + const records = await this.model + .find({ ...this.readDto }); + + const entities = records && records.map( + (record: any) => this.mapper + .fromModel(record) + ); + + return entities ?? [] + }; + + update = async (): Promise => { + + const updatedRecord = await this.model + .update(this.updateDto.id as string, { + ...this.updateDto + }); + + return updatedRecord + ? this.mapper.fromModel(updatedRecord) + : null; + } + + delete = async (): Promise => { + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + /* eslint @typescript-eslint/no-unused-vars: 0 */ + const deletedRecord = await this.model.delete(this.deleteDto.id as string); + + return deletedRecord + ? this.mapper.fromModel(deletedRecord) + : null; + } +}