Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 0 additions & 6 deletions .env.example

This file was deleted.

68 changes: 34 additions & 34 deletions prisma/schema.prisma
Original file line number Diff line number Diff line change
Expand Up @@ -12,22 +12,22 @@ datasource db {

// 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 {
Expand All @@ -40,31 +40,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
}
54 changes: 23 additions & 31 deletions src/controllers/customer.js
Original file line number Diff line number Diff line change
@@ -1,48 +1,40 @@
const { PrismaClientKnownRequestError } = require("@prisma/client")
const { createCustomerDb } = require('../domains/customer.js')
const { PrismaClientKnownRequestError } = require("@prisma/client");
const { createCustomerDb } = require("../domains/customer.js");

const createCustomer = async (req, res) => {
const {
name,
phone,
email
} = req.body
const { name, phone, email } = req.body;

if (!name || !phone || !email) {
return res.status(400).json({
error: "Missing fields in request body"
})
error: "Missing fields in request body",
});
}

// Try-catch is a very common way to handle errors in JavaScript.
// It allows us to customise how we want errors that are thrown to be handled.
// Read more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch

// Here, if Prisma throws an error in the process of trying to create a new customer,
// instead of the Prisma error being thrown (and the app potentially crashing) we exit the
// `try` block (bypassing the `res.status` code) and enter the `catch` block.
try {
const createdCustomer = await createCustomerDb(name, phone, email)
const createdCustomer = await createCustomerDb(name, phone, email);

res.status(201).json({ customer: createdCustomer })
res.status(201).json({ customer: createdCustomer });
} catch (e) {
// In this catch block, we are able to specify how different Prisma errors are handled.
// Prisma throws errors with its own codes. P2002 is the error code for
// "Unique constraint failed on the {constraint}". In our case, the {constraint} is the
// email field which we have set as needing to be unique in the prisma.schema.
// To handle this, we return a custom 409 (conflict) error as a response to the client.
// Prisma error codes: https://www.prisma.io/docs/orm/reference/error-reference#common
// HTTP error codes: https://developer.mozilla.org/en-US/docs/Web/HTTP/Status#client_error_responses
if (e instanceof PrismaClientKnownRequestError) {
if (e.code === "P2002") {
return res.status(409).json({ error: "A customer with the provided email already exists" })
return res
.status(409)
.json({ error: "A customer with the provided email already exists" });
}
}

res.status(500).json({ error: e.message })
res.status(500).json({ error: e.message });
}
}
};
const updateCustomer = async (req, res) => {
const paramsId = Number(req.params.id);
const { name, contact } = req.body;
const customer = await updateCostumerDb(paramsId, name, contact);
res.status(201).json({
customer,
});
};

module.exports = {
createCustomer
}
createCustomer,
updateCustomer,
};
71 changes: 71 additions & 0 deletions src/controllers/movies.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
const {
createMovieDb,
getAllMoviesDb,
findMovieByIdDb,
updateMovieByIdDb,
} = require("../domains/movies.js");
const { NotFoundError } = require("@prisma/client");

const getAllMovies = async (req, res) => {
try {
const { runtimeLt, runtimeGt } = req.query;
const movies = await getAllMoviesDb(Number(runtimeLt), Number(runtimeGt));
res.status(200).json({ movies });
} catch (error) {
res.status(500).json({ error: error.message });
}
};

const createMovie = async (req, res) => {
try {
const { title, runtimeMins } = req.body;
if (!title || !runtimeMins) {
return res.status(400).json({ error: "Missing fields in request body" });
}
const createdMovie = await createMovieDb(title, runtimeMins);
res.status(201).json({ movie: createdMovie });
} catch (error) {
res.status(500).json({ error: error.message });
}
};

const findMovieById = async (req, res) => {
try {
const { id } = req.params;
const searchedMovie = await findMovieByIdDb(id);
if (!searchedMovie) {
return res.status(404).json({ error: "Movie not found" });
}
res.status(200).json({ movie: searchedMovie });
} catch (error) {
if (error instanceof NotFoundError) {
res.status(404).json({ error: error.message });
} else {
res.status(500).json({ error: error.message });
}
}
};

const updateMovieById = async (req, res) => {
try {
const { id } = req.params;
const { title, runtimeMins } = req.body;
if (!title || !runtimeMins) {
return res.status(400).json({ error: "Missing fields in request body" });
}
const updatedMovie = await updateMovieByIdDb(
Number(id),
title,
runtimeMins
);
res.status(201).json({ movie: updatedMovie });
} catch (error) {
if (error.code === "P2015") {
res.status(404).json({ error: "Movie not found" });
} else {
res.status(500).json({ error: error.message });
}
}
};

module.exports = { getAllMovies, createMovie, findMovieById, updateMovieById };
33 changes: 33 additions & 0 deletions src/controllers/screens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
const { createScreenDb } = require("../domains/screens.js");
const { PrismaClientKnownRequestError } = require("@prisma/client");

const createScreen = async (req, res) => {
const { number, screenings } = req.body;

try {
if (!number) {
return res
.status(400)
.json({ error: "Missing number field in request body" });
}

const screenNumber = Number(number);

const createdScreen = await createScreenDb(screenNumber, screenings);

res.status(201).json({ screen: createdScreen });
} catch (error) {
if (error instanceof PrismaClientKnownRequestError) {
if (error.code === "P2002") {
return res
.status(409)
.json({ error: "A screen with the provided number already exists" });
}
}

console.error("Error creating screen:", error);
res.status(500).json({ error: "Failed to create screen" });
}
};

module.exports = { createScreen };
58 changes: 39 additions & 19 deletions src/domains/customer.js
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
const prisma = require('../utils/prisma')
const prisma = require("../utils/prisma");

/**
* This will create a Customer AND create a new Contact, then automatically relate them with each other
* @tutorial https://www.prisma.io/docs/concepts/components/prisma-client/relation-queries#create-a-related-record
*/
const createCustomerDb = async (name, phone, email) => await prisma.customer.create({
data: {
name,
contact: {
create: {
phone,
email
}
}
},
// We add an `include` outside of the `data` object to make sure the new contact is returned in the result
// This is like doing RETURNING in SQL
include: {
contact: true
}
})
const createCustomerDb = async (name, phone, email) =>
await prisma.customer.create({
data: {
name,
contact: {
create: {
phone,
email,
},
},
},
// We add an `include` outside of the `data` object to make sure the new contact is returned in the result
// This is like doing RETURNING in SQL
include: {
contact: true,
},
});

const updateCustomer = async (id, name, phone, email) =>
await prisma.customer.update({
where: {
id: id,
},
data: {
name: name,
contact: {
update: {
phone: phone,
email: email,
},
},
},
include: {
contact: true,
},
});
module.exports = {
createCustomerDb
}
createCustomerDb,
updateCustomer,
};
Loading