Step 5 migration: add localStorage to DB import flow
This commit is contained in:
132
api/server.js
132
api/server.js
@@ -357,6 +357,127 @@ async function toggleGameLoan(id) {
|
||||
return result.rowCount > 0;
|
||||
}
|
||||
|
||||
async function importCatalog(payload) {
|
||||
const brands = payload && payload.brands && typeof payload.brands === "object" ? payload.brands : {};
|
||||
const gamesByConsole =
|
||||
payload && payload.gamesByConsole && typeof payload.gamesByConsole === "object" ? payload.gamesByConsole : {};
|
||||
|
||||
const client = await pool.connect();
|
||||
let insertedConsoles = 0;
|
||||
let insertedGames = 0;
|
||||
|
||||
try {
|
||||
await client.query("BEGIN");
|
||||
|
||||
for (const [brandNameRaw, consoles] of Object.entries(brands)) {
|
||||
if (!Array.isArray(consoles)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (const consoleNameRaw of consoles) {
|
||||
const brandName = normalizeText(brandNameRaw).toUpperCase();
|
||||
const consoleName = normalizeText(consoleNameRaw);
|
||||
if (!brandName || !consoleName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const existingConsole = await client.query(
|
||||
`
|
||||
SELECT c.id
|
||||
FROM consoles c
|
||||
JOIN brands b ON b.id = c.brand_id
|
||||
WHERE b.name = $1 AND c.name = $2
|
||||
LIMIT 1;
|
||||
`,
|
||||
[brandName, consoleName],
|
||||
);
|
||||
|
||||
const result = await ensureConsole(client, brandNameRaw, consoleNameRaw);
|
||||
if (result && result.consoleId && !existingConsole.rowCount) {
|
||||
insertedConsoles += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (const [consoleNameRaw, games] of Object.entries(gamesByConsole)) {
|
||||
if (!Array.isArray(games) || !games.length) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const consoleName = normalizeText(consoleNameRaw);
|
||||
if (!consoleName) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const consoleRow = await client.query(
|
||||
`
|
||||
SELECT c.id, b.name AS brand_name
|
||||
FROM consoles c
|
||||
JOIN brands b ON b.id = c.brand_id
|
||||
WHERE c.name = $1
|
||||
ORDER BY c.id ASC
|
||||
LIMIT 1;
|
||||
`,
|
||||
[consoleName],
|
||||
);
|
||||
|
||||
if (!consoleRow.rowCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const consoleId = consoleRow.rows[0].id;
|
||||
for (const game of games) {
|
||||
const title = normalizeText(game && game.title);
|
||||
if (!title) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const genre = normalizeText(game && game.genre) || null;
|
||||
const publisher = normalizeText(game && game.publisher) || null;
|
||||
const loanedTo = normalizeText(game && game.loanedTo) || null;
|
||||
const year = game && game.year != null && game.year !== "" ? Number(game.year) : null;
|
||||
const value = game && game.value != null && game.value !== "" ? Number(game.value) : null;
|
||||
|
||||
const dedupeResult = await client.query(
|
||||
`
|
||||
SELECT 1
|
||||
FROM games
|
||||
WHERE console_id = $1
|
||||
AND LOWER(title) = LOWER($2)
|
||||
AND COALESCE(release_year, 0) = COALESCE($3, 0)
|
||||
LIMIT 1;
|
||||
`,
|
||||
[consoleId, title, year],
|
||||
);
|
||||
|
||||
if (dedupeResult.rowCount) {
|
||||
continue;
|
||||
}
|
||||
|
||||
await client.query(
|
||||
`
|
||||
INSERT INTO games(
|
||||
console_id, title, genre, publisher, release_year, estimated_value, loaned_to
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7);
|
||||
`,
|
||||
[consoleId, title, genre, publisher, year, value, loanedTo],
|
||||
);
|
||||
|
||||
insertedGames += 1;
|
||||
}
|
||||
}
|
||||
|
||||
await client.query("COMMIT");
|
||||
return { insertedConsoles, insertedGames };
|
||||
} catch (error) {
|
||||
await client.query("ROLLBACK");
|
||||
throw error;
|
||||
} finally {
|
||||
client.release();
|
||||
}
|
||||
}
|
||||
|
||||
async function handleRequest(request, response) {
|
||||
const url = new URL(request.url || "/", `http://${request.headers.host || "localhost"}`);
|
||||
|
||||
@@ -432,6 +553,17 @@ async function handleRequest(request, response) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method === "POST" && url.pathname === "/api/catalog/import") {
|
||||
try {
|
||||
const body = await readJsonBody(request);
|
||||
const result = await importCatalog(body);
|
||||
sendJson(response, 200, { status: "ok", ...result });
|
||||
} catch (error) {
|
||||
sendJson(response, 400, { status: "error", message: error.message });
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
const gameIdMatch = url.pathname.match(/^\/api\/catalog\/games\/([0-9a-fA-F-]+)$/);
|
||||
if (request.method === "PUT" && gameIdMatch) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user