Removing external id from some schemas, creating APIs for different schemas, and creating DB utils for the schemas.

This commit is contained in:
Bradley Shellnut 2024-02-20 17:47:37 -08:00
parent b7d7113262
commit c472f43b9e
18 changed files with 4053 additions and 893 deletions

View file

@ -0,0 +1,3 @@
ALTER TABLE "categories" DROP COLUMN IF EXISTS "external_id";--> statement-breakpoint
ALTER TABLE "mechanics" DROP COLUMN IF EXISTS "external_id";--> statement-breakpoint
ALTER TABLE "publishers" DROP COLUMN IF EXISTS "external_id";

View file

@ -0,0 +1 @@
DROP TABLE "expansions_to_external_ids";

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -92,6 +92,20 @@
"when": 1708330799655,
"tag": "0012_dizzy_lethal_legion",
"breakpoints": true
},
{
"idx": 13,
"version": "5",
"when": 1708453431550,
"tag": "0013_clever_monster_badoon",
"breakpoints": true
},
{
"idx": 14,
"version": "5",
"when": 1708479971410,
"tag": "0014_organic_morlocks",
"breakpoints": true
}
]
}

View file

@ -39,7 +39,7 @@
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
"autoprefixer": "^10.4.17",
"dotenv": "^16.4.4",
"dotenv": "^16.4.5",
"drizzle-kit": "^0.20.14",
"eslint": "^8.56.0",
"eslint-config-prettier": "^9.1.0",
@ -49,7 +49,7 @@
"postcss": "^8.4.35",
"postcss-import": "^16.0.1",
"postcss-load-config": "^5.0.3",
"postcss-preset-env": "^9.3.0",
"postcss-preset-env": "^9.4.0",
"prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.1",
"prisma": "^5.9.1",
@ -106,9 +106,9 @@
"just-kebab-case": "^4.2.0",
"loader": "^2.1.1",
"lucia": "3.0.1",
"lucide-svelte": "^0.323.0",
"lucide-svelte": "^0.335.0",
"mysql2": "^3.9.1",
"nanoid": "^5.0.5",
"nanoid": "^5.0.6",
"open-props": "^1.6.18",
"oslo": "^1.1.2",
"pg": "^8.11.3",

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,77 @@
import kebabCase from 'just-kebab-case';
import db from '$lib/drizzle';
import { externalIds, type Mechanics, type Categories, categories, categoriesToExternalIds } from '../../../schema';
import { eq } from 'drizzle-orm';
import { error } from '@sveltejs/kit';
import { PUBLIC_SITE_URL } from '$env/static/public';
export async function createCategory(locals: App.Locals, category: Categories, externalId: string) {
if (!category || !externalId || externalId === '') {
error(400, 'Invalid Request');
}
try {
const dbExternalId = await db.query.externalIds.findFirst({
where: eq(externalIds.externalId, externalId)
});
if (dbExternalId) {
const foundCategory = await db
.select({
id: categories.id,
name: categories.name,
slug: categories.slug
})
.from(categories)
.leftJoin(categoriesToExternalIds, eq(categoriesToExternalIds.externalId, externalId));
console.log('Mechanic already exists', foundCategory);
if (foundCategory.length > 0) {
console.log('Mechanic name', foundCategory[0].name);
return new Response('Mechanic already exists', {
headers: {
'Content-Type': 'application/json',
Location: `${PUBLIC_SITE_URL}/api/mechanic/${foundCategory[0].id}`
},
status: 409
});
}
}
let dbCategory: Mechanics[] = [];
console.log('Creating category', JSON.stringify(category, null, 2));
await db.transaction(async (transaction) => {
dbCategory = await transaction
.insert(categories)
.values({
name: category.name,
slug: kebabCase(category.name || category.slug || '')
})
.returning();
const dbExternalIds = await transaction
.insert(externalIds)
.values({
externalId,
type: 'category'
})
.returning({ id: externalIds.id });
await transaction.insert(categoriesToExternalIds).values({
categoryId: dbCategory[0].id,
externalId: dbExternalIds[0].id
});
});
if (dbCategory.length === 0) {
return new Response('Could not create category', {
status: 500
});
}
console.log('Created category', JSON.stringify(dbCategory[0], null, 2));
return new Response(JSON.stringify(dbCategory[0]), {
status: 201,
});
} catch (e) {
console.error(e);
throw new Error('Something went wrong creating Category');
}
}

View file

@ -0,0 +1,178 @@
import { error } from '@sveltejs/kit';
import { and, eq } from 'drizzle-orm';
import db from '$lib/drizzle';
import { type Expansions, expansions } from '../../../schema';
import { PUBLIC_SITE_URL } from '$env/static/public';
export async function createExpansion(locals: App.Locals, expansion: Expansions) {
if (!expansion || expansion?.base_game_id === '' || expansion?.game_id === '') {
error(400, 'Invalid Request');
}
try {
const foundExpansion = await db.query.expansions
.findFirst({
where: and(eq(expansions.base_game_id, expansion.base_game_id), eq(expansions.game_id, expansion.game_id)),
columns: {
id: true,
game_id: true,
base_game_id: true
}
});
console.log('Expansion already exists', foundExpansion);
if (foundExpansion) {
console.log('Expansion Game ID', foundExpansion.game_id);
return new Response('Expansion already exists', {
headers: {
'Content-Type': 'application/json',
Location: `${PUBLIC_SITE_URL}/api/game/${foundExpansion.game_id}`
},
status: 409
});
}
console.log('Creating expansion', JSON.stringify(expansion, null, 2));
const dbExpansion = await db
.insert(expansions)
.values({
base_game_id: expansion.base_game_id,
game_id: expansion.game_id,
})
.returning();
if (dbExpansion.length === 0) {
return new Response('Could not create expansion', {
status: 500
});
}
console.log('Created expansion', JSON.stringify(dbExpansion[0], null, 2));
return new Response(JSON.stringify(dbExpansion[0]), {
status: 201,
});
} catch (e) {
console.error(e);
throw new Error('Something went wrong creating Expansion');
}
}
// export async function createExpansion(
// locals: App.Locals,
// game: Game,
// externalExpansion: BggLinkDto,
// gameIsExpansion: boolean,
// eventFetch: Function
// ) {
// try {
// let dbExpansionGame = await prisma.game.findUnique({
// 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);
// const boredGame = mapAPIGameToBoredGame(externalGame);
// dbExpansionGame = await createOrUpdateGameMinimal(locals, boredGame);
// } else {
// throw new Error(
// `${gameIsExpansion ? 'Base game' : 'Expansion game'} not found and failed to create.`
// );
// }
// }
// let dbExpansion;
// let baseGameId;
// let gameId;
// if (gameIsExpansion) {
// console.log(
// 'External expansion is expansion. Looking for base game',
// JSON.stringify(game, null, 2)
// );
// dbExpansion = await prisma.expansion.findFirst({
// where: {
// game_id: dbExpansionGame.id
// },
// select: {
// id: true,
// base_game_id: true,
// game_id: true
// }
// });
// baseGameId = game.id;
// gameId = dbExpansionGame.id;
// } else {
// console.log(
// 'External Expansion is base game. Looking for expansion',
// JSON.stringify(game, null, 2)
// );
// dbExpansion = await prisma.expansion.findFirst({
// 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}`);
// const expansion = await prisma.expansion.create({
// data: {
// base_game_id: baseGameId,
// game_id: gameId
// }
// });
// console.log('Created expansion', JSON.stringify(expansion, null, 2));
// if (gameIsExpansion) {
// console.log('Connecting current game to expansion');
// await prisma.game.update({
// where: {
// id: gameId
// },
// data: {
// expansions: {
// connect: {
// id: expansion.id
// }
// }
// }
// });
// } else {
// console.log('Connecting current game to base game');
// await prisma.game.update({
// where: {
// id: baseGameId
// },
// data: {
// expansions: {
// connect: {
// id: expansion.id
// }
// }
// }
// });
// }
// return expansion;
// } catch (e) {
// console.error(e);
// throw new Error('Something went wrong creating Expansion');
// }
// }

View file

@ -0,0 +1,422 @@
import kebabCase from 'just-kebab-case';
import db from '$lib/drizzle';
import { externalIds, gamesToExternalIds, type Games, games } from '../../../schema';
import { eq } from 'drizzle-orm';
import { error } from '@sveltejs/kit';
import { PUBLIC_SITE_URL } from '$env/static/public';
export async function createGame(locals: App.Locals, game: Games, externalId: string) {
if (!game || !externalId || externalId === '') {
error(400, 'Invalid Request');
}
try {
const dbExternalId = await db.query.externalIds.findFirst({
where: eq(externalIds.externalId, externalId)
});
if (dbExternalId) {
const foundGame = await db
.select({
id: games.id,
name: games.name,
slug: games.slug
})
.from(games)
.leftJoin(gamesToExternalIds, eq(gamesToExternalIds.externalId, externalId));
console.log('Game already exists', foundGame);
if (foundGame.length > 0) {
console.log('Game name', foundGame[0].name);
return new Response('Game already exists', {
headers: {
'Content-Type': 'application/json',
Location: `${PUBLIC_SITE_URL}/api/game/${foundGame[0].id}`
},
status: 409
});
}
}
let dbGames: Games[] = [];
console.log('Creating game', JSON.stringify(game, null, 2));
await db.transaction(async (transaction) => {
dbGames = await transaction
.insert(games)
.values({
name: game.name,
slug: kebabCase(game.name || game.slug || ''),
description: game.description,
year_published: game.year_published,
url: game.url,
image_url: game.image_url,
thumb_url: game.thumb_url,
min_age: game.min_age,
min_players: game.min_players,
max_players: game.max_players,
min_playtime: game.min_playtime,
max_playtime: game.max_playtime
})
.returning();
const dbExternalIds = await transaction
.insert(externalIds)
.values({
externalId,
type: 'game'
})
.returning({ id: externalIds.id });
await transaction.insert(gamesToExternalIds).values({
gameId: dbGames[0].id,
externalId: dbExternalIds[0].id
});
});
if (dbGames.length === 0) {
return new Response('Could not create game', {
status: 500
});
}
console.log('Created game', JSON.stringify(dbGames[0], null, 2));
return new Response(JSON.stringify(dbGames[0]), {
status: 201,
});
} catch (e) {
console.error(e);
throw new Error('Something went wrong creating Game');
}
}
export async function createOrUpdateGameMinimal(locals: App.Locals, game: Games, externalId: string) {
if (!game || !externalId || externalId === '') {
error(400, 'Invalid Request');
}
console.log('Creating or updating minimal game data', JSON.stringify(game, null, 2));
const externalUrl = `https://boardgamegeek.com/boardgame/${externalId}`;
try {
let dbGames: Games[] = [];
console.log('Creating game', JSON.stringify(game, null, 2));
await db.transaction(async (transaction) => {
dbGames = await transaction
.insert(games)
.values({
name: game.name,
slug: kebabCase(game.name || game.slug || ''),
description: game.description,
year_published: game.year_published,
url: externalUrl,
image_url: game.image_url,
thumb_url: game.thumb_url,
min_age: game.min_age,
min_players: game.min_players,
max_players: game.max_players,
min_playtime: game.min_playtime,
max_playtime: game.max_playtime
})
.onConflictDoUpdate({
target: games.id,
set: {
name: game.name,
slug: kebabCase(game.name || game.slug || ''),
description: game.description,
year_published: game.year_published,
url: externalUrl,
image_url: game.image_url,
thumb_url: game.thumb_url,
min_age: game.min_age,
min_players: game.min_players,
max_players: game.max_players,
min_playtime: game.min_playtime,
max_playtime: game.max_playtime
}
})
.returning();
const dbExternalIds = await transaction
.insert(externalIds)
.values({
externalId,
type: 'game'
})
.onConflictDoNothing()
.returning({ id: externalIds.id });
await transaction.insert(gamesToExternalIds).values({
gameId: dbGames[0].id,
externalId: dbExternalIds[0].id
}).onConflictDoNothing();
});
if (dbGames.length === 0) {
return new Response('Could not create game', {
status: 500
});
}
console.log('Created game', JSON.stringify(dbGames[0], null, 2));
return new Response(JSON.stringify(dbGames[0]), {
status: 201,
});
} catch (e) {
console.error(e);
throw new Error('Something went wrong creating Game');
}
}
export async function createOrUpdateGame(locals: App.Locals, game: Games, externalId: string) {
if (!game || !externalId || externalId === '') {
error(400, 'Invalid Request');
}
try {
const externalUrl = `https://boardgamegeek.com/boardgame/${externalId}`;
const dbExternalId = await db.query.externalIds.findFirst({
where: eq(externalIds.externalId, externalId)
});
if (dbExternalId) {
const foundGame = await db
.select({
id: games.id,
name: games.name,
slug: games.slug
})
.from(games)
.leftJoin(gamesToExternalIds, eq(gamesToExternalIds.externalId, externalId));
console.log('Game already exists', foundGame);
if (foundGame.length > 0) {
console.log('Game name', foundGame[0].name);
return new Response('Game already exists', {
headers: {
'Content-Type': 'application/json',
Location: `${PUBLIC_SITE_URL}/api/game/${foundGame[0].id}`
},
status: 409
});
}
}
let dbGames: Games[] = [];
console.log('Creating game', JSON.stringify(game, null, 2));
await db.transaction(async (transaction) => {
dbGames = await transaction
.insert(games)
.values({
name: game.name,
slug: kebabCase(game.name || game.slug || ''),
description: game.description,
year_published: game.year_published,
url: game.url,
image_url: game.image_url,
thumb_url: game.thumb_url,
min_age: game.min_age,
min_players: game.min_players,
max_players: game.max_players,
min_playtime: game.min_playtime,
max_playtime: game.max_playtime
})
.onConflictDoUpdate({
target: games.id,
set: {
name: game.name,
slug: kebabCase(game.name || game.slug || ''),
description: game.description,
year_published: game.year_published,
url: externalUrl,
image_url: game.image_url,
thumb_url: game.thumb_url,
min_age: game.min_age,
min_players: game.min_players,
max_players: game.max_players,
min_playtime: game.min_playtime,
max_playtime: game.max_playtime
}
})
.returning();
const dbExternalIds = await transaction
.insert(externalIds)
.values({
externalId,
type: 'game'
})
.onConflictDoNothing()
.returning({ id: externalIds.id });
await transaction.insert(gamesToExternalIds).values({
gameId: dbGames[0].id,
externalId: dbExternalIds[0].id
}).onConflictDoNothing();
});
if (dbGames.length === 0) {
return new Response('Could not create game', {
status: 500
});
}
console.log('Created game', JSON.stringify(dbGames[0], null, 2));
return new Response(JSON.stringify(dbGames[0]), {
status: 201,
});
} catch (e) {
console.error(e);
throw new Error('Something went wrong creating Game');
}
}
export async function updateGame(locals: App.Locals, game: Games, id: string) {
if (!game || !id || id === '') {
error(400, 'Invalid Request');
}
try {
const dbGame = await db
.update(games)
.set({
name: game.name,
slug: kebabCase(game.name || game.slug || ''),
description: game.description,
year_published: game.year_published,
url: game.url,
image_url: game.image_url,
thumb_url: game.thumb_url,
min_age: game.min_age,
min_players: game.min_players,
max_players: game.max_players,
min_playtime: game.min_playtime,
max_playtime: game.max_playtime
})
.where(eq(games.id, id))
.returning();
return new Response(JSON.stringify(dbGame[0]), {
headers: {
'Content-Type': 'application/json'
}
});
} catch (e) {
console.error(e);
return new Response('Could not get publishers', {
status: 500
});
}
}
// 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;
// // const expansionIds = game.expansions;
// const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
// console.log('categoryIds', categoryIds);
// console.log('mechanicIds', mechanicIds);
// await db.transaction(async (transaction) => {
// const dbGame = await db.transaction(async (transaction) => {
// transaction.insert(games).values({
// 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(),
// }).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(),
// }
// }).returning();
// });
// // TODO: Connect to everything else
// });
// 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
// }
// }
// });

View file

@ -0,0 +1,77 @@
import kebabCase from 'just-kebab-case';
import db from '$lib/drizzle';
import { externalIds, mechanics, mechanicsToExternalIds, type Mechanics } from '../../../schema';
import { eq } from 'drizzle-orm';
import { error } from '@sveltejs/kit';
import { PUBLIC_SITE_URL } from '$env/static/public';
export async function createMechanic(locals: App.Locals, mechanic: Mechanics, externalId: string) {
if (!mechanic || !externalId || externalId === '') {
error(400, 'Invalid Request');
}
try {
const dbExternalId = await db.query.externalIds.findFirst({
where: eq(externalIds.externalId, externalId)
});
if (dbExternalId) {
const foundMechanic = await db
.select({
id: mechanics.id,
name: mechanics.name,
slug: mechanics.slug
})
.from(mechanics)
.leftJoin(mechanicsToExternalIds, eq(mechanicsToExternalIds.externalId, externalId));
console.log('Mechanic already exists', foundMechanic);
if (foundMechanic.length > 0) {
console.log('Mechanic name', foundMechanic[0].name);
return new Response('Mechanic already exists', {
headers: {
'Content-Type': 'application/json',
Location: `${PUBLIC_SITE_URL}/api/mechanic/${foundMechanic[0].id}`
},
status: 409
});
}
}
let dbMechanics: Mechanics[] = [];
console.log('Creating mechanic', JSON.stringify(mechanic, null, 2));
await db.transaction(async (transaction) => {
dbMechanics = await transaction
.insert(mechanics)
.values({
name: mechanic.name,
slug: kebabCase(mechanic.name || mechanic.slug || '')
})
.returning();
const dbExternalIds = await transaction
.insert(externalIds)
.values({
externalId,
type: 'mechanic'
})
.returning({ id: externalIds.id });
await transaction.insert(mechanicsToExternalIds).values({
mechanicId: dbMechanics[0].id,
externalId: dbExternalIds[0].id
});
});
if (dbMechanics.length === 0) {
return new Response('Could not create mechanic', {
status: 500
});
}
console.log('Created mechanic', JSON.stringify(dbMechanics[0], null, 2));
return new Response(JSON.stringify(dbMechanics[0]), {
status: 201,
});
} catch (e) {
console.error(e);
throw new Error('Something went wrong creating Mechanic');
}
}

View file

@ -0,0 +1,125 @@
import { error } from '@sveltejs/kit';
import { eq } from 'drizzle-orm';
import kebabCase from 'just-kebab-case';
import db from '$lib/drizzle';
import {
externalIds,
publishersToExternalIds,
type Publishers,
publishers,
} from '../../../schema';
import { PUBLIC_SITE_URL } from '$env/static/public';
export async function getPublisher(locals: App.Locals, id: string) {
const publisher = await db.select().from(publishers).where(eq(publishers.id, id));
if (publisher.length === 0) {
error(404, 'not found');
}
return new Response(JSON.stringify(publisher[0]), {
headers: {
'Content-Type': 'application/json'
}
});
}
export async function updatePublisher(locals: App.Locals, publisher: Publishers, id: string) {
if (!publisher || publisher.name === '' || !id || id === '') {
error(400, 'Invalid Request');
}
try {
const dbPublisher = await db
.update(publishers)
.set({
name: publisher.name,
slug: kebabCase(publisher.name || '')
})
.where(eq(publishers.id, id))
.returning();
return new Response(JSON.stringify(dbPublisher[0]), {
headers: {
'Content-Type': 'application/json'
}
});
} catch (e) {
console.error(e);
return new Response('Could not get publishers', {
status: 500
});
}
}
export async function createPublisher(
locals: App.Locals,
publisher: Publishers,
externalId: string
) {
if (!publisher || !externalId || externalId === '') {
error(400, 'Invalid Request');
}
try {
const dbExternalId = await db.query.externalIds.findFirst({
where: eq(externalIds.externalId, externalId)
});
if (dbExternalId) {
const foundPublisher = await db
.select({
id: publishers.id,
name: publishers.name,
slug: publishers.slug
})
.from(publishers)
.leftJoin(publishersToExternalIds, eq(publishersToExternalIds.externalId, externalId));
console.log('Publisher already exists', foundPublisher);
if (foundPublisher.length > 0) {
console.log('Publisher name', foundPublisher[0].name);
return new Response('Publisher already exists', {
headers: {
'Content-Type': 'application/json',
Location: `${PUBLIC_SITE_URL}/api/publisher/${foundPublisher[0].id}`
},
status: 409
});
}
}
let dbPublishers: Publishers[] = [];
console.log('Creating publisher', JSON.stringify(publisher, null, 2));
await db.transaction(async (transaction) => {
dbPublishers = await transaction
.insert(publishers)
.values({
name: publisher.name,
slug: kebabCase(publisher.name || publisher.slug || '')
})
.returning();
const dbExternalIds = await transaction
.insert(externalIds)
.values({
externalId,
type: 'publisher'
})
.returning({ id: externalIds.id });
await transaction.insert(publishersToExternalIds).values({
publisherId: dbPublishers[0].id,
externalId: dbExternalIds[0].id
});
});
if (dbPublishers.length === 0) {
return new Response('Could not create publisher', {
status: 500
});
}
console.log('Created publisher', JSON.stringify(dbPublishers[0], null, 2));
return new Response(JSON.stringify(dbPublishers[0]), {
status: 201,
});
} catch (e) {
console.error(e);
throw new Error('Something went wrong creating Publisher');
}
}

View file

@ -1,415 +0,0 @@
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';
import db from '$lib/drizzle';
import { externalIds, games, publishersToExternalIds, type Publishers, publishers } from '../../schema';
import { eq, sql } from 'drizzle-orm';
import { error } from '@sveltejs/kit';
export async function createPublisher(locals: App.Locals, publisher: Publishers, externalId: string) {
if (!publisher || !externalId || externalId === '') {
error(400, 'Invalid Request');
}
try {
let dbExternalId = await db.query.externalIds.findFirst({
where: eq(externalIds.id, externalId),
});
if (dbExternalId) {
const dbPublisher = await db.select().from(publishers).leftJoin(publishersToExternalIds, eq(publishersToExternalIds.externalId, externalId));
}
let dbPublisher = await db.query.publishers.findFirst({
where: eq(publishers.external_id, externalPublisher.id),
columns: {
id: true,
name: true,
slug: true,
external_id: true
},
with: {
publishersToExternalIds: {
columns: {
externalId: true
}
}
}
});
if (dbPublisher) {
console.log('Publisher already exists', dbPublisher.name);
return dbPublisher;
}
console.log('Creating publisher', JSON.stringify(externalPublisher, null, 2));
let publisher = await prisma.publisher.create({
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');
}
}
export async function createCategory(locals: App.Locals, externalCategory: BggLinkDto) {
try {
let dbCategory = await prisma.category.findFirst({
where: {
external_id: externalCategory.id
},
select: {
id: true,
name: true,
slug: true,
external_id: true
}
});
if (dbCategory) {
console.log('Category already exists', dbCategory.name);
return dbCategory;
}
console.log('Creating category', JSON.stringify(externalCategory, null, 2));
let category = await prisma.category.create({
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');
}
}
export async function createMechanic(locals: App.Locals, externalMechanic: BggLinkDto) {
try {
let dbMechanic = await prisma.mechanic.findFirst({
where: {
external_id: externalMechanic.id
},
select: {
id: true,
name: true,
slug: true,
external_id: true
}
});
if (dbMechanic) {
console.log('Mechanic already exists', dbMechanic.name);
return dbMechanic;
}
console.log('Creating mechanic', JSON.stringify(externalMechanic, null, 2));
let mechanic = await prisma.mechanic.upsert({
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');
}
}
export async function createExpansion(
locals: App.Locals,
game: Game,
externalExpansion: BggLinkDto,
gameIsExpansion: boolean,
eventFetch: Function
) {
try {
let dbExpansionGame = await prisma.game.findUnique({
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);
dbExpansionGame = await createOrUpdateGameMinimal(locals, boredGame);
} else {
throw new Error(
`${gameIsExpansion ? 'Base game' : 'Expansion game'} not found and failed to create.`
);
}
}
let dbExpansion;
let baseGameId;
let gameId;
if (gameIsExpansion) {
console.log(
'External expansion is expansion. Looking for base game',
JSON.stringify(game, null, 2)
);
dbExpansion = await prisma.expansion.findFirst({
where: {
game_id: dbExpansionGame.id
},
select: {
id: true,
base_game_id: true,
game_id: true
}
});
baseGameId = game.id;
gameId = dbExpansionGame.id;
} else {
console.log(
'External Expansion is base game. Looking for expansion',
JSON.stringify(game, null, 2)
);
dbExpansion = await prisma.expansion.findFirst({
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}`);
let expansion = await prisma.expansion.create({
data: {
base_game_id: baseGameId,
game_id: gameId
}
});
console.log('Created expansion', JSON.stringify(expansion, null, 2));
if (gameIsExpansion) {
console.log('Connecting current game to expansion');
await prisma.game.update({
where: {
id: gameId
},
data: {
expansions: {
connect: {
id: expansion.id
}
}
}
});
} else {
console.log('Connecting current game to base game');
await prisma.game.update({
where: {
id: baseGameId
},
data: {
expansions: {
connect: {
id: expansion.id
}
}
}
});
}
return expansion;
} catch (e) {
console.error(e);
throw new Error('Something went wrong creating Expansion');
}
}
export async function createOrUpdateGameMinimal(locals: App.Locals, game: Game) {
console.log('Creating or updating minimal game data', JSON.stringify(game, null, 2));
const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
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) });
}
export async function createOrUpdateGame(locals: App.Locals, game: Game) {
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;
// const expansionIds = game.expansions;
const externalUrl = `https://boardgamegeek.com/boardgame/${game.external_id}`;
console.log('categoryIds', categoryIds);
console.log('mechanicIds', mechanicIds);
await db.transaction(async (transaction) => {
const dbGame = await transaction.insert(games).values({
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(),
}).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(),
}
}).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
// }
// }
});
}

View file

@ -8,7 +8,7 @@ import {
createMechanic,
createOrUpdateGame,
createPublisher
} from '$lib/utils/dbUtils.js';
} from '$lib/utils/db/dbUtils.js';
import { mapAPIGameToBoredGame } from '$lib/utils/gameMapper.js';
import prisma from '$lib/prisma';
import type { PageServerLoad } from './$types';
@ -119,11 +119,11 @@ async function syncGameAndConnectedData(locals: App.Locals, game: Game, eventFet
if (externalGameResponse.ok) {
const externalGame = await externalGameResponse.json();
console.log('externalGame', externalGame);
let categories = [];
let mechanics = [];
let artists = [];
let designers = [];
let publishers = [];
const categories = [];
const mechanics = [];
const artists = [];
const designers = [];
const publishers = [];
for (const externalCategory of externalGame.categories) {
const category = await createCategory(locals, externalCategory);
categories.push({
@ -156,7 +156,7 @@ async function syncGameAndConnectedData(locals: App.Locals, game: Game, eventFet
}
}
let boredGame = mapAPIGameToBoredGame(externalGame);
const boredGame = mapAPIGameToBoredGame(externalGame);
boredGame.categories = categories;
boredGame.mechanics = mechanics;

View file

@ -15,7 +15,7 @@ import {
createOrUpdateGame,
createOrUpdateGameMinimal,
createPublisher
} from '$lib/utils/dbUtils.js';
} from '$lib/utils/db/dbUtils.js';
// import { listGameSchema } from '$lib/config/zod-schemas.js';
async function searchForGames(

View file

@ -0,0 +1,21 @@
import { createPublisher } from '$lib/utils/db/publisherUtils.js';
import type { Publishers } from '../../../schema.js';
type PublisherCreate = {
publisher: Publishers;
externalId: string;
}
export async function POST({ request, locals }) {
const data: PublisherCreate = await request.json();
console.log('data', data);
try {
return await createPublisher(locals, data.publisher, data.externalId);
} catch (e) {
console.error(e);
return new Response('Could not create publisher', {
status: 500
});
}
}

View file

@ -0,0 +1,19 @@
import { getPublisher, updatePublisher } from '$lib/utils/db/publisherUtils.js';
import type { Publishers } from '../../../../schema.js';
export async function GET({ locals, params }) {
try {
return await getPublisher(locals, params.id);
} catch (e) {
console.error(e);
return new Response('Could not get publishers', {
status: 500
});
}
}
export async function PUT({ locals, params, request }) {
const data: Publishers = await request.json();
const publisherId = params.id;
return await updatePublisher(locals, data, publisherId);
}

View file

@ -136,6 +136,8 @@ export const user_role_relations = relations(user_roles, ({ one }) => ({
})
}));
export type UserRoles = InferSelectModel<typeof user_roles>;
export const collections = pgTable('collections', {
id: varchar('id', {
length: 255
@ -195,6 +197,8 @@ export const collection_items = pgTable('collection_items', {
}).default(sql`now()`)
});
export type CollectionItems = InferSelectModel<typeof collection_items>;
export const collection_item_relations = relations(collection_items, ({ one }) => ({
collection: one(collections, {
fields: [collection_items.collection_id],
@ -229,6 +233,8 @@ export const wishlists = pgTable('wishlists', {
}).default(sql`now()`)
});
export type Wishlists = InferSelectModel<typeof wishlists>;
export const wishlists_relations = relations(wishlists, ({ one }) => ({
user: one(users, {
fields: [wishlists.user_id],
@ -264,6 +270,8 @@ export const wishlist_items = pgTable('wishlist_items', {
}).default(sql`now()`)
});
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
export const wishlist_item_relations = relations(wishlist_items, ({ one }) => ({
wishlist: one(wishlists, {
fields: [wishlist_items.wishlist_id],
@ -298,6 +306,8 @@ export const externalIds = pgTable('external_ids', {
}).notNull()
});
export type ExternalIds = InferSelectModel<typeof externalIds>;
export const games = pgTable(
'games',
{
@ -415,30 +425,9 @@ export const expansions = pgTable('expansions', {
}).default(sql`now()`)
});
export const expansionsToExternalIds = pgTable(
'expansions_to_external_ids',
{
expansionId: varchar('expansion_id', {
length: 255
})
.notNull()
.references(() => expansions.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: varchar('external_id', {
length: 255
})
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' })
},
(table) => {
return {
expansionsToExternalIdsPkey: primaryKey({
columns: [table.expansionId, table.externalId]
})
};
}
);
export type Expansions = InferSelectModel<typeof expansions>;
export const expansion_relations = relations(expansions, ({ one, many }) => ({
export const expansion_relations = relations(expansions, ({ one }) => ({
baseGame: one(games, {
fields: [expansions.base_game_id],
references: [games.id]
@ -446,8 +435,7 @@ export const expansion_relations = relations(expansions, ({ one, many }) => ({
game: one(games, {
fields: [expansions.game_id],
references: [games.id]
}),
expansionsToExternalIds: many(expansionsToExternalIds)
})
}));
export const publishers = pgTable('publishers', {
@ -462,7 +450,6 @@ export const publishers = pgTable('publishers', {
slug: varchar('slug', {
length: 255
}),
external_id: integer('external_id'),
created_at: timestamp('created_at', {
withTimezone: true,
mode: 'date',
@ -513,7 +500,6 @@ export const categories = pgTable('categories', {
slug: varchar('slug', {
length: 255
}),
external_id: integer('external_id'),
created_at: timestamp('created_at', {
withTimezone: true,
mode: 'date',
@ -526,6 +512,8 @@ export const categories = pgTable('categories', {
}).default(sql`now()`)
});
export type Categories = InferSelectModel<typeof categories>;
export const categoriesToExternalIds = pgTable('categories_to_external_ids', {
categoryId: varchar('category_id', {
length: 255
@ -592,7 +580,6 @@ export const mechanics = pgTable('mechanics', {
slug: varchar('slug', {
length: 255
}),
external_id: integer('external_id'),
created_at: timestamp('created_at', {
withTimezone: true,
mode: 'date',
@ -605,6 +592,8 @@ export const mechanics = pgTable('mechanics', {
}).default(sql`now()`)
});
export type Mechanics = InferSelectModel<typeof mechanics>;
export const mechanicsToExternalIds = pgTable('mechanics_to_external_ids', {
mechanicId: varchar('mechanic_id', {
length: 255