Skip to content

Commit 59f272f

Browse files
committed
feat: add QuestionDetails value object
1 parent da81055 commit 59f272f

File tree

4 files changed

+126
-5
lines changed

4 files changed

+126
-5
lines changed

src/domain/forum/application/repositories/questions-repository.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { PaginationParams } from '@/core/repositories/pagination-params'
22
import { Question } from '../../enterprise/entities/question'
3+
import { QuestionDetails } from '../../enterprise/entities/value-objects/question-details'
34

45
export abstract class QuestionsRepository {
56
abstract findById(id: string): Promise<Question | null>
67
abstract findBySlug(slug: string): Promise<Question | null>
8+
abstract findDetailsBySlug(slug: string): Promise<QuestionDetails | null>
79
abstract findManyRecent(params: PaginationParams): Promise<Question[]>
810
abstract save(question: Question): Promise<void>
911
abstract create(question: Question): Promise<void>

src/domain/forum/application/use-cases/get-question-by-slug.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { Either, left, right } from '@/core/either'
2-
import { Question } from '../../enterprise/entities/question'
32
import { QuestionsRepository } from '../repositories/questions-repository'
43
import { ResourceNotFoundError } from '@/core/errors/resource-not-found-error'
54
import { Injectable } from '@nestjs/common'
5+
import { QuestionDetails } from '../../enterprise/entities/value-objects/question-details'
66

77
interface GetQuestionBySlugUseCaseRequest {
88
slug: string
@@ -11,7 +11,7 @@ interface GetQuestionBySlugUseCaseRequest {
1111
type GetQuestionBySlugUseCaseResponse = Either<
1212
ResourceNotFoundError,
1313
{
14-
question: Question
14+
question: QuestionDetails
1515
}
1616
>
1717

@@ -22,7 +22,7 @@ export class GetQuestionBySlugUseCase {
2222
async execute({
2323
slug,
2424
}: GetQuestionBySlugUseCaseRequest): Promise<GetQuestionBySlugUseCaseResponse> {
25-
const question = await this.questionsRepository.findBySlug(slug)
25+
const question = await this.questionsRepository.findDetailsBySlug(slug)
2626

2727
if (!question) {
2828
return left(new ResourceNotFoundError())
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import { UniqueEntityID } from '@/core/entities/unique-entity-id'
2+
import { ValueObject } from '@/core/entities/value-object'
3+
import { Slug } from './slug'
4+
import { Attachment } from '../attachment'
5+
6+
export interface QuestionDetailsProps {
7+
questionId: UniqueEntityID
8+
authorId: UniqueEntityID
9+
author: string
10+
title: string
11+
content: string
12+
slug: Slug
13+
attachments: Attachment[]
14+
bestAnswerId?: UniqueEntityID | null
15+
createdAt: Date
16+
updatedAt?: Date | null
17+
}
18+
19+
export class QuestionDetails extends ValueObject<QuestionDetailsProps> {
20+
get questionId() {
21+
return this.props.questionId
22+
}
23+
24+
get authorId() {
25+
return this.props.authorId
26+
}
27+
28+
get author() {
29+
return this.props.author
30+
}
31+
32+
get title() {
33+
return this.props.title
34+
}
35+
36+
get content() {
37+
return this.props.content
38+
}
39+
40+
get slug() {
41+
return this.props.slug
42+
}
43+
44+
get attachments() {
45+
return this.props.attachments
46+
}
47+
48+
get bestAnswerId() {
49+
return this.props.bestAnswerId
50+
}
51+
52+
get createdAt() {
53+
return this.props.createdAt
54+
}
55+
56+
get updatedAt() {
57+
return this.props.updatedAt
58+
}
59+
60+
static create(props: QuestionDetailsProps) {
61+
return new QuestionDetails(props)
62+
}
63+
}

test/repositories/in-memory-questions-repository.ts

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
11
import { DomainEvents } from '@/core/events/domain-events'
22
import { PaginationParams } from '@/core/repositories/pagination-params'
3-
import { QuestionAttachmentsRepository } from '@/domain/forum/application/repositories/question-attachments-repository'
43
import { QuestionsRepository } from '@/domain/forum/application/repositories/questions-repository'
54
import { Question } from '@/domain/forum/enterprise/entities/question'
5+
import { InMemoryStudentsRepository } from './in-memory-students-repository'
6+
import { InMemoryAttachmentsRepository } from './in-memory-attachments-repository'
7+
import { InMemoryQuestionAttachmentsRepository } from './in-memory-question-attachments-repository'
8+
import { QuestionDetails } from '@/domain/forum/enterprise/entities/value-objects/question-details'
69

710
export class InMemoryQuestionsRepository implements QuestionsRepository {
811
public items: Question[] = []
912

1013
constructor(
11-
private questionAttachmentsRepository: QuestionAttachmentsRepository,
14+
private questionAttachmentsRepository: InMemoryQuestionAttachmentsRepository,
15+
private attachmentsRepository: InMemoryAttachmentsRepository,
16+
private studentsRepository: InMemoryStudentsRepository,
1217
) {}
1318

1419
async findById(id: string) {
@@ -31,6 +36,57 @@ export class InMemoryQuestionsRepository implements QuestionsRepository {
3136
return question
3237
}
3338

39+
async findDetailsBySlug(slug: string) {
40+
const question = this.items.find((item) => item.slug.value === slug)
41+
42+
if (!question) {
43+
return null
44+
}
45+
46+
const author = this.studentsRepository.items.find((student) => {
47+
return student.id.equals(question.authorId)
48+
})
49+
50+
if (!author) {
51+
throw new Error(
52+
`Author with ID "${question.authorId.toString()}" does not exist.`,
53+
)
54+
}
55+
56+
const questionAttachments = this.questionAttachmentsRepository.items.filter(
57+
(questionAttachment) => {
58+
return questionAttachment.questionId.equals(question.id)
59+
},
60+
)
61+
62+
const attachments = questionAttachments.map((questionAttachment) => {
63+
const attachment = this.attachmentsRepository.items.find((attachment) => {
64+
return attachment.id.equals(questionAttachment.attachmentId)
65+
})
66+
67+
if (!attachment) {
68+
throw new Error(
69+
`Attachment with ID "${questionAttachment.attachmentId.toString()}" does not exist.`,
70+
)
71+
}
72+
73+
return attachment
74+
})
75+
76+
return QuestionDetails.create({
77+
questionId: question.id,
78+
authorId: question.authorId,
79+
author: author.name,
80+
title: question.title,
81+
slug: question.slug,
82+
content: question.content,
83+
bestAnswerId: question.bestAnswerId,
84+
attachments,
85+
createdAt: question.createdAt,
86+
updatedAt: question.updatedAt,
87+
})
88+
}
89+
3490
async findManyRecent({ page }: PaginationParams) {
3591
const questions = this.items
3692
.sort((a, b) => b.createdAt.getTime() - a.createdAt.getTime())

0 commit comments

Comments
 (0)