import { sql } from 'db' ; import { InventoryItem } from 'entities/inventory/item' ; function FixInventoryStructure ( inv ) { const newInv = new Inventory ( ) ; Object . assign ( newInv , inv ) ; return newInv ; } /**
 * represents an user's inventory
 */ export class Inventory { param userId returns public static async getById ( userId ) { const resRows = await sql < Inventory > `SELECT * FROM inventories WHERE owner_id = ${ userId };` ; if ( resRows . count === 0 ) { return null ; } else if ( resRows . count === 1 ) { return FixInventoryStructure ( resRows [ 0 ] ) ; } else { throw new Error ( 'getById: got more than one row for an inventory' ) ; } } param userId returns public static async doesExist ( userId ) { const resRows = await sql < Inventory > `SELECT 1 FROM inventories WHERE owner_id = ${ userId };` ; if ( resRows . count > 1 ) { throw new Error ( 'getById: got more than one row for an inventory' ) ; } return resRows . count === 1 ; } param userId returns public static async create ( userId ) { const res = await sql < Inventory > `
            INSERT INTO inventories (owner_id) VALUES (${ userId }) RETURNING *;` ; if ( res . count !== 1 ) { throw new Error ( 'INSERT query did not return a single row' ) ; } return FixInventoryStructure ( res [ 0 ] ) ; } param userId returns public static async remove ( userId ) { if ( ( await this . doesExist ( userId ) ) === false ) { return false ; } await sql `
            DELETE FROM inventories
            WHERE owner_id = ${ userId };` ; return true ; } param itemId param itemAmmount param userId returns public static async addItem ( itemId , itemAmmount , userId ) { if ( ( await this . doesExist ( userId ) ) === false ) { return false ; } await sql `
            UPDATE inventories
            SET items = items || (${ itemId }, ${ itemAmmount })::InventoryItem
            WHERE owner_id = ${ userId };
        ` ; return true ; } param itemId param userId param itemAmmount returns public static async removeItem ( itemId , userId , itemAmmount ? ) { if ( itemAmmount ) { const inv = await Inventory . getById ( userId ) ; const targetItem = inv . items . find ( ( item ) => { return item . item_id === itemId ; } ) ; const newAmmount = targetItem . ammount - itemAmmount ; if ( newAmmount > 0 ) { return await Inventory . updateItemQuantity ( itemId , newAmmount , userId ) ; } else { return await Inventory . removeItemInternal ( itemId , userId ) ; } } else { return await Inventory . removeItemInternal ( itemId , userId ) ; } } param itemId param ownerId returns private static async removeItemInternal ( itemId , ownerId ) { const userInventory = await Inventory . getById ( ownerId ) ; if ( userInventory == null ) { throw new Error ( 'Tried to delete an item from a non existing inventory' ) ; } const oldItem = userInventory . GetItemById ( itemId ) ; if ( oldItem == null ) { throw new Error ( 'Could not find an item to be deleted' ) ; } await sql `
            UPDATE inventories
            SET items = array_remove(items, (${ oldItem . item_id }, ${ oldItem . ammount })::InventoryItem)
            WHERE owner_id = ${ ownerId };
        ` ; return true ; } param itemId param newAmmount param ownerId returns private static async updateItemQuantity ( itemId , newAmmount , ownerId ) { const userInventory = await Inventory . getById ( ownerId ) ; if ( userInventory == null ) { throw new Error ( 'Tried to delete an item from a non existing inventory' ) ; } const oldItem = userInventory . GetItemById ( itemId ) ; if ( oldItem == null ) { throw new Error ( 'Could not find an item to be deleted' ) ; } const newItem = new InventoryItem ( itemId , newAmmount ) ; await sql `
            UPDATE inventories
            SET items = array_replace(
                items,
                (${ oldItem . item_id }, ${ oldItem . ammount })::InventoryItem,
                (${ newItem . item_id }, ${ newItem . ammount })::InventoryItem)
            WHERE owner_id = ${ ownerId };
        ` ; return true ; } public GetItemById ( targetItemId ) { for ( const item of this . items ) { if ( item . item_id === targetItemId ) { return item ; } } return null ; } public owner_id : number ; public items : InventoryItem [ ] ; }