From 68020cc194db32c999b5d0347917c69f3fa85f38 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 00:51:54 -0300 Subject: [PATCH 01/20] feat(domain): adjust domain --- src/domain/entities/address.entity.ts | 10 --- src/domain/entities/address.ts | 68 +++++++++++++++++++ src/domain/entities/product.entity.ts | 2 +- .../{promotion.entity.ts => promotion.ts} | 0 src/domain/entities/restaurant.entity.ts | 4 +- src/domain/entities/schedule.entity.ts | 1 + .../repositories/restaurant.repository.ts | 10 +++ 7 files changed, 81 insertions(+), 14 deletions(-) delete mode 100644 src/domain/entities/address.entity.ts create mode 100644 src/domain/entities/address.ts rename src/domain/entities/{promotion.entity.ts => promotion.ts} (100%) create mode 100644 src/domain/repositories/restaurant.repository.ts diff --git a/src/domain/entities/address.entity.ts b/src/domain/entities/address.entity.ts deleted file mode 100644 index a92637c..0000000 --- a/src/domain/entities/address.entity.ts +++ /dev/null @@ -1,10 +0,0 @@ -export class Address { - constructor( - public readonly street: string, - public readonly number: string, - public readonly state: string, - public readonly city: string, - public readonly neighborhood: string, - public readonly zipcode: string, - ) {} -} diff --git a/src/domain/entities/address.ts b/src/domain/entities/address.ts new file mode 100644 index 0000000..5973e18 --- /dev/null +++ b/src/domain/entities/address.ts @@ -0,0 +1,68 @@ +export class Address { + constructor( + public readonly street: string, + public readonly number: string | null, + public readonly state: string, + public readonly city: string, + public readonly neighborhood: string, + public readonly zipcode: string, + ) {} + + static builder() { + return new AddressBuilder(); + } + + toString() { + return `${this.street}, ${this.number ?? "SN"} - ${this.neighborhood}, ${this.city} - ${this.state}, ${this.zipcode}`; + } +} + +class AddressBuilder { + private street!: string; + private number!: string | null; + private state!: string; + private city!: string; + private neighborhood!: string; + private zipcode!: string; + + withStreet(street: string) { + this.street = street; + return this; + } + + withNumber(number: string | null) { + this.number = number; + return this; + } + + withState(state: string) { + this.state = state; + return this; + } + + withCity(city: string) { + this.city = city; + return this; + } + + withNeighborhood(neighborhood: string) { + this.neighborhood = neighborhood; + return this; + } + + withZipcode(zipcode: string) { + this.zipcode = zipcode; + return this; + } + + build() { + return new Address( + this.street, + this.number, + this.state, + this.city, + this.neighborhood, + this.zipcode, + ); + } +} diff --git a/src/domain/entities/product.entity.ts b/src/domain/entities/product.entity.ts index 8165beb..c53e4d8 100644 --- a/src/domain/entities/product.entity.ts +++ b/src/domain/entities/product.entity.ts @@ -1,4 +1,4 @@ -import type { Promotion } from "@/domain/entities/promotion.entity"; +import type { Promotion } from "@/domain/entities/promotion"; export class Product { constructor( diff --git a/src/domain/entities/promotion.entity.ts b/src/domain/entities/promotion.ts similarity index 100% rename from src/domain/entities/promotion.entity.ts rename to src/domain/entities/promotion.ts diff --git a/src/domain/entities/restaurant.entity.ts b/src/domain/entities/restaurant.entity.ts index 34e1d2d..4b13a0e 100644 --- a/src/domain/entities/restaurant.entity.ts +++ b/src/domain/entities/restaurant.entity.ts @@ -1,5 +1,4 @@ -import type { Address } from "@/domain/entities/address.entity"; -import type { Product } from "@/domain/entities/product.entity"; +import type { Address } from "@/domain/entities/address"; import type { Schedule } from "@/domain/entities/schedule.entity"; export class Restaurant { @@ -9,6 +8,5 @@ export class Restaurant { public readonly picture: string, public readonly address: Address, public readonly schedules: Array, - public readonly products: Array, ) {} } diff --git a/src/domain/entities/schedule.entity.ts b/src/domain/entities/schedule.entity.ts index d6c456a..ba5ff7e 100644 --- a/src/domain/entities/schedule.entity.ts +++ b/src/domain/entities/schedule.entity.ts @@ -2,6 +2,7 @@ import { parserToMinutes } from "@/utils/hour"; export class Schedule { constructor( + public readonly id: string, public readonly begin: string, public readonly end: string, public readonly day: string, diff --git a/src/domain/repositories/restaurant.repository.ts b/src/domain/repositories/restaurant.repository.ts new file mode 100644 index 0000000..48cc348 --- /dev/null +++ b/src/domain/repositories/restaurant.repository.ts @@ -0,0 +1,10 @@ +import type { Address } from "@/domain/entities/address"; +import type { Restaurant } from "@/domain/entities/restaurant.entity"; + +export interface RestaurantRepository { + save(resturant: Restaurant): Promise; + create(name: string, address: Address): Promise; + list(): Promise; + get(id: string): Promise; + destroy(id: string): Promise; +} From 935b1b3d4f468e66544ab18b437d0aa0ef01a1a3 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 00:53:00 -0300 Subject: [PATCH 02/20] test(schedule): adjust test schedule --- tests/entities/schedule.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/entities/schedule.test.ts b/tests/entities/schedule.test.ts index b2d146a..2a9f755 100644 --- a/tests/entities/schedule.test.ts +++ b/tests/entities/schedule.test.ts @@ -22,11 +22,11 @@ describe("parsing input schedule hour to minutes", () => { describe("entity Schedule", () => { test("when valid input then ok", () => { - const result = new Schedule("12:00", "12:15", "sat"); + const result = new Schedule("0", "12:00", "12:15", "sat"); expect(result).toBeInstanceOf(Schedule); }); test("when valid input then ok", () => { - expect(() => new Schedule("12:15", "12:00", "sat")).toThrow(); + expect(() => new Schedule("0", "12:15", "12:00", "sat")).toThrow(); }); }); From 98a54a6549c1bcb1c1ecfe23f90d0b2ca551a579 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 00:53:56 -0300 Subject: [PATCH 03/20] feat(application): add restaurant use cases --- .../dtos/request/create-restaurant.dto.ts | 6 ++++ .../dtos/request/update-restaurant.dto.ts | 8 +++++ .../dtos/response/list-restaurant.dto.ts | 7 ++++ .../dtos/response/restaurant.dto.ts | 10 ++++++ src/application/dtos/shared/address.dto.ts | 8 +++++ src/application/dtos/shared/schedule.dto.ts | 6 ++++ src/application/useCases/create-restaurant.ts | 33 +++++++++++++++++++ src/application/useCases/delete-restaurant.ts | 9 +++++ src/application/useCases/get-restaurant.ts | 16 +++++++++ src/application/useCases/list-restaurant.ts | 17 ++++++++++ src/application/useCases/update-restaurant.ts | 22 +++++++++++++ 11 files changed, 142 insertions(+) create mode 100644 src/application/dtos/request/create-restaurant.dto.ts create mode 100644 src/application/dtos/request/update-restaurant.dto.ts create mode 100644 src/application/dtos/response/list-restaurant.dto.ts create mode 100644 src/application/dtos/response/restaurant.dto.ts create mode 100644 src/application/dtos/shared/address.dto.ts create mode 100644 src/application/dtos/shared/schedule.dto.ts create mode 100644 src/application/useCases/create-restaurant.ts create mode 100644 src/application/useCases/delete-restaurant.ts create mode 100644 src/application/useCases/get-restaurant.ts create mode 100644 src/application/useCases/list-restaurant.ts create mode 100644 src/application/useCases/update-restaurant.ts diff --git a/src/application/dtos/request/create-restaurant.dto.ts b/src/application/dtos/request/create-restaurant.dto.ts new file mode 100644 index 0000000..7a8acf1 --- /dev/null +++ b/src/application/dtos/request/create-restaurant.dto.ts @@ -0,0 +1,6 @@ +import type { AddressDto } from "@/application/dtos/shared/address.dto"; + +export type CreateRestaurantDto = { + name: string; + address: AddressDto; +}; diff --git a/src/application/dtos/request/update-restaurant.dto.ts b/src/application/dtos/request/update-restaurant.dto.ts new file mode 100644 index 0000000..500688a --- /dev/null +++ b/src/application/dtos/request/update-restaurant.dto.ts @@ -0,0 +1,8 @@ +import type { AddressDto } from "@/application/dtos/shared/address.dto"; +import type { Restaurant } from "@/domain/entities/restaurant.entity"; + +export type UpdateRestaurantDto = Partial< + Omit & { + address: AddressDto; + } +>; diff --git a/src/application/dtos/response/list-restaurant.dto.ts b/src/application/dtos/response/list-restaurant.dto.ts new file mode 100644 index 0000000..3870dd3 --- /dev/null +++ b/src/application/dtos/response/list-restaurant.dto.ts @@ -0,0 +1,7 @@ +import type { RestaurantDto } from "@/application/dtos/response/restaurant.dto"; + +type RestaurantItem = Omit & { + address: string; +}; + +export type ListRestaurantDto = Array; diff --git a/src/application/dtos/response/restaurant.dto.ts b/src/application/dtos/response/restaurant.dto.ts new file mode 100644 index 0000000..5f0f7cc --- /dev/null +++ b/src/application/dtos/response/restaurant.dto.ts @@ -0,0 +1,10 @@ +import type { AddressDto } from "@/application/dtos/shared/address.dto"; +import type { ScheduleDto } from "@/application/dtos/shared/schedule.dto"; + +export type RestaurantDto = { + id: string; + name: string; + picture: string | null; + address: AddressDto; + schedules: Array; +}; diff --git a/src/application/dtos/shared/address.dto.ts b/src/application/dtos/shared/address.dto.ts new file mode 100644 index 0000000..a772d4d --- /dev/null +++ b/src/application/dtos/shared/address.dto.ts @@ -0,0 +1,8 @@ +export type AddressDto = { + street: string; + number: string | null; + state: string; + city: string; + neighborhood: string; + zipcode: string; +}; diff --git a/src/application/dtos/shared/schedule.dto.ts b/src/application/dtos/shared/schedule.dto.ts new file mode 100644 index 0000000..0f2b643 --- /dev/null +++ b/src/application/dtos/shared/schedule.dto.ts @@ -0,0 +1,6 @@ +export type ScheduleDto = { + id: string; + begin: string; + end: string; + day: string; +}; diff --git a/src/application/useCases/create-restaurant.ts b/src/application/useCases/create-restaurant.ts new file mode 100644 index 0000000..bda7108 --- /dev/null +++ b/src/application/useCases/create-restaurant.ts @@ -0,0 +1,33 @@ +import type { CreateRestaurantDto } from "@/application/dtos/request/create-restaurant.dto"; +import type { RestaurantDto } from "@/application/dtos/response/restaurant.dto"; +import type { AddressDto } from "@/application/dtos/shared/address.dto"; +import { Address } from "@/domain/entities/address"; +import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; + +export class CreateRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute(request: CreateRestaurantDto): Promise { + const address = this.parseAddress(request.address); + + return await this.restaurantRepository.create(request.name, address); + } + + private parseAddress({ + street, + number, + neighborhood, + city, + state, + zipcode, + }: AddressDto) { + return Address.builder() + .withStreet(street) + .withNumber(number) + .withNeighborhood(neighborhood) + .withCity(city) + .withState(state) + .withZipcode(zipcode) + .build(); + } +} diff --git a/src/application/useCases/delete-restaurant.ts b/src/application/useCases/delete-restaurant.ts new file mode 100644 index 0000000..3b20b8a --- /dev/null +++ b/src/application/useCases/delete-restaurant.ts @@ -0,0 +1,9 @@ +import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; + +export class DeleteRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute(restaurantId: string) { + await this.restaurantRepository.destroy(restaurantId); + } +} diff --git a/src/application/useCases/get-restaurant.ts b/src/application/useCases/get-restaurant.ts new file mode 100644 index 0000000..6e3bf99 --- /dev/null +++ b/src/application/useCases/get-restaurant.ts @@ -0,0 +1,16 @@ +import type { RestaurantDto } from "@/application/dtos/response/restaurant.dto"; +import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; + +export class GetRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute(restaurantId: string): Promise { + const restaurant = await this.restaurantRepository.get(restaurantId); + + if (!restaurant) { + throw new Error("restaurant not found"); + } + + return restaurant; + } +} diff --git a/src/application/useCases/list-restaurant.ts b/src/application/useCases/list-restaurant.ts new file mode 100644 index 0000000..e106fb3 --- /dev/null +++ b/src/application/useCases/list-restaurant.ts @@ -0,0 +1,17 @@ +import type { ListRestaurantDto } from "@/application/dtos/response/list-restaurant.dto"; +import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; + +export class ListRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute(): Promise { + const resturants = await this.restaurantRepository.list(); + + return resturants.map((resturant) => ({ + id: resturant.id, + name: resturant.name, + picture: resturant.picture, + address: resturant.address.toString(), + })); + } +} diff --git a/src/application/useCases/update-restaurant.ts b/src/application/useCases/update-restaurant.ts new file mode 100644 index 0000000..66f96f6 --- /dev/null +++ b/src/application/useCases/update-restaurant.ts @@ -0,0 +1,22 @@ +import type { UpdateRestaurantDto } from "@/application/dtos/request/update-restaurant.dto"; +import type { RestaurantDto } from "@/application/dtos/response/restaurant.dto"; +import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; + +export class UpdateRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute( + restaurantId: string, + update: UpdateRestaurantDto, + ): Promise { + const restaurant = await this.restaurantRepository.get(restaurantId); + + if (!restaurant) { + throw new Error("resturant not found"); + } + + Object.assign(restaurant, update); + + return await this.restaurantRepository.save(restaurant); + } +} From 3077af0d8fb8a88063cdf3af5fdf72badf11ed4c Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 03:47:44 -0300 Subject: [PATCH 04/20] feat(schedule): create entity and dto --- src/schedule/application/dtos/schedule.dto.ts | 6 +++++ src/schedule/domain/schedule.entity.ts | 24 +++++++++++++++++++ 2 files changed, 30 insertions(+) create mode 100644 src/schedule/application/dtos/schedule.dto.ts create mode 100644 src/schedule/domain/schedule.entity.ts diff --git a/src/schedule/application/dtos/schedule.dto.ts b/src/schedule/application/dtos/schedule.dto.ts new file mode 100644 index 0000000..0f2b643 --- /dev/null +++ b/src/schedule/application/dtos/schedule.dto.ts @@ -0,0 +1,6 @@ +export type ScheduleDto = { + id: string; + begin: string; + end: string; + day: string; +}; diff --git a/src/schedule/domain/schedule.entity.ts b/src/schedule/domain/schedule.entity.ts new file mode 100644 index 0000000..9de5c80 --- /dev/null +++ b/src/schedule/domain/schedule.entity.ts @@ -0,0 +1,24 @@ +export class Schedule { + constructor( + public readonly id: string, + public readonly begin: string, + public readonly end: string, + public readonly day: string, + ) { + if (parseMinutes(end) - parseMinutes(begin) < 15) { + throw new Error("tempo minimo de 15 minutos"); + } + } +} + +function parseMinutes(input: string) { + const regex = /^\d{2}:\d{2}/g; + + if (!regex.test(input)) { + throw new Error(`horario no formato incorreto: ${input}`); + } + + const [hour, minutes] = input.split(":"); + + return Number.parseInt(hour) * 60 + Number.parseInt(minutes); +} From 41dbbe5398d467f93434c6c51fc09308fc24cf02 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 03:49:49 -0300 Subject: [PATCH 05/20] refactor: use modular architecture --- .../dtos/request/create-restaurant.dto.ts | 6 -- .../dtos/request/update-restaurant.dto.ts | 8 --- .../dtos/response/list-restaurant.dto.ts | 7 -- .../dtos/response/restaurant.dto.ts | 10 --- src/application/dtos/shared/address.dto.ts | 8 --- src/application/dtos/shared/schedule.dto.ts | 6 -- src/application/useCases/create-restaurant.ts | 33 --------- src/application/useCases/delete-restaurant.ts | 9 --- src/application/useCases/get-restaurant.ts | 16 ----- src/application/useCases/list-restaurant.ts | 17 ----- src/application/useCases/update-restaurant.ts | 22 ------ src/domain/entities/address.ts | 68 ------------------- src/domain/entities/product.entity.ts | 12 ---- src/domain/entities/promotion.ts | 9 --- src/domain/entities/restaurant.entity.ts | 12 ---- src/domain/entities/schedule.entity.ts | 14 ---- .../repositories/restaurant.repository.ts | 10 --- src/utils/hour.ts | 11 --- 18 files changed, 278 deletions(-) delete mode 100644 src/application/dtos/request/create-restaurant.dto.ts delete mode 100644 src/application/dtos/request/update-restaurant.dto.ts delete mode 100644 src/application/dtos/response/list-restaurant.dto.ts delete mode 100644 src/application/dtos/response/restaurant.dto.ts delete mode 100644 src/application/dtos/shared/address.dto.ts delete mode 100644 src/application/dtos/shared/schedule.dto.ts delete mode 100644 src/application/useCases/create-restaurant.ts delete mode 100644 src/application/useCases/delete-restaurant.ts delete mode 100644 src/application/useCases/get-restaurant.ts delete mode 100644 src/application/useCases/list-restaurant.ts delete mode 100644 src/application/useCases/update-restaurant.ts delete mode 100644 src/domain/entities/address.ts delete mode 100644 src/domain/entities/product.entity.ts delete mode 100644 src/domain/entities/promotion.ts delete mode 100644 src/domain/entities/restaurant.entity.ts delete mode 100644 src/domain/entities/schedule.entity.ts delete mode 100644 src/domain/repositories/restaurant.repository.ts delete mode 100644 src/utils/hour.ts diff --git a/src/application/dtos/request/create-restaurant.dto.ts b/src/application/dtos/request/create-restaurant.dto.ts deleted file mode 100644 index 7a8acf1..0000000 --- a/src/application/dtos/request/create-restaurant.dto.ts +++ /dev/null @@ -1,6 +0,0 @@ -import type { AddressDto } from "@/application/dtos/shared/address.dto"; - -export type CreateRestaurantDto = { - name: string; - address: AddressDto; -}; diff --git a/src/application/dtos/request/update-restaurant.dto.ts b/src/application/dtos/request/update-restaurant.dto.ts deleted file mode 100644 index 500688a..0000000 --- a/src/application/dtos/request/update-restaurant.dto.ts +++ /dev/null @@ -1,8 +0,0 @@ -import type { AddressDto } from "@/application/dtos/shared/address.dto"; -import type { Restaurant } from "@/domain/entities/restaurant.entity"; - -export type UpdateRestaurantDto = Partial< - Omit & { - address: AddressDto; - } ->; diff --git a/src/application/dtos/response/list-restaurant.dto.ts b/src/application/dtos/response/list-restaurant.dto.ts deleted file mode 100644 index 3870dd3..0000000 --- a/src/application/dtos/response/list-restaurant.dto.ts +++ /dev/null @@ -1,7 +0,0 @@ -import type { RestaurantDto } from "@/application/dtos/response/restaurant.dto"; - -type RestaurantItem = Omit & { - address: string; -}; - -export type ListRestaurantDto = Array; diff --git a/src/application/dtos/response/restaurant.dto.ts b/src/application/dtos/response/restaurant.dto.ts deleted file mode 100644 index 5f0f7cc..0000000 --- a/src/application/dtos/response/restaurant.dto.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { AddressDto } from "@/application/dtos/shared/address.dto"; -import type { ScheduleDto } from "@/application/dtos/shared/schedule.dto"; - -export type RestaurantDto = { - id: string; - name: string; - picture: string | null; - address: AddressDto; - schedules: Array; -}; diff --git a/src/application/dtos/shared/address.dto.ts b/src/application/dtos/shared/address.dto.ts deleted file mode 100644 index a772d4d..0000000 --- a/src/application/dtos/shared/address.dto.ts +++ /dev/null @@ -1,8 +0,0 @@ -export type AddressDto = { - street: string; - number: string | null; - state: string; - city: string; - neighborhood: string; - zipcode: string; -}; diff --git a/src/application/dtos/shared/schedule.dto.ts b/src/application/dtos/shared/schedule.dto.ts deleted file mode 100644 index 0f2b643..0000000 --- a/src/application/dtos/shared/schedule.dto.ts +++ /dev/null @@ -1,6 +0,0 @@ -export type ScheduleDto = { - id: string; - begin: string; - end: string; - day: string; -}; diff --git a/src/application/useCases/create-restaurant.ts b/src/application/useCases/create-restaurant.ts deleted file mode 100644 index bda7108..0000000 --- a/src/application/useCases/create-restaurant.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { CreateRestaurantDto } from "@/application/dtos/request/create-restaurant.dto"; -import type { RestaurantDto } from "@/application/dtos/response/restaurant.dto"; -import type { AddressDto } from "@/application/dtos/shared/address.dto"; -import { Address } from "@/domain/entities/address"; -import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; - -export class CreateRestaurantUseCase { - constructor(private readonly restaurantRepository: RestaurantRepository) {} - - async execute(request: CreateRestaurantDto): Promise { - const address = this.parseAddress(request.address); - - return await this.restaurantRepository.create(request.name, address); - } - - private parseAddress({ - street, - number, - neighborhood, - city, - state, - zipcode, - }: AddressDto) { - return Address.builder() - .withStreet(street) - .withNumber(number) - .withNeighborhood(neighborhood) - .withCity(city) - .withState(state) - .withZipcode(zipcode) - .build(); - } -} diff --git a/src/application/useCases/delete-restaurant.ts b/src/application/useCases/delete-restaurant.ts deleted file mode 100644 index 3b20b8a..0000000 --- a/src/application/useCases/delete-restaurant.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; - -export class DeleteRestaurantUseCase { - constructor(private readonly restaurantRepository: RestaurantRepository) {} - - async execute(restaurantId: string) { - await this.restaurantRepository.destroy(restaurantId); - } -} diff --git a/src/application/useCases/get-restaurant.ts b/src/application/useCases/get-restaurant.ts deleted file mode 100644 index 6e3bf99..0000000 --- a/src/application/useCases/get-restaurant.ts +++ /dev/null @@ -1,16 +0,0 @@ -import type { RestaurantDto } from "@/application/dtos/response/restaurant.dto"; -import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; - -export class GetRestaurantUseCase { - constructor(private readonly restaurantRepository: RestaurantRepository) {} - - async execute(restaurantId: string): Promise { - const restaurant = await this.restaurantRepository.get(restaurantId); - - if (!restaurant) { - throw new Error("restaurant not found"); - } - - return restaurant; - } -} diff --git a/src/application/useCases/list-restaurant.ts b/src/application/useCases/list-restaurant.ts deleted file mode 100644 index e106fb3..0000000 --- a/src/application/useCases/list-restaurant.ts +++ /dev/null @@ -1,17 +0,0 @@ -import type { ListRestaurantDto } from "@/application/dtos/response/list-restaurant.dto"; -import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; - -export class ListRestaurantUseCase { - constructor(private readonly restaurantRepository: RestaurantRepository) {} - - async execute(): Promise { - const resturants = await this.restaurantRepository.list(); - - return resturants.map((resturant) => ({ - id: resturant.id, - name: resturant.name, - picture: resturant.picture, - address: resturant.address.toString(), - })); - } -} diff --git a/src/application/useCases/update-restaurant.ts b/src/application/useCases/update-restaurant.ts deleted file mode 100644 index 66f96f6..0000000 --- a/src/application/useCases/update-restaurant.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { UpdateRestaurantDto } from "@/application/dtos/request/update-restaurant.dto"; -import type { RestaurantDto } from "@/application/dtos/response/restaurant.dto"; -import type { RestaurantRepository } from "@/domain/repositories/restaurant.repository"; - -export class UpdateRestaurantUseCase { - constructor(private readonly restaurantRepository: RestaurantRepository) {} - - async execute( - restaurantId: string, - update: UpdateRestaurantDto, - ): Promise { - const restaurant = await this.restaurantRepository.get(restaurantId); - - if (!restaurant) { - throw new Error("resturant not found"); - } - - Object.assign(restaurant, update); - - return await this.restaurantRepository.save(restaurant); - } -} diff --git a/src/domain/entities/address.ts b/src/domain/entities/address.ts deleted file mode 100644 index 5973e18..0000000 --- a/src/domain/entities/address.ts +++ /dev/null @@ -1,68 +0,0 @@ -export class Address { - constructor( - public readonly street: string, - public readonly number: string | null, - public readonly state: string, - public readonly city: string, - public readonly neighborhood: string, - public readonly zipcode: string, - ) {} - - static builder() { - return new AddressBuilder(); - } - - toString() { - return `${this.street}, ${this.number ?? "SN"} - ${this.neighborhood}, ${this.city} - ${this.state}, ${this.zipcode}`; - } -} - -class AddressBuilder { - private street!: string; - private number!: string | null; - private state!: string; - private city!: string; - private neighborhood!: string; - private zipcode!: string; - - withStreet(street: string) { - this.street = street; - return this; - } - - withNumber(number: string | null) { - this.number = number; - return this; - } - - withState(state: string) { - this.state = state; - return this; - } - - withCity(city: string) { - this.city = city; - return this; - } - - withNeighborhood(neighborhood: string) { - this.neighborhood = neighborhood; - return this; - } - - withZipcode(zipcode: string) { - this.zipcode = zipcode; - return this; - } - - build() { - return new Address( - this.street, - this.number, - this.state, - this.city, - this.neighborhood, - this.zipcode, - ); - } -} diff --git a/src/domain/entities/product.entity.ts b/src/domain/entities/product.entity.ts deleted file mode 100644 index c53e4d8..0000000 --- a/src/domain/entities/product.entity.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Promotion } from "@/domain/entities/promotion"; - -export class Product { - constructor( - public readonly id: string, - public readonly name: string, - public readonly category: string, - public readonly picture: string, - public readonly price: number, - public readonly promotion: Promotion, - ) {} -} diff --git a/src/domain/entities/promotion.ts b/src/domain/entities/promotion.ts deleted file mode 100644 index 8a48c5a..0000000 --- a/src/domain/entities/promotion.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { Schedule } from "@/domain/entities/schedule.entity"; - -export class Promotion { - constructor( - public readonly describe: string, - public readonly price: number, - public readonly schedules: Array, - ) {} -} diff --git a/src/domain/entities/restaurant.entity.ts b/src/domain/entities/restaurant.entity.ts deleted file mode 100644 index 4b13a0e..0000000 --- a/src/domain/entities/restaurant.entity.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Address } from "@/domain/entities/address"; -import type { Schedule } from "@/domain/entities/schedule.entity"; - -export class Restaurant { - constructor( - public readonly id: string, - public readonly name: string, - public readonly picture: string, - public readonly address: Address, - public readonly schedules: Array, - ) {} -} diff --git a/src/domain/entities/schedule.entity.ts b/src/domain/entities/schedule.entity.ts deleted file mode 100644 index ba5ff7e..0000000 --- a/src/domain/entities/schedule.entity.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { parserToMinutes } from "@/utils/hour"; - -export class Schedule { - constructor( - public readonly id: string, - public readonly begin: string, - public readonly end: string, - public readonly day: string, - ) { - if (parserToMinutes(end) - parserToMinutes(begin) < 15) { - throw new Error("tempo minimo de 15 minutos"); - } - } -} diff --git a/src/domain/repositories/restaurant.repository.ts b/src/domain/repositories/restaurant.repository.ts deleted file mode 100644 index 48cc348..0000000 --- a/src/domain/repositories/restaurant.repository.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { Address } from "@/domain/entities/address"; -import type { Restaurant } from "@/domain/entities/restaurant.entity"; - -export interface RestaurantRepository { - save(resturant: Restaurant): Promise; - create(name: string, address: Address): Promise; - list(): Promise; - get(id: string): Promise; - destroy(id: string): Promise; -} diff --git a/src/utils/hour.ts b/src/utils/hour.ts deleted file mode 100644 index b06c236..0000000 --- a/src/utils/hour.ts +++ /dev/null @@ -1,11 +0,0 @@ -export function parserToMinutes(input: string) { - const regex = /^\d{2}:\d{2}/g; - - if (!regex.test(input)) { - throw new Error(`horario no formato incorreto: ${input}`); - } - - const [hour, minutes] = input.split(":"); - - return Number.parseInt(hour) * 60 + Number.parseInt(minutes); -} From e6d313cba10ad7fa187e52aab59dcc81c4239a0f Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 03:51:12 -0300 Subject: [PATCH 06/20] feat(restaurant): domain --- src/restaurant/domain/address.ts | 68 +++++++++++++++++++ src/restaurant/domain/restaurant.entity.ts | 12 ++++ .../domain/restaurant.repository.ts | 10 +++ 3 files changed, 90 insertions(+) create mode 100644 src/restaurant/domain/address.ts create mode 100644 src/restaurant/domain/restaurant.entity.ts create mode 100644 src/restaurant/domain/restaurant.repository.ts diff --git a/src/restaurant/domain/address.ts b/src/restaurant/domain/address.ts new file mode 100644 index 0000000..5973e18 --- /dev/null +++ b/src/restaurant/domain/address.ts @@ -0,0 +1,68 @@ +export class Address { + constructor( + public readonly street: string, + public readonly number: string | null, + public readonly state: string, + public readonly city: string, + public readonly neighborhood: string, + public readonly zipcode: string, + ) {} + + static builder() { + return new AddressBuilder(); + } + + toString() { + return `${this.street}, ${this.number ?? "SN"} - ${this.neighborhood}, ${this.city} - ${this.state}, ${this.zipcode}`; + } +} + +class AddressBuilder { + private street!: string; + private number!: string | null; + private state!: string; + private city!: string; + private neighborhood!: string; + private zipcode!: string; + + withStreet(street: string) { + this.street = street; + return this; + } + + withNumber(number: string | null) { + this.number = number; + return this; + } + + withState(state: string) { + this.state = state; + return this; + } + + withCity(city: string) { + this.city = city; + return this; + } + + withNeighborhood(neighborhood: string) { + this.neighborhood = neighborhood; + return this; + } + + withZipcode(zipcode: string) { + this.zipcode = zipcode; + return this; + } + + build() { + return new Address( + this.street, + this.number, + this.state, + this.city, + this.neighborhood, + this.zipcode, + ); + } +} diff --git a/src/restaurant/domain/restaurant.entity.ts b/src/restaurant/domain/restaurant.entity.ts new file mode 100644 index 0000000..5a76d19 --- /dev/null +++ b/src/restaurant/domain/restaurant.entity.ts @@ -0,0 +1,12 @@ +import type { Address } from "@/restaurant/domain/address"; +import type { Schedule } from "@/schedule/domain/schedule.entity"; + +export class Restaurant { + constructor( + public readonly id: string, + public readonly name: string, + public readonly picture: string, + public readonly address: Address, + public readonly schedules: Array, + ) {} +} diff --git a/src/restaurant/domain/restaurant.repository.ts b/src/restaurant/domain/restaurant.repository.ts new file mode 100644 index 0000000..2ac7600 --- /dev/null +++ b/src/restaurant/domain/restaurant.repository.ts @@ -0,0 +1,10 @@ +import type { Address } from "@/restaurant/domain/address"; +import type { Restaurant } from "@/restaurant/domain/restaurant.entity"; + +export interface RestaurantRepository { + save(resturant: Restaurant): Promise; + create(name: string, address: Address): Promise; + list(): Promise; + get(id: string): Promise; + destroy(id: string): Promise; +} From df9f911f40454f97274abbe51f132c7eae1cea2c Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 03:51:53 -0300 Subject: [PATCH 07/20] feat(restaurant): create use cases and dtos --- .../application/dtos/address.dto.ts | 8 +++++ .../application/dtos/create-restaurant.dto.ts | 6 ++++ .../application/dtos/list-restaurant.dto.ts | 7 ++++ .../application/dtos/restaurant.dto.ts | 10 ++++++ .../application/dtos/update-restaurant.dto.ts | 8 +++++ .../application/useCases/create-restaurant.ts | 35 +++++++++++++++++++ .../application/useCases/delete-restaurant.ts | 9 +++++ .../application/useCases/get-restaurant.ts | 16 +++++++++ .../application/useCases/list-restaurant.ts | 17 +++++++++ .../application/useCases/update-restaurant.ts | 22 ++++++++++++ 10 files changed, 138 insertions(+) create mode 100644 src/restaurant/application/dtos/address.dto.ts create mode 100644 src/restaurant/application/dtos/create-restaurant.dto.ts create mode 100644 src/restaurant/application/dtos/list-restaurant.dto.ts create mode 100644 src/restaurant/application/dtos/restaurant.dto.ts create mode 100644 src/restaurant/application/dtos/update-restaurant.dto.ts create mode 100644 src/restaurant/application/useCases/create-restaurant.ts create mode 100644 src/restaurant/application/useCases/delete-restaurant.ts create mode 100644 src/restaurant/application/useCases/get-restaurant.ts create mode 100644 src/restaurant/application/useCases/list-restaurant.ts create mode 100644 src/restaurant/application/useCases/update-restaurant.ts diff --git a/src/restaurant/application/dtos/address.dto.ts b/src/restaurant/application/dtos/address.dto.ts new file mode 100644 index 0000000..a772d4d --- /dev/null +++ b/src/restaurant/application/dtos/address.dto.ts @@ -0,0 +1,8 @@ +export type AddressDto = { + street: string; + number: string | null; + state: string; + city: string; + neighborhood: string; + zipcode: string; +}; diff --git a/src/restaurant/application/dtos/create-restaurant.dto.ts b/src/restaurant/application/dtos/create-restaurant.dto.ts new file mode 100644 index 0000000..855209d --- /dev/null +++ b/src/restaurant/application/dtos/create-restaurant.dto.ts @@ -0,0 +1,6 @@ +import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; + +export type CreateRestaurantRequestDto = { + name: string; + address: AddressDto; +}; diff --git a/src/restaurant/application/dtos/list-restaurant.dto.ts b/src/restaurant/application/dtos/list-restaurant.dto.ts new file mode 100644 index 0000000..1a20c3e --- /dev/null +++ b/src/restaurant/application/dtos/list-restaurant.dto.ts @@ -0,0 +1,7 @@ +import type { RestaurantResponseDto } from "@/restaurant/application/dtos/restaurant.dto"; + +type RestaurantItem = Omit & { + address: string; +}; + +export type ListRestaurantResponseDto = Array; diff --git a/src/restaurant/application/dtos/restaurant.dto.ts b/src/restaurant/application/dtos/restaurant.dto.ts new file mode 100644 index 0000000..68e3c48 --- /dev/null +++ b/src/restaurant/application/dtos/restaurant.dto.ts @@ -0,0 +1,10 @@ +import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; +import type { ScheduleDto } from "@/schedule/application/dtos/schedule.dto"; + +export type RestaurantResponseDto = { + id: string; + name: string; + picture: string | null; + address: AddressDto; + schedules: Array; +}; diff --git a/src/restaurant/application/dtos/update-restaurant.dto.ts b/src/restaurant/application/dtos/update-restaurant.dto.ts new file mode 100644 index 0000000..36df2d6 --- /dev/null +++ b/src/restaurant/application/dtos/update-restaurant.dto.ts @@ -0,0 +1,8 @@ +import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; +import type { Restaurant } from "@/restaurant/domain/restaurant.entity"; + +export type UpdateRestaurantRequestDto = Partial< + Omit & { + address: AddressDto; + } +>; diff --git a/src/restaurant/application/useCases/create-restaurant.ts b/src/restaurant/application/useCases/create-restaurant.ts new file mode 100644 index 0000000..c555913 --- /dev/null +++ b/src/restaurant/application/useCases/create-restaurant.ts @@ -0,0 +1,35 @@ +import type { CreateRestaurantRequestDto } from "@/restaurant/application/dtos/create-restaurant.dto"; +import type { RestaurantResponseDto } from "@/restaurant/application/dtos/restaurant.dto"; +import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; +import { Address } from "@/restaurant/domain/address"; +import type { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; + +export class CreateRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute( + request: CreateRestaurantRequestDto, + ): Promise { + const address = this.parseAddress(request.address); + + return await this.restaurantRepository.create(request.name, address); + } + + private parseAddress({ + street, + number, + neighborhood, + city, + state, + zipcode, + }: AddressDto) { + return Address.builder() + .withStreet(street) + .withNumber(number) + .withNeighborhood(neighborhood) + .withCity(city) + .withState(state) + .withZipcode(zipcode) + .build(); + } +} diff --git a/src/restaurant/application/useCases/delete-restaurant.ts b/src/restaurant/application/useCases/delete-restaurant.ts new file mode 100644 index 0000000..3047fb8 --- /dev/null +++ b/src/restaurant/application/useCases/delete-restaurant.ts @@ -0,0 +1,9 @@ +import type { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; + +export class DeleteRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute(restaurantId: string) { + await this.restaurantRepository.destroy(restaurantId); + } +} diff --git a/src/restaurant/application/useCases/get-restaurant.ts b/src/restaurant/application/useCases/get-restaurant.ts new file mode 100644 index 0000000..247592b --- /dev/null +++ b/src/restaurant/application/useCases/get-restaurant.ts @@ -0,0 +1,16 @@ +import type { RestaurantResponseDto } from "@/restaurant/application/dtos/restaurant.dto"; +import type { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; + +export class GetRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute(restaurantId: string): Promise { + const restaurant = await this.restaurantRepository.get(restaurantId); + + if (!restaurant) { + throw new Error("restaurant not found"); + } + + return restaurant; + } +} diff --git a/src/restaurant/application/useCases/list-restaurant.ts b/src/restaurant/application/useCases/list-restaurant.ts new file mode 100644 index 0000000..ed24188 --- /dev/null +++ b/src/restaurant/application/useCases/list-restaurant.ts @@ -0,0 +1,17 @@ +import type { ListRestaurantResponseDto } from "@/restaurant/application/dtos/list-restaurant.dto"; +import type { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; + +export class ListRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute(): Promise { + const resturants = await this.restaurantRepository.list(); + + return resturants.map((resturant) => ({ + id: resturant.id, + name: resturant.name, + picture: resturant.picture, + address: resturant.address.toString(), + })); + } +} diff --git a/src/restaurant/application/useCases/update-restaurant.ts b/src/restaurant/application/useCases/update-restaurant.ts new file mode 100644 index 0000000..811d1f0 --- /dev/null +++ b/src/restaurant/application/useCases/update-restaurant.ts @@ -0,0 +1,22 @@ +import type { UpdateRestaurantRequestDto } from "@/restaurant/application/dtos/update-restaurant.dto"; +import type { RestaurantResponseDto } from "@/restaurant/application/dtos/restaurant.dto"; +import type { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; + +export class UpdateRestaurantUseCase { + constructor(private readonly restaurantRepository: RestaurantRepository) {} + + async execute( + restaurantId: string, + update: UpdateRestaurantRequestDto, + ): Promise { + const restaurant = await this.restaurantRepository.get(restaurantId); + + if (!restaurant) { + throw new Error("resturant not found"); + } + + Object.assign(restaurant, update); + + return await this.restaurantRepository.save(restaurant); + } +} From 3103c19021cb821a3956b70ab84a90972ad755b1 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 03:52:45 -0300 Subject: [PATCH 08/20] feat(product): create entity --- src/product/domain/product.entity.ts | 12 ++++++++++++ src/product/domain/promotion.ts | 9 +++++++++ 2 files changed, 21 insertions(+) create mode 100644 src/product/domain/product.entity.ts create mode 100644 src/product/domain/promotion.ts diff --git a/src/product/domain/product.entity.ts b/src/product/domain/product.entity.ts new file mode 100644 index 0000000..1d57003 --- /dev/null +++ b/src/product/domain/product.entity.ts @@ -0,0 +1,12 @@ +import type { Promotion } from "@/product/domain/promotion"; + +export class Product { + constructor( + public readonly id: string, + public readonly name: string, + public readonly category: string, + public readonly picture: string, + public readonly price: number, + public readonly promotion: Promotion, + ) {} +} diff --git a/src/product/domain/promotion.ts b/src/product/domain/promotion.ts new file mode 100644 index 0000000..f36dbaa --- /dev/null +++ b/src/product/domain/promotion.ts @@ -0,0 +1,9 @@ +import type { Schedule } from "@/schedule/domain/schedule.entity"; + +export class Promotion { + constructor( + public readonly describe: string, + public readonly price: number, + public readonly schedules: Array, + ) {} +} From 83fd88bbf9b3f8f8ccae254cdd90e9e28b5dd9d2 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 04:45:15 -0300 Subject: [PATCH 09/20] feat(schedule): scheduleRestaurantRepository --- src/schedule/domain/schedule.repository.ts | 6 ++++++ .../domain/scheduleRestaurant.repository.ts | 16 ++++++++++++++++ 2 files changed, 22 insertions(+) create mode 100644 src/schedule/domain/schedule.repository.ts create mode 100644 src/schedule/domain/scheduleRestaurant.repository.ts diff --git a/src/schedule/domain/schedule.repository.ts b/src/schedule/domain/schedule.repository.ts new file mode 100644 index 0000000..5285d0d --- /dev/null +++ b/src/schedule/domain/schedule.repository.ts @@ -0,0 +1,6 @@ +import type { Schedule } from "@/schedule/domain/schedule.entity"; + +export interface ScheduleRepository { + save(schedule: Schedule): Promise; + destroy(scheduleId: string): Promise; +} diff --git a/src/schedule/domain/scheduleRestaurant.repository.ts b/src/schedule/domain/scheduleRestaurant.repository.ts new file mode 100644 index 0000000..03ab666 --- /dev/null +++ b/src/schedule/domain/scheduleRestaurant.repository.ts @@ -0,0 +1,16 @@ +import type { Schedule } from "@/schedule/domain/schedule.entity"; +import type { ScheduleRepository } from "@/schedule/domain/schedule.repository"; + +export interface ScheduleRestaurantRepository extends ScheduleRepository { + create( + restaurantId: string, + begin: string, + end: string, + day: string, + ): Promise; + createBach( + restaurantId: string, + schedules: Omit[], + ): Promise; + listByRestaurantId(restaurantId: string): Promise; +} From 794b13f8757178b9bb4c89e65c2ccd5b077c609a Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 04:48:52 -0300 Subject: [PATCH 10/20] refactor(restaurant): decouple restaurant and schedule --- .../application/dtos/create-restaurant.dto.ts | 2 ++ .../application/useCases/create-restaurant.ts | 22 ++++++++++++++----- .../application/useCases/get-restaurant.ts | 14 ++++++++++-- src/restaurant/domain/restaurant.entity.ts | 2 -- 4 files changed, 31 insertions(+), 9 deletions(-) diff --git a/src/restaurant/application/dtos/create-restaurant.dto.ts b/src/restaurant/application/dtos/create-restaurant.dto.ts index 855209d..0922508 100644 --- a/src/restaurant/application/dtos/create-restaurant.dto.ts +++ b/src/restaurant/application/dtos/create-restaurant.dto.ts @@ -1,6 +1,8 @@ import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; +import type { ScheduleDto } from "@/schedule/application/dtos/schedule.dto"; export type CreateRestaurantRequestDto = { name: string; address: AddressDto; + schedules: Omit[]; }; diff --git a/src/restaurant/application/useCases/create-restaurant.ts b/src/restaurant/application/useCases/create-restaurant.ts index c555913..511e8cb 100644 --- a/src/restaurant/application/useCases/create-restaurant.ts +++ b/src/restaurant/application/useCases/create-restaurant.ts @@ -1,18 +1,30 @@ +import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; import type { CreateRestaurantRequestDto } from "@/restaurant/application/dtos/create-restaurant.dto"; import type { RestaurantResponseDto } from "@/restaurant/application/dtos/restaurant.dto"; -import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; import { Address } from "@/restaurant/domain/address"; import type { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; +import type { ScheduleRestaurantRepository } from "@/schedule/domain/scheduleRestaurant.repository"; export class CreateRestaurantUseCase { - constructor(private readonly restaurantRepository: RestaurantRepository) {} + constructor( + private readonly restaurantRepository: RestaurantRepository, + private readonly scheduleRepository: ScheduleRestaurantRepository, + ) {} async execute( - request: CreateRestaurantRequestDto, + dto: CreateRestaurantRequestDto, ): Promise { - const address = this.parseAddress(request.address); + const address = this.parseAddress(dto.address); + const resturant = await this.restaurantRepository.create(dto.name, address); + const schedules = await this.scheduleRepository.createBach( + resturant.id, + dto.schedules, + ); - return await this.restaurantRepository.create(request.name, address); + return { + ...resturant, + schedules, + }; } private parseAddress({ diff --git a/src/restaurant/application/useCases/get-restaurant.ts b/src/restaurant/application/useCases/get-restaurant.ts index 247592b..934eed7 100644 --- a/src/restaurant/application/useCases/get-restaurant.ts +++ b/src/restaurant/application/useCases/get-restaurant.ts @@ -1,8 +1,12 @@ import type { RestaurantResponseDto } from "@/restaurant/application/dtos/restaurant.dto"; import type { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; +import type { ScheduleRestaurantRepository } from "@/schedule/domain/scheduleRestaurant.repository"; export class GetRestaurantUseCase { - constructor(private readonly restaurantRepository: RestaurantRepository) {} + constructor( + private readonly restaurantRepository: RestaurantRepository, + private readonly scheduleRepository: ScheduleRestaurantRepository, + ) {} async execute(restaurantId: string): Promise { const restaurant = await this.restaurantRepository.get(restaurantId); @@ -11,6 +15,12 @@ export class GetRestaurantUseCase { throw new Error("restaurant not found"); } - return restaurant; + const schedules = + await this.scheduleRepository.listByRestaurantId(restaurantId); + + return { + ...restaurant, + schedules, + }; } } diff --git a/src/restaurant/domain/restaurant.entity.ts b/src/restaurant/domain/restaurant.entity.ts index 5a76d19..2926600 100644 --- a/src/restaurant/domain/restaurant.entity.ts +++ b/src/restaurant/domain/restaurant.entity.ts @@ -1,5 +1,4 @@ import type { Address } from "@/restaurant/domain/address"; -import type { Schedule } from "@/schedule/domain/schedule.entity"; export class Restaurant { constructor( @@ -7,6 +6,5 @@ export class Restaurant { public readonly name: string, public readonly picture: string, public readonly address: Address, - public readonly schedules: Array, ) {} } From 356731a86009843b1953b927ce6c385edb81b272 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 04:57:45 -0300 Subject: [PATCH 11/20] fix(restaurant-update): fetch schedules --- .../application/dtos/update-restaurant.dto.ts | 2 +- .../application/useCases/list-restaurant.ts | 10 +++++----- .../application/useCases/update-restaurant.ts | 18 +++++++++++++++--- src/restaurant/domain/restaurant.repository.ts | 2 +- 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/src/restaurant/application/dtos/update-restaurant.dto.ts b/src/restaurant/application/dtos/update-restaurant.dto.ts index 36df2d6..2a8e020 100644 --- a/src/restaurant/application/dtos/update-restaurant.dto.ts +++ b/src/restaurant/application/dtos/update-restaurant.dto.ts @@ -2,7 +2,7 @@ import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; import type { Restaurant } from "@/restaurant/domain/restaurant.entity"; export type UpdateRestaurantRequestDto = Partial< - Omit & { + Omit & { address: AddressDto; } >; diff --git a/src/restaurant/application/useCases/list-restaurant.ts b/src/restaurant/application/useCases/list-restaurant.ts index ed24188..ed4ae00 100644 --- a/src/restaurant/application/useCases/list-restaurant.ts +++ b/src/restaurant/application/useCases/list-restaurant.ts @@ -7,11 +7,11 @@ export class ListRestaurantUseCase { async execute(): Promise { const resturants = await this.restaurantRepository.list(); - return resturants.map((resturant) => ({ - id: resturant.id, - name: resturant.name, - picture: resturant.picture, - address: resturant.address.toString(), + return resturants.map(({ id, name, picture, address }) => ({ + id, + name, + picture, + address: address.toString(), })); } } diff --git a/src/restaurant/application/useCases/update-restaurant.ts b/src/restaurant/application/useCases/update-restaurant.ts index 811d1f0..65a363a 100644 --- a/src/restaurant/application/useCases/update-restaurant.ts +++ b/src/restaurant/application/useCases/update-restaurant.ts @@ -1,9 +1,13 @@ -import type { UpdateRestaurantRequestDto } from "@/restaurant/application/dtos/update-restaurant.dto"; import type { RestaurantResponseDto } from "@/restaurant/application/dtos/restaurant.dto"; +import type { UpdateRestaurantRequestDto } from "@/restaurant/application/dtos/update-restaurant.dto"; import type { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; +import type { ScheduleRestaurantRepository } from "@/schedule/domain/scheduleRestaurant.repository"; export class UpdateRestaurantUseCase { - constructor(private readonly restaurantRepository: RestaurantRepository) {} + constructor( + private readonly restaurantRepository: RestaurantRepository, + private readonly scheduleRepository: ScheduleRestaurantRepository, + ) {} async execute( restaurantId: string, @@ -17,6 +21,14 @@ export class UpdateRestaurantUseCase { Object.assign(restaurant, update); - return await this.restaurantRepository.save(restaurant); + await this.restaurantRepository.save(restaurant); + + const schedules = + await this.scheduleRepository.listByRestaurantId(restaurantId); + + return { + ...restaurant, + schedules, + }; } } diff --git a/src/restaurant/domain/restaurant.repository.ts b/src/restaurant/domain/restaurant.repository.ts index 2ac7600..d494966 100644 --- a/src/restaurant/domain/restaurant.repository.ts +++ b/src/restaurant/domain/restaurant.repository.ts @@ -2,8 +2,8 @@ import type { Address } from "@/restaurant/domain/address"; import type { Restaurant } from "@/restaurant/domain/restaurant.entity"; export interface RestaurantRepository { - save(resturant: Restaurant): Promise; create(name: string, address: Address): Promise; + save(resturant: Restaurant): Promise; list(): Promise; get(id: string): Promise; destroy(id: string): Promise; From 013f091cc6f31e971c62ab83c5e30693c407a2ac Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 05:10:01 -0300 Subject: [PATCH 12/20] chore: move schedule tests --- tests/{entities => schedule/domain}/schedule.test.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) rename tests/{entities => schedule/domain}/schedule.test.ts (64%) diff --git a/tests/entities/schedule.test.ts b/tests/schedule/domain/schedule.test.ts similarity index 64% rename from tests/entities/schedule.test.ts rename to tests/schedule/domain/schedule.test.ts index 2a9f755..3890860 100644 --- a/tests/entities/schedule.test.ts +++ b/tests/schedule/domain/schedule.test.ts @@ -1,21 +1,20 @@ -import { Schedule } from "@/domain/entities/schedule.entity"; -import { parserToMinutes } from "@/utils/hour"; +import { parseMinutes, Schedule } from "@/schedule/domain/schedule.entity"; describe("parsing input schedule hour to minutes", () => { test("when valid input then ok", () => { const expected = 90; const input = "01:30"; - const result = parserToMinutes(input); + const result = parseMinutes(input); expect(result).toBe(expected); }); test("when invalid input then throw error", () => { - const inputs = ["1:30", "001:30", "01:0", "001:330", "0130"]; + const inputs = ["1:30", "001:30", "01:0", "001:330", "0130", "12:377"]; for (const input of inputs) { - expect(() => parserToMinutes(input)).toThrow(); + expect(() => parseMinutes(input)).toThrow(); } }); }); @@ -26,7 +25,7 @@ describe("entity Schedule", () => { expect(result).toBeInstanceOf(Schedule); }); - test("when valid input then ok", () => { + test("when short interval then throw error", () => { expect(() => new Schedule("0", "12:15", "12:00", "sat")).toThrow(); }); }); From 466af82f5f0db05c079a479510f513ca8be3d21c Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Thu, 9 Jan 2025 05:11:02 -0300 Subject: [PATCH 13/20] fix(schedule|domain): fix parsing toMinutes --- src/schedule/domain/schedule.entity.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/schedule/domain/schedule.entity.ts b/src/schedule/domain/schedule.entity.ts index 9de5c80..7d960c0 100644 --- a/src/schedule/domain/schedule.entity.ts +++ b/src/schedule/domain/schedule.entity.ts @@ -11,8 +11,8 @@ export class Schedule { } } -function parseMinutes(input: string) { - const regex = /^\d{2}:\d{2}/g; +export function parseMinutes(input: string) { + const regex = /^\d{2}:\d{2}$/g; if (!regex.test(input)) { throw new Error(`horario no formato incorreto: ${input}`); From 4894538a713c17fdacc52f7e5d208fec06ea883f Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Fri, 10 Jan 2025 18:07:57 -0300 Subject: [PATCH 14/20] test(restaurant): create restaurant tests --- tests/helpers/restaurant-helper.ts | 45 +++++++++++++ tests/helpers/schedule-helper.ts | 25 ++++++++ tests/mocks/restaurant-repository.ts | 15 +++++ tests/mocks/schedule-repository.ts | 31 +++++++++ .../application/create-restaurant.test.ts | 64 +++++++++++++++++++ 5 files changed, 180 insertions(+) create mode 100644 tests/helpers/restaurant-helper.ts create mode 100644 tests/helpers/schedule-helper.ts create mode 100644 tests/mocks/restaurant-repository.ts create mode 100644 tests/mocks/schedule-repository.ts create mode 100644 tests/restaurant/application/create-restaurant.test.ts diff --git a/tests/helpers/restaurant-helper.ts b/tests/helpers/restaurant-helper.ts new file mode 100644 index 0000000..9567539 --- /dev/null +++ b/tests/helpers/restaurant-helper.ts @@ -0,0 +1,45 @@ +import { CreateRestaurantRequestDto } from "@/restaurant/application/dtos/create-restaurant.dto"; +import { Address } from "@/restaurant/domain/address"; +import { Restaurant } from "@/restaurant/domain/restaurant.entity"; + +export function makeRestaurant(data: { + id?: string; + picture?: string | null; + name: string; + address: Address; +}) { + const { city, neighborhood, number, state, street, zipcode } = data.address; + const { id, picture, name } = data; + + const address = Address.builder() + .withStreet(street) + .withCity(city) + .withNumber(number) + .withNeighborhood(neighborhood) + .withState(state) + .withZipcode(zipcode) + .build(); + + return new Restaurant(id ?? "1", name, picture ?? null, address); +} + +export function makeCreateRestaurantDto( + input?: Partial, +): CreateRestaurantRequestDto { + const dto = { + name: "rango brabo", + schedules: [], + address: { + city: "Rio de Janeiro", + street: "rua da luz", + number: null, + state: "RJ", + neighborhood: "centro", + zipcode: "000001", + }, + }; + + Object.assign(dto, input); + + return dto; +} diff --git a/tests/helpers/schedule-helper.ts b/tests/helpers/schedule-helper.ts new file mode 100644 index 0000000..feec1d3 --- /dev/null +++ b/tests/helpers/schedule-helper.ts @@ -0,0 +1,25 @@ +import { CreateScheduleDto } from "@/schedule/application/dtos/create-schedule.dto"; +import { ScheduleDto } from "@/schedule/application/dtos/schedule.dto"; +import { Schedule } from "@/schedule/domain/schedule.entity"; + +export function makeSchedule({ + id, + begin, + end, + day, +}: { id?: string; begin: string; end: string; day: string }) { + return new Schedule(id ?? "1", begin, end, day); +} + +export function makeCreateScheduleDto( + input?: Partial, +): CreateScheduleDto { + const dto = { + begin: "12:00", + end: "20:00", + day: "SAT", + }; + + Object.assign(dto, input); + return dto; +} diff --git a/tests/mocks/restaurant-repository.ts b/tests/mocks/restaurant-repository.ts new file mode 100644 index 0000000..819cfab --- /dev/null +++ b/tests/mocks/restaurant-repository.ts @@ -0,0 +1,15 @@ +import { RestaurantRepository } from "@/restaurant/domain/restaurant.repository"; +import { makeRestaurant } from "tests/helpers/restaurant-helper"; + +export const mockRestaurantRepository: jest.Mocked = { + create: jest.fn(), + destroy: jest.fn(), + get: jest.fn(), + list: jest.fn(), + save: jest.fn(), +}; + +mockRestaurantRepository.create.mockImplementation(async (name, address) => { + const id = mockRestaurantRepository.create.mock.calls.length.toString(); + return makeRestaurant({ id, name, address }); +}); diff --git a/tests/mocks/schedule-repository.ts b/tests/mocks/schedule-repository.ts new file mode 100644 index 0000000..d162d65 --- /dev/null +++ b/tests/mocks/schedule-repository.ts @@ -0,0 +1,31 @@ +import { Schedule } from "@/schedule/domain/schedule.entity"; +import { ScheduleRestaurantRepository } from "@/schedule/domain/scheduleRestaurant.repository"; +import { makeSchedule } from "tests/helpers/schedule-helper"; + +export const mockScheduleRestaurantRepository: jest.Mocked = + { + create: jest.fn(), + destroy: jest.fn(), + save: jest.fn(), + createBach: jest.fn(), + listByRestaurantId: jest.fn(), + }; + +mockScheduleRestaurantRepository.create.mockImplementation( + async (_restaurantId, begin, end, day) => { + return makeSchedule({ begin, end, day }); + }, +); + +mockScheduleRestaurantRepository.createBach.mockImplementation( + async (_restaurantId, schedulesDto) => { + const schedules: Schedule[] = []; + + for (const id in schedulesDto) { + const { begin, end, day } = schedulesDto[id]; + schedules.push(new Schedule(id, begin, end, day)); + } + + return schedules; + }, +); diff --git a/tests/restaurant/application/create-restaurant.test.ts b/tests/restaurant/application/create-restaurant.test.ts new file mode 100644 index 0000000..75507ff --- /dev/null +++ b/tests/restaurant/application/create-restaurant.test.ts @@ -0,0 +1,64 @@ +import { CreateRestaurantUseCase } from "@/restaurant/application/useCases/create-restaurant"; +import { makeCreateRestaurantDto } from "tests/helpers/restaurant-helper"; +import { makeCreateScheduleDto } from "tests/helpers/schedule-helper"; +import { mockRestaurantRepository } from "tests/mocks/restaurant-repository"; +import { mockScheduleRestaurantRepository } from "tests/mocks/schedule-repository"; + +describe("Create restaurant use case", () => { + let createRestaurantUseCase: CreateRestaurantUseCase; + + beforeEach(() => { + createRestaurantUseCase = new CreateRestaurantUseCase( + mockRestaurantRepository, + mockScheduleRestaurantRepository, + ); + }); + + test("when valid request then ok", async () => { + const input = makeCreateRestaurantDto(); + const result = await createRestaurantUseCase.execute(input); + + expect(result).toBeDefined(); + expect(result.id).toBeDefined(); + expect(result.picture).toBeNull(); + }); + + test("when with schedules then ok", async () => { + const input = makeCreateRestaurantDto({ + schedules: [ + makeCreateScheduleDto(), + makeCreateScheduleDto(), + makeCreateScheduleDto(), + ], + }); + const result = await createRestaurantUseCase.execute(input); + + expect(result).toBeDefined(); + expect(result.id).toBeDefined(); + expect(result.picture).toBeNull(); + expect(result.schedules.length).toBe(input.schedules.length); + }); + + test("when invalid scheule then throw error", async () => { + const input = makeCreateRestaurantDto({ + schedules: [ + makeCreateScheduleDto(), + makeCreateScheduleDto({ begin: "13:30", end: "13:35" }), + ], + }); + + expect( + async () => await createRestaurantUseCase.execute(input), + ).rejects.toThrow(); + }); + + test("when empty name then throw error", async () => { + const input = makeCreateRestaurantDto({ + name: "", + }); + + expect( + async () => await createRestaurantUseCase.execute(input), + ).rejects.toThrow(); + }); +}); From 842f416ecd55220237854c69ec962e3dcda53e71 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Fri, 10 Jan 2025 18:08:25 -0300 Subject: [PATCH 15/20] build: adjust jest config --- jest.config.js | 4 +++- tsconfig.json | 3 ++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/jest.config.js b/jest.config.js index 52592ad..235349e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,11 +1,13 @@ /** @type {import('ts-jest').JestConfigWithTsJest} **/ export default { + preset: 'ts-jest', testEnvironment: "node", transform: { "^.+.tsx?$": ["ts-jest",{}], }, moduleNameMapper: { - '^@/(.*)$': '/src/$1', // Mapeamento para suportar aliases + '^@/(.*)$': '/src/$1', + '^tests/(.*)$': '/tests/$1', }, collectCoverage: true, coverageDirectory: "coverage", diff --git a/tsconfig.json b/tsconfig.json index 6ea2a12..a0d7faf 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -12,7 +12,8 @@ ], "baseUrl": "./", "paths": { - "@/*": ["src/*"] + "@/*": ["src/*"], + "tests/*": ["tests/*"] } }, "include": ["src/**/*","tests/**/*"], From d82061a61f2b736f9fe56d0a3ed6fbca8464410b Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Fri, 10 Jan 2025 18:09:07 -0300 Subject: [PATCH 16/20] feat: create-schedule dto --- src/restaurant/application/dtos/create-restaurant.dto.ts | 4 ++-- src/schedule/application/dtos/create-schedule.dto.ts | 5 +++++ 2 files changed, 7 insertions(+), 2 deletions(-) create mode 100644 src/schedule/application/dtos/create-schedule.dto.ts diff --git a/src/restaurant/application/dtos/create-restaurant.dto.ts b/src/restaurant/application/dtos/create-restaurant.dto.ts index 0922508..3b5ce0d 100644 --- a/src/restaurant/application/dtos/create-restaurant.dto.ts +++ b/src/restaurant/application/dtos/create-restaurant.dto.ts @@ -1,8 +1,8 @@ import type { AddressDto } from "@/restaurant/application/dtos/address.dto"; -import type { ScheduleDto } from "@/schedule/application/dtos/schedule.dto"; +import type { CreateScheduleDto } from "@/schedule/application/dtos/create-schedule.dto"; export type CreateRestaurantRequestDto = { name: string; address: AddressDto; - schedules: Omit[]; + schedules: CreateScheduleDto[]; }; diff --git a/src/schedule/application/dtos/create-schedule.dto.ts b/src/schedule/application/dtos/create-schedule.dto.ts new file mode 100644 index 0000000..6cdfbf5 --- /dev/null +++ b/src/schedule/application/dtos/create-schedule.dto.ts @@ -0,0 +1,5 @@ +export type CreateScheduleDto = { + begin: string; + end: string; + day: string; +}; From e25d5a652348be7cdb59bbebdd3cc1d639cff0dc Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Fri, 10 Jan 2025 18:09:36 -0300 Subject: [PATCH 17/20] feat: restaurant with empty name --- src/product/domain/product.entity.ts | 12 ------------ src/product/domain/promotion.ts | 9 --------- src/restaurant/domain/restaurant.entity.ts | 8 ++++++-- 3 files changed, 6 insertions(+), 23 deletions(-) delete mode 100644 src/product/domain/product.entity.ts delete mode 100644 src/product/domain/promotion.ts diff --git a/src/product/domain/product.entity.ts b/src/product/domain/product.entity.ts deleted file mode 100644 index 1d57003..0000000 --- a/src/product/domain/product.entity.ts +++ /dev/null @@ -1,12 +0,0 @@ -import type { Promotion } from "@/product/domain/promotion"; - -export class Product { - constructor( - public readonly id: string, - public readonly name: string, - public readonly category: string, - public readonly picture: string, - public readonly price: number, - public readonly promotion: Promotion, - ) {} -} diff --git a/src/product/domain/promotion.ts b/src/product/domain/promotion.ts deleted file mode 100644 index f36dbaa..0000000 --- a/src/product/domain/promotion.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { Schedule } from "@/schedule/domain/schedule.entity"; - -export class Promotion { - constructor( - public readonly describe: string, - public readonly price: number, - public readonly schedules: Array, - ) {} -} diff --git a/src/restaurant/domain/restaurant.entity.ts b/src/restaurant/domain/restaurant.entity.ts index 2926600..791d7d6 100644 --- a/src/restaurant/domain/restaurant.entity.ts +++ b/src/restaurant/domain/restaurant.entity.ts @@ -4,7 +4,11 @@ export class Restaurant { constructor( public readonly id: string, public readonly name: string, - public readonly picture: string, + public readonly picture: string | null, public readonly address: Address, - ) {} + ) { + if (name === "") { + throw new Error("o nome não pode estar vazio"); + } + } } From 76fe1ae6c825eeecb0460dc0dc2a0baba551c1a7 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Fri, 10 Jan 2025 18:27:48 -0300 Subject: [PATCH 18/20] build: coverage on build --- .github/workflows/build.yml | 2 +- jest.config.js | 1 - package.json | 1 + 3 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 84783ea..cc63824 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -19,7 +19,7 @@ jobs: run: npm ci - name: run tests - run: npm run test + run: npm run test:cov - name: SonarQube Scan uses: SonarSource/sonarqube-scan-action@v4 diff --git a/jest.config.js b/jest.config.js index 235349e..b30b58e 100644 --- a/jest.config.js +++ b/jest.config.js @@ -9,7 +9,6 @@ export default { '^@/(.*)$': '/src/$1', '^tests/(.*)$': '/tests/$1', }, - collectCoverage: true, coverageDirectory: "coverage", coverageReporters: ["lcov", "text"] }; \ No newline at end of file diff --git a/package.json b/package.json index af3175a..f56b302 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "scripts": { "dev": "tsx watch src/index.ts", "test": "jest", + "test:cov": "jest --coverage", "sonar": "sonar-scanner", "prepare": "husky", "lint": "biome lint ./src/*", From 6b407a796ce3561cccdc7a2d90c9ba42089f6ea3 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Fri, 10 Jan 2025 18:34:35 -0300 Subject: [PATCH 19/20] chore: rename let to createRestaurant --- .../application/create-restaurant.test.ts | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/restaurant/application/create-restaurant.test.ts b/tests/restaurant/application/create-restaurant.test.ts index 75507ff..4a699fa 100644 --- a/tests/restaurant/application/create-restaurant.test.ts +++ b/tests/restaurant/application/create-restaurant.test.ts @@ -5,10 +5,10 @@ import { mockRestaurantRepository } from "tests/mocks/restaurant-repository"; import { mockScheduleRestaurantRepository } from "tests/mocks/schedule-repository"; describe("Create restaurant use case", () => { - let createRestaurantUseCase: CreateRestaurantUseCase; + let createRestaurant: CreateRestaurantUseCase; beforeEach(() => { - createRestaurantUseCase = new CreateRestaurantUseCase( + createRestaurant = new CreateRestaurantUseCase( mockRestaurantRepository, mockScheduleRestaurantRepository, ); @@ -16,7 +16,7 @@ describe("Create restaurant use case", () => { test("when valid request then ok", async () => { const input = makeCreateRestaurantDto(); - const result = await createRestaurantUseCase.execute(input); + const result = await createRestaurant.execute(input); expect(result).toBeDefined(); expect(result.id).toBeDefined(); @@ -31,7 +31,7 @@ describe("Create restaurant use case", () => { makeCreateScheduleDto(), ], }); - const result = await createRestaurantUseCase.execute(input); + const result = await createRestaurant.execute(input); expect(result).toBeDefined(); expect(result.id).toBeDefined(); @@ -47,9 +47,7 @@ describe("Create restaurant use case", () => { ], }); - expect( - async () => await createRestaurantUseCase.execute(input), - ).rejects.toThrow(); + expect(async () => await createRestaurant.execute(input)).rejects.toThrow(); }); test("when empty name then throw error", async () => { @@ -57,8 +55,6 @@ describe("Create restaurant use case", () => { name: "", }); - expect( - async () => await createRestaurantUseCase.execute(input), - ).rejects.toThrow(); + expect(async () => await createRestaurant.execute(input)).rejects.toThrow(); }); }); From 5092437f348f90bf92d063a8207ee610c5e1af22 Mon Sep 17 00:00:00 2001 From: fabiano de sousa lima Date: Fri, 10 Jan 2025 19:48:47 -0300 Subject: [PATCH 20/20] test(restaurant): list restaurant use case --- tests/helpers/restaurant-helper.ts | 49 +++++++++++++------ tests/mocks/restaurant-repository.ts | 8 +++ .../application/list-restaurant.test.ts | 30 ++++++++++++ 3 files changed, 72 insertions(+), 15 deletions(-) create mode 100644 tests/restaurant/application/list-restaurant.test.ts diff --git a/tests/helpers/restaurant-helper.ts b/tests/helpers/restaurant-helper.ts index 9567539..30d2fab 100644 --- a/tests/helpers/restaurant-helper.ts +++ b/tests/helpers/restaurant-helper.ts @@ -5,22 +5,16 @@ import { Restaurant } from "@/restaurant/domain/restaurant.entity"; export function makeRestaurant(data: { id?: string; picture?: string | null; - name: string; - address: Address; + name?: string; + address?: Address; }) { - const { city, neighborhood, number, state, street, zipcode } = data.address; - const { id, picture, name } = data; - - const address = Address.builder() - .withStreet(street) - .withCity(city) - .withNumber(number) - .withNeighborhood(neighborhood) - .withState(state) - .withZipcode(zipcode) - .build(); - - return new Restaurant(id ?? "1", name, picture ?? null, address); + const { id, picture, name, address } = data; + return new Restaurant( + id ?? "1", + name ?? "rango brabo", + picture ?? null, + address ?? makeAddress({}), + ); } export function makeCreateRestaurantDto( @@ -43,3 +37,28 @@ export function makeCreateRestaurantDto( return dto; } + +function makeAddress({ + city, + street, + number, + state, + neighborhood, + zipcode, +}: { + city?: string; + street?: string; + number?: string | null; + state?: string; + neighborhood?: string; + zipcode?: string; +}): Address { + return new Address( + street ?? "rua da luz", + number ?? null, + state ?? "RJ", + city ?? "Rio de janeiro", + neighborhood ?? "centro", + zipcode ?? "0001", + ); +} diff --git a/tests/mocks/restaurant-repository.ts b/tests/mocks/restaurant-repository.ts index 819cfab..d0717ad 100644 --- a/tests/mocks/restaurant-repository.ts +++ b/tests/mocks/restaurant-repository.ts @@ -13,3 +13,11 @@ mockRestaurantRepository.create.mockImplementation(async (name, address) => { const id = mockRestaurantRepository.create.mock.calls.length.toString(); return makeRestaurant({ id, name, address }); }); + +mockRestaurantRepository.list.mockImplementation(async () => { + return [ + makeRestaurant({ id: "1" }), + makeRestaurant({ id: "2" }), + makeRestaurant({ id: "3" }), + ]; +}); diff --git a/tests/restaurant/application/list-restaurant.test.ts b/tests/restaurant/application/list-restaurant.test.ts new file mode 100644 index 0000000..649a997 --- /dev/null +++ b/tests/restaurant/application/list-restaurant.test.ts @@ -0,0 +1,30 @@ +import { ListRestaurantUseCase } from "@/restaurant/application/useCases/list-restaurant"; +import { mockRestaurantRepository } from "tests/mocks/restaurant-repository"; + +describe("list restaurant test use case", () => { + let listRestaurant: ListRestaurantUseCase; + + beforeEach(() => { + jest.clearAllMocks(); + listRestaurant = new ListRestaurantUseCase(mockRestaurantRepository); + }); + + test("when list restaurant then output format", async () => { + const result = await listRestaurant.execute(); + + expect(result).toBeDefined(); + expect(result[0].id).toBeDefined(); + expect(result[0].name).toBeDefined(); + expect(result[0].picture).toBeDefined(); + expect(typeof result[0].address).toBe("string"); + }); + + test("when empty list ten ok", async () => { + mockRestaurantRepository.list.mockResolvedValueOnce([]); + const result = await listRestaurant.execute(); + + expect(result).toBeDefined(); + expect(result.length).toBe(0); + expect(mockRestaurantRepository.list.mock.calls.length).toBe(1); + }); +});