diff --git a/db/index.js b/db/index.js index af723442..5461e742 100644 --- a/db/index.js +++ b/db/index.js @@ -22,4 +22,4 @@ const client = { } } -module.exports = client; +module.exports = client; \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 37ccdff8..a9b52c26 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,8 @@ "dependencies": { "body-parser": "^1.20.2", "cors": "^2.8.5", + "date-fns": "^3.6.0", + "date-fns-tz": "^3.1.3", "dotenv": "^16.3.1", "express": "^4.18.2", "faker": "^5.5.3", @@ -1146,9 +1148,9 @@ } }, "node_modules/@types/node": { - "version": "20.10.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.5.tgz", - "integrity": "sha512-nNPsNE65wjMxEKI93yOP+NPGGBJz/PoN3kZsVLee0XMiJolxSekEVD8wRwBUBqkwc7UWop0edW50yrCQW4CyRw==", + "version": "20.14.9", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.9.tgz", + "integrity": "sha512-06OCtnTXtWOZBJlRApleWndH4JsRVs1pDCc8dLSQp+7PpUpX3ePdHyeNSFTeSe7FtKyQkrlPvHwJOW3SLd8Oyg==", "dev": true, "dependencies": { "undici-types": "~5.26.4" @@ -1784,6 +1786,23 @@ "node": ">= 8" } }, + "node_modules/date-fns": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } + }, + "node_modules/date-fns-tz": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/date-fns-tz/-/date-fns-tz-3.1.3.tgz", + "integrity": "sha512-ZfbMu+nbzW0mEzC8VZrLiSWvUIaI3aRHeq33mTe7Y38UctKukgqPR4nTDwcwS4d64Gf8GghnVsroBuMY3eiTeA==", + "peerDependencies": { + "date-fns": "^3.0.0" + } + }, "node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -3936,11 +3955,6 @@ "integrity": "sha512-xWPagP/4B6BgFO+EKz3JONXv3YDgvkbVrGw2mTo3D6tVDQRh1e7cqVGvyR3BE+eQgAvx1XhW/iEASj4/jCWl3Q==", "optional": true }, - "node_modules/pg-connection-string": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz", - "integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==" - }, "node_modules/pg-int8": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", @@ -3950,29 +3964,29 @@ } }, "node_modules/pg-minify": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/pg-minify/-/pg-minify-1.6.3.tgz", - "integrity": "sha512-NoSsPqXxbkD8RIe+peQCqiea4QzXgosdTKY8p7PsbbGsh2F8TifDj/vJxfuR8qJwNYrijdSs7uf0tAe6WOyCsQ==", + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/pg-minify/-/pg-minify-1.6.4.tgz", + "integrity": "sha512-cf6hBt1YqzqPX0OznXKSv4U7e4o7eUU4zp2zQsbJ+4OCNNr7EnnAVWkIz4k0dv6UN4ouS1ZL4WlXxCrZHHl69g==", "engines": { - "node": ">=12.0.0" + "node": ">=14.0.0" } }, "node_modules/pg-pool": { - "version": "3.6.1", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.1.tgz", - "integrity": "sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==", + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.6.2.tgz", + "integrity": "sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==", "peerDependencies": { "pg": ">=8.0" } }, "node_modules/pg-promise": { - "version": "11.5.4", - "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.5.4.tgz", - "integrity": "sha512-esYSkDt2h6NQOkfotGAm1Ld5OjoITJLpB88Z1PIlcAU/RQ0XQE2PxW0bLJEOMHPGV5iaRnj1Y7ARznXbgN4FNw==", + "version": "11.8.0", + "resolved": "https://registry.npmjs.org/pg-promise/-/pg-promise-11.8.0.tgz", + "integrity": "sha512-w9hTFpkM4FByJTJ7KCWLtZSOtQa2BKC+XIV8+3ZvDlfYfBYdz8V4V+BttnqhUPY/d12Itug7Bft4XdILihsY+w==", "dependencies": { "assert-options": "0.8.1", - "pg": "8.11.3", - "pg-minify": "1.6.3", + "pg": "8.11.5", + "pg-minify": "1.6.4", "spex": "3.3.0" }, "engines": { @@ -3980,15 +3994,13 @@ } }, "node_modules/pg-promise/node_modules/pg": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.3.tgz", - "integrity": "sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==", + "version": "8.11.5", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.11.5.tgz", + "integrity": "sha512-jqgNHSKL5cbDjFlHyYsCXmQDrfIX/3RsNwYqpd4N0Kt8niLuNoRNH+aazv6cOd43gPh9Y4DjQCtb+X0MH0Hvnw==", "dependencies": { - "buffer-writer": "2.0.0", - "packet-reader": "1.0.0", - "pg-connection-string": "^2.6.2", - "pg-pool": "^3.6.1", - "pg-protocol": "^1.6.0", + "pg-connection-string": "^2.6.4", + "pg-pool": "^3.6.2", + "pg-protocol": "^1.6.1", "pg-types": "^2.1.0", "pgpass": "1.x" }, @@ -4007,10 +4019,15 @@ } } }, + "node_modules/pg-promise/node_modules/pg-connection-string": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", + "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==" + }, "node_modules/pg-protocol": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.0.tgz", - "integrity": "sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==" + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.6.1.tgz", + "integrity": "sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==" }, "node_modules/pg-types": { "version": "2.2.0", @@ -4027,6 +4044,11 @@ "node": ">=4" } }, + "node_modules/pg/node_modules/pg-connection-string": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.4.tgz", + "integrity": "sha512-v+Z7W/0EO707aNMaAEfiGnGL9sxxumwLl2fJvCQtMn9Fxsg+lPpPkdcyBSv/KFgpGdYkMfn+EI1Or2EHjpgLCA==" + }, "node_modules/pgpass": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", diff --git a/package.json b/package.json index 57d8b4fb..8dbe3d2e 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,8 @@ "dependencies": { "body-parser": "^1.20.2", "cors": "^2.8.5", + "date-fns": "^3.6.0", + "date-fns-tz": "^3.1.3", "dotenv": "^16.3.1", "express": "^4.18.2", "faker": "^5.5.3", diff --git a/sql/create-books.sql b/sql/create-books.sql index 322f3c97..68b41169 100644 --- a/sql/create-books.sql +++ b/sql/create-books.sql @@ -8,4 +8,4 @@ CREATE TABLE IF NOT EXISTS books ( topic VARCHAR(255) NOT NULL, publication_date DATE NOT NULL, pages INTEGER NOT NULL -); +); \ No newline at end of file diff --git a/sql/create-pets.sql b/sql/create-pets.sql index 34398326..2c791be0 100644 --- a/sql/create-pets.sql +++ b/sql/create-pets.sql @@ -7,4 +7,4 @@ CREATE TABLE IF NOT EXISTS pets ( type VARCHAR(255) NOT NULL, breed VARCHAR(255) NOT NULL, has_microchip BOOLEAN NOT NULL -); +); \ No newline at end of file diff --git a/sql/insert-books.sql b/sql/insert-books.sql index b6712d59..056bf04c 100644 --- a/sql/insert-books.sql +++ b/sql/insert-books.sql @@ -104,4 +104,4 @@ INSERT INTO books (title, type, author, topic, publication_date, pages) VALUES ( INSERT INTO books (title, type, author, topic, publication_date, pages) VALUES ('placeat eius consectetur architecto', 'Non-Fiction', 'Nick Labadie', 'philosophy', '2018-02-20T07:56:03.841+00:00', 400); INSERT INTO books (title, type, author, topic, publication_date, pages) VALUES ('quia cumque maiores illum', 'Non-Fiction', 'Nick Labadie', 'philosophy', '2021-04-24T05:10:20.766+01:00', 400); INSERT INTO books (title, type, author, topic, publication_date, pages) VALUES ('ratione laudantium voluptas nihil voluptatem', 'Non-Fiction', 'Nick Labadie', 'philosophy', '2014-02-26T03:05:12.242+00:00', 400); -INSERT INTO books (title, type, author, topic, publication_date, pages) VALUES ('dolore qui accusamus sed', 'Non-Fiction', 'Arianna Dietrich', 'biography', '2004-06-23T09:29:19.212+01:00', 400); +INSERT INTO books (title, type, author, topic, publication_date, pages) VALUES ('dolore qui accusamus sed', 'Non-Fiction', 'Arianna Dietrich', 'biography', '2004-06-23T09:29:19.212+01:00', 400); \ No newline at end of file diff --git a/sql/insert-pets.sql b/sql/insert-pets.sql index 5b2033e4..81561b2a 100644 --- a/sql/insert-pets.sql +++ b/sql/insert-pets.sql @@ -337,4 +337,4 @@ INSERT INTO pets (name, age, type, breed, has_microchip) VALUES('Corbin', 19, 'r INSERT INTO pets (name, age, type, breed, has_microchip) VALUES('Jazmyne', 8, 'rabbit', 'Florida White', true); INSERT INTO pets (name, age, type, breed, has_microchip) VALUES('Ralph', 15, 'rabbit', 'Florida White', false); INSERT INTO pets (name, age, type, breed, has_microchip) VALUES('Yasmin', 16, 'rabbit', 'Florida White', false); -INSERT INTO pets (name, age, type, breed, has_microchip) VALUES('Joan', 4, 'rabbit', 'Florida White', true); +INSERT INTO pets (name, age, type, breed, has_microchip) VALUES('Joan', 4, 'rabbit', 'Florida White', true); \ No newline at end of file diff --git a/src/routers/books.js b/src/routers/books.js index 1551dd87..b78bf1b9 100644 --- a/src/routers/books.js +++ b/src/routers/books.js @@ -1,9 +1,72 @@ const express = require('express') const router = express.Router() const db = require("../../db"); +const { parseISO, format } = require('date-fns'); +const { utcToZonedTime } = require('date-fns-tz'); router.get('/', async (req, res) => { - + const queryOptions = [] + const queryParams = [] + const type = req.query.type + const topic = req.query.topic + if(type !== undefined){ + queryOptions.push(`LOWER(type) = $1`) + queryParams.push(type) + } + if(topic !== undefined){ + queryOptions.push(`LOWER(topic) = $${queryOptions.length + 1}`) + queryParams.push(topic) + } + console.log("query:", `select * FROM books ${queryOptions.length > 0 ? "WHERE " : ""}${queryOptions.join(" AND ")}`, queryParams) + const response = await db.query(`select * FROM books ${queryOptions.length > 0 ? "WHERE " : ""}${queryOptions.join(" AND ")}`, queryParams) + res.json({books: response.rows.map(parseBook)}) +}) +router.get('/:id', async (req, res) => { + const response = await db.query("select * FROM books WHERE id = $1 ", [req.params.id]) + res.json({book: parseBook(response.rows[0])}) +}) +router.put('/:id', async (req, res) => { + console.log("BumbaClap", req.body) + const update = await db.query( + `UPDATE books + SET title = $1, + type = $2, + author = $3, + topic = $4, + publication_date = $5, + pages = $6 + WHERE id = $7; +`, [req.body.title, req.body.type, req.body.author, req.body.topic, req.body.publication_date, req.body.pages, req.params.id ]) + const response = await db.query("select * FROM books WHERE id = $1 ", [req.params.id]) + res.status(201).json({book: parseBook(response.rows[0])}) +}) +router.delete('/:id', async (req, res) => { + const response = await db.query("select * FROM books WHERE id = $1 ", [req.params.id]) + await db.query("DELETE FROM books WHERE id = $1", [req.params.id]) + res.status(201).json({book: parseBook(response.rows[0])}) }) +router.post('/', async (req, res) => { + console.log("BumbaClap", req.body) + const update = await db.query( + `INSERT INTO books (title, type, author, topic, publication_date, pages) +VALUES ($1, $2, $3, $4, $5, $6) RETURNING *; +`, [req.body.title, req.body.type, req.body.author, req.body.topic, req.body.publication_date, req.body.pages]) + console.log("test", update.rows[0]) +const response = await db.query("select * FROM books WHERE id = $1 ", [update.rows[0].id]) + res.status(201).json({book: parseBook(response.rows[0])}) +}) + +function parseBook(bookData) { +// // Parse the input date string to a Date object +// const date = parseISO(bookData.publication_date); + +// // Convert the date to the local time zone +// const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone; +// const zonedDate = utcToZonedTime(date, timeZone); + +// Format the date to 'yyyy-MM-dd HH:mm:ss' +const outputDateStr = format(new Date(bookData.publication_date), 'yyyy-MM-dd HH:mm:ss'); +return {...bookData, publication_date:outputDateStr} +} module.exports = router diff --git a/src/routers/pets.js b/src/routers/pets.js new file mode 100644 index 00000000..6d52eb67 --- /dev/null +++ b/src/routers/pets.js @@ -0,0 +1,49 @@ +const express = require('express') +const router = express.Router() +const db = require("../../db"); + +router.get('/', async (req, res) => { + const type = req.query.type + const response = await db.query(`select * FROM pets ${type !==undefined ? "WHERE type = $1" : ""}`, type !== undefined ? [type] : []) + res.json({pets: response.rows.map(parsePet)}) +}) +router.get('/:id', async (req, res) => { + const response = await db.query("select * FROM pets WHERE id = $1 ", [req.params.id]) + res.json({pet: parsePet(response.rows[0])}) +}) +router.put('/:id', async (req, res) => { + // console.log("BumbaClap", req.body) + const update = await db.query( + `UPDATE pets + SET name = $1, + age = $2, + type = $3, + breed = $4, + has_microchip = $5 + WHERE id = $6; +`, [req.body.name, req.body.age, req.body.type, req.body.breed, req.body.has_microchip, req.params.id ]) + const response = await db.query("select * FROM pets WHERE id = $1 ", [req.params.id]) + res.status(201).json({pet: parsePet(response.rows[0])}) +}) +router.delete('/:id', async (req, res) => { + + const deleteResponse = await db.query("DELETE FROM pets WHERE id = $1 RETURNING *;", [req.params.id]) + // console.log("data", deleteResponse) + res.status(201).json({pet: parsePet(deleteResponse.rows[0])}) +}) +router.post('/', async (req, res) => { + // console.log("BumbaClap", req.body) + const update = await db.query( + `INSERT INTO pets (name, age, type, breed, has_microchip) +VALUES ($1, $2, $3, $4, $5) RETURNING *; +`, [req.body.name, req.body.age, req.body.type, req.body.breed, req.body.has_microchip]) + // console.log("test", update.rows[0]) +const response = await db.query("select * FROM pets WHERE id = $1 ", [update.rows[0].id]) + res.status(201).json({pet: parsePet(response.rows[0])}) +}) + +function parsePet(data) { + return {...data, has_microchip: !!data.has_microchip} +} + +module.exports = router diff --git a/src/server.js b/src/server.js index dac55e5d..233ceb88 100644 --- a/src/server.js +++ b/src/server.js @@ -10,7 +10,9 @@ app.use(express.json()); //TODO: Implement books and pets APIs using Express Modular Routers const booksRouter = require('./routers/books.js') +const petsRouter = require('./routers/pets.js') app.use('/books', booksRouter) +app.use('/pets', petsRouter) module.exports = app diff --git a/test/api/routes/pets.spec.js b/test/api/routes/pets.spec.js index 73e22597..f8b367a0 100644 --- a/test/api/routes/pets.spec.js +++ b/test/api/routes/pets.spec.js @@ -31,6 +31,7 @@ describe("Pets Endpoint", () => { expect(response.status).toEqual(200) expect(response.body.pets).not.toEqual(undefined) + console.log("response", response.body) expect(response.body.pets.length).toEqual(2) }) @@ -82,4 +83,4 @@ describe("Pets Endpoint", () => { } }) }) -}) +}) \ No newline at end of file diff --git a/test/fixtures/bookData.js b/test/fixtures/bookData.js index f337b765..09b346b6 100644 --- a/test/fixtures/bookData.js +++ b/test/fixtures/bookData.js @@ -4,7 +4,7 @@ module.exports = { type: "test1", author: "test1", topic: "test1", - publication_date: "2020-11-16T00:00:00.000Z", + publication_date: "2020-11-16 00:00:00", pages: 1 }, book2: { @@ -12,7 +12,7 @@ module.exports = { type: "test2", author: "test2", topic: "test2", - publication_date: "2020-11-17T00:00:00.000Z", + publication_date: "2020-11-17 00:00:00", pages: 2 }, book3: { @@ -20,7 +20,7 @@ module.exports = { type: "test3", author: "test3", topic: "test3", - publication_date: "2020-11-18T00:00:00.000Z", + publication_date: "2020-11-18 00:00:00", pages: 3 } } diff --git a/test/helpers/createBook.js b/test/helpers/createBook.js index 5f7e9c76..3ea356b0 100644 --- a/test/helpers/createBook.js +++ b/test/helpers/createBook.js @@ -8,4 +8,4 @@ const createBook = async (values) => { return result.rows[0] } -module.exports = createBook +module.exports = createBook \ No newline at end of file diff --git a/test/helpers/createPet.js b/test/helpers/createPet.js index 8dfca845..a85e248d 100644 --- a/test/helpers/createPet.js +++ b/test/helpers/createPet.js @@ -2,10 +2,10 @@ const client = require("../../db"); const createPet = async (values) => { const sqlString = `INSERT INTO "pets" (name, age, type, breed, has_microchip) VALUES ($1, $2, $3, $4, $5) RETURNING *;` - +console.log("insert pets", values) const result = await client.query(sqlString, values) return result.rows[0] } -module.exports = createPet +module.exports = createPet \ No newline at end of file diff --git a/test/helpers/insertBooks.js b/test/helpers/insertBooks.js index 54e720ca..295c6713 100644 --- a/test/helpers/insertBooks.js +++ b/test/helpers/insertBooks.js @@ -8,4 +8,4 @@ const insertBooks = async () => { await client.query(sqlStringForBooks) } -module.exports = insertBooks +module.exports = insertBooks \ No newline at end of file diff --git a/test/helpers/insertPets.js b/test/helpers/insertPets.js index eadddec2..771b706c 100644 --- a/test/helpers/insertPets.js +++ b/test/helpers/insertPets.js @@ -8,4 +8,4 @@ const insertPets = async () => { await client.query(sqlStringForPets) } -module.exports = insertPets +module.exports = insertPets \ No newline at end of file