Skip to content

Commit

Permalink
Merge pull request #20 from Artur-Poffo/feat-get-course-with-modules
Browse files Browse the repository at this point in the history
Feat(Course, Module): Get course details with their modules
  • Loading branch information
Artur-Poffo committed Feb 7, 2024
2 parents 038fba7 + d703838 commit f66c437
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 1 deletion.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
- [x] Return information of an instructor with their courses.

- [x] Return information about a course.
- [ ] Return information about a course with its modules.
- [x] Return information about a course with its modules.
- [x] Classes and modules must have a field informing their position, e.g. this class is number one, so this is the first class of the course.

- [x] Students can "enroll" to participate in the course.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { type Course } from '../../enterprise/entities/course'
import { type CompleteCourseDTO } from '../../enterprise/entities/dtos/complete-course'
import { type CourseWithModulesDTO } from '../../enterprise/entities/dtos/course-with-modules'
import { type CourseWithStudentsDTO } from '../../enterprise/entities/dtos/course-with-students'
import { type InstructorWithCoursesDTO } from '../../enterprise/entities/dtos/instructor-with-courses'

export interface CoursesRepository {
findById: (id: string) => Promise<Course | null>
findManyByInstructorId: (instructorId: string) => Promise<Course[]>
findCourseWithStudentsById: (id: string) => Promise<CourseWithStudentsDTO | null>
findCourseWithSModulesById: (id: string) => Promise<CourseWithModulesDTO | null>
findCompleteCourseEntityById: (id: string) => Promise<CompleteCourseDTO | null>
findInstructorWithCoursesByInstructorId: (instructorId: string) => Promise<InstructorWithCoursesDTO | null>
create: (course: Course) => Promise<Course>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { ResourceNotFoundError } from '@/core/errors/errors/resource-not-found-error'
import { makeCourse } from '../../../../../test/factories/make-course'
import { makeInstructor } from '../../../../../test/factories/make-instructor'
import { makeModule } from '../../../../../test/factories/make-module'
import { InMemoryClassesRepository } from '../../../../../test/repositories/in-memory-classes-repository'
import { InMemoryCoursesRepository } from '../../../../../test/repositories/in-memory-courses-repository'
import { InMemoryEnrollmentsRepository } from '../../../../../test/repositories/in-memory-enrollments-repository'
import { InMemoryInstructorRepository } from '../../../../../test/repositories/in-memory-instructors-repository'
import { InMemoryModulesRepository } from '../../../../../test/repositories/in-memory-modules-repository'
import { InMemoryStudentsRepository } from '../../../../../test/repositories/in-memory-students-repository'
import { GetCourseWithModulesUseCase } from './get-course-with-modules'

let inMemoryClassesRepository: InMemoryClassesRepository
let inMemoryEnrollmentsRepository: InMemoryEnrollmentsRepository
let inMemoryStudentsRepository: InMemoryStudentsRepository
let inMemoryInstructorsRepository: InMemoryInstructorRepository
let inMemoryModulesRepository: InMemoryModulesRepository
let inMemoryCoursesRepository: InMemoryCoursesRepository
let sut: GetCourseWithModulesUseCase

describe('Get course details with modules use case', () => {
beforeEach(() => {
inMemoryClassesRepository = new InMemoryClassesRepository()
inMemoryInstructorsRepository = new InMemoryInstructorRepository()
inMemoryEnrollmentsRepository = new InMemoryEnrollmentsRepository()
inMemoryStudentsRepository = new InMemoryStudentsRepository()

inMemoryModulesRepository = new InMemoryModulesRepository(inMemoryClassesRepository)
inMemoryCoursesRepository = new InMemoryCoursesRepository(inMemoryModulesRepository, inMemoryInstructorsRepository, inMemoryEnrollmentsRepository, inMemoryStudentsRepository)

sut = new GetCourseWithModulesUseCase(inMemoryCoursesRepository)
})

it('should be able to get course details with modules', async () => {
const instructor = makeInstructor()
await inMemoryInstructorsRepository.create(instructor)

const course = makeCourse({ name: 'John Doe Course', instructorId: instructor.id })
await inMemoryCoursesRepository.create(course)

const firstModule = makeModule({ name: 'First Module', courseId: course.id })
const secondModule = makeModule({ name: 'Second Module', courseId: course.id })

await Promise.all([
inMemoryModulesRepository.create(firstModule),
inMemoryModulesRepository.create(secondModule)
])

const result = await sut.exec({
courseId: course.id.toString()
})

expect(result.isRight()).toBe(true)
})

it('should not be able to get course details with modules of a inexistent course', async () => {
const result = await sut.exec({
courseId: 'inexistentCourseId'
})

expect(result.isLeft()).toBe(true)
expect(result.value).toBeInstanceOf(ResourceNotFoundError)
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { left, right, type Either } from '@/core/either'
import { ResourceNotFoundError } from '@/core/errors/errors/resource-not-found-error'
import { type UseCase } from '@/core/use-cases/use-case'
import { type CourseWithModulesDTO } from '../../enterprise/entities/dtos/course-with-modules'
import { type CoursesRepository } from '../repositories/courses-repository'

interface GetCourseWithModulesUseCaseRequest {
courseId: string
}

type GetCourseWithModulesUseCaseResponse = Either<
ResourceNotFoundError,
{
courseWithModules: CourseWithModulesDTO
}
>

export class GetCourseWithModulesUseCase implements UseCase<GetCourseWithModulesUseCaseRequest, GetCourseWithModulesUseCaseResponse> {
constructor(
private readonly coursesRepository: CoursesRepository
) { }

async exec({
courseId
}: GetCourseWithModulesUseCaseRequest): Promise<GetCourseWithModulesUseCaseResponse> {
const course = await this.coursesRepository.findById(courseId)

if (!course) {
return left(new ResourceNotFoundError())
}

const courseWithTheirModules = await this.coursesRepository.findCourseWithSModulesById(course.id.toString())

if (!courseWithTheirModules) {
return left(new ResourceNotFoundError())
}

return right({
courseWithModules: courseWithTheirModules
})
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type Module } from '../module'
import { type CourseDTO } from './course'

export interface CourseWithModulesDTO {
course: CourseDTO
modules: Module[]
}
25 changes: 25 additions & 0 deletions test/repositories/in-memory-courses-repository.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { type CoursesRepository } from '@/domain/course-management/application/repositories/courses-repository'
import { type CompleteCourseDTO } from '@/domain/course-management/enterprise/entities/dtos/complete-course'
import { type CourseWithModulesDTO } from '@/domain/course-management/enterprise/entities/dtos/course-with-modules'
import { type CourseWithStudentsDTO } from '@/domain/course-management/enterprise/entities/dtos/course-with-students'
import { type InstructorWithCoursesDTO } from '@/domain/course-management/enterprise/entities/dtos/instructor-with-courses'
import { type Student } from '@/domain/course-management/enterprise/entities/student'
Expand Down Expand Up @@ -61,6 +62,30 @@ export class InMemoryCoursesRepository implements CoursesRepository {
return courseWithStudents
}

async findCourseWithSModulesById(id: string): Promise<CourseWithModulesDTO | null> {
const course = this.items.find(courseToCompare => courseToCompare.id.toString() === id)

if (!course) {
return null
}

const courseModules = await this.inMemoryModulesRepository.findManyByCourseId(course.id.toString())

const courseWithModules: CourseWithModulesDTO = {
course: {
id: course.id,
name: course.name,
description: course.description,
coverImageKey: course.coverImageKey,
bannerImageKey: course.bannerImageKey,
createdAt: course.createdAt
},
modules: courseModules
}

return courseWithModules
}

async findCompleteCourseEntityById(id: string): Promise<CompleteCourseDTO | null> {
const course = this.items.find(courseToCompare => courseToCompare.id.toString() === id)

Expand Down

0 comments on commit f66c437

Please sign in to comment.