From e4d33e975c68f1474d3b2d3d79efe150554c41e7 Mon Sep 17 00:00:00 2001 From: Matheus Sanchez Date: Wed, 31 Jan 2024 13:37:55 -0300 Subject: [PATCH] Fix create project use case to accept tags as an string array --- .../migration.sql | 9 +++ prisma/schema.prisma | 2 +- src/controller/project/getProjectById.spec.ts | 2 +- .../project/getProjectByTags.spec.ts | 69 ------------------ src/controller/project/getProjectByTags.ts | 29 -------- .../project/getProjectsByUserId.spec.ts | 2 +- src/controller/project/routes.ts | 2 - .../in-memory-db/inMemoryProjectRepository.ts | 12 +--- src/repositories/project-repository.ts | 1 - src/use-cases/createProjectUseCase.spec.ts | 5 +- src/use-cases/createProjectUseCase.ts | 4 +- src/use-cases/getProjectsByIdUseCase.spec.ts | 3 +- .../getProjectsByTagsUseCase.spec.ts | 72 ------------------- src/use-cases/getProjectsByTagsUseCase.ts | 31 -------- .../getProjectsByUserIdUseCase.spec.ts | 4 +- 15 files changed, 22 insertions(+), 225 deletions(-) create mode 100644 prisma/migrations/20240131154951_add_tags_as_array/migration.sql delete mode 100644 src/controller/project/getProjectByTags.spec.ts delete mode 100644 src/controller/project/getProjectByTags.ts delete mode 100644 src/use-cases/getProjectsByTagsUseCase.spec.ts delete mode 100644 src/use-cases/getProjectsByTagsUseCase.ts diff --git a/prisma/migrations/20240131154951_add_tags_as_array/migration.sql b/prisma/migrations/20240131154951_add_tags_as_array/migration.sql new file mode 100644 index 0000000..0aad893 --- /dev/null +++ b/prisma/migrations/20240131154951_add_tags_as_array/migration.sql @@ -0,0 +1,9 @@ +/* + Warnings: + + - The `tags` column on the `Project` table would be dropped and recreated. This will lead to data loss if there is data in the column. + +*/ +-- AlterTable +ALTER TABLE "Project" DROP COLUMN "tags", +ADD COLUMN "tags" TEXT[]; diff --git a/prisma/schema.prisma b/prisma/schema.prisma index 436a3b6..4d548a7 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -23,7 +23,7 @@ model User { model Project { id String @id @default(uuid()) title String - tags String + tags String[] link String description String created_at DateTime @default(now()) diff --git a/src/controller/project/getProjectById.spec.ts b/src/controller/project/getProjectById.spec.ts index 9e1fa17..1191e05 100644 --- a/src/controller/project/getProjectById.spec.ts +++ b/src/controller/project/getProjectById.spec.ts @@ -26,7 +26,7 @@ describe('Get Projets By ID E2E', () => { it('should be able to get a project by ID', async () => { const description = 'ReactProject' const link = 'www.google.com.br' - const tags = 'React' + const tags = ['react', 'node'] const title = 'ReactProject' const newUser = await userRepository.create({ diff --git a/src/controller/project/getProjectByTags.spec.ts b/src/controller/project/getProjectByTags.spec.ts deleted file mode 100644 index 17d48f0..0000000 --- a/src/controller/project/getProjectByTags.spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { ProjectRepository } from "../../repositories/project-repository"; -import { UserRepository } from "../../repositories/user-repository"; -import { afterAll, beforeAll, describe, expect, it } from "vitest"; -import request from 'supertest' - -import { PrismaProjectRepository } from "../../repositories/prisma/prisma-project-repository"; -import { PrismaUsersRepository } from "../../repositories/prisma/prisma-users-repository"; -import { app } from "../../app"; - -let projectRepository: ProjectRepository -let userRepository: UserRepository - -describe('Get Projects By Tags E2E', () => { - beforeAll(async () => { - projectRepository = new PrismaProjectRepository() - userRepository = new PrismaUsersRepository() - - await app.ready() - }) - - afterAll(async () => { - await app.close() - }) - - it('should be able to get a project by Tags', async () => { - const newUser = await userRepository.create({ - email: 'john_doe@email.com', - name: 'John', - surname: 'Doe', - password_hash: 'password', - }) - - await projectRepository.create({ - title: 'Projeto 1', - tags: 'react', - description: 'Descrição 1', - link: 'https://github.com/pedrodecf', - user_id: newUser.id, - }) - - await projectRepository.create({ - title: 'Projeto 2', - tags: 'react', - description: 'Descrição 2', - link: 'https://www.linkedin.com/in/pedrodecf/', - user_id: newUser.id, - }) - - await projectRepository.create({ - title: 'Projeto 3', - tags: 'Node', - description: 'Descrição 3', - link: 'https://www.acabouminhasredesociais.com.br', - user_id: newUser.id, - }) - - const getProjectByTagsResponse = await request(app.server).get( - `/projects/tags/react`, - ) - - expect(getProjectByTagsResponse.statusCode).toEqual(200) - - expect(getProjectByTagsResponse.body.projects).toHaveLength(2); - - expect(getProjectByTagsResponse.body.projects[0]).toEqual( - expect.objectContaining({ tags: 'react' }), - ) - }) -}) diff --git a/src/controller/project/getProjectByTags.ts b/src/controller/project/getProjectByTags.ts deleted file mode 100644 index 5d4ac34..0000000 --- a/src/controller/project/getProjectByTags.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { FastifyReply, FastifyRequest } from "fastify"; -import { PrismaProjectRepository } from "../../repositories/prisma/prisma-project-repository"; -import { GetProjectsByTagsUseCase } from "../../use-cases/getProjectsByTagsUseCase"; -import { z } from "zod"; -import { ResourceNotFoundError } from "../../use-cases/errors/ResourceNotFoundError"; - - -export async function getProjectsByTags( - request: FastifyRequest, - response: FastifyReply -) { - const projectRepository = new PrismaProjectRepository() - const getProjectsByTagsUseCase = new GetProjectsByTagsUseCase(projectRepository) - - const GetProjectsByTagsParamsSchema = z.object({ - projectTags: z.string() - }) - - const { projectTags } = GetProjectsByTagsParamsSchema.parse(request.params) - - try { - const { projects } = await getProjectsByTagsUseCase.execute({ projectTags }) - return response.status(200).send({ projects }) - } catch (error) { - if (error instanceof ResourceNotFoundError) { - return response.status(404).send({ error: 'Project was not Found!'}) - } - } -} \ No newline at end of file diff --git a/src/controller/project/getProjectsByUserId.spec.ts b/src/controller/project/getProjectsByUserId.spec.ts index 169b049..5d61694 100644 --- a/src/controller/project/getProjectsByUserId.spec.ts +++ b/src/controller/project/getProjectsByUserId.spec.ts @@ -25,7 +25,7 @@ describe('Get Projets By UserId E2E', () => { it('should be able to get all projects from an user', async () => { const description = 'ReactProject' const link = 'www.google.com.br' - const tags = 'React' + const tags = ['react', 'node'] const title = 'ReactProject' const newUser = await userRepository.create({ diff --git a/src/controller/project/routes.ts b/src/controller/project/routes.ts index c7ec152..d6782d9 100644 --- a/src/controller/project/routes.ts +++ b/src/controller/project/routes.ts @@ -2,11 +2,9 @@ import { FastifyInstance } from 'fastify' import { createProject } from './createProject' import { getProjectsByUserId } from './getProjectsByUserId' import { getProjectsById } from './getProjectById' -import { getProjectsByTags } from './getProjectByTags' export async function projectRoutes(app: FastifyInstance) { app.get('/projects/:userId', getProjectsByUserId) - app.get('/projects/tags/:projectTags', getProjectsByTags) app.get('/project/:projectId', getProjectsById) app.post('/user/:userId/project', createProject) } diff --git a/src/repositories/in-memory-db/inMemoryProjectRepository.ts b/src/repositories/in-memory-db/inMemoryProjectRepository.ts index c6b4c7c..3472af4 100644 --- a/src/repositories/in-memory-db/inMemoryProjectRepository.ts +++ b/src/repositories/in-memory-db/inMemoryProjectRepository.ts @@ -13,7 +13,7 @@ export class InMemoryProjectRepository implements ProjectRepository { id: data.id ?? randomUUID(), title: data.title, description: data.description, - tags: data.tags, + tags: data.tags as string[], link: data.link, user_id: data.user_id, created_at: new Date(), @@ -40,14 +40,4 @@ export class InMemoryProjectRepository implements ProjectRepository { } return project } - - async fetchProjectByTags(projectTags: string): Promise { - const lowercasedTags = projectTags.toLowerCase(); - - const projects = this.dbProject.filter( - (project) => project.tags.toLowerCase() === lowercasedTags - ); - - return projects; - } } diff --git a/src/repositories/project-repository.ts b/src/repositories/project-repository.ts index b8feaf4..cbee4d3 100644 --- a/src/repositories/project-repository.ts +++ b/src/repositories/project-repository.ts @@ -4,5 +4,4 @@ export interface ProjectRepository { create(data: Prisma.ProjectUncheckedCreateInput): Promise fetchProjectsByUserId(userId: string): Promise fetchProjectById(projectId: string): Promise - fetchProjectByTags(projectTags: string): Promise } diff --git a/src/use-cases/createProjectUseCase.spec.ts b/src/use-cases/createProjectUseCase.spec.ts index d87706d..329d762 100644 --- a/src/use-cases/createProjectUseCase.spec.ts +++ b/src/use-cases/createProjectUseCase.spec.ts @@ -31,13 +31,14 @@ describe('Create Project Use Case', () => { const { project } = await createProjectUseCase.execute({ title: 'React Typescript', description: 'Melhor Projeto', - tags: 'React, Node', + tags: ['react', 'node'], link: 'https://github.com/luiseduardo3/nodets-petcanil', userId: newUser.id, }) expect(project.id).toEqual(expect.any(String)) expect(project.title).toEqual('React Typescript') + expect(project.tags).toEqual(['react', 'node']) }) it('should not be able to create a project if the user was not found.', async () => { @@ -45,7 +46,7 @@ describe('Create Project Use Case', () => { createProjectUseCase.execute({ title: 'Project with nonexistent user', description: 'Project without a valid user', - tags: 'Invalid, Project', + tags: ['react', 'node'], link: 'https://github.com/example/project-with-nonexistent-user', userId: 'non-existent-UserId', }), diff --git a/src/use-cases/createProjectUseCase.ts b/src/use-cases/createProjectUseCase.ts index 2b6ff58..cdd9f4a 100644 --- a/src/use-cases/createProjectUseCase.ts +++ b/src/use-cases/createProjectUseCase.ts @@ -8,7 +8,7 @@ import { ResourceNotFoundError } from './errors/ResourceNotFoundError' interface CreateProjectUseCaseRequest { title: string description: string - tags: string + tags: string[] link: string userId: string } @@ -36,7 +36,7 @@ export class CreateProjectUseCase { throw new ResourceNotFoundError() } - const lowercaseTags = tags.toLowerCase(); + const lowercaseTags = tags.map((tag) => tag.toLowerCase()) const project = await this.projectRepository.create({ title, diff --git a/src/use-cases/getProjectsByIdUseCase.spec.ts b/src/use-cases/getProjectsByIdUseCase.spec.ts index 6d7978e..20b8694 100644 --- a/src/use-cases/getProjectsByIdUseCase.spec.ts +++ b/src/use-cases/getProjectsByIdUseCase.spec.ts @@ -18,7 +18,7 @@ describe('Get Project By Id Use Case', () => { const newProject = await projectRepository.create({ title: 'React Typescript 1', description: 'Best Project', - tags: 'React', + tags: ['react', 'node'], link: 'https://github.com/luiseduardo3/nodets-petcanil', user_id: 'user_id', }) @@ -31,6 +31,7 @@ describe('Get Project By Id Use Case', () => { expect.objectContaining({ title: 'React Typescript 1', id: newProject.id, + tags: ['react', 'node'], }), ) }) diff --git a/src/use-cases/getProjectsByTagsUseCase.spec.ts b/src/use-cases/getProjectsByTagsUseCase.spec.ts deleted file mode 100644 index ad9b25c..0000000 --- a/src/use-cases/getProjectsByTagsUseCase.spec.ts +++ /dev/null @@ -1,72 +0,0 @@ -import { beforeEach, describe, expect, it } from "vitest"; -import { ProjectRepository } from "../repositories/project-repository"; -import { GetProjectsByTagsUseCase } from "./getProjectsByTagsUseCase"; -import { InMemoryProjectRepository } from "../repositories/in-memory-db/inMemoryProjectRepository"; -import { ResourceNotFoundError } from "./errors/ResourceNotFoundError"; - - -let projectRepository: ProjectRepository -let getProjectByTagsUseCase: GetProjectsByTagsUseCase - -describe('Get Projects By Tags Use Case', () => { - beforeEach(() => { - projectRepository = new InMemoryProjectRepository() - getProjectByTagsUseCase = new GetProjectsByTagsUseCase(projectRepository) - }) - - it('should be able get project by Tags', async () => { - await projectRepository.create({ - title: 'React Typescript 1', - description: 'Best Project', - tags: 'react', - link: 'https://github.com/luiseduardo3/nodets-petcanil', - user_id: 'user_id', - }) - - await projectRepository.create({ - title: 'React Typescript 2', - description: 'Best Project 2', - tags: 'react', - link: 'https://github.com/luiseduardo3/nodets-petcanil', - user_id: 'user_id', - }) - - await projectRepository.create({ - title: 'Node with Typescript', - description: 'Best Node Project', - tags: 'Node', - link: 'https://github.com/luiseduardo3/nodets-petcanil', - user_id: 'user_id', - }) - - const { projects } = await getProjectByTagsUseCase.execute({ - projectTags: 'React' - }) - - expect(projects).toHaveLength(2) - - expect(projects[0]).toEqual( - expect.objectContaining({ tags: 'react' }), - ) - - expect(projects[1]).toEqual( - expect.objectContaining({ tags: 'react' }), - ) - }) - - it('should not be able to get a project that dont have the searched tags' , async () => { - await projectRepository.create({ - title: 'Node with Typescript', - description: 'Best Node Project', - tags: 'Node', - link: 'https://github.com/luiseduardo3/nodets-petcanil', - user_id: 'user_id', - }) - - const { projects } = await getProjectByTagsUseCase.execute({ - projectTags: 'React' - }) - - expect(projects).toEqual([]) - }) -}) \ No newline at end of file diff --git a/src/use-cases/getProjectsByTagsUseCase.ts b/src/use-cases/getProjectsByTagsUseCase.ts deleted file mode 100644 index a025c49..0000000 --- a/src/use-cases/getProjectsByTagsUseCase.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Project } from '@prisma/client' - -import { ProjectRepository } from '../repositories/project-repository' - -import { ResourceNotFoundError } from './errors/ResourceNotFoundError' - -interface GetProjectByTagsRequest { - projectTags: string -} - -interface GetProjectByTagsResponse { - projects: Project[] -} - -export class GetProjectsByTagsUseCase { - constructor(private projectRepository: ProjectRepository) {} - - async execute({ - projectTags, - }: GetProjectByTagsRequest): Promise { - const projects = await this.projectRepository.fetchProjectByTags(projectTags) - - if (!projects) { - throw new ResourceNotFoundError() - } - - return { - projects - } - } -} \ No newline at end of file diff --git a/src/use-cases/getProjectsByUserIdUseCase.spec.ts b/src/use-cases/getProjectsByUserIdUseCase.spec.ts index 0b56788..2dea55e 100644 --- a/src/use-cases/getProjectsByUserIdUseCase.spec.ts +++ b/src/use-cases/getProjectsByUserIdUseCase.spec.ts @@ -33,7 +33,7 @@ describe('Get Project By User Id Use Case', () => { await projectRepository.create({ title: 'React Typescript 1', description: 'Best Project', - tags: 'React', + tags: ['react', 'node'], link: 'https://github.com/luiseduardo3/nodets-petcanil', user_id: newUser.id, }) @@ -41,7 +41,7 @@ describe('Get Project By User Id Use Case', () => { await projectRepository.create({ title: 'React Typescript 2', description: 'Best Project 2', - tags: 'React', + tags: ['react', 'node'], link: 'https://github.com/luiseduardo3/nodets-petcanil', user_id: newUser.id, })