From 8e6e6a1988aed724048d84bd468e48b3667ec2cb Mon Sep 17 00:00:00 2001 From: Jirachal Date: Thu, 15 Oct 2026 19:16:40 +0200 Subject: [PATCH] reverse the resolvers to previous stage --- server/src/graphQL/resolvers.ts | 174 +++++++++++++++++++++----------- 1 file changed, 115 insertions(+), 59 deletions(-) diff --git a/server/src/graphQL/resolvers.ts b/server/src/graphQL/resolvers.ts index 32cd435..275e424 100644 --- a/server/src/graphQL/resolvers.ts +++ b/server/src/graphQL/resolvers.ts @@ -1,71 +1,121 @@ import { pool } from '../database/connection.js'; -const formatCoverUrl = (filename: string | null) => { - if (!filename) return null; - if (filename.startsWith('http://') || filename.startsWith('https://')) { - return filename; - } - const baseUrl = process.env.SERVER_URL || 'http://it2810-05.idi.ntnu.no/project2'; - const cleanFilename = filename.replace(/^\/+/, ''); - return `${baseUrl}/covers/${cleanFilename}`; -}; - export const resolvers = { Query: { - albums: async (_: unknown, args: { search?: string; genre?: string; decade?: number; first?: number }) => { - let sql = ` - SELECT - a.id, - a.title, - a.artist, - a.release_year AS "releaseYear", - g.name AS genre, - a.cover_path AS "coverUrl" - FROM albums a - LEFT JOIN album_genres ag ON ag.album_id = a.id - LEFT JOIN genres g ON g.id = ag.genre_id - WHERE 1=1 - `; + albums: async ( + _: unknown, + args: { + search?: string; + genre?: string; + decade?: number; + first?: number; + after?: string; + } + ) => { const queryParams: (string | number)[] = []; - + const conditions: string[] = []; if (args.search) { queryParams.push(`%${args.search}%`); - sql += ` AND (LOWER(a.title) LIKE LOWER($${queryParams.length}) OR LOWER(a.artist) LIKE LOWER($${queryParams.length}))`; - } + const searchParam = queryParams.length; + conditions.push( + `(LOWER(a.title) LIKE LOWER($${searchParam}) OR LOWER(a.artist) LIKE LOWER($${searchParam}))` + ); + } if (args.genre) { queryParams.push(args.genre); - sql += ` AND LOWER(g.name) = LOWER($${queryParams.length})`; - } + const genreParam = queryParams.length; + conditions.push( + `LOWER(g.name) = LOWER($${genreParam})` + ); + } - if (args.decade) { + if (args.decade !== undefined) { queryParams.push(args.decade); - sql += ` AND a.release_year >= $${queryParams.length} AND a.release_year < $${queryParams.length} + 10`; + const decadeParam = queryParams.length; + + conditions.push( + `a.release_year >= $${decadeParam} AND a.release_year < $${decadeParam} + 10` + ); } - const limit = args.first || 10; - + const whereClause = + conditions.length > 0 + ? `WHERE ${conditions.join(' AND ')}` + : ''; - queryParams.push(limit + 1); - sql += ` ORDER BY a.title ASC LIMIT $${queryParams.length}`; + const countSql = ` + SELECT COUNT(DISTINCT a.id)::int AS count + FROM albums a + LEFT JOIN album_genres ag ON ag.album_id = a.id + LEFT JOIN genres g ON g.id = ag.genre_id + ${whereClause} + `; - const { rows } = await pool.query(sql, queryParams); + const { rows: countRows } = await pool.query( + countSql, + queryParams + ); - const hasNextPage = rows.length > limit; - const sliced = hasNextPage ? rows.slice(0, limit) : rows; + const totalCount = countRows[0]?.count ?? 0; - const formattedRows = sliced.map((album) => ({ - ...album, - coverUrl: formatCoverUrl(album.coverUrl), - })); + const limit = args.first ?? 8; + + const parsedOffset = Number.parseInt( + args.after ?? '0', + 10 + ); + + const offset = Number.isNaN(parsedOffset) + ? 0 + : parsedOffset; + + const dataParams = [...queryParams]; + + dataParams.push(limit + 1); + const limitParam = dataParams.length; + + dataParams.push(offset); + const offsetParam = dataParams.length; + + const sql = ` + SELECT + a.id, + a.title, + a.artist, + a.release_year AS "releaseYear", + g.name AS genre, + a.cover_path AS "coverUrl" + FROM albums a + LEFT JOIN album_genres ag ON ag.album_id = a.id + LEFT JOIN genres g ON g.id = ag.genre_id + ${whereClause} + ORDER BY a.title ASC + LIMIT $${limitParam} + OFFSET $${offsetParam} + `; + + const { rows } = await pool.query( + sql, + dataParams + ); + + const hasNextPage = rows.length > limit; + const sliced = hasNextPage + ? rows.slice(0, limit) + : rows; return { - edges: formattedRows, + edges: sliced, + totalCount, pageInfo: { - endCursor: formattedRows.length > 0 ? formattedRows[formattedRows.length - 1].id : null, + endCursor: + sliced.length > 0 + ? String(offset + sliced.length) + : null, hasNextPage, }, }; @@ -73,19 +123,23 @@ export const resolvers = { album: async (_: unknown, args: { id: string }) => { const albumSql = ` - SELECT - a.id, - a.title, - a.artist, - a.release_year AS "releaseYear", - g.name AS genre, + SELECT + a.id, + a.title, + a.artist, + a.release_year AS "releaseYear", + g.name AS genre, a.cover_path AS "coverUrl" FROM albums a LEFT JOIN album_genres ag ON ag.album_id = a.id LEFT JOIN genres g ON g.id = ag.genre_id WHERE a.id = $1 `; - const { rows: albumRows } = await pool.query(albumSql, [args.id]); + + const { rows: albumRows } = await pool.query( + albumSql, + [args.id] + ); if (albumRows.length === 0) { return null; @@ -93,21 +147,23 @@ export const resolvers = { const album = albumRows[0]; - const tracksSql = ` - SELECT - id, - title, - duration_ms AS "duration" - FROM tracks + SELECT + id, + title, + duration_ms AS "duration" + FROM tracks WHERE album_id = $1 ORDER BY track_number ASC `; - const { rows: trackRows } = await pool.query(tracksSql, [args.id]); + + const { rows: trackRows } = await pool.query( + tracksSql, + [args.id] + ); return { ...album, - coverUrl: formatCoverUrl(album.coverUrl), tracks: trackRows, }; },