Skip to content

Commit

Permalink
th-168: Add trucks table (BinaryStudioAcademy#232)
Browse files Browse the repository at this point in the history
* th-168: * business controller

* th-168: + get methods to backend for find all trucks by businessId

* th-168: + truck slice

* th-168: * migrate generate

* th-168: + styles for trucks table

* th-168: + add trucks form

* th-168: + notifications and sorted table

* th-168: * linting

* th-168: * linting

* th-168: * linting

* th-168: * comments

* th-168: * endpoint

* th-168: * swager

* th-168: * resolve comments

* th-168: * linting

* th-168: * linting

* th-168: * comments

* th-168: * actions

* th-168: * columns

* th-168: * error handle in action and slice

* th-168: * comments

* th-168: * actions and other comennts

* th-168: * linting

* th-168: + sort by year

* th-168: * style

* th-168: * comments

* th-168: * another comments

* th-168: * comments

* th-168: * comments
  • Loading branch information
MaxHopaytsa committed Sep 21, 2023
1 parent f15a295 commit 35193b2
Show file tree
Hide file tree
Showing 80 changed files with 802 additions and 312 deletions.
1 change: 1 addition & 0 deletions backend/src/libs/enums/enums.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,5 @@ export {
HttpCode,
HttpMessage,
ServerErrorType,
SortMethod,
} from 'shared/build/index.js';
7 changes: 7 additions & 0 deletions backend/src/libs/helpers/count-offset-by-query.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { type PaginationParameters } from '../types/types.js';

const countOffsetByQuery = ({ page, size }: PaginationParameters): number => {
return page * size;
};

export { countOffsetByQuery };
32 changes: 32 additions & 0 deletions backend/src/libs/helpers/get-sorted-by.helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import {
type AnyColumn,
type SQL,
type SQLWrapper,
asc,
desc,
} from 'drizzle-orm';

import { SortMethod } from '../enums/enums.js';
import { type SortMethodValue } from '../types/types.js';

type ColumnToSorted = SQLWrapper | AnyColumn;

const getSortedBy = (
sortedMethod: SortMethodValue | null,
requiredColumnToSorted: ColumnToSorted,
optionalColumnToSorted: ColumnToSorted,
): SQL[] => {
const sortedBy = [desc(requiredColumnToSorted)];

if (sortedMethod === SortMethod.ASC) {
sortedBy.unshift(asc(optionalColumnToSorted));
}

if (sortedMethod === SortMethod.DESC) {
sortedBy.unshift(desc(optionalColumnToSorted));
}

return sortedBy;
};

export { getSortedBy };
2 changes: 2 additions & 0 deletions backend/src/libs/helpers/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { countOffsetByQuery } from './count-offset-by-query.helper.js';
export { getSortedBy } from './get-sorted-by.helper.js';
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
ALTER TABLE "trucks"
ADD COLUMN "business_id" integer NOT NULL;

--> statement-breakpoint
DO $$ BEGIN
ALTER TABLE "trucks" ADD CONSTRAINT "trucks_business_id_business_details_id_fk" FOREIGN KEY ("business_id") REFERENCES "business_details"("id") ON DELETE no action ON UPDATE no action;
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
6 changes: 3 additions & 3 deletions backend/src/libs/packages/database/schema/tables-schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,15 @@ const trucks = pgTable(
id: serial('id').primaryKey(),
createdAt: timestamp('created_at').notNull().defaultNow(),
updatedAt: timestamp('updated_at').notNull().defaultNow(),
businessId: integer('business_id')
.notNull()
.references(() => business.id),
manufacturer: varchar('manufacturer').notNull(),
capacity: integer('capacity').notNull(),
pricePerKm: real('price_per_km').notNull(),
licensePlateNumber: varchar('license_plate_number').notNull(),
year: integer('year').notNull(),
towType: varchar('tow_type').notNull(),
businessId: integer('business_id')
.notNull()
.references(() => business.id),
},
(trucks) => {
return {
Expand Down
3 changes: 3 additions & 0 deletions backend/src/libs/types/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,12 @@ export {
type Id,
type NullableProperties,
type OperationResult,
type PaginationParameters,
type PaginationWithSortingParameters,
type RequireProperty,
type ServerCommonErrorResponse,
type ServerValidationErrorResponse,
type SortMethodValue,
type ValidationSchema,
type ValueOf,
} from 'shared/build/index.js';
68 changes: 65 additions & 3 deletions backend/src/packages/business/business.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
} from '~/libs/packages/controller/controller.js';
import { HttpCode } from '~/libs/packages/http/http.js';
import { type ILogger } from '~/libs/packages/logger/logger.js';
import { type PaginationWithSortingParameters } from '~/libs/types/types.js';
import { AuthStrategy } from '~/packages/auth/libs/enums/enums.js';

import {
Expand All @@ -16,6 +17,8 @@ import {
driverCreateUpdateRequestBody,
driverParameters,
} from '../drivers/libs/validation-schemas/validation-schemas.js';
import { type TruckAddRequestDto } from '../trucks/libs/types/types.js';
import { truckCreateRequestBody } from '../trucks/trucks.js';
import { type UserEntityObjectWithGroupT } from '../users/users.js';
import { type BusinessService } from './business.service.js';
import { BusinessApiPath } from './libs/enums/enums.js';
Expand Down Expand Up @@ -392,7 +395,23 @@ class BusinessController extends Controller {
handler: (options) =>
this.findAllTrucks(
options as ApiHandlerOptions<{
query: GetPaginatedPageQuery;
query: PaginationWithSortingParameters;
user: UserEntityObjectWithGroupT;
}>,
),
});

this.addRoute({
path: BusinessApiPath.TRUCKS,
method: 'POST',
authStrategy: defaultStrategies,
validation: {
body: truckCreateRequestBody,
},
handler: (request) =>
this.createTruck(
request as ApiHandlerOptions<{
body: TruckAddRequestDto;
user: UserEntityObjectWithGroupT;
}>,
),
Expand Down Expand Up @@ -873,11 +892,11 @@ class BusinessController extends Controller {

private async findAllTrucks(
options: ApiHandlerOptions<{
query: GetPaginatedPageQuery;
query: PaginationWithSortingParameters;
user: UserEntityObjectWithGroupT;
}>,
): Promise<ApiHandlerResponse> {
const trucks = await this.businessService.findAllTrucksByOwnerId(
const trucks = await this.businessService.findAllTrucksByBusinessId(
options.user.id,
options.query,
);
Expand All @@ -887,6 +906,49 @@ class BusinessController extends Controller {
payload: trucks,
};
}

/**
* @swagger
* /trucks:
* post:
* summary: Create a new truck
* tags:
* - business/trucks
* requestBody:
* description: Truck data to be added
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Truck'
* security:
* - bearerAuth: []
* responses:
* '201':
* description: Truck created successfully
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/TruckResponse'
* '400':
* description: Bad request
*
*/

private async createTruck(
options: ApiHandlerOptions<{
body: TruckAddRequestDto;
user: UserEntityObjectWithGroupT;
}>,
): Promise<ApiHandlerResponse> {
return {
status: HttpCode.CREATED,
payload: await this.businessService.createTruck(
options.body,
options.user.id,
),
};
}
}

export { BusinessController };
57 changes: 40 additions & 17 deletions backend/src/packages/business/business.service.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { NotFoundError } from '~/libs/exceptions/exceptions.js';
import { type IService } from '~/libs/interfaces/interfaces.js';
import { HttpCode, HttpError, HttpMessage } from '~/libs/packages/http/http.js';
import { type EntityPagination } from '~/libs/types/types.js';
import { type PaginationWithSortingParameters } from '~/libs/types/types.js';
import { UserGroupKey } from '~/packages/users/libs/enums/enums.js';

import { type DriverService } from '../drivers/driver.service.js';
Expand All @@ -12,7 +12,11 @@ import {
type DriverGetAllResponseDto,
} from '../drivers/drivers.js';
import { type ShiftEntity } from '../shifts/shift.js';
import { type TruckEntity } from '../trucks/libs/types/types.js';
import {
type TruckAddRequestDto,
type TruckEntity,
type TruckGetAllResponseDto,
} from '../trucks/libs/types/types.js';
import { type TruckService } from '../trucks/truck.service.js';
import { type UserEntityT } from '../users/users.js';
import { BusinessEntity } from './business.entity.js';
Expand Down Expand Up @@ -211,23 +215,26 @@ class BusinessService implements IService {
return await this.driverService.delete(driverId);
}

public checkisDriverBelongedToBusiness({
userId,
driverId,
}: {
userId: UserEntityT['id'];
driverId: ShiftEntity['driverId'];
}): Promise<boolean> {
return this.businessRepository.checkisDriverBelongedToBusiness(
userId,
driverId,
);
public async findAllTrucksByBusinessId(
userId: number,
query: PaginationWithSortingParameters,
): Promise<TruckGetAllResponseDto> {
const business = await this.findByOwnerId(userId);

if (!business) {
throw new HttpError({
status: HttpCode.BAD_REQUEST,
message: HttpMessage.BUSINESS_DOES_NOT_EXIST,
});
}

return await this.truckService.findAllByBusinessId(business.id, query);
}

public async findAllTrucksByOwnerId(
public async createTruck(
payload: TruckAddRequestDto,
userId: number,
query: GetPaginatedPageQuery,
): Promise<EntityPagination<TruckEntity>> {
): Promise<TruckEntity> {
const business = await this.findByOwnerId(userId);

if (!business) {
Expand All @@ -237,7 +244,23 @@ class BusinessService implements IService {
});
}

return await this.truckService.findAllByBusinessId(business.id, query);
return await this.truckService.create({
...payload,
businessId: business.id,
});
}

public checkisDriverBelongedToBusiness({
userId,
driverId,
}: {
userId: UserEntityT['id'];
driverId: ShiftEntity['driverId'];
}): Promise<boolean> {
return this.businessRepository.checkisDriverBelongedToBusiness(
userId,
driverId,
);
}
}

Expand Down
6 changes: 5 additions & 1 deletion backend/src/packages/trucks/libs/types/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
export { type DriverHaveAccessToTruck } from './driver-have-acces-to-truck.type.js';
export { type TruckDatabaseModel } from './truck-entity-type/truck-database-model.type.js';
export { type TruckEntity } from 'shared/build/index.js';
export {
type TruckAddRequestDto,
type TruckEntity,
type TruckGetAllResponseDto,
} from 'shared/build/index.js';
60 changes: 6 additions & 54 deletions backend/src/packages/trucks/truck.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import { type ILogger } from '~/libs/packages/logger/logger.js';
import { TruckApiPath } from './libs/enums/enums.js';
import { type TruckEntity } from './libs/types/types.js';
import {
truckCreateRequestBody,
truckGetParameters,
truckUpdateRequestBody,
} from './libs/validation-schema/validation-schemas.js';
} from './libs/validation-schemas/validation-schemas.js';
import { type TruckService } from './truck.service.js';

/**
Expand Down Expand Up @@ -102,6 +101,9 @@ import { type TruckService } from './truck.service.js';
* pricePerKm:
* type: number
* example: 5
* businessId:
* type: number
* example: 1
*
* ErrorType:
* type: object
Expand Down Expand Up @@ -136,20 +138,6 @@ class TruckController extends Controller {

this.truckService = truckService;

this.addRoute({
path: TruckApiPath.ROOT,
method: 'POST',
validation: {
body: truckCreateRequestBody,
},
handler: (request) =>
this.create(
request as ApiHandlerOptions<{
body: Omit<TruckEntity, 'id'>;
}>,
),
});

this.addRoute({
path: TruckApiPath.$ID,
method: 'PUT',
Expand All @@ -160,7 +148,7 @@ class TruckController extends Controller {
handler: (request) =>
this.update(
request as ApiHandlerOptions<{
body: Partial<TruckEntity>;
body: Partial<Omit<TruckEntity, 'createdAt'>>;
params: { id: number };
}>,
),
Expand Down Expand Up @@ -201,42 +189,6 @@ class TruckController extends Controller {
});
}

/**
* @swagger
* /trucks/:
* post:
* summary: Create a new truck
* tags:
* - truck
* requestBody:
* description: Truck data to be added
* required: true
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/Truck'
* responses:
* '201':
* description: Truck created successfully
* content:
* application/json:
* schema:
* $ref: '#/components/schemas/TruckResponse'
* '400':
* description: Bad request
*
*/
private async create(
options: ApiHandlerOptions<{
body: Omit<TruckEntity, 'id'>;
}>,
): Promise<ApiHandlerResponse> {
return {
status: HttpCode.CREATED,
payload: await this.truckService.create(options.body),
};
}

/**
* @swagger
* /trucks/{id}:
Expand Down Expand Up @@ -274,7 +226,7 @@ class TruckController extends Controller {

private async update(
options: ApiHandlerOptions<{
body: Partial<TruckEntity>;
body: Partial<Omit<TruckEntity, 'createdAt'>>;
params: { id: number };
}>,
): Promise<ApiHandlerResponse> {
Expand Down
Loading

0 comments on commit 35193b2

Please sign in to comment.