Skip to content

Commit

Permalink
Merge pull request #43 from MatheusSanchez/SFD-88-get-project-returni…
Browse files Browse the repository at this point in the history
…ng-user-data

Get project routes - returning user data
  • Loading branch information
pedrodecf authored Feb 3, 2024
2 parents 3342868 + b55932b commit 8745965
Show file tree
Hide file tree
Showing 12 changed files with 234 additions and 78 deletions.
10 changes: 5 additions & 5 deletions src/controller/project/getProjectById.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,11 @@ describe('Get Projets By ID E2E', () => {

expect(getProjectByIdResponse.statusCode).toEqual(200)
expect(getProjectByIdResponse.body.project).toEqual(
expect.objectContaining({ title }),
)

expect(getProjectByIdResponse.body.project).toEqual(
expect.objectContaining({ tags }),
expect.objectContaining({
title,
user: { name: 'John', surname: 'Doe', avatar_url: null },
tags,
}),
)
})

Expand Down
18 changes: 15 additions & 3 deletions src/controller/project/getProjectsByTags.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,22 @@ describe('Get Projets By Tags E2E', () => {
.post(`/projects/tags`)
.send({ tags })

console.log('getProjectsByTagsResponse')
console.log(getProjectsByTagsResponse.body.projects[0])

expect(getProjectsByTagsResponse.statusCode).toEqual(200)
expect(getProjectsByTagsResponse.body.projects).toHaveLength(2)
expect(getProjectsByTagsResponse.body.projects[0]).toEqual(
expect.objectContaining({ title: 'Project 01' }),
expect.objectContaining({
title: 'Project 01',
user: { name: 'John', surname: 'Doe', avatar_url: null },
}),
)
expect(getProjectsByTagsResponse.body.projects[1]).toEqual(
expect.objectContaining({ title: 'Project 02' }),
expect.objectContaining({
title: 'Project 02',
user: { name: 'John', surname: 'Doe', avatar_url: null },
}),
)
})

Expand Down Expand Up @@ -94,7 +103,10 @@ describe('Get Projets By Tags E2E', () => {
expect(getProjectsByTagsResponse.statusCode).toEqual(200)
expect(getProjectsByTagsResponse.body.projects).toHaveLength(1)
expect(getProjectsByTagsResponse.body.projects[0]).toEqual(
expect.objectContaining({ title: 'Project 03' }),
expect.objectContaining({
title: 'Project 03',
user: { name: 'John', surname: 'Doe', avatar_url: null },
}),
)
})
})
72 changes: 62 additions & 10 deletions src/repositories/in-memory-db/inMemoryProjectRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ import { randomUUID } from 'crypto'

import { Prisma, Project } from '@prisma/client'
import { ProjectRepository } from '../project-repository'
import { ProjectWithUserData } from '../prisma/prisma-project-with-user-data-type'
import { InMemoryUserRepository } from './inMemoryUserRepository'

export class InMemoryProjectRepository implements ProjectRepository {
public dbProject: Project[] = []
public dbUser: InMemoryUserRepository = new InMemoryUserRepository()

constructor() {}

Expand All @@ -18,6 +21,7 @@ export class InMemoryProjectRepository implements ProjectRepository {
user_id: data.user_id,
created_at: new Date(),
updated_at: new Date(),
photo_url: null,
}

this.dbProject.push(project)
Expand All @@ -43,34 +47,82 @@ export class InMemoryProjectRepository implements ProjectRepository {
return projects
}

async fetchProjectById(projectId: string): Promise<Project | null> {
async fetchProjectById(
projectId: string,
): Promise<ProjectWithUserData | null> {
const project = this.dbProject.find((project) => project.id === projectId)

if (!project) {
return null
}
return project
}

const {
created_at,
description,
id,
link,
photo_url,
tags,
title,
updated_at,
user_id,
} = project
const foundUser = this.dbUser.db.find((user) => user.id === project.user_id)

if (!foundUser) {
return null
}

return {
created_at,
description,
id,
link,
photo_url,
tags,
title,
updated_at,
user_id,
user: {
name: foundUser?.name,
surname: foundUser?.surname,
avatar_url: foundUser?.avatar_url,
},
}
}

async addPhotoUrl(projectId: string, photoUrl: string): Promise<Project> {
throw new Error('Method not implemented.')
}

async deleteProjectByID(projectId: string): Promise<void> {
const index = this.dbProject.findIndex((project) => project.id === projectId);
const index = this.dbProject.findIndex(
(project) => project.id === projectId,
)

if (index !== -1) {
this.dbProject.splice(index, 1);
this.dbProject.splice(index, 1)
}

return
}
async fetchProjectByTags(tags: string[]): Promise<Project[]> {

async fetchProjectByTags(tags: string[]): Promise<ProjectWithUserData[]> {
const projects = this.dbProject.filter((project) =>
project.tags.some((tag) => tags.includes(tag)),
)

return projects
const projectPromises = projects.map(async (project) => {
const user = await this.dbUser.findById(project.user_id)

return {
...project,
user: {
name: user.name,
surname: user.surname,
avatar_url: user.avatar_url,
},
}
})

return Promise.all(projectPromises)
}
}
7 changes: 3 additions & 4 deletions src/repositories/in-memory-db/inMemoryUserRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { UserRepository } from '../user-repository'
import { randomUUID } from 'crypto'

export class InMemoryUserRepository implements UserRepository {
private db: User[] = []
public db: User[] = []

constructor() {}

Expand All @@ -27,8 +27,6 @@ export class InMemoryUserRepository implements UserRepository {
return User
}

// create in a in-memory database is just used to help us on unit tests;
// that's why is not in our interface :)
async create({
id,
name,
Expand All @@ -38,7 +36,7 @@ export class InMemoryUserRepository implements UserRepository {
country,
}: Prisma.UserCreateInput) {
const user: User = {
id: id == undefined ? randomUUID() : id,
id: id === undefined ? randomUUID() : id,
name,
surname,

Expand All @@ -47,6 +45,7 @@ export class InMemoryUserRepository implements UserRepository {

created_at: new Date(),
updated_at: new Date(),
avatar_url: null,
country: country || 'brasil',
}

Expand Down
52 changes: 34 additions & 18 deletions src/repositories/prisma/prisma-project-repository.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Prisma, Project } from '@prisma/client'
import { ProjectRepository } from '../project-repository'
import { prisma } from '../../lib/prisma'
import { ProjectWithUserData } from './prisma-project-with-user-data-type'

export class PrismaProjectRepository implements ProjectRepository {
async create(data: Prisma.ProjectUncheckedCreateInput): Promise<Project> {
Expand All @@ -21,17 +22,6 @@ export class PrismaProjectRepository implements ProjectRepository {
return projects
}

async fetchProjectById(projectId: string): Promise<Project | null> {
const project = await prisma.project.findUnique({
where: {
id: projectId,
},
})

return project
}


async addPhotoUrl(projectId: string, photoUrl: string): Promise<Project> {
const project = await prisma.project.update({
where: {
Expand All @@ -45,27 +35,53 @@ export class PrismaProjectRepository implements ProjectRepository {
return project
}

async fetchProjectByTags(tags: string[]): Promise<Project[]> {
async fetchProjectByTags(tags: string[]): Promise<ProjectWithUserData[]> {
const project = await prisma.project.findMany({
where: {
tags: { hasEvery: tags },

},
include: {
user: {
select: {
avatar_url: true,
name: true,
surname: true,
},
},
},
})

return project
}

async deleteProjectByID(projectId: string):Promise<void> {
await prisma.project.delete({
async fetchProjectById(
projectId: string,
): Promise<ProjectWithUserData | null> {
const project = await prisma.project.findUnique({
where: {
id: projectId
}
id: projectId,
},
include: {
user: {
select: {
avatar_url: true,
name: true,
surname: true,
},
},
},
})

return
return project
}

async deleteProjectByID(projectId: string): Promise<void> {
await prisma.project.delete({
where: {
id: projectId,
},
})
}

async edit(data: Prisma.ProjectUncheckedCreateInput): Promise<Project> {
const project = await prisma.project.update({
Expand Down
13 changes: 13 additions & 0 deletions src/repositories/prisma/prisma-project-with-user-data-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { Prisma } from '@prisma/client'

const userAvatarUrlAndNameData = Prisma.validator<Prisma.UserDefaultArgs>()({
select: { avatar_url: true, name: true, surname: true },
})

const projectsWithUserData = Prisma.validator<Prisma.ProjectDefaultArgs>()({
include: { user: userAvatarUrlAndNameData },
})

export type ProjectWithUserData = Prisma.ProjectGetPayload<
typeof projectsWithUserData
>
5 changes: 3 additions & 2 deletions src/repositories/project-repository.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { Prisma, Project } from '@prisma/client'
import { ProjectWithUserData } from './prisma/prisma-project-with-user-data-type'

export interface ProjectRepository {
create(data: Prisma.ProjectUncheckedCreateInput): Promise<Project>
fetchProjectsByUserId(userId: string): Promise<Project[]>
fetchProjectById(projectId: string): Promise<Project | null>
fetchProjectById(projectId: string): Promise<ProjectWithUserData | null>
addPhotoUrl(projectId: string, photoUrl: string): Promise<Project>
fetchProjectByTags(tags: string[]): Promise<Project[]>
fetchProjectByTags(tags: string[]): Promise<ProjectWithUserData[]>
edit(data: Prisma.ProjectUncheckedCreateInput): Promise<Project>
deleteProjectByID(projectID: string): Promise<void>
}
15 changes: 11 additions & 4 deletions src/use-cases/project/editProjectUseCase.spec.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { expect, describe, it, beforeEach } from 'vitest'

import { InMemoryProjectRepository } from '../../repositories/in-memory-db/inMemoryProjectRepository'
import { ProjectRepository } from '../../repositories/project-repository'
import { ResourceNotFoundError } from '../errors/ResourceNotFoundError'
import { EditProjectUseCase } from './editProjectUseCase'
import { User } from '@prisma/client'

let projectRepository: ProjectRepository
let projectRepository: InMemoryProjectRepository
let editProjectUseCase: EditProjectUseCase
let newUser: User

describe('Edit Project By Id Use Case', () => {
beforeEach(() => {
beforeEach(async () => {
projectRepository = new InMemoryProjectRepository()
editProjectUseCase = new EditProjectUseCase(projectRepository)
newUser = await projectRepository.dbUser.create({
name: 'John',
surname: 'Doe',
email: '[email protected]',
password_hash: '123456',
})
})

it('should be able edit one project by ID', async () => {
Expand All @@ -20,7 +27,7 @@ describe('Edit Project By Id Use Case', () => {
description: 'Best Project',
tags: ['react', 'node'],
link: 'https://github.com/luiseduardo3/nodets-petcanil',
user_id: 'user_id',
user_id: newUser.id,
})

const { project: projectEdited } = await editProjectUseCase.execute({
Expand Down
12 changes: 9 additions & 3 deletions src/use-cases/project/getProjectsByIdUseCase.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { expect, describe, it, beforeEach } from 'vitest'

import { InMemoryProjectRepository } from '../../repositories/in-memory-db/inMemoryProjectRepository'
import { ProjectRepository } from '../../repositories/project-repository'
import { ResourceNotFoundError } from '../errors/ResourceNotFoundError'
import { GetProjectsByIdUseCase } from './getProjectsByIdUseCase'

let projectRepository: ProjectRepository
let projectRepository: InMemoryProjectRepository
let getProjectByIdUseCase: GetProjectsByIdUseCase

describe('Get Project By Id Use Case', () => {
Expand All @@ -15,12 +14,18 @@ describe('Get Project By Id Use Case', () => {
})

it('should be able get project by ID', async () => {
const newUser = await projectRepository.dbUser.create({
name: 'John',
surname: 'Doe',
email: '[email protected]',
password_hash: '123456',
})
const newProject = await projectRepository.create({
title: 'React Typescript 1',
description: 'Best Project',
tags: ['react', 'node'],
link: 'https://github.com/luiseduardo3/nodets-petcanil',
user_id: 'user_id',
user_id: newUser.id,
})

const { project } = await getProjectByIdUseCase.execute({
Expand All @@ -32,6 +37,7 @@ describe('Get Project By Id Use Case', () => {
title: 'React Typescript 1',
id: newProject.id,
tags: ['react', 'node'],
user: { name: 'John', surname: 'Doe', avatar_url: null },
}),
)
})
Expand Down
Loading

0 comments on commit 8745965

Please sign in to comment.