Skip to content

Commit

Permalink
refactor: optimize DbLoadAnswersBySurvey
Browse files Browse the repository at this point in the history
  • Loading branch information
rmanguinho committed Dec 3, 2020
1 parent f50ee20 commit c8f9d2f
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 24 deletions.
1 change: 1 addition & 0 deletions src/data/protocols/db/survey/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
export * from './add-survey-repository'
export * from './load-survey-by-id-repository'
export * from './load-answers-by-survey-repository'
export * from './check-survey-by-id-repository'
export * from './load-surveys-repository'
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export interface LoadAnswersBySurveyRepository {
loadAnswers: (id: string) => Promise<LoadAnswersBySurveyRepository.Result>
}

export namespace LoadAnswersBySurveyRepository {
export type Result = string[]
}
7 changes: 3 additions & 4 deletions src/data/usecases/db-load-answers-by-survey.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { LoadAnswersBySurvey } from '@/domain/usecases'
import { LoadSurveyByIdRepository } from '@/data/protocols'
import { LoadAnswersBySurveyRepository } from '@/data/protocols'

export class DbLoadAnswersBySurvey implements LoadAnswersBySurvey {
constructor (private readonly loadSurveyByIdRepository: LoadSurveyByIdRepository) {}
constructor (private readonly loadAnswersBySurveyRepository: LoadAnswersBySurveyRepository) {}

async loadAnswers (id: string): Promise<LoadAnswersBySurvey.Result> {
const survey = await this.loadSurveyByIdRepository.loadById(id)
return survey?.answers.map(a => a.answer) || []
return this.loadAnswersBySurveyRepository.loadAnswers(id)
}
}
19 changes: 17 additions & 2 deletions src/infra/db/mongodb/survey-mongo-repository.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { MongoHelper, QueryBuilder } from '@/infra/db'
import { SurveyModel } from '@/domain/models'
import { AddSurveyRepository, LoadSurveysRepository, LoadSurveyByIdRepository, CheckSurveyByIdRepository } from '@/data/protocols/db'
import { AddSurveyRepository, LoadSurveysRepository, LoadSurveyByIdRepository, CheckSurveyByIdRepository, LoadAnswersBySurveyRepository } from '@/data/protocols/db'

import { ObjectId } from 'mongodb'

export class SurveyMongoRepository implements AddSurveyRepository, LoadSurveysRepository, LoadSurveyByIdRepository, CheckSurveyByIdRepository {
export class SurveyMongoRepository implements AddSurveyRepository, LoadSurveysRepository, LoadSurveyByIdRepository, CheckSurveyByIdRepository, LoadAnswersBySurveyRepository {
async add (data: AddSurveyRepository.Params): Promise<void> {
const surveyCollection = await MongoHelper.getCollection('surveys')
await surveyCollection.insertOne(data)
Expand Down Expand Up @@ -49,6 +49,21 @@ export class SurveyMongoRepository implements AddSurveyRepository, LoadSurveysRe
return survey && MongoHelper.map(survey)
}

async loadAnswers (id: string): Promise<LoadAnswersBySurveyRepository.Result> {
const surveyCollection = await MongoHelper.getCollection('surveys')
const query = new QueryBuilder()
.match({
_id: new ObjectId(id)
})
.project({
_id: 0,
answers: '$answers.answer'
})
.build()
const surveys = await surveyCollection.aggregate(query).toArray()
return surveys[0]?.answers || []
}

async checkById (id: string): Promise<CheckSurveyByIdRepository.Result> {
const surveyCollection = await MongoHelper.getCollection('surveys')
const survey = await surveyCollection.findOne({
Expand Down
14 changes: 13 additions & 1 deletion tests/data/mocks/mock-db-survey.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { AddSurveyRepository, LoadSurveyByIdRepository, LoadSurveysRepository, CheckSurveyByIdRepository } from '@/data/protocols'
import { AddSurveyRepository, LoadSurveyByIdRepository, LoadSurveysRepository, CheckSurveyByIdRepository, LoadAnswersBySurveyRepository } from '@/data/protocols'
import { SurveyModel } from '@/domain/models'
import { mockSurveyModel, mockSurveyModels } from '@/tests/domain/mocks'

import faker from 'faker'

export class AddSurveyRepositorySpy implements AddSurveyRepository {
addSurveyParams: AddSurveyRepository.Params

Expand All @@ -20,6 +22,16 @@ export class LoadSurveyByIdRepositorySpy implements LoadSurveyByIdRepository {
}
}

export class LoadAnswersBySurveyRepositorySpy implements LoadAnswersBySurveyRepository {
result = [faker.random.word(), faker.random.word()]
id: string

async loadAnswers (id: string): Promise<LoadAnswersBySurveyRepository.Result> {
this.id = id
return this.result
}
}

export class CheckSurveyByIdRepositorySpy implements CheckSurveyByIdRepository {
result = true
id: string
Expand Down
34 changes: 17 additions & 17 deletions tests/data/usecases/db-load-answers-by-survey.spec.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,20 @@
import { DbLoadAnswersBySurvey } from '@/data/usecases'
import { LoadSurveyByIdRepositorySpy } from '@/tests/data/mocks'
import { LoadAnswersBySurveyRepositorySpy } from '@/tests/data/mocks'
import { throwError } from '@/tests/domain/mocks'

import faker from 'faker'

type SutTypes = {
sut: DbLoadAnswersBySurvey
loadSurveyByIdRepositorySpy: LoadSurveyByIdRepositorySpy
loadAnswersBySurveyRepositorySpy: LoadAnswersBySurveyRepositorySpy
}

const makeSut = (): SutTypes => {
const loadSurveyByIdRepositorySpy = new LoadSurveyByIdRepositorySpy()
const sut = new DbLoadAnswersBySurvey(loadSurveyByIdRepositorySpy)
const loadAnswersBySurveyRepositorySpy = new LoadAnswersBySurveyRepositorySpy()
const sut = new DbLoadAnswersBySurvey(loadAnswersBySurveyRepositorySpy)
return {
sut,
loadSurveyByIdRepositorySpy
loadAnswersBySurveyRepositorySpy
}
}

Expand All @@ -25,31 +25,31 @@ describe('DbLoadAnswersBySurvey', () => {
surveyId = faker.random.uuid()
})

test('Should call LoadSurveyByIdRepository', async () => {
const { sut, loadSurveyByIdRepositorySpy } = makeSut()
test('Should call LoadAnswersBySurveyRepository', async () => {
const { sut, loadAnswersBySurveyRepositorySpy } = makeSut()
await sut.loadAnswers(surveyId)
expect(loadSurveyByIdRepositorySpy.id).toBe(surveyId)
expect(loadAnswersBySurveyRepositorySpy.id).toBe(surveyId)
})

test('Should return answers on success', async () => {
const { sut, loadSurveyByIdRepositorySpy } = makeSut()
const { sut, loadAnswersBySurveyRepositorySpy } = makeSut()
const answers = await sut.loadAnswers(surveyId)
expect(answers).toEqual([
loadSurveyByIdRepositorySpy.result.answers[0].answer,
loadSurveyByIdRepositorySpy.result.answers[1].answer
loadAnswersBySurveyRepositorySpy.result[0],
loadAnswersBySurveyRepositorySpy.result[1]
])
})

test('Should return empty array if LoadSurveyByIdRepository returns null', async () => {
const { sut, loadSurveyByIdRepositorySpy } = makeSut()
loadSurveyByIdRepositorySpy.result = null
test('Should return empty array if LoadAnswersBySurveyRepository returns []', async () => {
const { sut, loadAnswersBySurveyRepositorySpy } = makeSut()
loadAnswersBySurveyRepositorySpy.result = []
const answers = await sut.loadAnswers(surveyId)
expect(answers).toEqual([])
})

test('Should throw if LoadSurveyByIdRepository throws', async () => {
const { sut, loadSurveyByIdRepositorySpy } = makeSut()
jest.spyOn(loadSurveyByIdRepositorySpy, 'loadById').mockImplementationOnce(throwError)
test('Should throw if LoadAnswersBySurveyRepository throws', async () => {
const { sut, loadAnswersBySurveyRepositorySpy } = makeSut()
jest.spyOn(loadAnswersBySurveyRepositorySpy, 'loadAnswers').mockImplementationOnce(throwError)
const promise = sut.loadAnswers(surveyId)
await expect(promise).rejects.toThrow()
})
Expand Down
22 changes: 22 additions & 0 deletions tests/infra/db/mongodb/survey-mongo-repository.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,28 @@ describe('SurveyMongoRepository', () => {
expect(survey).toBeTruthy()
expect(survey.id).toBeTruthy()
})

test('Should return null if survey does not exists', async () => {
const sut = makeSut()
const survey = await sut.loadById(FakeObjectId.generate())
expect(survey).toBeFalsy()
})
})

describe('loadAnswers()', () => {
test('Should load answers on success', async () => {
const res = await surveyCollection.insertOne(mockAddSurveyParams())
const survey = res.ops[0]
const sut = makeSut()
const answers = await sut.loadAnswers(survey._id)
expect(answers).toEqual([survey.answers[0].answer, survey.answers[1].answer])
})

test('Should return empty array if survey does not exists', async () => {
const sut = makeSut()
const answers = await sut.loadAnswers(FakeObjectId.generate())
expect(answers).toEqual([])
})
})

describe('checkById()', () => {
Expand Down

0 comments on commit c8f9d2f

Please sign in to comment.