Compare commits

...

4 Commits

Author SHA1 Message Date
Alex Piqueras 4d1da02b5f Add express routes 2024-12-02 11:17:14 +01:00
Alex Piqueras ffd23217da Add controllers 2024-12-02 11:10:01 +01:00
Alex Piqueras 07533dbdcb Add repositories 2024-12-02 10:23:16 +01:00
Alex Piqueras b6458d0488 Remove redundant code 2024-12-02 10:01:43 +01:00
13 changed files with 688 additions and 36 deletions

View File

@ -0,0 +1,90 @@
import { Request, Response } from "express";
import Booking from "../models/booking.model";
import BookingRepository from "../repositories/booking.repository";
export default class BookingController {
async create(req: Request, res Response) {
if (!req.body.hotelId || !req.body.clientId) {
res.status(400).json({
message: "Content cannot be empty"
});
}
const booking = {
hotelId: req.body.hotelId,
clientId: req.body.clientId,
};
try {
const booking = await BookingRepository.create(booking);
res.status(201).json(booking);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!"
});
}
}
async findAll(req: Request, res Response) {
try {
const bookings = await BookingRepository.retrieveAll();
res.status(200).json(bookings);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async findOne(req: Request, res Response) {
if (!req.body.id) {
res.status(400).json({
message: "id cannot be empty"
});
}
try {
const booking = await BookingRepository.retrieveById(req.body.id);
res.status(200).json(booking);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async update(req: Request, res Response) {
res.status(405).json({
message: "Cannot update booking"
});
}
async delete(req: Request, res Response) {
if (!req.body.id) {
res.status(400).json({
message: "id cannot be empty"
});
}
try {
await BookingRepository.delete(req.body.id);
res.status(204);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async deleteAll(req: Request, res Response) {
try {
await BookingRepository.deleteAll();
res.status(204);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
}

View File

@ -0,0 +1,125 @@
import { Request, Response } from "express";
import Client from "../models/client.model";
import ClientRepository from "../repositories/client.repository";
export default class ClientController {
async create(req: Request, res Response) {
if (!req.body.name || !req.body.address || !req.body.phone) {
res.status(400).json({
message: "Content cannot be empty"
});
}
const client = {
name: req.body.name,
address: req.body.address,
phone: req.body.phone,
};
try {
const client = await ClientRepository.create(client);
res.status(201).json(client);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!"
});
}
}
async findAll(req: Request, res Response) {
const name = req.query.name;
const address = req.query.address;
const phone = req.query.phone;
try {
const clients = await ClientRepository.retrieveAll({name, address, phone});
res.status(200).json(clients);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async findOne(req: Request, res Response) {
if (!req.body.id) {
res.status(400).json({
message: "id cannot be empty"
});
}
try {
const client = await ClientRepository.retrieveById(req.body.id);
res.status(200).json(client);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async update(req: Request, res Response) {
if (!req.body.id) {
res.status(400).json({
message: "id cannot be empty"
});
}
if (!req.body.name && !req.body.address && !req.body.phone) {
res.status(400).json({
message: "Content cannot be empty"
});
}
try {
const client = await clientRepository.retrieveById(id);
if (req.body.name) {
client.name = req.body.name;
}
if (req.body.address) {
client.name = req.body.address;
}
if (req.body.address) {
client.phone = req.body.phone;
}
await clientRepository.update(client);
} catch (err) {
res.status(404).json({
message: err || "Not found"
});
}
}
async delete(req: Request, res Response) {
if (!req.body.id) {
res.status(400).json({
message: "id cannot be empty"
});
}
try {
await ClientRepository.delete(req.body.id);
res.status(204);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async deleteAll(req: Request, res Response) {
try {
await ClientRepository.deleteAll();
res.status(204);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
}

View File

@ -0,0 +1,119 @@
import { Request, Response } from "express";
import Hotel from "../models/hotel.model";
import HotelRepository from "../repositories/hotel.repository";
export default class HotelController {
async create(req: Request, res Response) {
if (!req.body.name || !req.body.address) {
res.status(400).json({
message: "Content cannot be empty"
});
}
const hotel = {
name: req.body.name,
address: req.body.address,
};
try {
const hotel = await HotelRepository.create(hotel);
res.status(201).json(hotel);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!"
});
}
}
async findAll(req: Request, res Response) {
const name = req.query.name;
const address = req.query.address;
try {
const hotels = await HotelRepository.retrieveAll({name, address});
res.status(200).json(hotels);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async findOne(req: Request, res Response) {
if (!req.body.id) {
res.status(400).json({
message: "id cannot be empty"
});
}
try {
const hotel = await HotelRepository.retrieveById(req.body.id);
res.status(200).json(hotel);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async update(req: Request, res Response) {
if (!req.body.id) {
res.status(400).json({
message: "id cannot be empty"
});
}
if (!req.body.name && !req.body.address) {
res.status(400).json({
message: "Content cannot be empty"
});
}
try {
const hotel = await hotelRepository.retrieveById(id);
if (req.body.name) {
hotel.name = req.body.name;
}
if (req.body.address) {
hotel.name = req.body.address;
}
await hotelRepository.update(hotel);
} catch (err) {
res.status(404).json({
message: err || "Not found"
});
}
}
async delete(req: Request, res Response) {
if (!req.body.id) {
res.status(400).json({
message: "id cannot be empty"
});
}
try {
await HotelRepository.delete(req.body.id);
res.status(204);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
async deleteAll(req: Request, res Response) {
try {
await HotelRepository.deleteAll();
res.status(204);
} catch (err) {
res.status(500).json({
message: err || "Internal Server Error!",
});
}
}
}

View File

@ -9,7 +9,6 @@ import Client from "./client.model.ts";
export default class Booking extends Model {
@Unique
@Column({
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true,
field: "id"
@ -18,7 +17,6 @@ export default class Booking extends Model {
@ForeignKey(() => Hotel)
@Column({
type: DataType.INTEGER,
field: "HotelId"
})
hotelId: number;
@ -26,28 +24,11 @@ export default class Booking extends Model {
@BelongsTo(() => Hotel)
hotel: Hotel;
@Column({
type: DataType.STRING(255),
field: "Name"
})
name?: string;
@Column({
type: DataType.STRING(255),
field: "Address"
})
address?: string;
@Column({
type: DataType.DATE,
field: "CreatedDate"
defaultValue: DataType.NOW
})
@CreatedAt
createdDate: Date;
@ForeignKey(() => Client)
@Column({
type: DataType.INTEGER,
field: "clientId"
})
clientId: number;

View File

@ -9,7 +9,6 @@ import Booking from "./booking.model.ts";
export default class Client extends Model {
@Unique
@Column({
type: DataType.INTEGER,
primaryKey: true,
autoIncrement: true,
field: "id"
@ -17,28 +16,21 @@ export default class Client extends Model {
id: number;
@Column({
type: DataType.STRING(255),
field: "Name"
})
name: string;
@Column({
type: DataType.STRING(255),
field: "Address"
})
address: string;
@Column({
type: DataType.STRING(255),
field: "Phone"
})
phone: string;
@Column({
type: DataType.DATE,
field: "CreatedDate"
defaultValue: DataType.NOW
})
@CreatedAt
createdDate: Date;
@HasMany(() => Booking)

View File

@ -17,22 +17,16 @@ export default class Hotel extends Model {
id: number;
@Column({
type: DataType.STRING(255),
field: "Name"
})
name: string;
@Column({
type: DataType.STRING(255),
field: "Address"
})
address: string;
@Column({
type: DataType.DATE,
field: "CreatedDate"
defaultValue: DataType.NOW
})
@CreatedAt
createdDate: Date;
@HasMany(() => Booking)

View File

@ -0,0 +1,65 @@
import { Op } from "sequelize";
import Booking from "../models/booking.model";
interface IBookingRepository {
create(booking: {clientId: number, hotelId: number}): Promise<Booking>;
retrieveAll(searchParams: {name: string, address: string}): Promise<Booking[]>;
retrieveById(bookingId: number): Promise<Booking | null>;
update(booking: Booking): Promise<number>;
delete(bookingId: number): Promise<number>;
deleteAll(): Promise<number>;
}
class BookingRepository implements IBookingRepository {
async save(booking: {clientId: number, hotelId: number}): Promise<Booking> {
try {
return await Booking.create(booking);
} catch (err) {
throw new Error("Failed to create Booking!");
}
}
async retrieveAll(): Promise<Booking[]> {
try {
return await Booking.findAll();
} catch (error) {
throw new Error("Failed to retrieve Bookings!");
}
}
async retrieveById(bookingId: number): Promise<Booking | null> {
try {
return await Booking.findByPk(bookingId);
} catch (error) {
throw new Error("Failed to retrieve Booking!");
}
}
async update(booking: Booking): Promise<number> {
throw new Error("Failed to update Booking!");
}
async delete(bookingId: number): Promise<number> {
try {
const affectedRows = await Booking.destroy({ where: { id: bookingId } });
return affectedRows;
} catch (error) {
throw new Error("Failed to delete Booking!");
}
}
async deleteAll(): Promise<number> {
try {
return Booking.destroy({
where: {},
truncate: false
});
} catch (error) {
throw new Error("Failed to delete Bookings!");
}
}
}
export default new BookingRepository();

View File

@ -0,0 +1,93 @@
import { Op } from "sequelize";
import Client from "../models/client.model";
interface IClientRepository {
create(client: {name: string, address: string, phone: string}): Promise<Client>;
retrieveAll(searchParams: {name: string, address: string}): Promise<Client[]>;
retrieveById(clientId: number): Promise<Client | null>;
update(client: Client): Promise<number>;
delete(clientId: number): Promise<number>;
deleteAll(): Promise<number>;
}
class ClientRepository implements IClientRepository {
async create(client: {name: string, address: string, phone: string}): Promise<Client> {
try {
return await Client.create({
name: client.name,
address: client.address,
phone: client.phone,
});
} catch (err) {
throw new Error("Failed to create Client!");
}
}
async retrieveAll(searchParams: {name?: string, address?: string, phone?: string): Promise<Client[]> {
try {
let condition: SearchCondition = {};
if (searchParams?.name) {
condition.name = { [Op.like]: `%${searchParams.name}%` };
}
if (searchParams?.address) {
condition.address = { [Op.like]: `%${searchParams.address}%` };
}
if (searchParams?.phone) {
condition.phone = { [Op.like]: `%${searchParams.phone}%` };
}
return await Client.findAll({ where: condition });
} catch (error) {
throw new Error("Failed to retrieve Clients!");
}
}
async retrieveById(clientId: number): Promise<Client | null> {
try {
return await Client.findByPk(clientId);
} catch (error) {
throw new Error("Failed to retrieve Client!");
}
}
async update(client: Client): Promise<number> {
const { id, name, address, phone } = client;
try {
const affectedRows = await Client.update(
{ name, address, phone},
{ where: { id: id } }
);
return affectedRows[0];
} catch (error) {
throw new Error("Failed to update Client!");
}
}
async delete(clientId: number): Promise<number> {
try {
const affectedRows = await Client.destroy({ where: { id: clientId } });
return affectedRows;
} catch (error) {
throw new Error("Failed to delete Client!");
}
}
async deleteAll(): Promise<number> {
try {
return Client.destroy({
where: {},
truncate: false
});
} catch (error) {
throw new Error("Failed to delete Clients!");
}
}
}
export default new ClientRepository();

View File

@ -0,0 +1,87 @@
import { Op } from "sequelize";
import Hotel from "../models/hotel.model";
interface IHotelRepository {
create(hotel: {name: string, address: string}): Promise<Hotel>;
retrieveAll(searchParams: {name: string, address: string}): Promise<Hotel[]>;
retrieveById(hotelId: number): Promise<Hotel | null>;
update(hotel: Hotel): Promise<number>;
delete(hotelId: number): Promise<number>;
deleteAll(): Promise<number>;
}
class HotelRepository implements IHotelRepository {
async create(hotel: {name: string, address: string}): Promise<Hotel> {
try {
return await Hotel.create({
name: hotel.name,
address: hotel.address,
});
} catch (err) {
throw new Error("Failed to create Hotel!");
}
}
async retrieveAll(searchParams: {name?: string, address?: string): Promise<Hotel[]> {
try {
let condition: SearchCondition = {};
if (searchParams?.name) {
condition.name = { [Op.like]: `%${searchParams.name}%` };
}
if (searchParams?.address) {
condition.address = { [Op.like]: `%${searchParams.address}%` };
}
return await Hotel.findAll({ where: condition });
} catch (error) {
throw new Error("Failed to retrieve Hotels!");
}
}
async retrieveById(hotelId: number): Promise<Hotel | null> {
try {
return await Hotel.findByPk(hotelId);
} catch (error) {
throw new Error("Failed to retrieve Hotel!");
}
}
async update(hotel: Hotel): Promise<number> {
const { id, name, address } = hotel;
try {
const affectedRows = await Hotel.update(
{ name, address },
{ where: { id: id } }
);
return affectedRows[0];
} catch (error) {
throw new Error("Failed to update Hotel!");
}
}
async delete(hotelId: number): Promise<number> {
try {
const affectedRows = await Hotel.destroy({ where: { id: hotelId } });
return affectedRows;
} catch (error) {
throw new Error("Failed to delete Hotel!");
}
}
async deleteAll(): Promise<number> {
try {
return Hotel.destroy({
where: {},
truncate: false
});
} catch (error) {
throw new Error("Failed to delete Hotels!");
}
}
}
export default new HotelRepository();

View File

@ -0,0 +1,31 @@
import { Router } from "express";
import BookingController from "../controllers/booking.controller";
class BookingRoutes {
router = Router();
controller = new BookingController();
constructor() {
this.intializeRoutes();
}
intializeRoutes() {
// Create a new Booking
this.router.post("/", this.controller.create);
// Retrieve all Bookings
this.router.get("/", this.controller.findAll);
// Retrieve a single Booking with id
this.router.get("/:id", this.controller.findOne);
// Update a Booking with id
this.router.put("/:id", this.controller.update);
// Delete a Booking with id
this.router.delete("/:id", this.controller.delete);
}
}
export default new BookingRoutes().router;

View File

@ -0,0 +1,31 @@
import { Router } from "express";
import ClientController from "../controllers/client.controller";
class ClientRoutes {
router = Router();
controller = new ClientController();
constructor() {
this.intializeRoutes();
}
intializeRoutes() {
// Create a new Client
this.router.post("/", this.controller.create);
// Retrieve all Clients
this.router.get("/", this.controller.findAll);
// Retrieve a single Client with id
this.router.get("/:id", this.controller.findOne);
// Update a Client with id
this.router.put("/:id", this.controller.update);
// Delete a Client with id
this.router.delete("/:id", this.controller.delete);
}
}
export default new ClientRoutes().router;

View File

@ -0,0 +1,31 @@
import { Router } from "express";
import HotelController from "../controllers/hotel.controller";
class HotelRoutes {
router = Router();
controller = new HotelController();
constructor() {
this.intializeRoutes();
}
intializeRoutes() {
// Create a new Hotel
this.router.post("/", this.controller.create);
// Retrieve all Hotels
this.router.get("/", this.controller.findAll);
// Retrieve a single Hotel with id
this.router.get("/:id", this.controller.findOne);
// Update a Hotel with id
this.router.put("/:id", this.controller.update);
// Delete a Hotel with id
this.router.delete("/:id", this.controller.delete);
}
}
export default new HotelRoutes().router;

13
src/routes/index.ts Normal file
View File

@ -0,0 +1,13 @@
import { Application } from "express";
import hotelRoutes from "./hotel.routes";
import clientRoutes from "./client.routes";
import bookingRoutes from "./booking.routes";
export default class Routes {
constructor(app: Application) {
app.use("/api/hotels", hotelRoutes);
app.use("/api/client", clientRoutes);
app.use("/api/booking", bookingRoutes);
}
}