Artteiv commited on
Commit
d9eec61
1 Parent(s): 081f4d5

feat: add menu item and module and migrations

Browse files
backend/package-lock.json CHANGED
@@ -17,6 +17,7 @@
17
  "@nestjs/platform-express": "^10.0.0",
18
  "@nestjs/typeorm": "^10.0.2",
19
  "bcrypt": "^5.1.1",
 
20
  "class-validator": "^0.14.1",
21
  "dotenv": "^16.4.5",
22
  "mysql2": "^3.11.3",
@@ -3394,6 +3395,12 @@
3394
  "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==",
3395
  "dev": true
3396
  },
 
 
 
 
 
 
3397
  "node_modules/class-validator": {
3398
  "version": "0.14.1",
3399
  "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz",
 
17
  "@nestjs/platform-express": "^10.0.0",
18
  "@nestjs/typeorm": "^10.0.2",
19
  "bcrypt": "^5.1.1",
20
+ "class-transformer": "^0.5.1",
21
  "class-validator": "^0.14.1",
22
  "dotenv": "^16.4.5",
23
  "mysql2": "^3.11.3",
 
3395
  "integrity": "sha512-cuSVIHi9/9E/+821Qjdvngor+xpnlwnuwIyZOaLmHBVdXL+gP+I6QQB9VkO7RI77YIcTV+S1W9AreJ5eN63JBA==",
3396
  "dev": true
3397
  },
3398
+ "node_modules/class-transformer": {
3399
+ "version": "0.5.1",
3400
+ "resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
3401
+ "integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw==",
3402
+ "license": "MIT"
3403
+ },
3404
  "node_modules/class-validator": {
3405
  "version": "0.14.1",
3406
  "resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.1.tgz",
backend/package.json CHANGED
@@ -33,6 +33,7 @@
33
  "@nestjs/platform-express": "^10.0.0",
34
  "@nestjs/typeorm": "^10.0.2",
35
  "bcrypt": "^5.1.1",
 
36
  "class-validator": "^0.14.1",
37
  "dotenv": "^16.4.5",
38
  "mysql2": "^3.11.3",
 
33
  "@nestjs/platform-express": "^10.0.0",
34
  "@nestjs/typeorm": "^10.0.2",
35
  "bcrypt": "^5.1.1",
36
+ "class-transformer": "^0.5.1",
37
  "class-validator": "^0.14.1",
38
  "dotenv": "^16.4.5",
39
  "mysql2": "^3.11.3",
backend/src/app.controller.ts CHANGED
@@ -1,10 +1,12 @@
1
  import { Controller, Get } from '@nestjs/common';
2
  import { AppService } from './app.service.js';
 
3
 
4
  @Controller()
5
  export class AppController {
6
  constructor(private readonly appService: AppService) {}
7
 
 
8
  @Get()
9
  getHello(): string {
10
  return this.appService.getHello();
 
1
  import { Controller, Get } from '@nestjs/common';
2
  import { AppService } from './app.service.js';
3
+ import { Public } from './modules/authentication/authentication.decorator.js';
4
 
5
  @Controller()
6
  export class AppController {
7
  constructor(private readonly appService: AppService) {}
8
 
9
+ @Public()
10
  @Get()
11
  getHello(): string {
12
  return this.appService.getHello();
backend/src/app.module.ts CHANGED
@@ -10,6 +10,7 @@ import { DeviceInfoMiddleware } from './common/middlewares/device-info.middlewar
10
  import { UserModule } from './modules/user/user.module.js';
11
  import { BranchModule } from './modules/branch/branch.module.js';
12
  import { AuthenticationModule } from './modules/authentication/authentication.module.js';
 
13
  @Module({
14
  imports: [
15
  ConfigModule.forRoot({
@@ -23,6 +24,7 @@ import { AuthenticationModule } from './modules/authentication/authentication.mo
23
  UserModule,
24
  BranchModule,
25
  AuthenticationModule,
 
26
  ],
27
  controllers: [AppController],
28
  providers: [AppService],
 
10
  import { UserModule } from './modules/user/user.module.js';
11
  import { BranchModule } from './modules/branch/branch.module.js';
12
  import { AuthenticationModule } from './modules/authentication/authentication.module.js';
13
+ import { MenuItemModule } from './modules/menu-item/menu-item.module.js';
14
  @Module({
15
  imports: [
16
  ConfigModule.forRoot({
 
24
  UserModule,
25
  BranchModule,
26
  AuthenticationModule,
27
+ MenuItemModule,
28
  ],
29
  controllers: [AppController],
30
  providers: [AppService],
backend/src/entities/branch-menu.entity.ts ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ BaseEntity,
3
+ Column,
4
+ Entity,
5
+ ManyToOne,
6
+ OneToMany,
7
+ PrimaryGeneratedColumn,
8
+ Relation,
9
+ } from 'typeorm';
10
+ import { BranchEntity } from './branch.entity.js';
11
+ import { MenuItemEntity } from './menu-item.entity.js';
12
+
13
+ @Entity('branch_menu')
14
+ export class BranchMenuEntity extends BaseEntity {
15
+ @PrimaryGeneratedColumn('uuid')
16
+ id: string;
17
+
18
+ @Column()
19
+ branch_id: string;
20
+
21
+ @Column()
22
+ menu_id: string;
23
+
24
+ @Column()
25
+ description: string;
26
+
27
+ @Column()
28
+ is_open: boolean;
29
+
30
+ @ManyToOne(() => BranchEntity, (a) => a.menu_items)
31
+ branch: Relation<BranchEntity>;
32
+
33
+ @ManyToOne(() => MenuItemEntity, (a) => a.branch_menus)
34
+ menu_item: Relation<MenuItemEntity>;
35
+ }
backend/src/entities/branch.entity.ts CHANGED
@@ -3,10 +3,12 @@ import {
3
  Column,
4
  Entity,
5
  ManyToOne,
 
6
  PrimaryGeneratedColumn,
7
  Relation,
8
  } from 'typeorm';
9
  import { UserEntity } from './user.entity.js';
 
10
 
11
  @Entity('branches')
12
  export class BranchEntity extends BaseEntity {
@@ -25,6 +27,9 @@ export class BranchEntity extends BaseEntity {
25
  @ManyToOne(() => UserEntity, (user) => user.branches)
26
  owner: Relation<UserEntity>;
27
 
 
 
 
28
  @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
29
  create_at: Date;
30
  }
 
3
  Column,
4
  Entity,
5
  ManyToOne,
6
+ OneToMany,
7
  PrimaryGeneratedColumn,
8
  Relation,
9
  } from 'typeorm';
10
  import { UserEntity } from './user.entity.js';
11
+ import { BranchMenuEntity } from './branch-menu.entity.js';
12
 
13
  @Entity('branches')
14
  export class BranchEntity extends BaseEntity {
 
27
  @ManyToOne(() => UserEntity, (user) => user.branches)
28
  owner: Relation<UserEntity>;
29
 
30
+ @OneToMany(() => BranchMenuEntity, (a) => a.branch)
31
+ menu_items: Relation<BranchMenuEntity>[];
32
+
33
  @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
34
  create_at: Date;
35
  }
backend/src/entities/menu-item.entity.ts ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ BaseEntity,
3
+ Column,
4
+ Entity,
5
+ ManyToOne,
6
+ OneToMany,
7
+ PrimaryColumn,
8
+ Relation,
9
+ } from 'typeorm';
10
+ import { BranchMenuEntity } from './branch-menu.entity.js';
11
+
12
+ @Entity('menu_items')
13
+ export class MenuItemEntity extends BaseEntity {
14
+ @PrimaryColumn()
15
+ id: string;
16
+
17
+ @Column()
18
+ item_name: string;
19
+
20
+ @Column({ nullable: true })
21
+ image_url: string;
22
+
23
+ @Column({ nullable: true })
24
+ item_group_id: string;
25
+
26
+ @Column()
27
+ description: string;
28
+
29
+ @Column()
30
+ price: number;
31
+
32
+ @OneToMany(() => BranchMenuEntity, (a) => a.menu_item)
33
+ branch_menus: Relation<BranchMenuEntity>[];
34
+
35
+ @Column({ type: 'timestamp', default: () => 'CURRENT_TIMESTAMP' })
36
+ create_at: Date;
37
+ }
backend/src/main.ts CHANGED
@@ -1,8 +1,10 @@
1
  import { NestFactory } from '@nestjs/core';
2
  import { AppModule } from './app.module.js';
 
3
 
4
  async function bootstrap() {
5
  const app = await NestFactory.create(AppModule, { cors: true });
 
6
  await app.listen(3000);
7
  }
8
  bootstrap();
 
1
  import { NestFactory } from '@nestjs/core';
2
  import { AppModule } from './app.module.js';
3
+ import { ValidationPipe } from '@nestjs/common';
4
 
5
  async function bootstrap() {
6
  const app = await NestFactory.create(AppModule, { cors: true });
7
+ app.useGlobalPipes(new ValidationPipe());
8
  await app.listen(3000);
9
  }
10
  bootstrap();
backend/src/migrations/1729703705445-AddBranchMenus.ts ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { MigrationInterface, QueryRunner } from "typeorm";
2
+
3
+ export class AddBranchMenus1729703705445 implements MigrationInterface {
4
+ name = 'AddBranchMenus1729703705445'
5
+
6
+ public async up(queryRunner: QueryRunner): Promise<void> {
7
+ await queryRunner.query(`CREATE TABLE "menu_items" ("id" character varying NOT NULL, "item_name" character varying NOT NULL, "image_url" character varying, "item_group_id" character varying, "description" character varying NOT NULL, "price" integer NOT NULL, "create_at" TIMESTAMP NOT NULL DEFAULT now(), CONSTRAINT "PK_57e6188f929e5dc6919168620c8" PRIMARY KEY ("id"))`);
8
+ await queryRunner.query(`CREATE TABLE "branch_menu" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "branch_id" character varying NOT NULL, "menu_id" character varying NOT NULL, "description" character varying NOT NULL, "is_open" boolean NOT NULL, "branchId" uuid, "menuItemId" character varying, CONSTRAINT "PK_977becffe98bbc626a56031b9e7" PRIMARY KEY ("id"))`);
9
+ await queryRunner.query(`ALTER TABLE "branch_menu" ADD CONSTRAINT "FK_e0c721a124fa03ea4cef6f28f42" FOREIGN KEY ("branchId") REFERENCES "branches"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
10
+ await queryRunner.query(`ALTER TABLE "branch_menu" ADD CONSTRAINT "FK_cbfb42df5887653593974e3e285" FOREIGN KEY ("menuItemId") REFERENCES "menu_items"("id") ON DELETE NO ACTION ON UPDATE NO ACTION`);
11
+ }
12
+
13
+ public async down(queryRunner: QueryRunner): Promise<void> {
14
+ await queryRunner.query(`ALTER TABLE "branch_menu" DROP CONSTRAINT "FK_cbfb42df5887653593974e3e285"`);
15
+ await queryRunner.query(`ALTER TABLE "branch_menu" DROP CONSTRAINT "FK_e0c721a124fa03ea4cef6f28f42"`);
16
+ await queryRunner.query(`DROP TABLE "branch_menu"`);
17
+ await queryRunner.query(`DROP TABLE "menu_items"`);
18
+ }
19
+
20
+ }
backend/src/modules/menu-item/dto/create-menu-item.dto.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { IsNumber, IsOptional, IsString, IsUrl } from 'class-validator';
2
+
3
+ export class CreateMenuItemDto {
4
+ @IsString()
5
+ id: string;
6
+
7
+ @IsString()
8
+ item_name: string;
9
+
10
+ @IsUrl()
11
+ image_url: string;
12
+
13
+ @IsString()
14
+ @IsOptional()
15
+ item_group_id?: string;
16
+
17
+ @IsString()
18
+ @IsOptional()
19
+ description?: string;
20
+
21
+ @IsNumber()
22
+ price: number;
23
+ }
backend/src/modules/menu-item/dto/update-menu-item.dto.ts ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { IsNumber, IsOptional, IsString, IsUrl } from 'class-validator';
2
+
3
+ export class UpdateMenuItemDto {
4
+ @IsString()
5
+ @IsOptional()
6
+ item_name: string;
7
+
8
+ @IsUrl()
9
+ @IsOptional()
10
+ image_url: string;
11
+
12
+ @IsString()
13
+ @IsOptional()
14
+ item_group_id?: string;
15
+
16
+ @IsString()
17
+ @IsOptional()
18
+ description?: string;
19
+
20
+ @IsNumber()
21
+ @IsOptional()
22
+ price: number;
23
+ }
backend/src/modules/menu-item/menu-item.controller.ts ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import {
2
+ Controller,
3
+ Get,
4
+ Post,
5
+ Body,
6
+ Patch,
7
+ Param,
8
+ Delete,
9
+ } from '@nestjs/common';
10
+ import { MenuItemService } from './menu-item.service.js';
11
+ import { CreateMenuItemDto } from './dto/create-menu-item.dto.js';
12
+ import { UpdateMenuItemDto } from './dto/update-menu-item.dto.js';
13
+ import { Public } from '../authentication/authentication.decorator.js';
14
+
15
+ @Public()
16
+ @Controller('menu-items')
17
+ export class MenuItemController {
18
+ constructor(private readonly menuItemService: MenuItemService) {}
19
+
20
+ @Post()
21
+ async create(@Body() createMenuItemDto: CreateMenuItemDto) {
22
+ return this.menuItemService.create(createMenuItemDto);
23
+ }
24
+
25
+ @Get()
26
+ async findAll() {
27
+ return this.menuItemService.findAll();
28
+ }
29
+
30
+ @Get(':id')
31
+ async findOne(@Param('id') id: string) {
32
+ return this.menuItemService.findOne(id);
33
+ }
34
+
35
+ @Patch(':id')
36
+ async update(
37
+ @Param('id') id: string,
38
+ @Body() updateMenuItemDto: UpdateMenuItemDto,
39
+ ) {
40
+ return this.menuItemService.update(id, updateMenuItemDto);
41
+ }
42
+
43
+ @Delete(':id')
44
+ remove(@Param('id') id: string) {
45
+ return this.menuItemService.remove(id);
46
+ }
47
+ }
backend/src/modules/menu-item/menu-item.module.ts ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
 
1
+ import { Module } from '@nestjs/common';
2
+ import { MenuItemService } from './menu-item.service.js';
3
+ import { MenuItemController } from './menu-item.controller.js';
4
+
5
+ @Module({
6
+ controllers: [MenuItemController],
7
+ providers: [MenuItemService],
8
+ })
9
+ export class MenuItemModule {}
backend/src/modules/menu-item/menu-item.service.ts ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { Injectable, NotFoundException } from '@nestjs/common';
2
+ import { CreateMenuItemDto } from './dto/create-menu-item.dto.js';
3
+ import { UpdateMenuItemDto } from './dto/update-menu-item.dto.js';
4
+ import { MenuItemEntity } from '../../entities/menu-item.entity.js';
5
+ import { Public } from '../authentication/authentication.decorator.js';
6
+ import { plainToClass } from 'class-transformer';
7
+
8
+ @Public()
9
+ @Injectable()
10
+ export class MenuItemService {
11
+ async create(createMenuItemDto: CreateMenuItemDto) {
12
+ return await MenuItemEntity.create({ ...createMenuItemDto }).save();
13
+ }
14
+
15
+ async findAll() {
16
+ return await MenuItemEntity.find();
17
+ }
18
+
19
+ async findOne(id: string) {
20
+ return await MenuItemEntity.findOneBy({ id: id });
21
+ }
22
+
23
+ async getMenuItemOrError(id: string) {
24
+ let menuItem = await MenuItemEntity.findOneBy({ id });
25
+ if (!menuItem) {
26
+ throw new NotFoundException('Menu item not found');
27
+ }
28
+ return menuItem;
29
+ }
30
+
31
+ async update(id: string, updateMenuItemDto: UpdateMenuItemDto) {
32
+ let menuItem = await this.getMenuItemOrError(id);
33
+ menuItem = plainToClass(MenuItemEntity, {
34
+ ...menuItem,
35
+ ...updateMenuItemDto,
36
+ });
37
+ return await menuItem.save();
38
+ }
39
+
40
+ async remove(id: string) {
41
+ let menuItem = await this.getMenuItemOrError(id);
42
+ return await menuItem.remove();
43
+ }
44
+ }