mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 16:55:37 +02:00
⭐feat: Implement Game Image Support with Metadata & Schema Updates (#277)
## Description <!-- Briefly describe the purpose and scope of your changes --> <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit - **New Features** - Introduced support for associating rich image metadata (color, dimensions, file size) with games, organized by categories like screenshots, box art, posters, hero art, backgrounds, logos, and icons. - Game and library listings now include related image collections for enhanced browsing and detail views. - **Improvements** - Updated game library management to use a consistent base game identifier, improving data consistency and reliability. - Enhanced data schemas and access permissions to allow public viewing of game images and refined access control for game libraries. - Added comprehensive database schema updates for games, categories, images, and libraries to support new features and ensure data integrity. <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
@@ -1,14 +1,15 @@
|
||||
import { z } from "zod";
|
||||
import { fn } from "../utils";
|
||||
import { Game } from "../game";
|
||||
import { Actor } from "../actor";
|
||||
import { gamesTable } from "../game/game.sql";
|
||||
import { createSelectSchema } from "drizzle-zod";
|
||||
import { steamLibraryTable } from "./library.sql";
|
||||
import { and, eq, inArray, isNull, sql } from "drizzle-orm";
|
||||
import { imagesTable } from "../images/images.sql";
|
||||
import { and, eq, isNull, sql } from "drizzle-orm";
|
||||
import { baseGamesTable } from "../base-game/base-game.sql";
|
||||
import { categoriesTable } from "../categories/categories.sql";
|
||||
import { createTransaction, useTransaction } from "../drizzle/transaction";
|
||||
import { Actor } from "../actor";
|
||||
|
||||
export namespace Library {
|
||||
export const Info = createSelectSchema(steamLibraryTable)
|
||||
@@ -26,7 +27,7 @@ export namespace Library {
|
||||
.from(steamLibraryTable)
|
||||
.where(
|
||||
and(
|
||||
eq(steamLibraryTable.gameID, input.gameID),
|
||||
eq(steamLibraryTable.baseGameID, input.baseGameID),
|
||||
eq(steamLibraryTable.ownerID, input.ownerID),
|
||||
isNull(steamLibraryTable.timeDeleted)
|
||||
)
|
||||
@@ -37,12 +38,9 @@ export namespace Library {
|
||||
|
||||
await tx
|
||||
.insert(steamLibraryTable)
|
||||
.values({
|
||||
ownerID: input.ownerID,
|
||||
gameID: input.gameID
|
||||
})
|
||||
.values(input)
|
||||
.onConflictDoUpdate({
|
||||
target: [steamLibraryTable.ownerID, steamLibraryTable.gameID],
|
||||
target: [steamLibraryTable.ownerID, steamLibraryTable.baseGameID],
|
||||
set: { timeDeleted: null }
|
||||
})
|
||||
|
||||
@@ -59,7 +57,7 @@ export namespace Library {
|
||||
.where(
|
||||
and(
|
||||
eq(steamLibraryTable.ownerID, input.ownerID),
|
||||
eq(steamLibraryTable.gameID, input.gameID),
|
||||
eq(steamLibraryTable.baseGameID, input.baseGameID),
|
||||
)
|
||||
)
|
||||
)
|
||||
@@ -71,6 +69,7 @@ export namespace Library {
|
||||
.select({
|
||||
games: baseGamesTable,
|
||||
categories: categoriesTable,
|
||||
images: imagesTable
|
||||
})
|
||||
.from(steamLibraryTable)
|
||||
.where(
|
||||
@@ -81,7 +80,7 @@ export namespace Library {
|
||||
)
|
||||
.innerJoin(
|
||||
baseGamesTable,
|
||||
eq(baseGamesTable.id, steamLibraryTable.gameID),
|
||||
eq(baseGamesTable.id, steamLibraryTable.baseGameID),
|
||||
)
|
||||
.leftJoin(
|
||||
gamesTable,
|
||||
@@ -94,6 +93,20 @@ export namespace Library {
|
||||
eq(categoriesTable.type, gamesTable.categoryType),
|
||||
)
|
||||
)
|
||||
// Joining imagesTable 1-N with gamesTable multiplies rows; the subsequent Game.serialize has to uniqueBy to undo this.
|
||||
// For large libraries with many screenshots the Cartesian effect can significantly bloat the result and network payload.
|
||||
// One option is to aggregate the images in SQL before joining to keep exactly one row per game:
|
||||
// .leftJoin(
|
||||
// sql<typeof imagesTable.$inferSelect[]>`(SELECT * FROM images WHERE base_game_id = ${gamesTable.baseGameID} AND time_deleted IS NULL ORDER BY type, position)`.as("images"),
|
||||
// sql`TRUE`
|
||||
// )
|
||||
.leftJoin(
|
||||
imagesTable,
|
||||
and(
|
||||
eq(imagesTable.baseGameID, gamesTable.baseGameID),
|
||||
isNull(imagesTable.timeDeleted),
|
||||
)
|
||||
)
|
||||
.execute()
|
||||
.then(rows => Game.serialize(rows))
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user