diff --git a/__tests__/location.test.ts b/__tests__/location.test.ts new file mode 100644 index 0000000..ae6ba9c --- /dev/null +++ b/__tests__/location.test.ts @@ -0,0 +1,72 @@ +import request from 'supertest' +import app from '../src/app' +import prisma from '../src/services/prisma' + +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') + + // Verify it exists in the DB + 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() +}) + +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') +}) + +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/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) 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..d33e9a9 --- /dev/null +++ b/src/resources/locations/controller.ts @@ -0,0 +1,108 @@ +import { Request, Response, NextFunction } from 'express' +import { + createLocation, + deleteLocation, + getAllLocations, + getLocationById, + updateLocationName, +} 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) + } +} + +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) + } +} + +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) + } +} + +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 new file mode 100644 index 0000000..b053d60 --- /dev/null +++ b/src/resources/locations/routes.ts @@ -0,0 +1,12 @@ +import { Router } from 'express' +import locationController from './controller' + +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) +router.put('/:id', locationController.updateLocation) +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 diff --git a/src/services/locationService.ts b/src/services/locationService.ts new file mode 100644 index 0000000..340bbb1 --- /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 updateLocationName = 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 } }) +}