From 96b06cf92d06865268c3ba08593182975a90bcc7 Mon Sep 17 00:00:00 2001 From: Joseph Nelson Date: Sat, 16 May 2026 23:42:41 -0700 Subject: [PATCH] added item route details (#6) Reviewed-on: https://gitea.nelson-household.com/Hard-at-Work/tcg-collectors-server/pulls/6 Co-authored-by: Joseph Nelson Co-committed-by: Joseph Nelson --- .gitea/workflows/build.yaml | 4 +- migrations-config.json | 3 - package.json | 2 +- src/app.js | 2 + ...8_add-fk-relationship-items-with-set-id.js | 16 ++ src/routes/items/index.js | 141 ++++++++++++++++++ src/routes/sets/index.js | 2 +- 7 files changed, 163 insertions(+), 7 deletions(-) delete mode 100644 migrations-config.json create mode 100644 src/migrations/008_add-fk-relationship-items-with-set-id.js create mode 100644 src/routes/items/index.js diff --git a/.gitea/workflows/build.yaml b/.gitea/workflows/build.yaml index b107ff1..995b515 100644 --- a/.gitea/workflows/build.yaml +++ b/.gitea/workflows/build.yaml @@ -24,8 +24,8 @@ jobs: - name: Delete Old Images and Containers run: | - docker ps -a -q -f "name=tcg-collectors-server" | xargs -I {} docker rm {} || true - docker images --format "{{.Repository}}:{{.Tag}}" | grep "tcg-collectors-server" | xargs -I {} docker rmi {} || true + docker ps -a -q -f "name=tcg-collectors-server" | xargs -I {} docker rm -f {} || true + docker images --format "{{.Repository}}:{{.Tag}}" | grep "tcg-collectors-server" | xargs -I {} docker rmi -f {} || true - name: Build and Push Image run: | diff --git a/migrations-config.json b/migrations-config.json deleted file mode 100644 index 6f6305b..0000000 --- a/migrations-config.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "migrations-dir": "./src/migrations" -} diff --git a/package.json b/package.json index 9a590be..0308093 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "dev": "nodemon app.js", "lint": "eslint .", "lint:fix": "eslint . --fix", - "migrate": "node-pg-migrate", + "migrate": "node-pg-migrate -m ./src/migrations", "test": "jest --forceExit" }, "type": "module", diff --git a/src/app.js b/src/app.js index cf891e1..db7150e 100644 --- a/src/app.js +++ b/src/app.js @@ -9,6 +9,7 @@ import locationRoutes from './routes/locations' import imageRoutes from './routes/images' import collectionRoutes from './routes/collections' import setRoutes from './routes/sets' +import itemRoutes from './routes/items' const app = express() const port = process.env.PORT || 3000 @@ -27,6 +28,7 @@ app.use('/locations', locationRoutes) app.use('/images', imageRoutes) app.use('/collections', collectionRoutes) app.use('/sets', setRoutes) +app.use('/items', itemRoutes) // Default Route (Catch-all for undefined routes) app.use((req, res, next) => { 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 new file mode 100644 index 0000000..953019c --- /dev/null +++ b/src/migrations/008_add-fk-relationship-items-with-set-id.js @@ -0,0 +1,16 @@ +export const up = (pgm) => { + pgm.sql(` + ALTER TABLE "items" + ADD CONSTRAINT "set_id" + FOREIGN KEY ("set_id") + REFERENCES "sets" ("id") + ON DELETE CASCADE; + `) +} + +export const down = (pgm) => { + pgm.sql(` + ALTER TABLE "items" + DROP CONSTRAINT "fk_name"; + `) +} diff --git a/src/routes/items/index.js b/src/routes/items/index.js new file mode 100644 index 0000000..6c207f1 --- /dev/null +++ b/src/routes/items/index.js @@ -0,0 +1,141 @@ +import express from 'express' +import { Pool } from 'pg' +import { database } from '../../config' + +const { check, validationResult } = require('express-validator') + +const router = express.Router() + +// Create a connection pool to the database +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() + } +}) + +// 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() + } +}) + +// 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() + } + } +) + +// 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)] + ) + if (result.rows.length === 0) { + return res.status(404).json({ message: 'Item not found' }) + } + res.json(result.rows[0]) + } 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() + } +}) + +export default router diff --git a/src/routes/sets/index.js b/src/routes/sets/index.js index e02cd10..26929fd 100644 --- a/src/routes/sets/index.js +++ b/src/routes/sets/index.js @@ -109,4 +109,4 @@ router.delete('/:id', async (req, res) => { } }) -module.exports = router +export default router