From 73fff64a759940bd4416b352bfdcaadccde8bd9c Mon Sep 17 00:00:00 2001 From: jeffvli Date: Tue, 1 Nov 2022 11:30:40 -0700 Subject: [PATCH] Add genres route --- server/controllers/genres.controller.ts | 23 ++++++++++ server/controllers/index.ts | 2 + server/helpers/api-model.ts | 22 +++++++++ server/routes/genres.route.ts | 12 +++++ server/routes/index.ts | 2 + server/services/genres.service.ts | 59 +++++++++++++++++++++++++ server/services/index.ts | 2 + server/validations/genres.validation.ts | 12 +++++ server/validations/index.ts | 2 + 9 files changed, 136 insertions(+) create mode 100644 server/controllers/genres.controller.ts create mode 100644 server/routes/genres.route.ts create mode 100644 server/services/genres.service.ts create mode 100644 server/validations/genres.validation.ts diff --git a/server/controllers/genres.controller.ts b/server/controllers/genres.controller.ts new file mode 100644 index 000000000..ab11bba9b --- /dev/null +++ b/server/controllers/genres.controller.ts @@ -0,0 +1,23 @@ +import { Response } from 'express'; +import { toApiModel } from '@helpers/api-model'; +import { service } from '@services/index'; +import { ApiSuccess } from '@utils/api-success'; +import { getSuccessResponse } from '@utils/get-success-response'; +import { validation } from '@validations/index'; +import { TypedRequest } from '@validations/shared.validation'; + +const getList = async ( + req: TypedRequest, + res: Response +) => { + const { serverId } = req.params; + + const data = await service.genres.findManyByServer({ serverId }); + + const success = ApiSuccess.ok({ data: toApiModel.genres(data) }); + return res.status(success.statusCode).json(getSuccessResponse(success)); +}; + +export const genresController = { + getList, +}; diff --git a/server/controllers/index.ts b/server/controllers/index.ts index 16c2b1896..77874d42c 100644 --- a/server/controllers/index.ts +++ b/server/controllers/index.ts @@ -2,6 +2,7 @@ import { albumArtistsController } from '@controllers/album-artists.controller'; import { albumsController } from '@controllers/albums.controller'; import { artistsController } from '@controllers/artists.controller'; import { authController } from '@controllers/auth.controller'; +import { genresController } from '@controllers/genres.controller'; import { serversController } from '@controllers/servers.controller'; import { songsController } from '@controllers/songs.controller'; import { tasksController } from '@controllers/tasks.controller'; @@ -12,6 +13,7 @@ export const controller = { albums: albumsController, artists: artistsController, auth: authController, + genres: genresController, servers: serversController, songs: songsController, tasks: tasksController, diff --git a/server/helpers/api-model.ts b/server/helpers/api-model.ts index 5b1590c3f..736fbe3c5 100644 --- a/server/helpers/api-model.ts +++ b/server/helpers/api-model.ts @@ -210,6 +210,28 @@ const relatedGenres = (items: Genre[]) => { ); }; +const genres = (items: (Genre & { _count?: any })[]) => { + return ( + items?.map((item) => { + const totalCount = Object.keys(item._count) + .map((key) => item._count[key]) + .reduce((a, b) => a + b, 0); + + return { + /* eslint-disable sort-keys-fix/sort-keys-fix */ + id: item.id, + name: item.name, + songCount: item._count?.songs, + albumCount: item._count?.albums, + artistCount: item._count?.artists, + albumArtistCount: item._count?.albumArtists, + totalCount, + /* eslint-enable sort-keys-fix/sort-keys-fix */ + }; + }) || [] + ); +}; + const relatedServerFolders = (items: ServerFolder[]) => { const serverFolders = items?.map((item) => { return { diff --git a/server/routes/genres.route.ts b/server/routes/genres.route.ts new file mode 100644 index 000000000..ba4be064b --- /dev/null +++ b/server/routes/genres.route.ts @@ -0,0 +1,12 @@ +import express, { Router } from 'express'; +import { controller } from '@controllers/index'; +import { validation } from '@validations/index'; +import { validateRequest } from '@validations/shared.validation'; + +export const router: Router = express.Router({ mergeParams: true }); + +router.get( + '/', + validateRequest(validation.genres.list), + controller.genres.getList +); diff --git a/server/routes/index.ts b/server/routes/index.ts index 3faebd4f1..40d20aa05 100644 --- a/server/routes/index.ts +++ b/server/routes/index.ts @@ -5,6 +5,7 @@ import { router as albumArtistsRouter } from './album-artists.route'; import { router as albumsRouter } from './albums.route'; import { router as artistsRouter } from './artists.route'; import { router as authRouter } from './auth.route'; +import { router as genresRouter } from './genres.route'; import { router as serversRouter } from './servers.route'; import { router as songsRouter } from './songs.route'; import { router as tasksRouter } from './tasks.route'; @@ -44,4 +45,5 @@ routes.param('serverId', (req, _res, next, serverId) => { routes.use('/api/servers/:serverId/album-artists', albumArtistsRouter); routes.use('/api/servers/:serverId/artists', artistsRouter); routes.use('/api/servers/:serverId/albums', albumsRouter); +routes.use('/api/servers/:serverId/genres', genresRouter); routes.use('/api/servers/:serverId/songs', songsRouter); diff --git a/server/services/genres.service.ts b/server/services/genres.service.ts new file mode 100644 index 000000000..16b56dd14 --- /dev/null +++ b/server/services/genres.service.ts @@ -0,0 +1,59 @@ +import { prisma } from '@lib/prisma'; +import { ApiError } from '@utils/api-error'; + +const findManyByServer = async (options: { serverId: string }) => { + const { serverId } = options; + + const genres = await prisma.genre.findMany({ + include: { + _count: { + select: { + albumArtists: { where: { serverId } }, + albums: { where: { serverId } }, + artists: { where: { serverId } }, + songs: { where: { serverId } }, + }, + }, + }, + where: { + OR: [ + { albumArtists: { some: { serverId } } }, + { albums: { some: { serverId } } }, + { artists: { some: { serverId } } }, + { songs: { some: { serverId } } }, + ], + }, + }); + + if (!genres) { + throw ApiError.notFound(''); + } + + return genres; +}; + +const findMany = async () => { + const genres = await prisma.genre.findMany({ + include: { + _count: { + select: { + albumArtists: true, + albums: true, + artists: true, + songs: true, + }, + }, + }, + }); + + if (!genres) { + throw ApiError.notFound(''); + } + + return genres; +}; + +export const genresService = { + findMany, + findManyByServer, +}; diff --git a/server/services/index.ts b/server/services/index.ts index f5aabd89a..c7fc7258f 100644 --- a/server/services/index.ts +++ b/server/services/index.ts @@ -2,6 +2,7 @@ import { albumArtistsService } from './album-artists.service'; import { albumsService } from './albums.service'; import { artistsService } from './artists.service'; import { authService } from './auth.service'; +import { genresService } from './genres.service'; import { serversService } from './servers.service'; import { usersService } from './users.service'; @@ -10,6 +11,7 @@ export const service = { albums: albumsService, artists: artistsService, auth: authService, + genres: genresService, servers: serversService, users: usersService, }; diff --git a/server/validations/genres.validation.ts b/server/validations/genres.validation.ts new file mode 100644 index 000000000..ceb0c5a65 --- /dev/null +++ b/server/validations/genres.validation.ts @@ -0,0 +1,12 @@ +import { z } from 'zod'; +import { idValidation } from '@validations/shared.validation'; + +const list = { + body: z.object({}), + params: z.object({ ...idValidation('serverId') }), + query: z.object({}), +}; + +export const genresValidation = { + list, +}; diff --git a/server/validations/index.ts b/server/validations/index.ts index ad5520046..13c1828d6 100644 --- a/server/validations/index.ts +++ b/server/validations/index.ts @@ -2,6 +2,7 @@ import { albumArtistsValidation } from '@validations/album-artists.validation'; import { albumsValidation } from '@validations/albums.validation'; import { artistsValidation } from '@validations/artists.validation'; import { authValidation } from '@validations/auth.validation'; +import { genresValidation } from '@validations/genres.validation'; import { serversValidation } from '@validations/servers.validation'; import { songsValidation } from '@validations/songs.validation'; import { tasksValidation } from '@validations/tasks.validation'; @@ -14,6 +15,7 @@ export const validation = { albums: albumsValidation, artists: artistsValidation, auth: authValidation, + genres: genresValidation, servers: serversValidation, songs: songsValidation, tasks: tasksValidation,