From 4f73991360ab9b00d49746f63496929f04ebe5cf Mon Sep 17 00:00:00 2001 From: Joseph Nelson Date: Sat, 16 May 2026 23:15:06 -0700 Subject: [PATCH] added collection and set APIs (#5) Reviewed-on: https://gitea.nelson-household.com/Hard-at-Work/tcg-collectors-server/pulls/5 Co-authored-by: Joseph Nelson Co-committed-by: Joseph Nelson --- migrations-config.json | 3 + src/app.js | 4 ++ src/routes/collections/index.js | 111 +++++++++++++++++++++++++++++++ src/routes/sets/index.js | 112 ++++++++++++++++++++++++++++++++ 4 files changed, 230 insertions(+) create mode 100644 migrations-config.json create mode 100644 src/routes/collections/index.js create mode 100644 src/routes/sets/index.js diff --git a/migrations-config.json b/migrations-config.json new file mode 100644 index 0000000..6f6305b --- /dev/null +++ b/migrations-config.json @@ -0,0 +1,3 @@ +{ + "migrations-dir": "./src/migrations" +} diff --git a/src/app.js b/src/app.js index 598f2a8..cf891e1 100644 --- a/src/app.js +++ b/src/app.js @@ -7,6 +7,8 @@ import userRoutes from './routes/users' import roleRoutes from './routes/roles' import locationRoutes from './routes/locations' import imageRoutes from './routes/images' +import collectionRoutes from './routes/collections' +import setRoutes from './routes/sets' const app = express() const port = process.env.PORT || 3000 @@ -23,6 +25,8 @@ app.use('/users', userRoutes) app.use('/roles', roleRoutes) app.use('/locations', locationRoutes) app.use('/images', imageRoutes) +app.use('/collections', collectionRoutes) +app.use('/sets', setRoutes) // Default Route (Catch-all for undefined routes) app.use((req, res, next) => { diff --git a/src/routes/collections/index.js b/src/routes/collections/index.js new file mode 100644 index 0000000..85267a0 --- /dev/null +++ b/src/routes/collections/index.js @@ -0,0 +1,111 @@ +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 collections +router.get('/', async (req, res) => { + try { + const result = await pool.query('SELECT * FROM collections') + res.json(result.rows) + } catch (error) { + console.error(error) + res.status(500).send('Server error') + } +}) + +// Get a single collection by id +router.get('/:id', async (req, res) => { + const { id } = req.params + + try { + const result = await pool.query('SELECT * FROM collections WHERE id = $1', [ + id, + ]) + if (result.rows.length === 0) { + return res.status(404).send('Collection not found') + } + res.json(result.rows[0]) + } catch (error) { + console.error(error) + res.status(500).send('Server error') + } +}) + +// Create a new collection +router.post( + '/', + [ + check('name', 'Name is required').not().isEmpty(), + check('image_id', 'Image id is required').not().isEmpty(), + ], + async (req, res) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }) + } + + const { name, image_id } = req.body + + try { + const result = await pool.query( + 'INSERT INTO collections (name, image_id, created_at, updated_at) VALUES ($1, $2, NOW(), NOW()) RETURNING *', + [name, image_id] + ) + res.status(201).json(result.rows[0]) + } catch (error) { + console.error(error) + res.status(500).send('Server error') + } + } +) + +// Update an existing collection +router.put( + '/:id', + [ + check('name', 'Name is required').not().isEmpty(), + check('image_id', 'Image id is required').not().isEmpty(), + ], + async (req, res) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }) + } + + const { name, image_id } = req.body + const { id } = req.params + + try { + await pool.query( + 'UPDATE collections SET name = $1, image_id = $2, updated_at = NOW() WHERE id = $3', + [name, image_id, id] + ) + res.send('Collection updated') + } catch (error) { + console.error(error) + res.status(500).send('Server error') + } + } +) + +// Delete an existing collection +router.delete('/:id', async (req, res) => { + const { id } = req.params + + try { + await pool.query('DELETE FROM collections WHERE id = $1', [id]) + res.send('Collection deleted') + } catch (error) { + console.error(error) + res.status(500).send('Server error') + } +}) + +export default router diff --git a/src/routes/sets/index.js b/src/routes/sets/index.js new file mode 100644 index 0000000..e02cd10 --- /dev/null +++ b/src/routes/sets/index.js @@ -0,0 +1,112 @@ +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 sets +router.get('/', async (req, res) => { + try { + const result = await pool.query('SELECT * FROM sets') + res.json(result.rows) + } catch (error) { + res.status(500).json({ message: error.message }) + } +}) + +// Create a new set +router.post( + '/', + [ + check('collection_id').not().isEmpty(), + check('name').not().isEmpty(), + check('location_id').not().isEmpty(), + check('image_id').not().isEmpty(), + ], + async (req, res) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }) + } + + try { + const result = await pool.query( + 'INSERT INTO sets (collection_id, name, location_id, image_id, created_at, updated_at) VALUES ($1, $2, $3, $4, NOW(), NOW()) RETURNING *', + [ + req.body.collection_id, + req.body.name, + req.body.location_id, + req.body.image_id, + ] + ) + res.status(201).json(result.rows[0]) + } catch (error) { + res.status(500).json({ message: error.message }) + } + } +) + +// Get a single set by ID +router.get('/:id', async (req, res) => { + try { + const result = await pool.query('SELECT * FROM sets WHERE id = $1', [ + req.params.id, + ]) + + if (result.rows.length === 0) { + return res.status(404).json({ message: 'Set not found' }) + } + + res.json(result.rows[0]) + } catch (error) { + res.status(500).json({ message: error.message }) + } +}) + +// Update a set by ID +router.put('/:id', [check('name').not().isEmpty()], async (req, res) => { + const errors = validationResult(req) + if (!errors.isEmpty()) { + return res.status(400).json({ errors: errors.array() }) + } + + try { + const result = await pool.query( + 'UPDATE sets SET name = $1, updated_at = NOW() WHERE id = $2 RETURNING *', + [req.body.name, req.params.id] + ) + + if (result.rows.length === 0) { + return res.status(404).json({ message: 'Set not found' }) + } + + res.json(result.rows[0]) + } catch (error) { + res.status(500).json({ message: error.message }) + } +}) + +// Delete a set by ID +router.delete('/:id', async (req, res) => { + try { + const result = await pool.query( + 'DELETE FROM sets WHERE id = $1 RETURNING *', + [req.params.id] + ) + + if (result.rows.length === 0) { + return res.status(404).json({ message: 'Set not found' }) + } + + res.json(result.rows[0]) + } catch (error) { + res.status(500).json({ message: error.message }) + } +}) + +module.exports = router