feat(repo): implémentation MongoDB de CardRepository
This commit is contained in:
1 parent
ab24d329b9
commit
dca234f298
1 file changed
+126
@@ -0,0 +1,126 @@
|
|||||||
|
import { MongoClient, type Collection } from 'mongodb'
|
||||||
|
import type { Card, CardInput } from '../domain/card'
|
||||||
|
import type { CardRepository } from '../domain/card-repository'
|
||||||
|
|
||||||
|
interface CardDocument {
|
||||||
|
c_id: string
|
||||||
|
question: string
|
||||||
|
response: string
|
||||||
|
theme: string
|
||||||
|
tags: string[]
|
||||||
|
createdAt: Date
|
||||||
|
updatedAt: Date
|
||||||
|
}
|
||||||
|
|
||||||
|
const DOC_FIELDS = {
|
||||||
|
_id: 0,
|
||||||
|
c_id: 1,
|
||||||
|
question: 1,
|
||||||
|
response: 1,
|
||||||
|
theme: 1,
|
||||||
|
tags: 1,
|
||||||
|
createdAt: 1,
|
||||||
|
updatedAt: 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export class MongoCardRepository implements CardRepository {
|
||||||
|
private readonly collection: Collection<CardDocument>
|
||||||
|
|
||||||
|
constructor(collection?: Collection<CardDocument>) {
|
||||||
|
if (collection) {
|
||||||
|
this.collection = collection
|
||||||
|
} else {
|
||||||
|
const client = new MongoClient(
|
||||||
|
process.env.MONGODB_URI ?? 'mongodb://flashcards:flashcards@localhost:127017/flashcards',
|
||||||
|
)
|
||||||
|
this.collection = client
|
||||||
|
.db(process.env.MONGODB_DATABASE ?? 'flashcards')
|
||||||
|
.collection<CardDocument>('cards')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private mapDoc(doc: CardDocument): Card {
|
||||||
|
return {
|
||||||
|
id: doc.c_id,
|
||||||
|
question: doc.question,
|
||||||
|
response: doc.response,
|
||||||
|
theme: doc.theme,
|
||||||
|
tags: doc.tags,
|
||||||
|
createdAt: doc.createdAt,
|
||||||
|
updatedAt: doc.updatedAt,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async findAll(): Promise<Card[]> {
|
||||||
|
const docs = await this.collection.find({}, { projection: DOC_FIELDS }).toArray()
|
||||||
|
return docs.map((doc) => this.mapDoc(doc))
|
||||||
|
}
|
||||||
|
|
||||||
|
async findById(id: string): Promise<Card | null> {
|
||||||
|
const doc = await this.collection.findOne({ c_id: id }, { projection: DOC_FIELDS })
|
||||||
|
return doc ? this.mapDoc(doc) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(input: CardInput): Promise<Card> {
|
||||||
|
const doc: CardDocument = {
|
||||||
|
c_id: crypto.randomUUID(),
|
||||||
|
question: input.question,
|
||||||
|
response: input.response,
|
||||||
|
theme: input.theme,
|
||||||
|
tags: input.tags ?? [],
|
||||||
|
createdAt: new Date(),
|
||||||
|
updatedAt: new Date(),
|
||||||
|
}
|
||||||
|
await this.collection.insertOne(doc)
|
||||||
|
return this.mapDoc(doc)
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, input: Partial<CardInput>): Promise<Card | null> {
|
||||||
|
const set: Partial<CardDocument> = { updatedAt: new Date() }
|
||||||
|
if (input.question !== undefined) {
|
||||||
|
set.question = input.question
|
||||||
|
}
|
||||||
|
if (input.response !== undefined) {
|
||||||
|
set.response = input.response
|
||||||
|
}
|
||||||
|
if (input.theme !== undefined) {
|
||||||
|
set.theme = input.theme
|
||||||
|
}
|
||||||
|
if (input.tags !== undefined) {
|
||||||
|
set.tags = input.tags
|
||||||
|
}
|
||||||
|
const result = await this.collection.updateOne({ c_id: id }, { $set: set })
|
||||||
|
if (result.matchedCount === 0) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return this.findById(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
async delete(id: string): Promise<boolean> {
|
||||||
|
const result = await this.collection.deleteOne({ c_id: id })
|
||||||
|
return result.deletedCount > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
async findRandom(): Promise<Card | null> {
|
||||||
|
const docs = await this.collection
|
||||||
|
.aggregate<CardDocument>([{ $sample: { size: 1 } }, { $project: DOC_FIELDS }])
|
||||||
|
.toArray()
|
||||||
|
return docs[0] ? this.mapDoc(docs[0]) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
async findRandomByTheme(theme: string): Promise<Card | null> {
|
||||||
|
const docs = await this.collection
|
||||||
|
.aggregate<CardDocument>([
|
||||||
|
{ $match: { theme } },
|
||||||
|
{ $sample: { size: 1 } },
|
||||||
|
{ $project: DOC_FIELDS },
|
||||||
|
])
|
||||||
|
.toArray()
|
||||||
|
return docs[0] ? this.mapDoc(docs[0]) : null
|
||||||
|
}
|
||||||
|
|
||||||
|
async findThemes(): Promise<string[]> {
|
||||||
|
const themes: string[] = await this.collection.distinct('theme')
|
||||||
|
return themes.sort()
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in new issue
Block a user