diff --git a/src/migrations/008_add-fk-relationship-items-with-set-id.js b/src/migrations/008_add-fk-relationship-items-with-set-id.js index 953019c..10c66fc 100644 --- a/src/migrations/008_add-fk-relationship-items-with-set-id.js +++ b/src/migrations/008_add-fk-relationship-items-with-set-id.js @@ -1,9 +1,10 @@ export const up = (pgm) => { pgm.sql(` ALTER TABLE "items" - ADD CONSTRAINT "set_id" + ADD COLUMN "set_id" UUID, + ADD CONSTRAINT "fk_set_id" FOREIGN KEY ("set_id") - REFERENCES "sets" ("id") + REFERENCES "sets"("id") ON DELETE CASCADE; `) } @@ -11,6 +12,7 @@ export const up = (pgm) => { export const down = (pgm) => { pgm.sql(` ALTER TABLE "items" - DROP CONSTRAINT "fk_name"; + DROP COLUMN "set_id", + DROP CONSTRAINT "fk_set_id"; `) } diff --git a/src/routes/items/index.js b/src/routes/items/index.js index 71f37cc..d535df4 100644 --- a/src/routes/items/index.js +++ b/src/routes/items/index.js @@ -11,99 +11,213 @@ const pool = new Pool(database) // Get all items router.get('/', async (req, res) => { - const client = await pool.connect() - try { - const result = await client.query('SELECT * FROM items') - res.json(result.rows) - } finally { - client.release() - } + const client = await pool.connect() + try { + const result = await client.query('SELECT * FROM items') + res.json(result.rows) + } finally { + client.release() + } }) // Get a single item by id router.get('/:id', async (req, res) => { - const { id } = req.params - const client = await pool.connect() - try { - const result = await client.query('SELECT * FROM items WHERE id = $1', [id]) - if (result.rows.length === 0) { - return res.status(404).json({ message: 'Item not found' }) - } - res.json(result.rows[0]) - } finally { - client.release() - } + const { id } = req.params + const client = await pool.connect() + try { + const result = await client.query('SELECT * FROM items WHERE id = $1', [id]) + if (result.rows.length === 0) { + return res.status(404).json({ message: 'Item not found' }) + } + res.json(result.rows[0]) + } finally { + client.release() + } }) // Create a new item -router.post('/', [ - check('collection_id').not().isEmpty(), - check('image_id').not().isEmpty(), - check('productId').not().isEmpty(), - check('name').not().isEmpty(), - check('cleanName').not().isEmpty(), - check('extCardText').not().isEmpty(), - check('marketPrice').not().isEmpty(), - check('extRarity').not().isEmpty(), - check('set_id').not().isEmpty() // Add validation for set_id -], async (req, res) => { - const errors = validationResult(req) - if (!errors.isEmpty()) { - return res.status(400).json({ errors: errors.array() }) - } - const { collection_id, image_id, productId, name, cleanName, extCardText, marketPrice, extRarity, set_id } = req.body - const client = await pool.connect() - try { - const result = await client.query('INSERT INTO items (collection_id, image_id, productId, name, cleanName, extCardText, marketPrice, extRarity, set_id, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), NOW()) RETURNING *', [collection_id, image_id, productId, name, cleanName, extCardText, marketPrice, extRarity, set_id]) - res.status(201).json(result.rows[0]) - } finally { - client.release() - } -}) +router.post( + '/', + [ + check('collection_id').not().isEmpty(), + check('image_id').not().isEmpty(), + check('productId').not().isEmpty(), + check('name').not().isEmpty(), + check('cleanName').not().isEmpty(), + check('extCardText').not().isEmpty(), + check('marketPrice').not().isEmpty(), + check('extRarity').not().isEmpty(), + check('set_id').not().isEmpty(), // Add validation for set_id + ], + async (req, res) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }) + } + const { + collection_id, + image_id, + productId, + name, + cleanName, + extCardText, + marketPrice, + extRarity, + set_id, + } = req.body + const client = await pool.connect() + try { + const result = await client.query( + 'INSERT INTO items (collection_id, image_id, productId, name, cleanName, extCardText, marketPrice, extRarity, set_id, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), NOW()) RETURNING *', + [ + collection_id, + image_id, + productId, + name, + cleanName, + extCardText, + marketPrice, + extRarity, + set_id, + ] + ) + res.status(201).json(result.rows[0]) + } finally { + client.release() + } + } +) // Update an existing item router.put('/:id', async (req, res) => { - const { id } = req.params - const updates = {} - if (req.body.collection_id) updates.collection_id = req.body.collection_id - if (req.body.image_id) updates.image_id = req.body.image_id - if (req.body.productId) updates.productId = req.body.productId - if (req.body.name) updates.name = req.body.name - if (req.body.cleanName) updates.cleanName = req.body.cleanName - if (req.body.extCardText) updates.extCardText = req.body.extCardText - if (req.body.marketPrice) updates.marketPrice = req.body.marketPrice - if (req.body.extRarity) updates.extRarity = req.body.extRarity - const client = await pool.connect() - try { - if (Object.keys(updates).length > 0) { - const updateFields = Object.keys(updates).map(key => `${key} = $${Object.keys(updates).indexOf(key) + 2}`).join(', ') - updates.updated_at = 'NOW()' - const result = await client.query(`UPDATE items SET ${updateFields}, updated_at = $${Object.keys(updates).length + 1} WHERE id = $1 RETURNING *`, [id, ...Object.values(updates)]) - return res.json(result.rows[0]) - } - if (result.rows.length === 0) { - return res.status(404).json({ message: 'Item not found' }) - } else { - return res.status(204).json() - } - } finally { - client.release() - } + const { id } = req.params + const updates = {} + if (req.body.collection_id) updates.collection_id = req.body.collection_id + if (req.body.image_id) updates.image_id = req.body.image_id + if (req.body.productId) updates.productId = req.body.productId + if (req.body.name) updates.name = req.body.name + if (req.body.cleanName) updates.cleanName = req.body.cleanName + if (req.body.extCardText) updates.extCardText = req.body.extCardText + if (req.body.marketPrice) updates.marketPrice = req.body.marketPrice + if (req.body.extRarity) updates.extRarity = req.body.extRarity + const client = await pool.connect() + try { + if (Object.keys(updates).length > 0) { + const updateFields = Object.keys(updates) + .map((key) => `${key} = $${Object.keys(updates).indexOf(key) + 2}`) + .join(', ') + updates.updated_at = 'NOW()' + const result = await client.query( + `UPDATE items SET ${updateFields}, updated_at = $${Object.keys(updates).length + 1} WHERE id = $1 RETURNING *`, + [id, ...Object.values(updates)] + ) + return res.json(result.rows[0]) + } + if (result.rows.length === 0) { + return res.status(404).json({ message: 'Item not found' }) + } else { + return res.status(204).json() + } + } finally { + client.release() + } }) // Delete an item router.delete('/:id', async (req, res) => { - const { id } = req.params - const client = await pool.connect() - try { - const result = await client.query('DELETE FROM items WHERE id = $1', [id]) - if (result.rows.length === 0) { - return res.status(404).json({ message: 'Item not found' }) - } - res.json({ message: 'Item deleted' }) - } finally { - client.release() - } + const { id } = req.params + const client = await pool.connect() + try { + const result = await client.query('DELETE FROM items WHERE id = $1', [id]) + if (result.rows.length === 0) { + return res.status(404).json({ message: 'Item not found' }) + } + res.json({ message: 'Item deleted' }) + } finally { + client.release() + } }) +// Create a new item from CSV +router.post( + '/csv', + [ + check('collection_id').not().isEmpty(), + check('set_id').not().isEmpty(), // Add validation for set_id + ], + async (req, res) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }) + } + const { collection_id, set_id } = req.body + const csvBuffer = req.files.file.buffer.toString('utf8') + const csvLines = csvBuffer + .split('\n') + .filter((line) => line.trim().length > 0) + const client = await pool.connect() + try { + // Insert each row into the items table + for (const line of csvLines) { + const [ + productId, + name, + cleanName, + imageUrl, + categoryId, + groupId, + url, + modifiedOn, + imageCount, + extCardText, + extUPC, + lowPrice, + midPrice, + highPrice, + marketPrice, + directLowPrice, + subTypeName, + extNumber, + extRarity, + extCardType, + extHP, + extStage, + extAttack1, + extWeakness, + extRetreatCost, + extAttack2, + extResistance, + ] = line.split(',').map((value) => value.trim()) + // Fetch the image from imageUrl + const imageResponse = await fetch(imageUrl) + const imageBuffer = await imageResponse.buffer() + + // Insert the image into the images table + const insertImageResult = await client.query( + 'INSERT INTO images (file, image) VALUES ($1::TEXT, $2::BYTEA) RETURNING id', + [`${productId}.jpg`, imageBuffer] + ) + + await client.query( + 'INSERT INTO items (collection_id, image_id, productId, name, cleanName, extCardText, marketPrice, extRarity, set_id, created_at, updated_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, NOW(), NOW())', + [ + collection_id, + insertImageResult.rows[0].id, + productId, + name, + cleanName, + extCardText, + marketPrice, + extRarity, + set_id, + ] + ) + } + res.status(201).json({ message: 'Items created' }) + } finally { + client.release() + } + } +) + export default router