feat: add to favorites

This commit is contained in:
2024-05-30 20:33:17 +02:00
parent 6604b880bf
commit aba09f5367
6 changed files with 117 additions and 53 deletions

View File

@@ -50,6 +50,7 @@ import {
GetDeckByIdCommand,
GetMinMaxCardsUseCaseCommand,
GetRandomCardInDeckCommand,
RemoveDeckFromFavoritesCommand,
SaveGradeCommand,
UpdateDeckCommand,
} from './use-cases'
@@ -261,4 +262,18 @@ export class DecksController {
async addToFavorites(@Req() req, @Param('id') deckId: string): Promise<CardWithGrade> {
return await this.commandBus.execute(new AddDeckToFavoritesCommand(req.user.id, deckId))
}
@ApiBearerAuth()
@UseGuards(JwtAuthGuard)
@ApiUnauthorizedResponse({ description: 'Unauthorized' })
@HttpCode(HttpStatus.NO_CONTENT)
@ApiNoContentResponse({ description: 'Added to favorites' })
@Delete(':id/favorite')
@ApiOperation({
description: 'Add deck to favorites',
summary: 'Add deck to favorites',
})
async removeFromFavorites(@Req() req, @Param('id') deckId: string): Promise<CardWithGrade> {
return await this.commandBus.execute(new RemoveDeckFromFavoritesCommand(req.user.id, deckId))
}
}

View File

@@ -21,6 +21,7 @@ import {
AddDeckToFavoritesHandler,
SaveGradeHandler,
GetRandomCardInDeckHandler,
RemoveDeckFromFavoritesHandler,
} from './use-cases'
const commandHandlers = [
@@ -36,6 +37,7 @@ const commandHandlers = [
CreateCardHandler,
SaveGradeHandler,
AddDeckToFavoritesHandler,
RemoveDeckFromFavoritesHandler,
]
@Module({

View File

@@ -129,38 +129,42 @@ export class DecksRepository {
// Construct the raw SQL query for fetching decks
const query = `
SELECT
d.*,
COUNT(c.id) AS "cardsCount",
a."id" AS "authorId",
a."name" AS "authorName"
FROM flashcards.deck AS "d"
LEFT JOIN "flashcards"."card" AS c ON d."id" = c."deckId"
LEFT JOIN "flashcards"."user" AS a ON d."userId" = a.id
LEFT JOIN "flashcards"."favoriteDeck" AS fd ON d."id" = fd."deckId"
${
conditions.length
? `WHERE ${conditions
.map((_, index) => `${_.replace('?', `$${index + 1}`)}`)
.join(' AND ')}`
: ''
}
GROUP BY d."id", a."id"
${
havingConditions.length
? `HAVING ${havingConditions
.map((_, index) => `${_.replace('?', `$${conditions.length + index + 1}`)}`)
.join(' AND ')}`
: ''
}
ORDER BY ${orderField} ${orderDirection}
LIMIT $${conditions.length + havingConditions.length + 1} OFFSET $${
conditions.length + havingConditions.length + 2
};
`
SELECT
d.*,
COUNT(c.id) AS "cardsCount",
a."id" AS "authorId",
a."name" AS "authorName",
(fd."userId" IS NOT NULL) AS "isFavorite"
FROM flashcards.deck AS "d"
LEFT JOIN "flashcards"."card" AS c ON d."id" = c."deckId"
LEFT JOIN "flashcards"."user" AS a ON d."userId" = a.id
LEFT JOIN "flashcards"."favoriteDeck" AS fd ON d."id" = fd."deckId" AND fd."userId" = $1
${
conditions.length
? `WHERE ${conditions
.map((condition, index) => `${condition.replace('?', `$${index + 2}`)}`)
.join(' AND ')}`
: ''
}
GROUP BY d."id", a."id", fd."userId"
${
havingConditions.length
? `HAVING ${havingConditions
.map(
(condition, index) => `${condition.replace('?', `$${conditions.length + index + 2}`)}`
)
.join(' AND ')}`
: ''
}
ORDER BY ${orderField} ${orderDirection}
LIMIT $${conditions.length + havingConditions.length + 2} OFFSET $${
conditions.length + havingConditions.length + 3
};
`
// Parameters for fetching decks
const deckQueryParams = [
userId,
...(name ? [name] : []),
...(authorId ? [authorId] : []),
...(userId ? [userId] : []),
@@ -177,38 +181,43 @@ export class DecksRepository {
Deck & {
authorId: string
authorName: string
isFavorite: boolean
}
>
>(query, ...deckQueryParams)
// Construct the raw SQL query for total count
const countQuery = `
SELECT COUNT(*) AS total
FROM (
SELECT d.id
FROM flashcards.deck AS d
LEFT JOIN flashcards.card AS c ON d.id = c."deckId"
LEFT JOIN flashcards."favoriteDeck" AS fd ON d."id" = fd."deckId"
${
conditions.length
? `WHERE ${conditions
.map((_, index) => `${_.replace('?', `$${index + 1}`)}`)
.join(' AND ')}`
: ''
}
GROUP BY d.id
${
havingConditions.length
? `HAVING ${havingConditions
.map((_, index) => `${_.replace('?', `$${conditions.length + index + 1}`)}`)
.join(' AND ')}`
: ''
}
) AS subquery;
`
SELECT COUNT(*) AS total
FROM (
SELECT d.id
FROM flashcards.deck AS d
LEFT JOIN flashcards.card AS c ON d.id = c."deckId"
LEFT JOIN flashcards."favoriteDeck" AS fd ON d."id" = fd."deckId" AND fd."userId" = $1
${
conditions.length
? `WHERE ${conditions
.map((condition, index) => `${condition.replace('?', `$${index + 2}`)}`)
.join(' AND ')}`
: ''
}
GROUP BY d.id, fd."userId"
${
havingConditions.length
? `HAVING ${havingConditions
.map(
(condition, index) =>
`${condition.replace('?', `$${conditions.length + index + 2}`)}`
)
.join(' AND ')}`
: ''
}
) AS subquery;
`
// Parameters for total count query
const countQueryParams = [
userId,
...(name ? [name] : []),
...(authorId ? [authorId] : []),
...(userId ? [userId] : []),
@@ -220,6 +229,7 @@ export class DecksRepository {
// Execute the raw SQL query for total count
const totalResult = await this.prisma.$queryRawUnsafe<any[]>(countQuery, ...countQueryParams)
const total = Number(totalResult[0]?.total) ?? 1
const modifiedDecks = decks.map(deck => {
const cardsCount = deck.cardsCount

View File

@@ -9,4 +9,5 @@ export * from './get-random-card-in-deck-use-case'
export * from './save-grade-use-case'
export * from './update-deck-use-case'
export * from './get-min-max-cards-use-case'
export * from './add-card-to-favorites.use-case'
export * from './add-deck-to-favorites.use-case'
export * from './remove-deck-from-favorites.use-case'

View File

@@ -0,0 +1,36 @@
import { BadRequestException, NotFoundException } from '@nestjs/common'
import { CommandHandler, ICommandHandler } from '@nestjs/cqrs'
import { DecksRepository } from '../infrastructure/decks.repository'
export class RemoveDeckFromFavoritesCommand {
constructor(
public readonly userId: string,
public readonly deckId: string
) {}
}
@CommandHandler(RemoveDeckFromFavoritesCommand)
export class RemoveDeckFromFavoritesHandler
implements ICommandHandler<RemoveDeckFromFavoritesCommand>
{
constructor(private readonly decksRepository: DecksRepository) {}
async execute(command: RemoveDeckFromFavoritesCommand): Promise<void> {
const deck = await this.decksRepository.findDeckById(command.deckId)
if (!deck) {
throw new NotFoundException(`Deck with id ${command.deckId} not found`)
}
const favorites = await this.decksRepository.findFavoritesByUserId(
command.userId,
command.deckId
)
if (!favorites?.includes(command.deckId)) {
throw new BadRequestException(`Deck with id ${command.deckId} is not a favorite`)
}
return await this.decksRepository.removeDeckFromFavorites(command.userId, command.deckId)
}
}