From 437bee2eeb7abae3ce4c6731a07172f6d445d139 Mon Sep 17 00:00:00 2001 From: Matheus Sanchez Date: Wed, 31 Jan 2024 15:04:53 -0300 Subject: [PATCH] get project by tag use case --- .../in-memory-db/inMemoryProjectRepository.ts | 8 ++ .../prisma/prisma-project-repository.ts | 4 + src/repositories/project-repository.ts | 1 + src/use-cases/getProjetsByTagsUseCase.spec.ts | 114 ++++++++++++++++++ src/use-cases/getProjetsByTagsUseCase.ts | 32 +++++ 5 files changed, 159 insertions(+) create mode 100644 src/use-cases/getProjetsByTagsUseCase.spec.ts create mode 100644 src/use-cases/getProjetsByTagsUseCase.ts diff --git a/src/repositories/in-memory-db/inMemoryProjectRepository.ts b/src/repositories/in-memory-db/inMemoryProjectRepository.ts index 3472af4..a83a1b4 100644 --- a/src/repositories/in-memory-db/inMemoryProjectRepository.ts +++ b/src/repositories/in-memory-db/inMemoryProjectRepository.ts @@ -40,4 +40,12 @@ export class InMemoryProjectRepository implements ProjectRepository { } return project } + + async fetchProjectByTags(tags: string[]): Promise { + const projects = this.dbProject.filter((project) => + project.tags.some((tag) => tags.includes(tag)), + ) + + return projects + } } diff --git a/src/repositories/prisma/prisma-project-repository.ts b/src/repositories/prisma/prisma-project-repository.ts index b7d759e..ec81085 100644 --- a/src/repositories/prisma/prisma-project-repository.ts +++ b/src/repositories/prisma/prisma-project-repository.ts @@ -30,4 +30,8 @@ export class PrismaProjectRepository implements ProjectRepository { return project } + + async fetchProjectByTags(tags: string[]): Promise { + throw new Error('Method not implemented.') + } } diff --git a/src/repositories/project-repository.ts b/src/repositories/project-repository.ts index cbee4d3..aed277d 100644 --- a/src/repositories/project-repository.ts +++ b/src/repositories/project-repository.ts @@ -4,4 +4,5 @@ export interface ProjectRepository { create(data: Prisma.ProjectUncheckedCreateInput): Promise fetchProjectsByUserId(userId: string): Promise fetchProjectById(projectId: string): Promise + fetchProjectByTags(tags: string[]): Promise } diff --git a/src/use-cases/getProjetsByTagsUseCase.spec.ts b/src/use-cases/getProjetsByTagsUseCase.spec.ts new file mode 100644 index 0000000..ee7f1f2 --- /dev/null +++ b/src/use-cases/getProjetsByTagsUseCase.spec.ts @@ -0,0 +1,114 @@ +import { expect, describe, it, beforeEach } from 'vitest' + +import { InMemoryProjectRepository } from '../repositories/in-memory-db/inMemoryProjectRepository' + +import { ProjectRepository } from '../repositories/project-repository' +import { GetProjectsByTagsUseCase } from './getProjetsByTagsUseCase' + +let projectRepository: ProjectRepository +let getProjectsByTagsUseCase: GetProjectsByTagsUseCase + +describe('Get Project By Tags', () => { + beforeEach(() => { + projectRepository = new InMemoryProjectRepository() + getProjectsByTagsUseCase = new GetProjectsByTagsUseCase(projectRepository) + }) + + it('should be able get projects that include a tag', async () => { + await projectRepository.create({ + title: 'React Typescript 1', + description: 'Best Project', + tags: ['react', 'node'], + link: 'https://github.com/luiseduardo3/nodets-petcanil', + user_id: 'user_id', + }) + + await projectRepository.create({ + title: 'React Typescript 2', + description: 'Best Project 2', + tags: ['react', 'node', 'typescript'], + link: 'https://github.com/luiseduardo3/nodets-petcanil', + user_id: 'user_id', + }) + + const { projects } = await getProjectsByTagsUseCase.execute({ + projectTags: ['typescript'], + }) + + expect(projects).toHaveLength(1) + expect(projects[0]).toEqual( + expect.objectContaining({ title: 'React Typescript 2' }), + ) + + expect(projects[0]).toEqual( + expect.objectContaining({ tags: ['react', 'node', 'typescript'] }), + ) + }) + + it('Should be able to get projects that include some tags without duplicating the results.', async () => { + await projectRepository.create({ + title: 'React Typescript 1', + description: 'Best Project', + tags: ['react', 'node'], + link: 'https://github.com/luiseduardo3/nodets-petcanil', + user_id: 'user_id', + }) + + await projectRepository.create({ + title: 'React Typescript 2', + description: 'Best Project 2', + tags: ['react', 'node', 'typescript'], + link: 'https://github.com/luiseduardo3/nodets-petcanil', + user_id: 'user_id', + }) + + await projectRepository.create({ + title: 'React Typescript 3', + description: 'Best Project 2', + tags: ['react', 'node'], + link: 'https://github.com/luiseduardo3/nodets-petcanil', + user_id: 'user_id', + }) + + const { projects } = await getProjectsByTagsUseCase.execute({ + projectTags: ['react', 'node'], + }) + + expect(projects).toHaveLength(3) + expect(projects[0]).toEqual( + expect.objectContaining({ title: 'React Typescript 1' }), + ) + + expect(projects[1]).toEqual( + expect.objectContaining({ title: 'React Typescript 2' }), + ) + + expect(projects[2]).toEqual( + expect.objectContaining({ title: 'React Typescript 3' }), + ) + }) + + it('should not be able to get a project if the tag was not registered', async () => { + await projectRepository.create({ + title: 'React Typescript 1', + description: 'Best Project', + tags: ['tag'], + link: 'https://github.com/luiseduardo3/nodets-petcanil', + user_id: 'user_id', + }) + + await projectRepository.create({ + title: 'React Typescript 2', + description: 'Best Project 2', + tags: ['tag'], + link: 'https://github.com/luiseduardo3/nodets-petcanil', + user_id: 'user_id', + }) + + const { projects } = await getProjectsByTagsUseCase.execute({ + projectTags: ['react', 'node'], + }) + + expect(projects).toHaveLength(0) + }) +}) diff --git a/src/use-cases/getProjetsByTagsUseCase.ts b/src/use-cases/getProjetsByTagsUseCase.ts new file mode 100644 index 0000000..b924b11 --- /dev/null +++ b/src/use-cases/getProjetsByTagsUseCase.ts @@ -0,0 +1,32 @@ +import { Project } from '@prisma/client' + +import { ProjectRepository } from '../repositories/project-repository' + +import { ResourceNotFoundError } from './errors/ResourceNotFoundError' + +interface GetProjectsByTagsRequest { + projectTags: string[] +} + +interface GetProjectsByTagsResponse { + projects: Project[] +} + +export class GetProjectsByTagsUseCase { + constructor(private projectRepository: ProjectRepository) {} + + async execute({ + projectTags, + }: GetProjectsByTagsRequest): Promise { + const projects = + await this.projectRepository.fetchProjectByTags(projectTags) + + if (!projects) { + throw new ResourceNotFoundError() + } + + return { + projects, + } + } +}