Skip to content

Commit

Permalink
feat: create rental routes, infra, domain
Browse files Browse the repository at this point in the history
  • Loading branch information
GabrielCoruja committed Jan 11, 2024
1 parent 6e65988 commit 08c989c
Show file tree
Hide file tree
Showing 13 changed files with 381 additions and 0 deletions.
10 changes: 10 additions & 0 deletions src/application/routes/rentalCarRoutes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import { Router, Request, Response } from 'express';
import rentalCarController from '../../infraestructure/factories/RentalCarFactory';

const router = Router();

router.post('/', (req: Request, res: Response) => rentalCarController.create(req, res));
router.put('/:driverId', (req: Request, res: Response) => rentalCarController.update(req, res));
router.get('/:driverId', (req: Request, res: Response) => rentalCarController.getById(req, res));

export default router;
11 changes: 11 additions & 0 deletions src/domain/entities/RentalCar.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class RentalCar {
constructor(
public licensePlateId: string,
public driverId: number,
public startDate: Date,
public endDate: Date | null,
public description: string,
) { }
}

export default RentalCar;
10 changes: 10 additions & 0 deletions src/domain/repositories/RentalCar/IRentalCarPersistence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
import RentalCar from '../../entities/RentalCar';

interface IRentalCarPersistence {
save(rentalCar: Omit<RentalCar, 'startDate' | 'endDate'>): Promise<RentalCar>;
update(driverId: string): Promise<RentalCar | null>;
getById(driverId: string): Promise<RentalCar | null>;
getCarAndDriberAbleToRent(driverId: number, licensePlateId: string): Promise<RentalCar | null>;
}

export default IRentalCarPersistence;
28 changes: 28 additions & 0 deletions src/domain/repositories/RentalCar/RentalCarRepository.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import RentalCar from '../../entities/RentalCar';
import IRentalCarPersistence from './IRentalCarPersistence';

class DriverRepository {
constructor(private iRentalCarPersistence: IRentalCarPersistence) { }

async create(rentalCar: Omit<RentalCar, 'startDate' | 'endDate'>): Promise<RentalCar> {
console.log('testresesse', rentalCar);
return this.iRentalCarPersistence.save(rentalCar);
}

async update(driverId: string): Promise<RentalCar | null> {
return this.iRentalCarPersistence.update(driverId);
}

async getById(driverId: string): Promise<RentalCar | null> {
return this.iRentalCarPersistence.getById(driverId);
}

async getCarAndDriberAbleToRent(
driverId: number,
licensePlateId: string,
): Promise<RentalCar | null> {
return this.iRentalCarPersistence.getCarAndDriberAbleToRent(driverId, licensePlateId);
}
}

export default DriverRepository;
34 changes: 34 additions & 0 deletions src/domain/usecase/RentalCarUseCase.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import RentalCar from '../entities/RentalCar';
import RentalCarRepository from '../repositories/RentalCar/RentalCarRepository';

class CarUseCase {
constructor(private carRepository: RentalCarRepository) {}

public async create(
rentalCar: Omit<RentalCar, 'startDate' | 'endDate'>,
): Promise<RentalCar | null> {
const findCar = await this.carRepository.getCarAndDriberAbleToRent(
rentalCar.driverId,
rentalCar.licensePlateId,
);

if (findCar) return null;

return this.carRepository.create(rentalCar);
}

public async getById(driverId: string): Promise<RentalCar | null> {
const findCar = await this.carRepository.getById(driverId);
return findCar;
}

public async update(driverId: string): Promise<RentalCar | null> {
const findCar = await this.carRepository.getById(driverId);

if (!findCar) return null;

return this.carRepository.update(driverId);
}
}

export default CarUseCase;
48 changes: 48 additions & 0 deletions src/infraestructure/controllers/RentalCarController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { Request, Response } from 'express';
import RentalCarUseCase from '../../domain/usecase/RentalCarUseCase';
import StatusCode from '../enum/statusCode';

class DriverController {
private messageDriverNotFound = 'Driver not found';

constructor(private rentalCarUseCase: RentalCarUseCase) { }

async create(req: Request, res: Response): Promise<Response> {
const { licensePlateId, driverId, description } = req.body;
console.log('test coruja');

const createNewRentalDriver = await this.rentalCarUseCase.create({
licensePlateId, driverId, description,
});

if (!createNewRentalDriver) {
return res.status(StatusCode.BAD_REQUEST).json({ message: 'Driver already rented' });
}

return res.status(StatusCode.CREATED).json(createNewRentalDriver);
}

async update(req: Request, res: Response): Promise<Response> {
const { driverId } = req.params;

const driverReturningCar = await this.rentalCarUseCase.update(driverId);
if (!driverReturningCar) {
return res.status(StatusCode.NOT_FOUND).json({ message: this.messageDriverNotFound });
}

return res.status(StatusCode.OK).json(driverReturningCar);
}

async getById(req: Request, res: Response): Promise<Response> {
const { driverId } = req.params;

const driverData = await this.rentalCarUseCase.getById(driverId);
if (!driverData) {
return res.status(StatusCode.NOT_FOUND).json({ message: this.messageDriverNotFound });
}

return res.status(StatusCode.OK).json(driverData);
}
}

export default DriverController;
14 changes: 14 additions & 0 deletions src/infraestructure/factories/RentalCarFactory.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import RentalCarController from '../controllers/RentalCarController';
import RentalCarRepository from '../../domain/repositories/RentalCar/RentalCarRepository';
import RentalCarUseCase from '../../domain/usecase/RentalCarUseCase';
import RentalCarPersistence from '../persistence/RentalCarPersistence';
import RentalCarModel from '../persistence/database/models/RentalCarModel';
import DriverModel from '../persistence/database/models/DriverModel';
import CarModel from '../persistence/database/models/CarModel';

const rentalCarPersistence = new RentalCarPersistence(RentalCarModel, DriverModel, CarModel);
const rentalCarRepository = new RentalCarRepository(rentalCarPersistence);
const rentalCarUseCases = new RentalCarUseCase(rentalCarRepository);
const controller = new RentalCarController(rentalCarUseCases);

export default controller;
77 changes: 77 additions & 0 deletions src/infraestructure/persistence/RentalCarPersistence.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import { ModelStatic, Op } from 'sequelize';
import RentalCar from '../../domain/entities/RentalCar';
import IRentalCarPersistence from '../../domain/repositories/RentalCar/IRentalCarPersistence';
import RentalCarModel from './database/models/RentalCarModel';
import DriverModel from './database/models/DriverModel';
import CarModel from './database/models/CarModel';

class RentalCarPersistence implements IRentalCarPersistence {
constructor(
private rentalCarModel: ModelStatic<RentalCarModel>,
private driverModel: ModelStatic<DriverModel>,
private carModel: ModelStatic<CarModel>,
) { }

async save(rentalCar: Omit<RentalCar, 'startDate' | 'endDate'>): Promise<RentalCar> {
const newDriver = await this.rentalCarModel.create({
licensePlateId: rentalCar.licensePlateId,
driverId: rentalCar.driverId,
description: rentalCar.description,
});
return newDriver.dataValues;
}

async update(id: string): Promise<RentalCar | null> {
const findDriver = await this.rentalCarModel.findOne({
where: { driverId: id, endDate: null as any },

Check warning on line 26 in src/infraestructure/persistence/RentalCarPersistence.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
attributes: ['licensePlateId', 'driverId', 'startDate', 'endDate', 'description'],
});

console.log('findDriver', findDriver);
if (!findDriver) return null;

return (await findDriver.update({ endDate: new Date() })).dataValues;
}

async getById(driverId: string): Promise<RentalCar | null> {
const findDriver = await this.driverModel.findOne({
where: { id: driverId },
include: [{
model: this.carModel,
as: 'rentalCars',
attributes: ['licensePlateId', 'name', 'brand', 'color'],
through: {
attributes: ['startDate', 'endDate', 'description'],
},
}],
});
if (!findDriver) return null;

return findDriver.dataValues as unknown as RentalCar;
}

async getCarAndDriberAbleToRent(
driverId: number,
licensePlateId: string,
): Promise<RentalCar | null> {
const findDriverOrCar = await this.rentalCarModel.findOne({
where: {
[Op.and]: [
{ endDate: null as any },

Check warning on line 60 in src/infraestructure/persistence/RentalCarPersistence.ts

View workflow job for this annotation

GitHub Actions / build

Unexpected any. Specify a different type
{
[Op.or]: [
{ driverId },
{ licensePlateId },
],
},
],
},
});

if (!findDriverOrCar) return null;

return findDriverOrCar.dataValues;
}
}

export default RentalCarPersistence;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { DataTypes, Model, QueryInterface } from 'sequelize';
import RentalCar from '../../../../domain/entities/RentalCar';

export default {
up(queryInterface: QueryInterface) {
return queryInterface.createTable<Model<RentalCar>>('rental_cars', {
licensePlateId: {
type: DataTypes.CHAR(8),
allowNull: false,
field: 'license_plate_id',
references: {
model: 'cars',
key: 'license_plate_id',
},
},
driverId: {
type: DataTypes.INTEGER,
allowNull: false,
field: 'driver_id',
references: {
model: 'drivers',
key: 'id',
},
},
startDate: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: new Date(),
field: 'start_date',
},
endDate: {
type: DataTypes.DATE,
allowNull: true,
field: 'end_date',
},
description: {
type: DataTypes.STRING,
allowNull: false,
},
});
},

down(queryInterface: QueryInterface) {
return queryInterface.dropTable('rental_cars');
},
};
63 changes: 63 additions & 0 deletions src/infraestructure/persistence/database/models/RentalCarModel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import {
DataTypes,
Model,
InferAttributes,
InferCreationAttributes,
CreationOptional,
} from 'sequelize';
import db from '.';
import DriverModel from './DriverModel';
import CarModel from './CarModel';

class RentalCarModel extends Model<InferAttributes<RentalCarModel>,
InferCreationAttributes<RentalCarModel>> {
declare licensePlateId: string;
declare driverId: number;
declare startDate: CreationOptional<Date>;
declare endDate: CreationOptional<Date> | null;
declare description: string;
}

RentalCarModel.init({
licensePlateId: {
type: DataTypes.CHAR(8),
primaryKey: true,
},
driverId: {
type: DataTypes.INTEGER,
allowNull: false,
field: 'driver_id',
},
startDate: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: new Date(),
},
endDate: {
type: DataTypes.DATE,
allowNull: true,
},
description: {
type: DataTypes.STRING,
allowNull: false,
},
}, {
tableName: 'rental_cars',
timestamps: false,
underscored: true,
sequelize: db,
});

CarModel.belongsToMany(DriverModel, {
through: RentalCarModel,
foreignKey: 'license_plate_id',
as: 'drivers',
});

DriverModel.belongsToMany(CarModel, {
through: RentalCarModel,
foreignKey: 'driver_id',
as: 'rentalCars',
});

export default RentalCarModel;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { QueryInterface } from 'sequelize';

export default {
up(queryInterface: QueryInterface) {
return queryInterface.bulkInsert('rental_cars', [
{
license_plate_id: 'ABC-1234',
driver_id: 1,
start_date: new Date(),
end_date: new Date(),
description: 'Rental car 1',
},
{
license_plate_id: 'DEF-5678',
driver_id: 2,
start_date: new Date(),
end_date: null,
description: 'Rental car 1',
},
{
license_plate_id: 'GHI-9012',
driver_id: 3,
start_date: new Date(),
end_date: new Date(),
description: 'Rental car 1',
},
{
license_plate_id: 'JKL-3456',
driver_id: 1,
start_date: new Date(),
end_date: null,
description: 'Rental car 1',
},
], {});
},

down(queryInterface: QueryInterface) {
return queryInterface.bulkDelete('rental_cars', {});
}
};
Empty file.
Empty file.

0 comments on commit 08c989c

Please sign in to comment.