2023-10-16 02:42:34 +00:00
|
|
|
import type { Game } from '@prisma/client';
|
|
|
|
|
import kebabCase from 'just-kebab-case';
|
|
|
|
|
import type { BggLinkDto } from 'boardgamegeekclient/dist/esm/dto/concrete/subdto';
|
|
|
|
|
import { mapAPIGameToBoredGame } from './gameMapper';
|
2024-02-09 02:56:09 +00:00
|
|
|
import db from '$lib/drizzle';
|
2024-02-19 08:22:05 +00:00
|
|
|
import { externalIds, games, publishersToExternalIds, type Publishers, publishers } from '../../schema';
|
2024-02-09 02:56:09 +00:00
|
|
|
import { eq, sql } from 'drizzle-orm';
|
2024-02-19 08:22:05 +00:00
|
|
|
import { error } from '@sveltejs/kit';
|
2023-10-14 09:06:57 +00:00
|
|
|
|
2024-02-19 08:22:05 +00:00
|
|
|
export async function createPublisher(locals: App.Locals, publisher: Publishers, externalId: string) {
|
|
|
|
|
if (!publisher || !externalId || externalId === '') {
|
|
|
|
|
error(400, 'Invalid Request');
|
2023-10-14 09:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
2024-02-19 08:22:05 +00:00
|
|
|
let dbExternalId = await db.query.externalIds.findFirst({
|
|
|
|
|
where: eq(externalIds.id, externalId),
|
2023-10-14 09:06:57 +00:00
|
|
|
});
|
2024-02-19 08:22:05 +00:00
|
|
|
|
|
|
|
|
if (dbExternalId) {
|
|
|
|
|
const dbPublisher = await db.select().from(publishers).leftJoin(publishersToExternalIds, eq(publishersToExternalIds.externalId, externalId));
|
2023-10-14 09:06:57 +00:00
|
|
|
}
|
2024-02-19 08:22:05 +00:00
|
|
|
let dbPublisher = await db.query.publishers.findFirst({
|
|
|
|
|
where: eq(publishers.external_id, externalPublisher.id),
|
|
|
|
|
columns: {
|
2023-10-14 09:06:57 +00:00
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
slug: true,
|
|
|
|
|
external_id: true
|
|
|
|
|
},
|
2024-02-19 08:22:05 +00:00
|
|
|
with: {
|
|
|
|
|
publishersToExternalIds: {
|
|
|
|
|
columns: {
|
|
|
|
|
externalId: true
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-10-14 09:06:57 +00:00
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (dbPublisher) {
|
2023-10-17 09:28:53 +00:00
|
|
|
console.log('Publisher already exists', dbPublisher.name);
|
2023-10-14 09:06:57 +00:00
|
|
|
return dbPublisher;
|
|
|
|
|
}
|
|
|
|
|
console.log('Creating publisher', JSON.stringify(externalPublisher, null, 2));
|
2023-11-05 00:03:28 +00:00
|
|
|
let publisher = await prisma.publisher.create({
|
2023-10-14 09:06:57 +00:00
|
|
|
data: {
|
|
|
|
|
name: externalPublisher.value,
|
|
|
|
|
external_id: externalPublisher.id,
|
|
|
|
|
slug: kebabCase(externalPublisher.value)
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
slug: true,
|
|
|
|
|
external_id: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('Created publisher', JSON.stringify(publisher, null, 2));
|
|
|
|
|
return publisher;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
throw new Error('Something went wrong creating Publisher');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-17 09:28:53 +00:00
|
|
|
export async function createCategory(locals: App.Locals, externalCategory: BggLinkDto) {
|
2023-10-14 09:06:57 +00:00
|
|
|
try {
|
2023-11-05 00:03:28 +00:00
|
|
|
let dbCategory = await prisma.category.findFirst({
|
2023-10-14 09:06:57 +00:00
|
|
|
where: {
|
|
|
|
|
external_id: externalCategory.id
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
slug: true,
|
|
|
|
|
external_id: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (dbCategory) {
|
2023-10-17 09:28:53 +00:00
|
|
|
console.log('Category already exists', dbCategory.name);
|
2023-10-14 09:06:57 +00:00
|
|
|
return dbCategory;
|
|
|
|
|
}
|
|
|
|
|
console.log('Creating category', JSON.stringify(externalCategory, null, 2));
|
2023-11-05 00:03:28 +00:00
|
|
|
let category = await prisma.category.create({
|
2023-10-14 09:06:57 +00:00
|
|
|
data: {
|
|
|
|
|
name: externalCategory.value,
|
|
|
|
|
external_id: externalCategory.id,
|
|
|
|
|
slug: kebabCase(externalCategory.value)
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
slug: true,
|
|
|
|
|
external_id: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('Created category', JSON.stringify(category, null, 2));
|
|
|
|
|
|
|
|
|
|
return category;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
throw new Error('Something went wrong creating Category');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-17 09:28:53 +00:00
|
|
|
export async function createMechanic(locals: App.Locals, externalMechanic: BggLinkDto) {
|
2023-10-14 09:06:57 +00:00
|
|
|
try {
|
2023-11-05 00:03:28 +00:00
|
|
|
let dbMechanic = await prisma.mechanic.findFirst({
|
2023-10-14 09:06:57 +00:00
|
|
|
where: {
|
|
|
|
|
external_id: externalMechanic.id
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
slug: true,
|
|
|
|
|
external_id: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
if (dbMechanic) {
|
2023-10-17 09:28:53 +00:00
|
|
|
console.log('Mechanic already exists', dbMechanic.name);
|
2023-10-14 09:06:57 +00:00
|
|
|
return dbMechanic;
|
|
|
|
|
}
|
|
|
|
|
console.log('Creating mechanic', JSON.stringify(externalMechanic, null, 2));
|
2023-11-05 00:03:28 +00:00
|
|
|
let mechanic = await prisma.mechanic.upsert({
|
2023-10-14 09:06:57 +00:00
|
|
|
where: {
|
|
|
|
|
external_id: externalMechanic.id
|
|
|
|
|
},
|
|
|
|
|
create: {
|
|
|
|
|
name: externalMechanic.value,
|
|
|
|
|
external_id: externalMechanic.id,
|
|
|
|
|
slug: kebabCase(externalMechanic.value)
|
|
|
|
|
},
|
|
|
|
|
update: {
|
|
|
|
|
name: externalMechanic.value,
|
|
|
|
|
slug: kebabCase(externalMechanic.value)
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('Created mechanic', JSON.stringify(mechanic, null, 2));
|
|
|
|
|
|
|
|
|
|
return mechanic;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
throw new Error('Something went wrong creating Mechanic');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-16 02:42:34 +00:00
|
|
|
export async function createExpansion(
|
2023-10-17 09:28:53 +00:00
|
|
|
locals: App.Locals,
|
2023-10-16 02:42:34 +00:00
|
|
|
game: Game,
|
|
|
|
|
externalExpansion: BggLinkDto,
|
|
|
|
|
gameIsExpansion: boolean,
|
|
|
|
|
eventFetch: Function
|
|
|
|
|
) {
|
2023-10-14 09:06:57 +00:00
|
|
|
try {
|
2023-11-05 00:03:28 +00:00
|
|
|
let dbExpansionGame = await prisma.game.findUnique({
|
2023-10-14 09:06:57 +00:00
|
|
|
where: {
|
|
|
|
|
external_id: externalExpansion.id
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
if (!dbExpansionGame) {
|
|
|
|
|
const externalGameResponse = await eventFetch(
|
|
|
|
|
`/api/external/game/${externalExpansion.id}?simplified=true`
|
|
|
|
|
);
|
|
|
|
|
if (externalGameResponse.ok) {
|
|
|
|
|
const externalGame = await externalGameResponse.json();
|
|
|
|
|
console.log('externalGame', externalGame);
|
|
|
|
|
let boredGame = mapAPIGameToBoredGame(externalGame);
|
2023-10-17 09:28:53 +00:00
|
|
|
dbExpansionGame = await createOrUpdateGameMinimal(locals, boredGame);
|
2023-10-14 09:06:57 +00:00
|
|
|
} else {
|
2023-10-16 02:42:34 +00:00
|
|
|
throw new Error(
|
|
|
|
|
`${gameIsExpansion ? 'Base game' : 'Expansion game'} not found and failed to create.`
|
|
|
|
|
);
|
2023-10-14 09:06:57 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
let dbExpansion;
|
|
|
|
|
let baseGameId;
|
|
|
|
|
let gameId;
|
|
|
|
|
if (gameIsExpansion) {
|
2023-10-16 02:42:34 +00:00
|
|
|
console.log(
|
|
|
|
|
'External expansion is expansion. Looking for base game',
|
|
|
|
|
JSON.stringify(game, null, 2)
|
|
|
|
|
);
|
2023-11-05 00:03:28 +00:00
|
|
|
dbExpansion = await prisma.expansion.findFirst({
|
2023-10-14 09:06:57 +00:00
|
|
|
where: {
|
|
|
|
|
game_id: dbExpansionGame.id
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
base_game_id: true,
|
|
|
|
|
game_id: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
baseGameId = game.id;
|
|
|
|
|
gameId = dbExpansionGame.id;
|
|
|
|
|
} else {
|
2023-10-16 02:42:34 +00:00
|
|
|
console.log(
|
|
|
|
|
'External Expansion is base game. Looking for expansion',
|
|
|
|
|
JSON.stringify(game, null, 2)
|
|
|
|
|
);
|
2023-11-05 00:03:28 +00:00
|
|
|
dbExpansion = await prisma.expansion.findFirst({
|
2023-10-14 09:06:57 +00:00
|
|
|
where: {
|
|
|
|
|
base_game_id: dbExpansionGame.id
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
base_game_id: true,
|
|
|
|
|
game_id: true
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
baseGameId = dbExpansionGame.id;
|
|
|
|
|
gameId = game.id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dbExpansion) {
|
|
|
|
|
console.log('Expansion already exists', JSON.stringify(dbExpansion, null, 2));
|
|
|
|
|
return dbExpansion;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
console.log(`Creating expansion. baseGameId: ${baseGameId}, gameId: ${gameId}`);
|
2023-11-05 00:03:28 +00:00
|
|
|
let expansion = await prisma.expansion.create({
|
2023-10-14 09:06:57 +00:00
|
|
|
data: {
|
|
|
|
|
base_game_id: baseGameId,
|
|
|
|
|
game_id: gameId
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
console.log('Created expansion', JSON.stringify(expansion, null, 2));
|
|
|
|
|
|
2023-10-17 09:28:53 +00:00
|
|
|
if (gameIsExpansion) {
|
|
|
|
|
console.log('Connecting current game to expansion');
|
2023-11-05 00:03:28 +00:00
|
|
|
await prisma.game.update({
|
2023-10-17 09:28:53 +00:00
|
|
|
where: {
|
|
|
|
|
id: gameId
|
|
|
|
|
},
|
|
|
|
|
data: {
|
|
|
|
|
expansions: {
|
|
|
|
|
connect: {
|
|
|
|
|
id: expansion.id
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
} else {
|
|
|
|
|
console.log('Connecting current game to base game');
|
2023-11-05 00:03:28 +00:00
|
|
|
await prisma.game.update({
|
2023-10-17 09:28:53 +00:00
|
|
|
where: {
|
2023-11-05 00:03:28 +00:00
|
|
|
id: baseGameId
|
2023-10-17 09:28:53 +00:00
|
|
|
},
|
|
|
|
|
data: {
|
|
|
|
|
expansions: {
|
|
|
|
|
connect: {
|
|
|
|
|
id: expansion.id
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-14 09:06:57 +00:00
|
|
|
return expansion;
|
|
|
|
|
} catch (e) {
|
|
|
|
|
console.error(e);
|
|
|
|
|
throw new Error('Something went wrong creating Expansion');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-17 09:28:53 +00:00
|
|
|
export async function createOrUpdateGameMinimal(locals: App.Locals, game: Game) {
|
2023-10-14 09:06:57 +00:00
|
|
|
console.log('Creating or updating minimal game data', JSON.stringify(game, null, 2));
|
|
|
|
|
const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
|
2024-02-09 02:56:09 +00:00
|
|
|
await db.insert(games).values({
|
|
|
|
|
external_id: game.external_id,
|
|
|
|
|
name: game.name,
|
|
|
|
|
slug: kebabCase(game.name),
|
|
|
|
|
description: game.description,
|
|
|
|
|
url: externalUrl,
|
|
|
|
|
thumb_url: game.thumb_url,
|
|
|
|
|
image_url: game.image_url,
|
|
|
|
|
min_age: game.min_age || 0,
|
|
|
|
|
min_players: game.min_players || 0,
|
|
|
|
|
max_players: game.max_players || 0,
|
|
|
|
|
min_playtime: game.min_playtime || 0,
|
|
|
|
|
max_playtime: game.max_playtime || 0,
|
|
|
|
|
year_published: game.year_published || 0,
|
|
|
|
|
}).onDuplicateKeyUpdate({ set: { external_id: sql`external_id` } });
|
|
|
|
|
|
|
|
|
|
return db.query.games.findFirst({ where: eq(games.external_id, game.external_id) });
|
2023-10-14 09:06:57 +00:00
|
|
|
}
|
|
|
|
|
|
2023-10-17 09:28:53 +00:00
|
|
|
export async function createOrUpdateGame(locals: App.Locals, game: Game) {
|
2023-10-14 09:06:57 +00:00
|
|
|
console.log('Creating or updating game', JSON.stringify(game, null, 2));
|
|
|
|
|
const categoryIds = game.categories;
|
|
|
|
|
const mechanicIds = game.mechanics;
|
|
|
|
|
const publisherIds = game.publishers;
|
|
|
|
|
const designerIds = game.designers;
|
|
|
|
|
const artistIds = game.artists;
|
2023-10-17 09:28:53 +00:00
|
|
|
// const expansionIds = game.expansions;
|
2023-10-14 09:06:57 +00:00
|
|
|
const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
|
|
|
|
|
console.log('categoryIds', categoryIds);
|
|
|
|
|
console.log('mechanicIds', mechanicIds);
|
2024-02-09 02:56:09 +00:00
|
|
|
await db.transaction(async (transaction) => {
|
2024-02-10 01:49:39 +00:00
|
|
|
const dbGame = await transaction.insert(games).values({
|
2023-10-14 09:06:57 +00:00
|
|
|
name: game.name,
|
|
|
|
|
slug: kebabCase(game.name),
|
|
|
|
|
description: game.description,
|
|
|
|
|
external_id: game.external_id,
|
|
|
|
|
url: externalUrl,
|
|
|
|
|
thumb_url: game.thumb_url,
|
|
|
|
|
image_url: game.image_url,
|
|
|
|
|
min_age: game.min_age || 0,
|
|
|
|
|
min_players: game.min_players || 0,
|
|
|
|
|
max_players: game.max_players || 0,
|
|
|
|
|
min_playtime: game.min_playtime || 0,
|
|
|
|
|
max_playtime: game.max_playtime || 0,
|
|
|
|
|
year_published: game.year_published || 0,
|
|
|
|
|
last_sync_at: new Date(),
|
2024-02-10 01:49:39 +00:00
|
|
|
}).onConflictDoUpdate({
|
|
|
|
|
target: games.id, set: {
|
|
|
|
|
name: game.name,
|
|
|
|
|
slug: kebabCase(game.name),
|
|
|
|
|
description: game.description,
|
|
|
|
|
external_id: game.external_id,
|
|
|
|
|
url: externalUrl,
|
|
|
|
|
thumb_url: game.thumb_url,
|
|
|
|
|
image_url: game.image_url,
|
|
|
|
|
min_age: game.min_age || 0,
|
|
|
|
|
min_players: game.min_players || 0,
|
|
|
|
|
max_players: game.max_players || 0,
|
|
|
|
|
min_playtime: game.min_playtime || 0,
|
|
|
|
|
max_playtime: game.max_playtime || 0,
|
|
|
|
|
year_published: game.year_published || 0,
|
|
|
|
|
last_sync_at: new Date(),
|
2023-10-14 09:06:57 +00:00
|
|
|
}
|
2024-02-10 01:49:39 +00:00
|
|
|
}).returning();
|
|
|
|
|
|
|
|
|
|
// TODO: Connect to everything else
|
|
|
|
|
// await transaction.insert()
|
|
|
|
|
});
|
|
|
|
|
// await db.insert(games).values({
|
|
|
|
|
// include: {
|
|
|
|
|
// mechanics: true,
|
|
|
|
|
// publishers: true,
|
|
|
|
|
// designers: true,
|
|
|
|
|
// artists: true,
|
|
|
|
|
// expansions: true
|
|
|
|
|
// },
|
|
|
|
|
// where: {
|
|
|
|
|
// external_id: game.external_id
|
|
|
|
|
// },
|
|
|
|
|
// create: {
|
|
|
|
|
// name: game.name,
|
|
|
|
|
// slug: kebabCase(game.name),
|
|
|
|
|
// description: game.description,
|
|
|
|
|
// external_id: game.external_id,
|
|
|
|
|
// url: externalUrl,
|
|
|
|
|
// thumb_url: game.thumb_url,
|
|
|
|
|
// image_url: game.image_url,
|
|
|
|
|
// min_age: game.min_age || 0,
|
|
|
|
|
// min_players: game.min_players || 0,
|
|
|
|
|
// max_players: game.max_players || 0,
|
|
|
|
|
// min_playtime: game.min_playtime || 0,
|
|
|
|
|
// max_playtime: game.max_playtime || 0,
|
|
|
|
|
// year_published: game.year_published || 0,
|
|
|
|
|
// last_sync_at: new Date(),
|
|
|
|
|
// categories: {
|
|
|
|
|
// connect: categoryIds
|
|
|
|
|
// },
|
|
|
|
|
// mechanics: {
|
|
|
|
|
// connect: mechanicIds
|
|
|
|
|
// },
|
|
|
|
|
// publishers: {
|
|
|
|
|
// connect: publisherIds
|
|
|
|
|
// },
|
|
|
|
|
// designers: {
|
|
|
|
|
// connect: designerIds
|
|
|
|
|
// },
|
|
|
|
|
// artists: {
|
|
|
|
|
// connect: artistIds
|
|
|
|
|
// }
|
|
|
|
|
// },
|
|
|
|
|
// update: {
|
|
|
|
|
// name: game.name,
|
|
|
|
|
// slug: kebabCase(game.name),
|
|
|
|
|
// description: game.description,
|
|
|
|
|
// external_id: game.external_id,
|
|
|
|
|
// url: externalUrl,
|
|
|
|
|
// thumb_url: game.thumb_url,
|
|
|
|
|
// image_url: game.image_url,
|
|
|
|
|
// min_age: game.min_age || 0,
|
|
|
|
|
// min_players: game.min_players || 0,
|
|
|
|
|
// max_players: game.max_players || 0,
|
|
|
|
|
// min_playtime: game.min_playtime || 0,
|
|
|
|
|
// max_playtime: game.max_playtime || 0,
|
|
|
|
|
// year_published: game.year_published || 0,
|
|
|
|
|
// last_sync_at: new Date(),
|
|
|
|
|
// categories: {
|
|
|
|
|
// connect: categoryIds
|
|
|
|
|
// },
|
|
|
|
|
// mechanics: {
|
|
|
|
|
// connect: mechanicIds
|
|
|
|
|
// },
|
|
|
|
|
// publishers: {
|
|
|
|
|
// connect: publisherIds
|
|
|
|
|
// },
|
|
|
|
|
// designers: {
|
|
|
|
|
// connect: designerIds
|
|
|
|
|
// },
|
|
|
|
|
// artists: {
|
|
|
|
|
// connect: artistIds
|
|
|
|
|
// }
|
|
|
|
|
// }
|
2023-10-14 09:06:57 +00:00
|
|
|
});
|
|
|
|
|
}
|