Update packages, add to game types and mapping values, adding slug to publisher, and creating things when searching.

This commit is contained in:
Bradley Shellnut 2023-06-25 23:14:26 -07:00
parent b23a101c0f
commit b02609f009
7 changed files with 276 additions and 116 deletions

View file

@ -26,7 +26,7 @@
"@rgossiaux/svelte-heroicons": "^0.1.2",
"@sveltejs/adapter-auto": "^1.0.3",
"@sveltejs/adapter-vercel": "^1.0.6",
"@sveltejs/kit": "^1.20.4",
"@sveltejs/kit": "^1.20.5",
"@types/cookie": "^0.5.1",
"@types/node": "^18.16.18",
"@typescript-eslint/eslint-plugin": "^5.60.0",
@ -34,7 +34,7 @@
"autoprefixer": "^10.4.14",
"eslint": "^8.43.0",
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-svelte": "^2.31.0",
"eslint-plugin-svelte": "^2.31.1",
"just-clone": "^6.2.0",
"just-debounce-it": "^3.2.0",
"postcss": "^8.4.24",
@ -48,7 +48,7 @@
"svelte": "^3.59.2",
"svelte-check": "^2.10.3",
"svelte-preprocess": "^5.0.4",
"sveltekit-superforms": "^1.1.1",
"sveltekit-superforms": "^1.1.2",
"ts-node": "^10.9.1",
"tslib": "^2.5.3",
"typescript": "^4.9.5",

View file

@ -70,7 +70,7 @@ dependencies:
version: 0.2.1(svelte@3.59.2)
sveltekit-flash-message:
specifier: ^0.11.3
version: 0.11.3(@sveltejs/kit@1.20.4)(svelte@3.59.2)
version: 0.11.3(@sveltejs/kit@1.20.5)(svelte@3.59.2)
zod-to-json-schema:
specifier: ^3.21.2
version: 3.21.2(zod@3.21.4)
@ -87,13 +87,13 @@ devDependencies:
version: 0.1.2(svelte@3.59.2)
'@sveltejs/adapter-auto':
specifier: ^1.0.3
version: 1.0.3(@sveltejs/kit@1.20.4)
version: 1.0.3(@sveltejs/kit@1.20.5)
'@sveltejs/adapter-vercel':
specifier: ^1.0.6
version: 1.0.6(@sveltejs/kit@1.20.4)
version: 1.0.6(@sveltejs/kit@1.20.5)
'@sveltejs/kit':
specifier: ^1.20.4
version: 1.20.4(svelte@3.59.2)(vite@4.3.9)
specifier: ^1.20.5
version: 1.20.5(svelte@3.59.2)(vite@4.3.9)
'@types/cookie':
specifier: ^0.5.1
version: 0.5.1
@ -116,8 +116,8 @@ devDependencies:
specifier: ^8.8.0
version: 8.8.0(eslint@8.43.0)
eslint-plugin-svelte:
specifier: ^2.31.0
version: 2.31.0(eslint@8.43.0)(svelte@3.59.2)(ts-node@10.9.1)
specifier: ^2.31.1
version: 2.31.1(eslint@8.43.0)(svelte@3.59.2)(ts-node@10.9.1)
just-clone:
specifier: ^6.2.0
version: 6.2.0
@ -158,8 +158,8 @@ devDependencies:
specifier: ^5.0.4
version: 5.0.4(postcss-load-config@4.0.1)(postcss@8.4.24)(sass@1.63.6)(svelte@3.59.2)(typescript@4.9.5)
sveltekit-superforms:
specifier: ^1.1.1
version: 1.1.1(@sveltejs/kit@1.20.4)(svelte@3.59.2)(zod@3.21.4)
specifier: ^1.1.2
version: 1.1.2(@sveltejs/kit@1.20.5)(svelte@3.59.2)(zod@3.21.4)
ts-node:
specifier: ^10.9.1
version: 10.9.1(@types/node@18.16.18)(typescript@4.9.5)
@ -1123,7 +1123,7 @@ packages:
nopt: 5.0.0
npmlog: 5.0.1
rimraf: 3.0.2
semver: 7.5.2
semver: 7.5.3
tar: 6.1.13
transitivePeerDependencies:
- encoding
@ -1211,21 +1211,21 @@ packages:
picomatch: 2.3.1
dev: true
/@sveltejs/adapter-auto@1.0.3(@sveltejs/kit@1.20.4):
/@sveltejs/adapter-auto@1.0.3(@sveltejs/kit@1.20.5):
resolution: {integrity: sha512-hc7O12YQqvZ1CD4fo1gMJuPzBZvuoG5kwxb2RRoz4fVoB8B2vuPO2cY751Ln0G6T/HMrAf8kCqw6Pg+wbxcstw==}
peerDependencies:
'@sveltejs/kit': ^1.0.0
dependencies:
'@sveltejs/kit': 1.20.4(svelte@3.59.2)(vite@4.3.9)
'@sveltejs/kit': 1.20.5(svelte@3.59.2)(vite@4.3.9)
import-meta-resolve: 2.2.0
dev: true
/@sveltejs/adapter-vercel@1.0.6(@sveltejs/kit@1.20.4):
/@sveltejs/adapter-vercel@1.0.6(@sveltejs/kit@1.20.5):
resolution: {integrity: sha512-fo6aaEygPd/6B5Jms4Ff7R4jbADnppuLvKOWBNTGe5MGB7ZRUkl+gxHWMQx2av2knyEZkA6V8y5M6R3ML5yN4g==}
peerDependencies:
'@sveltejs/kit': ^1.0.0
dependencies:
'@sveltejs/kit': 1.20.4(svelte@3.59.2)(vite@4.3.9)
'@sveltejs/kit': 1.20.5(svelte@3.59.2)(vite@4.3.9)
'@vercel/nft': 0.22.6
esbuild: 0.16.8
transitivePeerDependencies:
@ -1233,8 +1233,8 @@ packages:
- supports-color
dev: true
/@sveltejs/kit@1.20.4(svelte@3.59.2)(vite@4.3.9):
resolution: {integrity: sha512-MmAzIuMrP7A+8fqDVbxm6ekGHRHL/+Fk8sQPAzPG4G2TxUDtHdn/WcIxeEqHzARMf0OtGSC+VPyOSFuw2Cy2Mg==}
/@sveltejs/kit@1.20.5(svelte@3.59.2)(vite@4.3.9):
resolution: {integrity: sha512-8rJYZ2boRlO75lwpbpB+DlSzIwmTuamXTpVlDtw4dBk86o3UaDe/+Ro4xCsV/4FtTw2U8xPHyV83edAWbQHG0w==}
engines: {node: ^16.14 || >=18}
hasBin: true
requiresBuild: true
@ -1446,7 +1446,7 @@ packages:
debug: 4.3.4
globby: 11.1.0
is-glob: 4.0.3
semver: 7.5.2
semver: 7.5.3
tsutils: 3.21.0(typescript@4.9.5)
typescript: 4.9.5
transitivePeerDependencies:
@ -2027,8 +2027,8 @@ packages:
eslint: 8.43.0
dev: true
/eslint-plugin-svelte@2.31.0(eslint@8.43.0)(svelte@3.59.2)(ts-node@10.9.1):
resolution: {integrity: sha512-Q70jPFRraTkc/giPSfY7yuatmJcb5fPelWNplevqd45gfaJDjc3qXRtWQ6m9U5tWVVYERU9dcdUod294vwD8Gw==}
/eslint-plugin-svelte@2.31.1(eslint@8.43.0)(svelte@3.59.2)(ts-node@10.9.1):
resolution: {integrity: sha512-08v+DqzHiwIVEbi+266D7+BDhayp9OSqCwa/lHaZlZOlFY0vZLYs/h7SkkUPzA5fTVt8OUJBtvCxFiWEYOvvGg==}
engines: {node: ^14.17.0 || >=16.0.0}
peerDependencies:
eslint: ^7.0.0 || ^8.0.0-0
@ -2047,6 +2047,7 @@ packages:
postcss-load-config: 3.1.4(postcss@8.4.24)(ts-node@10.9.1)
postcss-safe-parser: 6.0.0(postcss@8.4.24)
postcss-selector-parser: 6.0.13
semver: 7.5.3
svelte: 3.59.2
svelte-eslint-parser: 0.31.0(svelte@3.59.2)
transitivePeerDependencies:
@ -3447,8 +3448,8 @@ packages:
lru-cache: 6.0.0
dev: true
/semver@7.5.2:
resolution: {integrity: sha512-SoftuTROv/cRjCze/scjGyiDtcUyxw1rgYQSZY7XTmtR5hX+dm76iDbTH8TkLPHCQmlbQVSSbNZCPM2hb0knnQ==}
/semver@7.5.3:
resolution: {integrity: sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==}
engines: {node: '>=10'}
hasBin: true
dependencies:
@ -3764,24 +3765,24 @@ packages:
resolution: {integrity: sha512-vzSyuGr3eEoAtT/A6bmajosJZIUWySzY2CzB3w2pgPvnkUjGqlDnsNnA0PMO+mMAhuyMul6C2uuZzY6ELSkzyA==}
engines: {node: '>= 8'}
/sveltekit-flash-message@0.11.3(@sveltejs/kit@1.20.4)(svelte@3.59.2):
/sveltekit-flash-message@0.11.3(@sveltejs/kit@1.20.5)(svelte@3.59.2):
resolution: {integrity: sha512-tMKBobVFLYth0z2Kq9M+pi7Ip2OBhOrzivzx64v9+D2bWRwnZ3pmdWStYfQYxlz5CayozRQsmtipNg1vM+JN9Q==}
peerDependencies:
'@sveltejs/kit': ^1.0.0
svelte: ^3
dependencies:
'@sveltejs/kit': 1.20.4(svelte@3.59.2)(vite@4.3.9)
'@sveltejs/kit': 1.20.5(svelte@3.59.2)(vite@4.3.9)
svelte: 3.59.2
dev: false
/sveltekit-superforms@1.1.1(@sveltejs/kit@1.20.4)(svelte@3.59.2)(zod@3.21.4):
resolution: {integrity: sha512-lD3ov06C/O8hD7mCzEQZ7CTsbHrh6kWhRP3njI9ZSwvG5DW6vhfi6Re/cyYy//cS0oMONI0xBieWyr9s24Y9jA==}
/sveltekit-superforms@1.1.2(@sveltejs/kit@1.20.5)(svelte@3.59.2)(zod@3.21.4):
resolution: {integrity: sha512-oWW3+Phcs/CkUKGEx0IsCr6Dw3a22/MVs4Tvi8k/jh66pqwP/jOZu3/dT367pkbIh5T7NK20yrnbHu8nm2E7pQ==}
peerDependencies:
'@sveltejs/kit': 1.x
svelte: 3.x
svelte: 3.x || 4.x
zod: 3.x
dependencies:
'@sveltejs/kit': 1.20.4(svelte@3.59.2)(vite@4.3.9)
'@sveltejs/kit': 1.20.5(svelte@3.59.2)(vite@4.3.9)
svelte: 3.59.2
zod: 3.21.4
dev: true

View file

@ -129,8 +129,8 @@ model Game {
id String @id @default(cuid())
name String
slug String
description String?
description_preview String?
description String? @db.LongText
description_preview String? @db.LongText
year_published Int?
min_players Int?
max_players Int?
@ -143,6 +143,8 @@ model Game {
rules_url String?
primary_publisher_id String?
primary_publisher Publisher? @relation("PrimaryPublishers", references: [id], fields: [primary_publisher_id])
primary_designer_id String?
primary_designer Designer? @relation("PrimaryDesigners", references: [id], fields: [primary_designer_id])
categories Category[]
mechanics Mechanic[]
designers Designer[]
@ -162,37 +164,39 @@ model Game {
}
model GameName {
id String @id @default(cuid())
name String
game_id String
game Game @relation(references: [id], fields: [game_id])
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
id String @id @default(cuid())
name String
game_id String
game Game @relation(references: [id], fields: [game_id])
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
@@index([game_id])
@@map("game_names")
}
model Publisher {
id String @id @default(cuid())
name String
games Game[]
primary_publisher Game[] @relation("PrimaryPublishers")
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
id String @id @default(cuid())
name String
slug String
external_id String @unique
games Game[]
primary_publisher Game[] @relation("PrimaryPublishers")
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
@@fulltext([name])
@@map("publishers")
}
model Category {
id String @id @default(cuid())
name String
slug String
games Game[]
external_id String @unique
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
id String @id @default(cuid())
name String
slug String
games Game[]
external_id String @unique
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
@@fulltext([name])
@@map("categories")
@ -212,36 +216,39 @@ model Mechanic {
}
model Designer {
id String @id @default(cuid())
name String
games Game[]
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
id String @id @default(cuid())
name String
external_id String @unique
games Game[]
primary_designer Game[] @relation("PrimaryDesigners")
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
@@fulltext([name])
@@map("designers")
}
model Artist {
id String @id @default(cuid())
name String
games Game[]
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
id String @id @default(cuid())
name String
external_id String @unique
games Game[]
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
@@fulltext([name])
@@map("artists")
}
model Expansion {
id String @id @default(cuid())
name String
year_published Int?
baseGame Game? @relation(fields: [base_game_id], references: [id])
id String @id @default(cuid())
name String
year_published Int?
baseGame Game? @relation(fields: [base_game_id], references: [id])
base_game_id String?
external_id String @unique
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
external_id String @unique
created_at DateTime @default(now()) @db.Timestamp(6)
updated_at DateTime @updatedAt @db.Timestamp(6)
@@fulltext([name])
@@index([base_game_id])

View file

@ -57,6 +57,24 @@ export type SavedGameType = {
includeInRandom: boolean;
};
export type MechanicType = {
id: string;
};
export type CategoryType = {
id: string;
};
export type PublisherType = {
id: string;
name: string;
};
export type DesignerType = {
id: string;
name: string;
};
export type GameType = {
id: string;
handle: string;
@ -71,6 +89,14 @@ export type GameType = {
price_au: number;
msrp: number;
year_published: number;
categories: CategoryType[];
mechanics: MechanicType[];
primary_publisher: PublisherType;
publishers: PublisherType[];
primary_designer: DesignerType;
designers: DesignerType[];
developers: String[];
artists: String[];
min_players: number;
max_players: number;
min_playtime: number;

View file

@ -41,22 +41,23 @@ export function mapSavedGameToGame(game: SavedGameType): GameType {
};
}
// TODO: TYpe API response
// TODO: Type API response
export function mapAPIGameToBoredGame(game: any): GameType {
const {
id,
handle,
name,
url,
edit_url,
thumb_url,
image_url,
price,
price_ca,
price_uk,
price_au,
msrp,
year_published,
categories,
mechanics,
primary_designer,
designers,
primary_publisher,
publishers,
artists,
min_players,
max_players,
min_playtime,
@ -72,15 +73,16 @@ export function mapAPIGameToBoredGame(game: any): GameType {
handle,
name,
url,
edit_url,
thumb_url,
image_url,
price,
price_ca,
price_uk,
price_au,
msrp,
year_published,
categories,
mechanics,
primary_designer,
designers,
primary_publisher,
publishers,
artists,
min_players,
max_players,
min_playtime,

View file

@ -1,46 +1,87 @@
import { BOARD_GAME_ATLAS_CLIENT_ID } from '$env/static/private';
import { error } from '@sveltejs/kit';
import { superValidate } from 'sveltekit-superforms/server';
import kebabCase from 'just-kebab-case';
import { BOARD_GAME_ATLAS_CLIENT_ID } from '$env/static/private';
import prisma from '$lib/prisma.js';
import type { GameType, SearchQuery } from '$lib/types';
import { mapAPIGameToBoredGame } from '$lib/util/gameMapper';
import { search_schema } from '$lib/zodValidation';
async function searchForGames(urlQueryParams: SearchQuery) {
try {
const url = `https://api.boardgameatlas.com/api/search${
urlQueryParams ? `?${urlQueryParams}` : ''
}`;
const response = await fetch(url, {
method: 'get',
headers: {
'content-type': 'application/json'
let dbGames = await prisma.game.findMany({
where: {
name: {
search: urlQueryParams?.name
},
min_players: {
gte: urlQueryParams?.min_players || 0
},
max_players: {
lte: urlQueryParams?.max_players || 100
},
min_playtime: {
gte: urlQueryParams?.min_playtime || 0
},
max_playtime: {
lte: urlQueryParams?.max_playtime || 5000
},
min_age: {
gte: urlQueryParams?.min_age || 130
}
},
skip: urlQueryParams?.skip,
take: urlQueryParams?.limit,
orderBy: {
name: 'asc'
}
});
console.log('dbGames', dbGames);
if (!response.ok) {
console.log('Status not 200', response.status);
throw error(response.status);
}
if (!dbGames || dbGames.length === 0) {
const url = new URL(
`https://api.boardgameatlas.com/api/search${urlQueryParams ? `?${urlQueryParams}` : ''}`
);
const headers: HeadersInit = new Headers();
headers.set('Content-Type', 'application/json');
const requestInit: RequestInit = {
method: 'GET',
headers
};
const response = await fetch(url, requestInit);
const games: GameType[] = [];
let totalCount = 0;
if (response.ok) {
const gameResponse = await response.json();
const gameList: GameType[] = gameResponse?.games;
totalCount = gameResponse?.count;
console.log('totalCount', totalCount);
gameList.forEach((game) => {
if (game?.min_players && game?.max_players) {
game.players = `${game.min_players}-${game.max_players}`;
game.playtime = `${game.min_playtime}-${game.max_playtime}`;
}
games.push(mapAPIGameToBoredGame(game));
});
if (!response.ok) {
console.log('Status not 200', response.status);
throw error(response.status);
}
const games: GameType[] = [];
let totalCount = 0;
if (response.ok) {
const gameResponse = await response.json();
const gameList: GameType[] = gameResponse?.games;
totalCount = gameResponse?.count;
console.log('totalCount', totalCount);
gameList.forEach((game) => {
if (game?.min_players && game?.max_players) {
game.players = `${game.min_players}-${game.max_players}`;
game.playtime = `${game.min_playtime}-${game.max_playtime}`;
}
const boredGame = mapAPIGameToBoredGame(game);
createOrUpdateGame(boredGame);
games.push(boredGame);
});
}
return {
totalCount,
games
};
} else {
return {
totalCount: dbGames.length,
dbGames
};
}
return {
totalCount,
games
};
} catch (e) {
console.log(`Error searching board games ${e}`);
}
@ -50,7 +91,85 @@ async function searchForGames(urlQueryParams: SearchQuery) {
};
}
export const load = async ({ fetch, url }) => {
async function createOrUpdateGame(game: GameType) {
const categoryIds = game.categories.map((category) => ({
external_id: category.id
}));
const mechanicIds = game.mechanics.map((mechanic) => ({
external_id: mechanic.id
}));
return await prisma.game.upsert({
where: {
external_id: game.id
},
create: {
name: game.name,
slug: kebabCase(game.name),
description: game.description,
description_preview: game.description_preview,
external_id: game.id,
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,
year_published: game.year_published,
primary_publisher: {
connectOrCreate: {
where: {
external_id: game.primary_publisher.id
},
create: {
external_id: game.primary_publisher.id,
name: game.primary_publisher.name,
slug: kebabCase(game.primary_publisher.name)
}
}
},
categories: {
connect: categoryIds
},
mechanics: {
connect: mechanicIds
}
},
update: {
name: game.name,
slug: kebabCase(game.name),
description: game.description,
description_preview: game.description_preview,
external_id: game.id,
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,
year_published: game.year_published,
primary_publisher: {
connectOrCreate: {
where: {
external_id: game.primary_publisher.id
},
create: {
external_id: game.primary_publisher.id,
name: game.primary_publisher.name
}
}
},
categories: {
connect: categoryIds
},
mechanics: {
connect: mechanicIds
}
}
});
}
export const load = async (event) => {
const { params, locals, request, fetch, url } = event;
const defaults = {
limit: 10,
skip: 0

View file

@ -48,15 +48,20 @@ export const actions = {
throw redirect(302, '/auth/signin');
}
const game = await prisma.game.findUnique({
let game = await prisma.game.findUnique({
where: {
id: form.id
}
});
// if (!game) {
// throw redirect(302, '/404');
// }
if (!game) {
game = await prisma.game.create({
data: {
name: form.name
}
});
throw redirect(302, '/404');
}
if (game) {
const wishlist = await prisma.wishlist.create({