Skip to content

Commit

Permalink
feat: introduce base repository for basic crud
Browse files Browse the repository at this point in the history
  • Loading branch information
acellam committed Sep 19, 2024
1 parent acc04f9 commit a084c75
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 65 deletions.
31 changes: 24 additions & 7 deletions components/task/controllers/tasks_controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,73 @@ 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();
}

return res.status(StatusCodes.OK).json(json);
};

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({});
};
}
49 changes: 3 additions & 46 deletions components/task/public/repositories/task_repository.ts
Original file line number Diff line number Diff line change
@@ -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<TaskEntity> {
const task = await TaskModel.create({
name: dto.name,
description: dto.description
});

return new TaskMapper().fromModel(task);
}

async read(dto: ReadDto): Promise<TaskEntity[]> {
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<TaskEntity> {
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
}
40 changes: 28 additions & 12 deletions components/task/tests/public/respositories/task_respository.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -13,6 +15,10 @@ describe("Task Repository", () => {
before(() => {
modelMock = sandbox.stub();
new DataBaseMock(modelMock).setNosqlMock();

taskRepository
.setMapper(new TaskMapper())
.setModel(TaskModel);
});

describe("find()", () => {
Expand All @@ -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;
Expand All @@ -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;
Expand All @@ -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;
});
});
Expand All @@ -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);
});
Expand All @@ -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,
Expand All @@ -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
Expand Down
94 changes: 94 additions & 0 deletions public/repositories/fracatal_repository.ts
Original file line number Diff line number Diff line change
@@ -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<any> => {
const record = await this.model.create({ ...this.createDto });

return this.mapper.fromModel(record);
}

read = async (): Promise<object[] | never[] | undefined | any[]> => {
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<object | null | any> => {

const updatedRecord = await this.model
.update(this.updateDto.id as string, {
...this.updateDto
});

return updatedRecord
? this.mapper.fromModel(updatedRecord)
: null;
}

delete = async (): Promise<object | null | any> => {
// 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;
}
}

0 comments on commit a084c75

Please sign in to comment.