From fe0c65e2210edfcdcc68c348284362e2643cbc0a Mon Sep 17 00:00:00 2001 From: daxantz Date: Wed, 24 Sep 2025 18:42:18 -0400 Subject: [PATCH 1/6] created util functions for location model --- src/services/locationService.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/services/locationService.ts diff --git a/src/services/locationService.ts b/src/services/locationService.ts new file mode 100644 index 0000000..2f2ac06 --- /dev/null +++ b/src/services/locationService.ts @@ -0,0 +1,31 @@ +import prisma from './prisma' + +export const createLocation = async (name: string) => { + return prisma.location.create({ + data: { name }, + }) +} + +export const getLocationById = async (id: number) => { + return prisma.location.findUnique({ + where: { id }, + include: { entrances: true }, + }) +} + +export const getAllLocations = async () => { + return prisma.location.findMany({ + include: { entrances: true }, + }) +} + +export const updateLocation = async (id: number, name: string) => { + return prisma.location.update({ + where: { id }, + data: { name }, + }) +} + +export const deleteLocation = async (id: number) => { + return prisma.location.delete({ where: { id } }) +} From bd084c4044a029372cab9c6314ab04d29440f352 Mon Sep 17 00:00:00 2001 From: daxantz Date: Wed, 24 Sep 2025 18:44:39 -0400 Subject: [PATCH 2/6] setup location route/tests --- __tests__/location.test.ts | 14 +++++++++++++ src/common/routes.ts | 4 ++-- src/resources/locations/controller.ts | 29 +++++++++++++++++++++++++++ src/resources/locations/routes.ts | 9 +++++++++ src/resources/users/controller.ts | 15 -------------- src/resources/users/model.ts | 15 -------------- src/resources/users/routes.ts | 9 --------- 7 files changed, 54 insertions(+), 41 deletions(-) create mode 100644 __tests__/location.test.ts create mode 100644 src/resources/locations/controller.ts create mode 100644 src/resources/locations/routes.ts delete mode 100644 src/resources/users/controller.ts delete mode 100644 src/resources/users/model.ts delete mode 100644 src/resources/users/routes.ts diff --git a/__tests__/location.test.ts b/__tests__/location.test.ts new file mode 100644 index 0000000..df8f414 --- /dev/null +++ b/__tests__/location.test.ts @@ -0,0 +1,14 @@ +import request from 'supertest' +import app from '../src/app' +import prisma from '../src/services/prisma' + +test('POST /v1/user creates a new location', async () => { + const res = await request(app).post('/v1/location').send({ name: 'New Location' }) + + expect(res.status).toBe(201) + expect(res.body).toHaveProperty('message', 'Location created successfully: New Location') + + // Verify it exists in the DB + const locationInDb = await prisma.location.findFirst({ where: { name: 'New Location' } }) + expect(locationInDb).not.toBeNull() +}) diff --git a/src/common/routes.ts b/src/common/routes.ts index 44adc0a..1c2b9b8 100644 --- a/src/common/routes.ts +++ b/src/common/routes.ts @@ -3,9 +3,9 @@ import { Router } from 'express' const router: Router = Router() // import routes -import userRouter from '../resources/users/routes' +import locationRouter from '../resources/locations/routes' // Higher level routes definition -router.use('/user', userRouter) +router.use('/location', locationRouter) export default router diff --git a/src/resources/locations/controller.ts b/src/resources/locations/controller.ts new file mode 100644 index 0000000..8730f5d --- /dev/null +++ b/src/resources/locations/controller.ts @@ -0,0 +1,29 @@ +import { Request, Response, NextFunction } from 'express' +import { createLocation } from '../../services/locationService' + +const getAll = async (req: Request, res: Response, next: NextFunction) => { + try { + // use dummy data for now + const users = ['John Doe', 'Jane Doe', 'John Smith', 'Jane Smith'] + res.status(200).json(users) + } catch (error) { + next(error) + } +} + +const makeLocation = async (req: Request, res: Response, next: NextFunction) => { + try { + if (!req.body.name) { + return res.status(400).json({ error: 'Name is required' }) + } + const location = await createLocation(req.body.name) + // logic to create a new location + res.status(201).json({ message: `Location created successfully: ${location.name}` }) + } catch (error) { + next(error) + } +} +export default { + getAll, + makeLocation, +} diff --git a/src/resources/locations/routes.ts b/src/resources/locations/routes.ts new file mode 100644 index 0000000..ef5877f --- /dev/null +++ b/src/resources/locations/routes.ts @@ -0,0 +1,9 @@ +import { Router } from 'express' +import locationController from './controller' + +const router = Router() + +// define routes +router.route('/').post(locationController.makeLocation) + +export default router diff --git a/src/resources/users/controller.ts b/src/resources/users/controller.ts deleted file mode 100644 index 34abb6f..0000000 --- a/src/resources/users/controller.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Request, Response, NextFunction } from 'express' - -const getAll = async (req: Request, res: Response, next: NextFunction) => { - try { - // use dummy data for now - const users = ['John Doe', 'Jane Doe', 'John Smith', 'Jane Smith'] - res.status(200).json(users) - } catch (error) { - next(error) - } -} - -export default { - getAll, -} diff --git a/src/resources/users/model.ts b/src/resources/users/model.ts deleted file mode 100644 index 3b1dc27..0000000 --- a/src/resources/users/model.ts +++ /dev/null @@ -1,15 +0,0 @@ -// import mongoose, { Schema } from 'mongoose' -// import UserInterface from './interface' - -// // Define the User Schema -// const UserSchema = new Schema({ -// name: { -// type: String, -// required: true, -// }, -// }) - -// // Create the User model -// const User = mongoose.model('User', UserSchema) - -// export default User diff --git a/src/resources/users/routes.ts b/src/resources/users/routes.ts deleted file mode 100644 index 49a9052..0000000 --- a/src/resources/users/routes.ts +++ /dev/null @@ -1,9 +0,0 @@ -import { Router } from 'express' -import userController from './controller' - -const router = Router() - -// define routes -router.route('/').get(userController.getAll) - -export default router From 394e8b12527609500a9cad7ddb3f7e15f1a17e95 Mon Sep 17 00:00:00 2001 From: daxantz Date: Wed, 24 Sep 2025 19:57:23 -0400 Subject: [PATCH 3/6] fix: remove unnecessary backslash in code --- src/app.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.ts b/src/app.ts index 152e680..649ff07 100644 --- a/src/app.ts +++ b/src/app.ts @@ -34,7 +34,7 @@ app.get('/health', async (req: Request, res: Response) => { res.json({ status: 'ok' }) }) -app.use('/v1/', routes) +app.use('/v1', routes) // Handle unknown endpoints app.use('*', unknownEndpoint) From 6de345beced235ba9eada72950a99583c462bb9f Mon Sep 17 00:00:00 2001 From: daxantz Date: Wed, 24 Sep 2025 19:59:32 -0400 Subject: [PATCH 4/6] feat: add delete /location route to delete locations --- __tests__/location.test.ts | 18 ++++++++++++++++-- src/resources/locations/controller.ts | 18 +++++++++++++++++- src/resources/locations/routes.ts | 4 ++-- 3 files changed, 35 insertions(+), 5 deletions(-) diff --git a/__tests__/location.test.ts b/__tests__/location.test.ts index df8f414..8754f23 100644 --- a/__tests__/location.test.ts +++ b/__tests__/location.test.ts @@ -2,8 +2,8 @@ import request from 'supertest' import app from '../src/app' import prisma from '../src/services/prisma' -test('POST /v1/user creates a new location', async () => { - const res = await request(app).post('/v1/location').send({ name: 'New Location' }) +test('POST /v1/location creates a new location', async () => { + const res = await request(app).post('/v1/location/create').send({ name: 'New Location' }) expect(res.status).toBe(201) expect(res.body).toHaveProperty('message', 'Location created successfully: New Location') @@ -12,3 +12,17 @@ test('POST /v1/user creates a new location', async () => { const locationInDb = await prisma.location.findFirst({ where: { name: 'New Location' } }) expect(locationInDb).not.toBeNull() }) + +test('DELETE /v1/location/:id deletes a location', async () => { + // First, create a location to delete + const newLocation = await prisma.location.create({ data: { name: 'Location To Delete' } }) + + const res = await request(app).delete(`/v1/location/${newLocation.id}`) + + expect(res.status).toBe(200) + expect(res.body).toHaveProperty('message', `Location: ${newLocation.name} deleted successfully`) + + // Verify it no longer exists in the DB + const locationInDb = await prisma.location.findUnique({ where: { id: newLocation.id } }) + expect(locationInDb).toBeNull() +}) diff --git a/src/resources/locations/controller.ts b/src/resources/locations/controller.ts index 8730f5d..5d3d1e8 100644 --- a/src/resources/locations/controller.ts +++ b/src/resources/locations/controller.ts @@ -1,5 +1,5 @@ import { Request, Response, NextFunction } from 'express' -import { createLocation } from '../../services/locationService' +import { createLocation, deleteLocation } from '../../services/locationService' const getAll = async (req: Request, res: Response, next: NextFunction) => { try { @@ -23,7 +23,23 @@ const makeLocation = async (req: Request, res: Response, next: NextFunction) => next(error) } } + +const removeLocation = async (req: Request, res: Response, next: NextFunction) => { + try { + const { id } = req.params + if (!id) { + return res.status(400).json({ error: 'Could not find this location' }) + } + const deletedLocation = await deleteLocation(parseInt(id)) + + // logic to delete a location by id + res.status(200).json({ message: `Location: ${deletedLocation.name} deleted successfully` }) + } catch (error) { + next(error) + } +} export default { getAll, makeLocation, + removeLocation, } diff --git a/src/resources/locations/routes.ts b/src/resources/locations/routes.ts index ef5877f..4e15ad7 100644 --- a/src/resources/locations/routes.ts +++ b/src/resources/locations/routes.ts @@ -4,6 +4,6 @@ import locationController from './controller' const router = Router() // define routes -router.route('/').post(locationController.makeLocation) - +router.route('/create').post(locationController.makeLocation) +router.delete('/:id', locationController.removeLocation) export default router From ca21cd184c3d6fcf14876af3519a813091565ab7 Mon Sep 17 00:00:00 2001 From: daxantz Date: Wed, 24 Sep 2025 22:14:30 -0400 Subject: [PATCH 5/6] Add endpoints to get all locations and a single one by id --- __tests__/location.test.ts | 26 ++++++++++++++++++++ src/resources/locations/controller.ts | 35 ++++++++++++++++++++++++++- src/resources/locations/routes.ts | 2 ++ 3 files changed, 62 insertions(+), 1 deletion(-) diff --git a/__tests__/location.test.ts b/__tests__/location.test.ts index 8754f23..bf54b33 100644 --- a/__tests__/location.test.ts +++ b/__tests__/location.test.ts @@ -26,3 +26,29 @@ test('DELETE /v1/location/:id deletes a location', async () => { const locationInDb = await prisma.location.findUnique({ where: { id: newLocation.id } }) expect(locationInDb).toBeNull() }) + +test('GET /v1/location retrieves all locations', async () => { + // Create some locations to retrieve + await prisma.location.createMany({ + data: [{ name: 'Location 1' }, { name: 'Location 2' }], + }) + + const res = await request(app).get('/v1/location') + + expect(res.status).toBe(200) + expect(res.body).toHaveProperty('locations') + expect(Array.isArray(res.body.locations)).toBe(true) + expect(res.body.locations.length).toBeGreaterThanOrEqual(2) // At least the two we just created +}) + +test('GET /v1/location/:id retrieves a single location', async () => { + // First, create a location to retrieve + const newLocation = await prisma.location.create({ data: { name: 'Single Location' } }) + + const res = await request(app).get(`/v1/location/${newLocation.id}`) + + expect(res.status).toBe(200) + expect(res.body).toHaveProperty('location') + expect(res.body.location).toHaveProperty('id', newLocation.id) + expect(res.body.location).toHaveProperty('name', 'Single Location') +}) diff --git a/src/resources/locations/controller.ts b/src/resources/locations/controller.ts index 5d3d1e8..fdf2564 100644 --- a/src/resources/locations/controller.ts +++ b/src/resources/locations/controller.ts @@ -1,5 +1,5 @@ import { Request, Response, NextFunction } from 'express' -import { createLocation, deleteLocation } from '../../services/locationService' +import { createLocation, deleteLocation, getAllLocations, getLocationById } from '../../services/locationService' const getAll = async (req: Request, res: Response, next: NextFunction) => { try { @@ -38,8 +38,41 @@ const removeLocation = async (req: Request, res: Response, next: NextFunction) = next(error) } } + +const getLocations = async (req: Request, res: Response, next: NextFunction) => { + try { + const locations = await getAllLocations() + + if (!locations || locations.length === 0) { + return res.status(404).json({ message: 'No locations found' }) + } + // logic to get all locations + res.status(200).json({ message: 'Retrieved all locations', locations: locations }) + } catch (error) { + next(error) + } +} + +const getSingleLocation = async (req: Request, res: Response, next: NextFunction) => { + try { + const { id } = req.params + if (!id) { + return res.status(400).json({ error: 'Could not find this location' }) + } + const location = await getLocationById(parseInt(id)) + if (!location) { + return res.status(404).json({ message: 'Location not found' }) + } + // logic to get a single location by id + res.status(200).json({ message: `Retrieved location with id: ${id}`, location: location }) + } catch (error) { + next(error) + } +} export default { getAll, makeLocation, removeLocation, + getLocations, + getSingleLocation, } diff --git a/src/resources/locations/routes.ts b/src/resources/locations/routes.ts index 4e15ad7..a49f8d7 100644 --- a/src/resources/locations/routes.ts +++ b/src/resources/locations/routes.ts @@ -6,4 +6,6 @@ const router = Router() // define routes router.route('/create').post(locationController.makeLocation) router.delete('/:id', locationController.removeLocation) +router.get('/', locationController.getLocations) +router.get('/:id', locationController.getSingleLocation) export default router From b490ac32c93c37738957ba1f2e4583c69fb0740e Mon Sep 17 00:00:00 2001 From: daxantz Date: Wed, 24 Sep 2025 22:34:52 -0400 Subject: [PATCH 6/6] add enpoint to update location names --- __tests__/location.test.ts | 18 +++++++++++++++ src/resources/locations/controller.ts | 32 ++++++++++++++++++++++++++- src/resources/locations/routes.ts | 1 + src/services/locationService.ts | 2 +- 4 files changed, 51 insertions(+), 2 deletions(-) diff --git a/__tests__/location.test.ts b/__tests__/location.test.ts index bf54b33..ae6ba9c 100644 --- a/__tests__/location.test.ts +++ b/__tests__/location.test.ts @@ -52,3 +52,21 @@ test('GET /v1/location/:id retrieves a single location', async () => { expect(res.body.location).toHaveProperty('id', newLocation.id) expect(res.body.location).toHaveProperty('name', 'Single Location') }) + +test('PUT /v1/location/:id updates a location name', async () => { + // First, create a location to update + const newLocation = await prisma.location.create({ data: { name: 'Old Location Name' } }) + + const res = await request(app).put(`/v1/location/${newLocation.id}`).send({ name: 'Updated Location Name' }) + + expect(res.status).toBe(200) + expect(res.body).toHaveProperty('message', 'Location updated successfully') + expect(res.body).toHaveProperty('location') + expect(res.body.location).toHaveProperty('id', newLocation.id) + expect(res.body.location).toHaveProperty('name', 'Updated Location Name') + + // Verify the update in the DB + const locationInDb = await prisma.location.findUnique({ where: { id: newLocation.id } }) + expect(locationInDb).not.toBeNull() + expect(locationInDb?.name).toBe('Updated Location Name') +}) diff --git a/src/resources/locations/controller.ts b/src/resources/locations/controller.ts index fdf2564..d33e9a9 100644 --- a/src/resources/locations/controller.ts +++ b/src/resources/locations/controller.ts @@ -1,5 +1,11 @@ import { Request, Response, NextFunction } from 'express' -import { createLocation, deleteLocation, getAllLocations, getLocationById } from '../../services/locationService' +import { + createLocation, + deleteLocation, + getAllLocations, + getLocationById, + updateLocationName, +} from '../../services/locationService' const getAll = async (req: Request, res: Response, next: NextFunction) => { try { @@ -69,10 +75,34 @@ const getSingleLocation = async (req: Request, res: Response, next: NextFunction next(error) } } + +const updateLocation = async (req: Request, res: Response, next: NextFunction) => { + try { + const { id } = req.params + const { name } = req.body + if (!id) { + return res.status(400).json({ error: 'ID was not provided' }) + } + if (!req.body.name) { + return res.status(400).json({ error: 'Name is required' }) + } + + const updatedLocation = await updateLocationName(parseInt(id), name) + if (!updatedLocation) { + return res.status(404).json({ message: 'Location not found' }) + } + // logic to update a location by id + res.status(200).json({ message: 'Location updated successfully', location: updatedLocation }) + } catch (error) { + next(error) + } +} + export default { getAll, makeLocation, removeLocation, getLocations, getSingleLocation, + updateLocation, } diff --git a/src/resources/locations/routes.ts b/src/resources/locations/routes.ts index a49f8d7..b053d60 100644 --- a/src/resources/locations/routes.ts +++ b/src/resources/locations/routes.ts @@ -8,4 +8,5 @@ router.route('/create').post(locationController.makeLocation) router.delete('/:id', locationController.removeLocation) router.get('/', locationController.getLocations) router.get('/:id', locationController.getSingleLocation) +router.put('/:id', locationController.updateLocation) export default router diff --git a/src/services/locationService.ts b/src/services/locationService.ts index 2f2ac06..340bbb1 100644 --- a/src/services/locationService.ts +++ b/src/services/locationService.ts @@ -19,7 +19,7 @@ export const getAllLocations = async () => { }) } -export const updateLocation = async (id: number, name: string) => { +export const updateLocationName = async (id: number, name: string) => { return prisma.location.update({ where: { id }, data: { name },