Skip to content

Commit

Permalink
UseCase get projects by tag
Browse files Browse the repository at this point in the history
  • Loading branch information
pedrodecf committed Jan 31, 2024
1 parent 717c6cd commit 468c0b1
Show file tree
Hide file tree
Showing 10 changed files with 232 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/controller/project/createProject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ export async function createProject(
)
const { userId } = createProjectParamsSchema.parse(request.params)

const lowercaseTags = tags.toLowerCase();

const userRepository = new PrismaUsersRepository()
const projectRepository = new PrismaProjectRepository()
const createProjectUseCase = new CreateProjectUseCase(
Expand All @@ -35,7 +37,7 @@ export async function createProject(
const project = await createProjectUseCase.execute({
userId,
title,
tags,
tags: lowercaseTags,
link,
description,
})
Expand Down
69 changes: 69 additions & 0 deletions src/controller/project/getProjectByTags.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
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: '[email protected]',
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' }),
)
})
})
29 changes: 29 additions & 0 deletions src/controller/project/getProjectByTags.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
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!'})
}
}
}
2 changes: 2 additions & 0 deletions src/controller/project/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@ 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)
}
10 changes: 10 additions & 0 deletions src/repositories/in-memory-db/inMemoryProjectRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,14 @@ export class InMemoryProjectRepository implements ProjectRepository {
}
return project
}

async fetchProjectByTags(projectTags: string): Promise<Project[]> {
const lowercasedTags = projectTags.toLowerCase();

const projects = this.dbProject.filter(
(project) => project.tags.toLowerCase() === lowercasedTags
);

return projects;
}
}
12 changes: 12 additions & 0 deletions src/repositories/prisma/prisma-project-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,16 @@ export class PrismaProjectRepository implements ProjectRepository {

return project
}

async fetchProjectByTags(projectTags: string): Promise<Project[]> {
const lowercasedTags = projectTags.toLowerCase()

const projects = await prisma.project.findMany({
where: {
tags: lowercasedTags,
},
})

return projects;
}
}
1 change: 1 addition & 0 deletions src/repositories/project-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ export interface ProjectRepository {
create(data: Prisma.ProjectUncheckedCreateInput): Promise<Project>
fetchProjectsByUserId(userId: string): Promise<Project[]>
fetchProjectById(projectId: string): Promise<Project | null>
fetchProjectByTags(projectTags: string): Promise<Project[]>
}
4 changes: 3 additions & 1 deletion src/use-cases/createProjectUseCase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,10 +36,12 @@ export class CreateProjectUseCase {
throw new ResourceNotFoundError()
}

const lowercaseTags = tags.toLowerCase();

const project = await this.projectRepository.create({
title,
description,
tags,
tags: lowercaseTags,
link,
user_id: userId,
})
Expand Down
72 changes: 72 additions & 0 deletions src/use-cases/getProjectsByTagsUseCase.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
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([])
})
})
31 changes: 31 additions & 0 deletions src/use-cases/getProjectsByTagsUseCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
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<GetProjectByTagsResponse> {
const projects = await this.projectRepository.fetchProjectByTags(projectTags)

if (!projects) {
throw new ResourceNotFoundError()
}

return {
projects
}
}
}

0 comments on commit 468c0b1

Please sign in to comment.