From 12d1df4f541fef64378dfb79be13e189d39f99df Mon Sep 17 00:00:00 2001 From: Ben <36240171+benkyd@users.noreply.github.com> Date: Tue, 26 Apr 2022 19:00:53 +0100 Subject: [PATCH] different type of dbres error correction and mitigation Former-commit-id: f888994e969a3b58fb748ddf00146609256021a7 --- client/public/components/basket-popout.mjs | 14 ++- client/public/components/basket.mjs | 68 +++++++---- src/controllers/brick-controller.js | 134 +++++++++++---------- src/controllers/set-controller.js | 122 +++++++++---------- 4 files changed, 189 insertions(+), 149 deletions(-) diff --git a/client/public/components/basket-popout.mjs b/client/public/components/basket-popout.mjs index 72ea736..fabadf0 100644 --- a/client/public/components/basket-popout.mjs +++ b/client/public/components/basket-popout.mjs @@ -17,7 +17,6 @@ import { RegisterComponent, Component } from './components.mjs'; let basketCallback = null; - // TODO: Does the localstorage have a problem with mutual exclusion? // TODO: Should the basket be persisted to the server? export function AddProductToBasket(product, type, amount, brickModifier = 'none') { @@ -77,6 +76,19 @@ export function RemoveProductFromBasket(product, type, amount, brickModifier = ' } } +export function GetBasketTotal() { + if (localStorage.getItem('basket') === null || !localStorage.getItem('basket')) { + return 0; + } + + const basket = JSON.parse(localStorage.getItem('basket')); + + return basket.total; +} + +export function GetBasketTotalPrice() { + +} class BasketPopout extends Component { static __IDENTIFY() { return 'basket-popout'; } diff --git a/client/public/components/basket.mjs b/client/public/components/basket.mjs index 3b473f2..04119f0 100644 --- a/client/public/components/basket.mjs +++ b/client/public/components/basket.mjs @@ -1,3 +1,4 @@ +import { AddProductToBasket, GetBasketTotal, RemoveProductFromBasket } from './basket-popout.mjs'; import { RegisterComponent, Component } from './components.mjs'; class Basket extends Component { @@ -145,6 +146,19 @@ class Basket extends Component { if (mutation.attributeName === 'stock') { const stock = parseInt(mutation.target.getAttribute('stock')); + const itemCompositeId = mutation.target.getAttribute('id') + (mutation.target.getAttribute('modifier') ? '~' + mutation.target.getAttribute('modifier') : ''); + const item = this.state.items[itemCompositeId]; + if (item) { + item.stock = stock; + this.setState({ + items: { + ...this.state.items, + [itemCompositeId]: item, + }, + ...this.state, + }, false); + } + // update the stock number const stockNumber = mutation.target.parentElement.querySelector('.stock-number'); stockNumber.innerText = stock; @@ -162,40 +176,48 @@ class Basket extends Component { // set up each button to update the quantity and remove if it is zero this.root.querySelectorAll('.product-quantity-button').forEach((button) => { button.addEventListener('click', (event) => { - const item = event.target.parentElement.parentElement; - const id = item.getAttribute('id'); - const type = item.getAttribute('type'); - const modifier = item.getAttribute('modifier'); - const quantity = parseInt(item.querySelector('.quantity-input').value); - const stock = parseInt(item.querySelector('.stock-number').innerText); + let clickedItem = event.target.parentElement; + let listing = clickedItem.querySelector('.basket-item-listing'); + if (!listing) { + clickedItem = clickedItem.parentElement; + listing = clickedItem.querySelector('.basket-item-listing'); + } + + const id = listing.getAttribute('id'); + const modifier = listing.getAttribute('modifier'); + const compositeId = id + (modifier ? `~${modifier}` : ''); + const item = this.state.items[compositeId]; + console.log(id, modifier, item); // update the quantity if (event.target.classList.contains('reduce-quantity')) { - if (quantity > 0) { - item.querySelector('.quantity-input').value = quantity - 1; + if (item.quantity > 0) { + item.quantity--; + RemoveProductFromBasket(id, item.type, 1, modifier); + } + if (item.quantity === 0) { + RemoveProductFromBasket(id, item.type, item.quantity, modifier); + delete this.state.items[compositeId]; } } else if (event.target.classList.contains('increase-quantity')) { - if (quantity < stock) { - item.querySelector('.quantity-input').value = quantity + 1; + if (item.quantity < item.stock) { + item.quantity++; + AddProductToBasket(id, item.type, 1, modifier); } } else if (event.target.classList.contains('remove-quantity')) { - // remove the item from the basket - // delete this.state.items[id]; - // this.setState({ - // items: this.state.items, - // }, true); + RemoveProductFromBasket(id, item.type, item.quantity, modifier); + delete this.state.items[compositeId]; } // update the total this.setState({ - total: Object.keys(this.state.items).reduce((total, key) => { - const item = this.state.items[key]; - return total + (item.quantity * item.price); - }, 0), - }, true); - - // update the basket in local storage - // localStorage.setItem('basket', JSON.stringify(this.state)); + ...this.state, + total: GetBasketTotal(), + items: { + ...this.state.items, + [compositeId]: item, + }, + }); }); }); } diff --git a/src/controllers/brick-controller.js b/src/controllers/brick-controller.js index f2af91e..e4f1da7 100644 --- a/src/controllers/brick-controller.js +++ b/src/controllers/brick-controller.js @@ -6,24 +6,24 @@ const PgFormat = require('pg-format'); async function Search(fuzzyStrings) { await Database.Query('BEGIN TRANSACTION;'); - let dbres; - try { - dbres = await Database.Query(PgFormat(` - SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", inv.price, inv.new_price AS "discount" - FROM lego_brick - LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id - LEFT JOIN tag AS tag ON tags.tag = tag.id - LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id - WHERE lego_brick.id ~* ANY(ARRAY[%L]) OR lego_brick.name ~* ANY(ARRAY[%L]) OR tag.name ~* ANY(ARRAY[%L]) - `, fuzzyStrings, fuzzyStrings, fuzzyStrings), []); - await Database.Query('COMMIT TRANSACTION;'); - } catch { - await Database.Query('ROLLBACK TRANSACTION;'); - Logger.Error('Database Error'); + const dbres = await Database.Query(PgFormat(` + SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", inv.price, inv.new_price AS "discount" + FROM lego_brick + LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id + LEFT JOIN tag AS tag ON tags.tag = tag.id + LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id + WHERE lego_brick.id ~* ANY(ARRAY[%L]) OR lego_brick.name ~* ANY(ARRAY[%L]) OR tag.name ~* ANY(ARRAY[%L]) + `, fuzzyStrings, fuzzyStrings, fuzzyStrings), []).catch(() => { return { error: 'Database error', }; + }); + if (dbres.error) { + Database.Query('ROLLBACK TRANSACTION;'); + Logger.Error(dbres.error); + return dbres; } + await Database.Query('COMMIT TRANSACTION;'); // validate database response if (dbres.rows.length === 0) { @@ -74,22 +74,22 @@ async function Search(fuzzyStrings) { async function SumPrices(bricksArr, quantityArray) { await Database.Query('BEGIN TRANSACTION;'); - let dbres; - try { - dbres = await Database.Query(PgFormat(` - SELECT COALESCE(new_price, price) AS "price" - FROM lego_brick - LEFT JOIN lego_brick_inventory AS brick_inventory ON brick_inventory.brick_id = lego_brick.id - WHERE lego_brick.id IN (%L); - `, bricksArr), []); - await Database.Query('COMMIT TRANSACTION;'); - } catch { - await Database.Query('ROLLBACK TRANSACTION;'); - Logger.Error('Database Error'); + const dbres = await Database.Query(PgFormat(` + SELECT COALESCE(new_price, price) AS "price" + FROM lego_brick + LEFT JOIN lego_brick_inventory AS brick_inventory ON brick_inventory.brick_id = lego_brick.id + WHERE lego_brick.id IN (%L); + `, bricksArr), []).catch(() => { return { error: 'Database error', }; + }); + if (dbres.error) { + Database.Query('ROLLBACK TRANSACTION;'); + Logger.Error(dbres.error); + return dbres; } + await Database.Query('COMMIT TRANSACTION;'); // validate database response if (dbres.rows.length === 0) { @@ -109,24 +109,24 @@ async function SumPrices(bricksArr, quantityArray) { async function GetBulkBricks(bricksArr) { await Database.Query('BEGIN TRANSACTION;'); - let dbres; - try { - dbres = await Database.Query(PgFormat(` - SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", inv.price, inv.new_price AS "discount" - FROM lego_brick - LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id - LEFT JOIN tag AS tag ON tags.tag = tag.id - LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id - WHERE lego_brick.id IN (%L); - `, bricksArr), []); - await Database.Query('COMMIT TRANSACTION;'); - } catch { - await Database.Query('ROLLBACK TRANSACTION;'); - Logger.Error('Database Error'); + const dbres = await Database.Query(PgFormat(` + SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", inv.price, inv.new_price AS "discount" + FROM lego_brick + LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id + LEFT JOIN tag AS tag ON tags.tag = tag.id + LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id + WHERE lego_brick.id IN (%L); + `, bricksArr), []).catch(() => { return { error: 'Database error', }; + }); + if (dbres.error) { + Database.Query('ROLLBACK TRANSACTION;'); + Logger.Error(dbres.error); + return dbres; } + await Database.Query('COMMIT TRANSACTION;'); // validate database response if (dbres.rows.length === 0) { @@ -148,35 +148,41 @@ async function GetBulkBricks(bricksArr) { async function GetBrick(brickId) { await Database.Query('BEGIN TRANSACTION;'); - let dbres; - let colDbres; - try { - dbres = await Database.Query(` - SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", - inv.price, inv.new_price AS "discount", inv.stock, - inv.last_updated AS "last_stock_update", - weight, dimensions_x, dimensions_y, dimensions_z - FROM lego_brick - LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id - LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id - LEFT JOIN tag AS tag ON tags.tag = tag.id - WHERE lego_brick.id = $1; - `, [brickId]); - colDbres = await Database.Query(` - SELECT lego_brick_colour.id, lego_brick_colour.name, lego_brick_colour.hexrgb, - colour_type.name AS "colour_type" - FROM lego_brick_colour - LEFT JOIN colour_type AS colour_type ON lego_brick_colour.col_type = colour_type.id - `, []); - await Database.Query('COMMIT TRANSACTION;'); - } catch { - await Database.Query('ROLLBACK TRANSACTION;'); - Logger.Error('Database Error'); + const dbres = await Database.Query(` + SELECT lego_brick.id, lego_brick.name, tag.name AS "tag", + inv.price, inv.new_price AS "discount", inv.stock, + inv.last_updated AS "last_stock_update", + weight, dimensions_x, dimensions_y, dimensions_z + FROM lego_brick + LEFT JOIN lego_brick_inventory AS inv ON inv.brick_id = lego_brick.id + LEFT JOIN lego_brick_tag AS tags ON tags.brick_id = lego_brick.id + LEFT JOIN tag AS tag ON tags.tag = tag.id + WHERE lego_brick.id = $1; + `, [brickId]).catch(() => { return { error: 'Database error', }; + }); + + const colDbres = await Database.Query(` + SELECT lego_brick_colour.id, lego_brick_colour.name, lego_brick_colour.hexrgb, + colour_type.name AS "colour_type" + FROM lego_brick_colour + LEFT JOIN colour_type AS colour_type ON lego_brick_colour.col_type = colour_type.id + `, []).catch(() => { + return { + error: 'Database error', + }; + }); + + if (dbres.error || colDbres.error) { + Database.Query('ROLLBACK TRANSACTION;'); + Logger.Error(dbres.error || colDbres.error); + return dbres || colDbres; } + await Database.Query('COMMIT TRANSACTION;'); + // validate database response if (dbres.rows.length === 0) { return { diff --git a/src/controllers/set-controller.js b/src/controllers/set-controller.js index 8deb79f..5dc42f0 100644 --- a/src/controllers/set-controller.js +++ b/src/controllers/set-controller.js @@ -6,24 +6,24 @@ const PgFormat = require('pg-format'); async function Search(fuzzyStrings) { await Database.Query('BEGIN TRANSACTION;'); - let dbres; - try { - dbres = await Database.Query(PgFormat(` - SELECT lego_set.id, lego_set.name, tag.name AS "tag", inv.price, inv.new_price AS "discount" - FROM lego_set - LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id - LEFT JOIN tag AS tag ON tags.tag = tag.id - LEFT JOIN lego_set_inventory AS inv ON inv.set_id = lego_set.id - WHERE lego_set.id ~* ANY(ARRAY[%L]) OR lego_set.name ~* ANY(ARRAY[%L]) OR tag.name ~* ANY(ARRAY[%L]) - `, fuzzyStrings, fuzzyStrings, fuzzyStrings), []); - await Database.Query('COMMIT TRANSACTION;'); - } catch { - await Database.Query('ROLLBACK TRANSACTION;'); - Logger.Error('Database Error'); + const dbres = await Database.Query(PgFormat(` + SELECT lego_set.id, lego_set.name, tag.name AS "tag", inv.price, inv.new_price AS "discount" + FROM lego_set + LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id + LEFT JOIN tag AS tag ON tags.tag = tag.id + LEFT JOIN lego_set_inventory AS inv ON inv.set_id = lego_set.id + WHERE lego_set.id ~* ANY(ARRAY[%L]) OR lego_set.name ~* ANY(ARRAY[%L]) OR tag.name ~* ANY(ARRAY[%L]) + `, fuzzyStrings, fuzzyStrings, fuzzyStrings), []).catch(() => { return { error: 'Database error', }; + }); + if (dbres.error) { + Database.Query('ROLLBACK TRANSACTION;'); + Logger.Error(dbres.error); + return dbres; } + await Database.Query('COMMIT TRANSACTION;'); // validate database response if (dbres.rows.length === 0) { @@ -84,22 +84,22 @@ async function Search(fuzzyStrings) { async function SumPrices(setsArray, quantityArray) { await Database.Query('BEGIN TRANSACTION;'); - let dbres; - try { - dbres = await Database.Query(PgFormat(` - SELECT COALESCE(new_price, price) AS "price" - FROM lego_set - LEFT JOIN lego_set_inventory AS set_inventory ON set_inventory.set_id = lego_set.id - WHERE lego_set.id IN (%L); - `, setsArray), []); - await Database.Query('COMMIT TRANSACTION;'); - } catch { - await Database.Query('ROLLBACK TRANSACTION;'); - Logger.Error('Database Error'); + const dbres = await Database.Query(PgFormat(` + SELECT COALESCE(new_price, price) AS "price" + FROM lego_set + LEFT JOIN lego_set_inventory AS set_inventory ON set_inventory.set_id = lego_set.id + WHERE lego_set.id IN (%L); + `, setsArray), []).catch(() => { return { error: 'Database error', }; + }); + if (dbres.error) { + Database.Query('ROLLBACK TRANSACTION;'); + Logger.Error(dbres.error); + return dbres; } + await Database.Query('COMMIT TRANSACTION;'); // validate database response if (dbres.rows.length === 0) { @@ -120,28 +120,28 @@ async function SumPrices(setsArray, quantityArray) { async function GetSet(setId) { await Database.Query('BEGIN TRANSACTION;'); - let dbres; - try { - dbres = await Database.Query(` - SELECT lego_set.id, lego_set.name, description, tag.name AS "tag", - set_contents.brick_id, set_contents.amount, inv.price, - date_released, weight, dimensions_x, dimensions_y, dimensions_z, - new_price AS "discount", inv.stock, inv.last_updated AS "last_stock_update" - FROM lego_set - LEFT JOIN lego_set_inventory AS inv ON inv.set_id = lego_set.id - LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id - LEFT JOIN tag AS tag ON tags.tag = tag.id - LEFT JOIN set_descriptor AS set_contents ON set_contents.set_id = lego_set.id - WHERE lego_set.id = $1; - `, [setId]); - await Database.Query('COMMIT TRANSACTION;'); - } catch { - await Database.Query('ROLLBACK TRANSACTION;'); - Logger.Error('Database Error'); + const dbres = await Database.Query(` + SELECT lego_set.id, lego_set.name, description, tag.name AS "tag", + set_contents.brick_id, set_contents.amount, inv.price, + date_released, weight, dimensions_x, dimensions_y, dimensions_z, + new_price AS "discount", inv.stock, inv.last_updated AS "last_stock_update" + FROM lego_set + LEFT JOIN lego_set_inventory AS inv ON inv.set_id = lego_set.id + LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id + LEFT JOIN tag AS tag ON tags.tag = tag.id + LEFT JOIN set_descriptor AS set_contents ON set_contents.set_id = lego_set.id + WHERE lego_set.id = $1; + `, [setId]).catch(() => { return { error: 'Database error', }; + }); + if (dbres.error) { + Database.Query('ROLLBACK TRANSACTION;'); + Logger.Error(dbres.error); + return dbres; } + await Database.Query('COMMIT TRANSACTION;'); // validate database response if (dbres.rows.length === 0) { @@ -171,29 +171,29 @@ async function GetSet(setId) { async function GetSets(page, resPerPage) { await Database.Query('BEGIN TRANSACTION;'); - let countRes; - let dbres; - try { - countRes = await Database.Query('SELECT COUNT (*) FROM lego_set;'); - dbres = await Database.Query(` + const countRes = await Database.Query('SELECT COUNT (*) FROM lego_set;'); + const dbres = await Database.Query(` SELECT lego_set.id, lego_set.name, price, new_price AS "discount", tag.name AS "tag" - FROM lego_set - LEFT JOIN lego_set_inventory as inv ON lego_set.id = inv.set_id - LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id - LEFT JOIN tag AS tag ON tags.tag = tag.id - ORDER BY id ASC - LIMIT $1 - OFFSET $2;`, - [resPerPage, page * resPerPage]); - await Database.Query('COMMIT TRANSACTION;'); - } catch { - await Database.Query('ROLLBACK TRANSACTION;'); - Logger.Error('Database Error'); + FROM lego_set + LEFT JOIN lego_set_inventory as inv ON lego_set.id = inv.set_id + LEFT JOIN lego_set_tag AS tags ON tags.set_id = lego_set.id + LEFT JOIN tag AS tag ON tags.tag = tag.id + ORDER BY id ASC + LIMIT $1 + OFFSET $2;`, + [resPerPage, page * resPerPage]).catch(() => { return { error: 'Database error', }; + }); + if (dbres.error) { + Database.Query('ROLLBACK TRANSACTION;'); + Logger.Error(dbres.error); + return dbres; } + await Database.Query('COMMIT TRANSACTION;'); + const total = parseInt(countRes.rows[0].count); // validate database response