From 789f680a402beed0756e1e83b18f28f9e05465ca Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Tue, 27 Aug 2024 12:42:09 +0300 Subject: [PATCH 01/12] handoff between computers --- .env.example | 6 -- package-lock.json | 76 ++++++++++++------- .../20240825122842_all/migration.sql | 1 + src/routers/customer.js | 8 +- src/routers/movies.js | 51 +++++++++++++ src/server.js | 21 ++--- 6 files changed, 115 insertions(+), 48 deletions(-) delete mode 100644 .env.example create mode 100644 prisma/migrations/20240825122842_all/migration.sql create mode 100644 src/routers/movies.js diff --git a/.env.example b/.env.example deleted file mode 100644 index 60f3a816..00000000 --- a/.env.example +++ /dev/null @@ -1,6 +0,0 @@ -DATABASE_URL="YOUR_DB_URL" - -# We need the following URL environment variable for test purposes: -# - TEST_DATABASE_URL must be a **completely separate** database from any other used in this file - -TEST_DATABASE_URL="YOUR_TEST_DB_URL" diff --git a/package-lock.json b/package-lock.json index 0fc727e5..7055cad1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1433,12 +1433,13 @@ } }, "node_modules/body-parser": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz", - "integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", - "content-type": "~1.0.4", + "content-type": "~1.0.5", "debug": "2.6.9", "depd": "2.0.0", "destroy": "1.2.0", @@ -1446,7 +1447,7 @@ "iconv-lite": "0.4.24", "on-finished": "2.4.1", "qs": "6.11.0", - "raw-body": "2.5.1", + "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" }, @@ -1459,6 +1460,7 @@ "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", "dependencies": { "ms": "2.0.0" } @@ -1466,12 +1468,14 @@ "node_modules/body-parser/node_modules/ms": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT" }, "node_modules/body-parser/node_modules/qs": { "version": "6.11.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "license": "BSD-3-Clause", "dependencies": { "side-channel": "^1.0.4" }, @@ -1493,12 +1497,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -1555,6 +1560,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "license": "MIT", "engines": { "node": ">= 0.8" } @@ -1773,6 +1779,7 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -1784,9 +1791,10 @@ "dev": true }, "node_modules/cookie": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz", - "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==", + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -2106,16 +2114,17 @@ } }, "node_modules/express": { - "version": "4.18.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz", - "integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==", + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "license": "MIT", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.1", + "body-parser": "1.20.2", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.5.0", + "cookie": "0.6.0", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", @@ -2195,10 +2204,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -2529,6 +2539,7 @@ "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "license": "MIT", "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -2667,6 +2678,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -3531,6 +3543,7 @@ "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "license": "MIT", "engines": { "node": ">= 0.6" } @@ -3555,12 +3568,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -4134,9 +4148,10 @@ } }, "node_modules/raw-body": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz", - "integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==", + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "license": "MIT", "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", @@ -4243,7 +4258,8 @@ "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, "node_modules/semver": { "version": "6.3.1", @@ -4678,6 +4694,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, @@ -4730,6 +4747,7 @@ "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "license": "MIT", "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" diff --git a/prisma/migrations/20240825122842_all/migration.sql b/prisma/migrations/20240825122842_all/migration.sql new file mode 100644 index 00000000..af5102c8 --- /dev/null +++ b/prisma/migrations/20240825122842_all/migration.sql @@ -0,0 +1 @@ +-- This is an empty migration. \ No newline at end of file diff --git a/src/routers/customer.js b/src/routers/customer.js index f14a87fc..7a46c74f 100644 --- a/src/routers/customer.js +++ b/src/routers/customer.js @@ -1,10 +1,12 @@ const express = require("express"); -const { - createCustomer -} = require('../controllers/customer'); +const { createCustomer } = require("../controllers/customer"); const router = express.Router(); +router.get("/", async (req, res) => { + res.json("bruh"); +}); + // In index.js, we told express that the /customer route should use this router file // The below /register route extends that, so the end result will be a URL // that looks like http://localhost:4040/customer/register diff --git a/src/routers/movies.js b/src/routers/movies.js new file mode 100644 index 00000000..e58e4613 --- /dev/null +++ b/src/routers/movies.js @@ -0,0 +1,51 @@ +const express = require("express"); +const prisma = require("../utils/prisma.js"); +const { response } = require("../server.js"); + +const router = express.Router(); + +// GET REQUESTS + +router.get("/", async (req, res) => { + // GET ALL THE MOVIES AND THEIR SCREENINGS + const response = []; + + const movies = await prisma.movie.findMany(); // GET ALL MOVIES + + for (const movie of movies) { + const screening = await prisma.screening.findMany({ + // GET SCREENINGS FOR CURRENT MOVIE + where: { movieId: movie.id }, + }); + + movie.screenings = screening; // ADD SCREENINGS FIELD INTO THE CURRENT MOVIE OBJECT + + response.push(movie); // ADD MOVIE INTO THE RESPONSE ARRAY + } + res.json({ movies: response }); +}); + +router.get("/:id", async (req, res) => {}); + +// POST REQUESTS + +router.post("/", async (req, res) => { + const movie = await prisma.movie.create({ + // CREATES A NEW MOVIE WITH THE GIVEN TITLE AND RUNTIME IN THE REQUEST BODY + data: { + title: req.body.title, + runtimeMins: req.body.runtimeMins, + }, + }); + + const screening = await prisma.screening.findMany({ + //FINDS SCREENINGS IF THE CREATED MOVIE HAS ANY + where: { movieId: movie.id }, + }); + + movie.screenings = screening; // ADD SCREENINGS FIELD INTO THE CURRENT MOVIE OBJECT + + res.status(201).json({ movie: movie }); +}); + +module.exports = router; diff --git a/src/server.js b/src/server.js index 93d47a16..01334a4b 100644 --- a/src/server.js +++ b/src/server.js @@ -1,21 +1,22 @@ -const express = require('express'); +const express = require("express"); const app = express(); -const cors = require('cors'); -const morgan = require('morgan'); +const cors = require("cors"); +const morgan = require("morgan"); -app.disable('x-powered-by'); +app.disable("x-powered-by"); // Add middleware app.use(cors()); -app.use(morgan('dev')); +app.use(morgan("dev")); app.use(express.json()); app.use(express.urlencoded({ extended: true })); - // Tell express to use your routers here -const customerRouter = require('./routers/customer'); -app.use('/customers', customerRouter); - +const customerRouter = require("./routers/customer"); +const moviesRouter = require("./routers/movies"); +const prisma = require("./utils/prisma"); +app.use("/customers", customerRouter); +app.use("/movies", moviesRouter); -module.exports = app +module.exports = app; From f743ef69f11da4d99271b125cc8df200ccdcbd8f Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Tue, 27 Aug 2024 17:21:28 +0300 Subject: [PATCH 02/12] added put request and get by id --- src/routers/movies.js | 49 ++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/routers/movies.js b/src/routers/movies.js index e58e4613..78f1e187 100644 --- a/src/routers/movies.js +++ b/src/routers/movies.js @@ -25,7 +25,31 @@ router.get("/", async (req, res) => { res.json({ movies: response }); }); -router.get("/:id", async (req, res) => {}); +router.get("/:id", async (req, res) => { + try { + // TRY TO RUN THE ASYNC AWAIT FUNCTION + const [movie] = await prisma.movie.findMany({ + // GET MOVIE WITH GIVEN ID + where: { + id: Number(req.params.id), + }, + }); + + // TRY TO GET THE SCREENINGS + const screenings = await prisma.screening.findMany({ + // GET SCREENINGS FOR CURRENT MOVIE + where: { movieId: movie.id }, + }); + + movie.screenings = screenings; // ADD SCREENINGS FIELD INTO THE CURRENT MOVIE OBJECT + // IF THERE ARE NO SCREENINGS IT WILL DISPLAY THE FOLLOWING MESSAGE + + res.json({ movie }); + } catch (error) { + // IF THERE ARE NO MOVIES THE AWAIT WILL THROW AN ERROR. THIS WILL CATCH IT + res.status(404).json({ error: "MOVIE NOT FOUND" }); + } +}); // POST REQUESTS @@ -48,4 +72,27 @@ router.post("/", async (req, res) => { res.status(201).json({ movie: movie }); }); +// PUT REQUESTS + +router.put("/:id", async (req, res) => { + try { + // TRY TO RUN THE ASYNC AWAIT FUNCTION + const movie = await prisma.movie.update({ + // UPDATE MOVIE WITH GIVEN ID + where: { + id: Number(req.params.id), + }, + data: { + title: req.body.title, + runtimeMins: req.body.runtimeMins, + }, + }); + + res.status(201).json({ movie }); + } catch (error) { + // IF THERE ARE NO MOVIES THE AWAIT WILL THROW AN ERROR. THIS WILL CATCH IT + res.status(404).json({ error: "MOVIE NOT FOUND" }); + } +}); + module.exports = router; From e0c830a02f216c67c5793e8a1483b1529a63c579 Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Tue, 27 Aug 2024 18:59:16 +0300 Subject: [PATCH 03/12] added DIRECT_URL for supabase compatibility --- prisma/schema.prisma | 73 ++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/prisma/schema.prisma b/prisma/schema.prisma index dd9b27f1..8eafddc7 100644 --- a/prisma/schema.prisma +++ b/prisma/schema.prisma @@ -6,28 +6,29 @@ generator client { } datasource db { - provider = "postgresql" - url = env("DATABASE_URL") + provider = "postgresql" + url = env("DATABASE_URL") + directUrl = env("DIRECT_URL") } // https://www.prisma.io/docs/concepts/components/prisma-schema/data-model model Customer { - id Int @id @default(autoincrement()) - name String - contact Contact? - tickets Ticket[] - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id Int @id @default(autoincrement()) + name String + contact Contact? + tickets Ticket[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model Contact { - id Int @id @default(autoincrement()) - customer Customer @relation(fields: [customerId], references: [id]) - customerId Int @unique - phone String - email String @unique - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id Int @id @default(autoincrement()) + customer Customer @relation(fields: [customerId], references: [id]) + customerId Int @unique + phone String + email String @unique + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model Movie { @@ -40,31 +41,31 @@ model Movie { } model Screen { - id Int @id @default(autoincrement()) - number Int - screenings Screening[] - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id Int @id @default(autoincrement()) + number Int + screenings Screening[] + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model Screening { - id Int @id @default(autoincrement()) - tickets Ticket[] - movie Movie @relation(fields: [movieId], references: [id]) - movieId Int - screen Screen @relation(fields: [screenId], references: [id]) - screenId Int - startsAt DateTime - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id Int @id @default(autoincrement()) + tickets Ticket[] + movie Movie @relation(fields: [movieId], references: [id]) + movieId Int + screen Screen @relation(fields: [screenId], references: [id]) + screenId Int + startsAt DateTime + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } model Ticket { - id Int @id @default(autoincrement()) - screening Screening @relation(fields: [screeningId], references: [id]) - screeningId Int - customer Customer @relation(fields: [customerId], references: [id]) - customerId Int - createdAt DateTime @default(now()) - updatedAt DateTime @updatedAt + id Int @id @default(autoincrement()) + screening Screening @relation(fields: [screeningId], references: [id]) + screeningId Int + customer Customer @relation(fields: [customerId], references: [id]) + customerId Int + createdAt DateTime @default(now()) + updatedAt DateTime @updatedAt } From edf53dde2805bd7832923479b78502f4b58c5334 Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Tue, 27 Aug 2024 18:59:41 +0300 Subject: [PATCH 04/12] updated prisma --- package-lock.json | 78 +++++++++++-------- package.json | 4 +- .../20240825122842_all/migration.sql | 1 - 3 files changed, 46 insertions(+), 37 deletions(-) delete mode 100644 prisma/migrations/20240825122842_all/migration.sql diff --git a/package-lock.json b/package-lock.json index 7055cad1..6d38ea40 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "1.0.0", "license": "ISC", "dependencies": { - "@prisma/client": "^5.16.1", + "@prisma/client": "^5.19.0", "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", @@ -18,7 +18,7 @@ "devDependencies": { "jest": "^29.7.0", "nodemon": "^3.0.2", - "prisma": "^5.16.1", + "prisma": "^5.19.0", "supertest": "^6.3.3" } }, @@ -1009,10 +1009,11 @@ } }, "node_modules/@prisma/client": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.16.1.tgz", - "integrity": "sha512-wM9SKQjF0qLxdnOZIVAIMKiz6Hu7vDt4FFAih85K1dk/Rr2mdahy6d3QP41K62N9O0DJJA//gUDA3Mp49xsKIg==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-5.19.0.tgz", + "integrity": "sha512-CzOpau+q1kEWQyoQMvlnXIHqPvwmWbh48xZ4n8KWbAql0p8PC0BIgSTYW5ncxXa4JSEff0tcoxSZB874wDstdg==", "hasInstallScript": true, + "license": "Apache-2.0", "engines": { "node": ">=16.13" }, @@ -1026,48 +1027,53 @@ } }, "node_modules/@prisma/debug": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.16.1.tgz", - "integrity": "sha512-JsNgZAg6BD9RInLSrg7ZYzo11N7cVvYArq3fHGSD89HSgtN0VDdjV6bib7YddbcO6snzjchTiLfjeTqBjtArVQ==", - "devOptional": true + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-5.19.0.tgz", + "integrity": "sha512-+b/G0ubAZlrS+JSiDhXnYV5DF/aTJ3pinktkiV/L4TtLRLZO6SVGyFELgxBsicCTWJ2ZMu5vEV/jTtYCdjFTRA==", + "devOptional": true, + "license": "Apache-2.0" }, "node_modules/@prisma/engines": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.16.1.tgz", - "integrity": "sha512-KkyF3eIUtBIyp5A/rJHCtwQO18OjpGgx18PzjyGcJDY/+vNgaVyuVd+TgwBgeq6NLdd1XMwRCI+58vinHsAdfA==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-5.19.0.tgz", + "integrity": "sha512-UtW+0m4HYoRSSR3LoDGKF3Ud4BSMWYlLEt4slTnuP1mI+vrV3zaDoiAPmejdAT76vCN5UqnWURbkXxf66nSylQ==", "devOptional": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.16.1", - "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", - "@prisma/fetch-engine": "5.16.1", - "@prisma/get-platform": "5.16.1" + "@prisma/debug": "5.19.0", + "@prisma/engines-version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", + "@prisma/fetch-engine": "5.19.0", + "@prisma/get-platform": "5.19.0" } }, "node_modules/@prisma/engines-version": { - "version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303.tgz", - "integrity": "sha512-HkT2WbfmFZ9WUPyuJHhkiADxazHg8Y4gByrTSVeb3OikP6tjQ7txtSUGu9OBOBH0C13dPKN2qqH12xKtHu/Hiw==", - "devOptional": true + "version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f.tgz", + "integrity": "sha512-GimI9aZIFy/yvvR11KfXRn3pliFn1QAkdebVlsXlnoh5uk0YhLblVmeYiHfsu+wDA7BeKqYT4sFfzg8mutzuWw==", + "devOptional": true, + "license": "Apache-2.0" }, "node_modules/@prisma/fetch-engine": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.16.1.tgz", - "integrity": "sha512-oOkjaPU1lhcA/Rvr4GVfd1NLJBwExgNBE36Ueq7dr71kTMwy++a3U3oLd2ZwrV9dj9xoP6LjCcky799D9nEt4w==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-5.19.0.tgz", + "integrity": "sha512-oOiPNtmJX0cP/ebu7BBEouJvCw8T84/MFD/Hf2zlqjxkK4ojl38bB9i9J5LAxotL6WlYVThKdxc7HqoWnPOhqQ==", "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.16.1", - "@prisma/engines-version": "5.16.0-24.34ace0eb2704183d2c05b60b52fba5c43c13f303", - "@prisma/get-platform": "5.16.1" + "@prisma/debug": "5.19.0", + "@prisma/engines-version": "5.19.0-31.5fe21811a6ba0b952a3bc71400666511fe3b902f", + "@prisma/get-platform": "5.19.0" } }, "node_modules/@prisma/get-platform": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.16.1.tgz", - "integrity": "sha512-R4IKnWnMkR2nUAbU5gjrPehdQYUUd7RENFD2/D+xXTNhcqczp0N+WEGQ3ViyI3+6mtVcjjNIMdnUTNyu3GxIgA==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-5.19.0.tgz", + "integrity": "sha512-s9DWkZKnuP4Y8uy6yZfvqQ/9X3/+2KYf3IZUVZz5OstJdGBJrBlbmIuMl81917wp5TuK/1k2TpHNCEdpYLPKmg==", "devOptional": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/debug": "5.16.1" + "@prisma/debug": "5.19.0" } }, "node_modules/@sinclair/typebox": { @@ -4062,19 +4068,23 @@ } }, "node_modules/prisma": { - "version": "5.16.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.16.1.tgz", - "integrity": "sha512-Z1Uqodk44diztImxALgJJfNl2Uisl9xDRvqybMKEBYJLNKNhDfAHf+ZIJbZyYiBhLMbKU9cYGdDVG5IIXEnL2Q==", + "version": "5.19.0", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-5.19.0.tgz", + "integrity": "sha512-Pu7lUKpVyTx8cVwM26dYh8NdvMOkMnJXzE8L6cikFuR4JwyMU5NKofQkWyxJKlTT4fNjmcnibTvklV8oVMrn+g==", "devOptional": true, "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@prisma/engines": "5.16.1" + "@prisma/engines": "5.19.0" }, "bin": { "prisma": "build/index.js" }, "engines": { "node": ">=16.13" + }, + "optionalDependencies": { + "fsevents": "2.3.3" } }, "node_modules/prompts": { diff --git a/package.json b/package.json index ebaf03be..4793339a 100644 --- a/package.json +++ b/package.json @@ -26,11 +26,11 @@ "devDependencies": { "jest": "^29.7.0", "nodemon": "^3.0.2", - "prisma": "^5.16.1", + "prisma": "^5.19.0", "supertest": "^6.3.3" }, "dependencies": { - "@prisma/client": "^5.16.1", + "@prisma/client": "^5.19.0", "cors": "^2.8.5", "dotenv": "^16.3.1", "express": "^4.18.2", diff --git a/prisma/migrations/20240825122842_all/migration.sql b/prisma/migrations/20240825122842_all/migration.sql deleted file mode 100644 index af5102c8..00000000 --- a/prisma/migrations/20240825122842_all/migration.sql +++ /dev/null @@ -1 +0,0 @@ --- This is an empty migration. \ No newline at end of file From 78446ff58116c8a7e780857e7e6cafdc45b8fa2b Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Tue, 27 Aug 2024 19:00:54 +0300 Subject: [PATCH 05/12] Add Migration --- prisma/migrations/20240827155623_bruhmoment/migration.sql | 1 + 1 file changed, 1 insertion(+) create mode 100644 prisma/migrations/20240827155623_bruhmoment/migration.sql diff --git a/prisma/migrations/20240827155623_bruhmoment/migration.sql b/prisma/migrations/20240827155623_bruhmoment/migration.sql new file mode 100644 index 00000000..af5102c8 --- /dev/null +++ b/prisma/migrations/20240827155623_bruhmoment/migration.sql @@ -0,0 +1 @@ +-- This is an empty migration. \ No newline at end of file From 1a24c5f9f80376ebb2a4f3d9b871b6603dc64e4b Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Tue, 27 Aug 2024 19:36:30 +0300 Subject: [PATCH 06/12] just learned about include --- src/routers/movies.js | 34 ++++++---------------------------- 1 file changed, 6 insertions(+), 28 deletions(-) diff --git a/src/routers/movies.js b/src/routers/movies.js index 78f1e187..d6184582 100644 --- a/src/routers/movies.js +++ b/src/routers/movies.js @@ -8,20 +8,11 @@ const router = express.Router(); router.get("/", async (req, res) => { // GET ALL THE MOVIES AND THEIR SCREENINGS - const response = []; - const movies = await prisma.movie.findMany(); // GET ALL MOVIES + const response = await prisma.movie.findMany({ + include: { screenings: true }, + }); // GET ALL MOVIES - for (const movie of movies) { - const screening = await prisma.screening.findMany({ - // GET SCREENINGS FOR CURRENT MOVIE - where: { movieId: movie.id }, - }); - - movie.screenings = screening; // ADD SCREENINGS FIELD INTO THE CURRENT MOVIE OBJECT - - response.push(movie); // ADD MOVIE INTO THE RESPONSE ARRAY - } res.json({ movies: response }); }); @@ -33,17 +24,9 @@ router.get("/:id", async (req, res) => { where: { id: Number(req.params.id), }, + include: { screenings: true }, }); - // TRY TO GET THE SCREENINGS - const screenings = await prisma.screening.findMany({ - // GET SCREENINGS FOR CURRENT MOVIE - where: { movieId: movie.id }, - }); - - movie.screenings = screenings; // ADD SCREENINGS FIELD INTO THE CURRENT MOVIE OBJECT - // IF THERE ARE NO SCREENINGS IT WILL DISPLAY THE FOLLOWING MESSAGE - res.json({ movie }); } catch (error) { // IF THERE ARE NO MOVIES THE AWAIT WILL THROW AN ERROR. THIS WILL CATCH IT @@ -60,15 +43,9 @@ router.post("/", async (req, res) => { title: req.body.title, runtimeMins: req.body.runtimeMins, }, + include: { screenings: true }, }); - const screening = await prisma.screening.findMany({ - //FINDS SCREENINGS IF THE CREATED MOVIE HAS ANY - where: { movieId: movie.id }, - }); - - movie.screenings = screening; // ADD SCREENINGS FIELD INTO THE CURRENT MOVIE OBJECT - res.status(201).json({ movie: movie }); }); @@ -86,6 +63,7 @@ router.put("/:id", async (req, res) => { title: req.body.title, runtimeMins: req.body.runtimeMins, }, + include: { screenings: true }, }); res.status(201).json({ movie }); From 09f002cf85c9b1b71b18c6365200a3460a324ab7 Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Tue, 27 Aug 2024 19:36:48 +0300 Subject: [PATCH 07/12] added customers section --- src/routers/{customer.js => customers.js} | 26 +++++++++++++++++++---- src/server.js | 4 ++-- 2 files changed, 24 insertions(+), 6 deletions(-) rename src/routers/{customer.js => customers.js} (54%) diff --git a/src/routers/customer.js b/src/routers/customers.js similarity index 54% rename from src/routers/customer.js rename to src/routers/customers.js index 7a46c74f..b2e757dd 100644 --- a/src/routers/customer.js +++ b/src/routers/customers.js @@ -1,15 +1,33 @@ const express = require("express"); const { createCustomer } = require("../controllers/customer"); +const prisma = require("../utils/prisma"); const router = express.Router(); -router.get("/", async (req, res) => { - res.json("bruh"); -}); - // In index.js, we told express that the /customer route should use this router file // The below /register route extends that, so the end result will be a URL // that looks like http://localhost:4040/customer/register + +// POST REQUESTS + router.post("/register", createCustomer); +// PUT REQUESTS + +router.put("/:id", async (req, res) => { + const customer = await prisma.customer.update({ + where: { + id: Number(req.params.id), + }, + data: { + name: req.body.name, + }, + include: { + contact: true, + }, + }); + + res.status(201).json({ customer }); +}); + module.exports = router; diff --git a/src/server.js b/src/server.js index 01334a4b..f062f5da 100644 --- a/src/server.js +++ b/src/server.js @@ -13,10 +13,10 @@ app.use(express.json()); app.use(express.urlencoded({ extended: true })); // Tell express to use your routers here -const customerRouter = require("./routers/customer"); +const customersRouter = require("./routers/customers"); const moviesRouter = require("./routers/movies"); const prisma = require("./utils/prisma"); -app.use("/customers", customerRouter); +app.use("/customers", customersRouter); app.use("/movies", moviesRouter); module.exports = app; From 4020b75b32ecaadadfcb5241732e10578c32eef0 Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Tue, 27 Aug 2024 19:44:24 +0300 Subject: [PATCH 08/12] finished core criteria --- src/routers/screens.js | 19 +++++++++++++++++++ src/server.js | 2 ++ 2 files changed, 21 insertions(+) create mode 100644 src/routers/screens.js diff --git a/src/routers/screens.js b/src/routers/screens.js new file mode 100644 index 00000000..7eab53c0 --- /dev/null +++ b/src/routers/screens.js @@ -0,0 +1,19 @@ +const express = require("express"); +const prisma = require("../utils/prisma.js"); +const { response } = require("../server.js"); + +const router = express.Router(); + +// THE SOLE POST REQUEST + +router.post("/", async (req, res) => { + const screen = await prisma.screen.create({ + data: { + number: Number(req.body.number), + }, + }); + + res.status(201).json({ screen }); +}); + +module.exports = router; diff --git a/src/server.js b/src/server.js index f062f5da..3a14319d 100644 --- a/src/server.js +++ b/src/server.js @@ -15,8 +15,10 @@ app.use(express.urlencoded({ extended: true })); // Tell express to use your routers here const customersRouter = require("./routers/customers"); const moviesRouter = require("./routers/movies"); +const screensRouter = require("./routers/screens"); const prisma = require("./utils/prisma"); app.use("/customers", customersRouter); app.use("/movies", moviesRouter); +app.use("/screens", screensRouter); module.exports = app; From f9419c56cea797c55313fa7ae10079ba8dbfc98d Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Wed, 20 Nov 2024 20:50:33 +0300 Subject: [PATCH 09/12] modified: .gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 586e2f80..e670051d 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ node_modules # Keep environment variables out of version control .env ._* +.vscode \ No newline at end of file From 18e8261d2c0e52e83e9dcbbdda6c49c7282b9c57 Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Wed, 20 Nov 2024 21:09:36 +0300 Subject: [PATCH 10/12] added .env for testing --- .env | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .env diff --git a/.env b/.env new file mode 100644 index 00000000..ec3581a1 --- /dev/null +++ b/.env @@ -0,0 +1,3 @@ + +DATABASE_URL="postgresql://postgres.chktyotdknycnpyqgmmu:K8wtBMrikPzdAY8G@aws-0-eu-central-1.pooler.supabase.com:6543/postgres?pgbouncer=true" +DIRECT_URL="postgresql://postgres.chktyotdknycnpyqgmmu:K8wtBMrikPzdAY8G@aws-0-eu-central-1.pooler.supabase.com:5432/postgres" \ No newline at end of file From bc78cafc59efa06f28b880d8427e0f2b1a22fbd7 Mon Sep 17 00:00:00 2001 From: Atakan Temizkan Date: Wed, 20 Nov 2024 21:09:50 +0300 Subject: [PATCH 11/12] modified readme --- README.md | 85 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 47 insertions(+), 38 deletions(-) diff --git a/README.md b/README.md index bcdd1da3..3e1efa7f 100644 --- a/README.md +++ b/README.md @@ -1,61 +1,70 @@ # Cinema Booking API -> API stands for Application Programming Interface, which is a set of definitions and protocols for building and integrating software. Simply put, they allow two pieces of software to communicate with each other through a pre-defined interface. +## Introduction -## Learning Objectives +This project demonstrates my skill to create a working RESTful API using PostgreSQL and Prisma. The API allows interaction with a cinema booking system database and can be tested using tools like Postman. -- Design and build a database-backend API +## Installation -## Introduction +1. Clone the repository: + + ```bash + git clone https://github.com/AtikoSpeed/database-cinema-booking-api + ``` + +2. Navigate to the project directory: + + ```bash + cd database-cinema-booking-api + ``` -So far, we've designed a database structure for a cinema booking system and implemented that design using an ORM. The next step is to build an API that allows the cinema and its customers to interact with the database. +3. Install dependencies: -Frontend applications usually won't interact with a database directly, especially if it's a web app; they'll instead send instructions to a server which will process those instructions and give back a response. We decide how the server receives instructions, processes them and responds back by creating an API. + ```bash + npm ci + ``` -## Setting up +4. I've included my own .env file for demonstration purposes. **This is temporary and will be deleted** -The full database schema and seed file for this exercise has already been implemented, your focus is on building the API itself. +5. Reset Prisma migrations and set up the database schema: -**Note: Although we need to create a new primary database, we can reuse a shadow database across multiple projects since Prisma resets it after using it.** + ```bash + npx prisma migrate reset --force + ``` -1. Rename the `.env.example` file to `.env` -2. Edit the `DATABASE_URL` variable in `.env`, swapping `YOUR_DATABASE_URL` for the URL of your database -3. Create another separate **TEST** database instance; you may need to use a different cloud provider as some only allow one instance per free account. [Supabase](https://supabase.com/) may be a good option -4. Edit the `TEST_DATABASE_URL` variable in `.env`, swapping `YOUR_TEST_DB_URL` for the URL of the separate **TEST** database instance you just created -7. Run `npm ci` to install the project dependencies. -8. Run `npx prisma migrate reset` to execute the existing migrations & data seed. Press `y` when it asks if you're sure. +## Usage -## Instructions +Start the server: -- Run the app with `npm start` -- Work through each route detailed in the [API Spec](https://boolean-uk.github.io/database-cinema-booking-api/standard). +```bash +npm start +``` -## Extensions +## Testing with Postman -- Work through each route detailed in the [extended API Spec](https://boolean-uk.github.io/database-cinema-booking-api/extensions). This will require making changes to your existing routes, creating error responses for certain situations, and introducing a new route. -- You will need to create your own tests for these endpoints. Use the existing test provided in `test/api/extensions` as a guide. +Use Postman or any other API client to interact with the API endpoints. The available endpoints are: -## Extensions to the Extensions +### Movies -- Change your movie list GET route to only respond with movies that have a future screening time -- Add the ability for customers to leave reviews on movies - - This will require a new entity in your diagram, schema file and seed file. Remember the `npx prisma generate`, `npx prisma migrate dev --create-only --skip-seed --name reviews` and `npx prisma migrate reset` commands from an earlier exercise! -- You will need to create your own tests for these endpoints. Use the existing test provided in `test/api/extensions` as a guide. - - If you create the new `Review` entity, then you will also need to re-run `npm run test:migration` so that your test database runs the migration to create this table. Do this AFTER you have created the new migration file. +- `GET /movies` - Retrieve a list of movies along with their screenings. +- `GET /movies/{id}` - Retrieve a specific movie by ID along with its screenings. +- `POST /movies` - Create a new movie. +- `PUT /movies/{id}` - Update an existing movie. +- `DELETE /movies/{id}` - Delete a movie. -## Testing your work +### Customers -- First, make sure you have created / setup the test database instance and env var, as described in the "Setting Up" section. -- Next, run the command `npm run test:migration` - this will run the schema migrations against the test database. **You only need to do this the one time.** +- `POST /customers/register` - Register a new customer. +- `PUT /customers/{id}` - Update a customer's information. -Now, whenever you want to run tests locally: -- Run the test suite with `npm test` for core requirements. -- Run the extension test suite with `npm run test-extensions`. - - When working on extensions, create your own tests by using the one provided in `test/api/extensions` as a guide. +### Screens -So far, you may have been using `curl` to manually test your API endpoints. You can continue to use this approach if you choose, or you can download a tool to make things a little easier. There are two main options: +- `POST /screens` - Create a new screen. -- [Insomnia](https://insomnia.rest/download) (recommended) -- [Postman](https://www.postman.com/) +## Technologies Used -These tools are quite similar to your web browser but have some additional functionality to make structuring API requests easier. +- Node.js +- Express.js +- PostgreSQL +- Prisma ORM +- Postman (for testing) From 6d46ba492b04b0973acb5c9b971433bd21c48e2b Mon Sep 17 00:00:00 2001 From: AtikoSpeed <157288392+AtikoSpeed@users.noreply.github.com> Date: Tue, 26 Nov 2024 11:06:27 +0300 Subject: [PATCH 12/12] Delete .env --- .env | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .env diff --git a/.env b/.env deleted file mode 100644 index ec3581a1..00000000 --- a/.env +++ /dev/null @@ -1,3 +0,0 @@ - -DATABASE_URL="postgresql://postgres.chktyotdknycnpyqgmmu:K8wtBMrikPzdAY8G@aws-0-eu-central-1.pooler.supabase.com:6543/postgres?pgbouncer=true" -DIRECT_URL="postgresql://postgres.chktyotdknycnpyqgmmu:K8wtBMrikPzdAY8G@aws-0-eu-central-1.pooler.supabase.com:5432/postgres" \ No newline at end of file