From caa7b9f0cd3fc8aeff7dcf96c94100821d363857 Mon Sep 17 00:00:00 2001 From: Simone Carriero Date: Tue, 12 Mar 2024 08:29:33 +0100 Subject: [PATCH] Get users from request in the book use case --- src/application/book.test.ts | 54 +++++++++++++++++-- src/application/book.ts | 16 +++--- src/domain/FreeSpot.ts | 1 + src/domain/User.ts | 6 +++ .../in-memory/UserRepositoryInMemory.ts | 9 ++++ 5 files changed, 71 insertions(+), 15 deletions(-) create mode 100644 src/domain/User.ts create mode 100644 src/infrastructure/in-memory/UserRepositoryInMemory.ts diff --git a/src/application/book.test.ts b/src/application/book.test.ts index ca538dd..e7b5cd6 100644 --- a/src/application/book.test.ts +++ b/src/application/book.test.ts @@ -2,10 +2,29 @@ import { justDate } from '../domain/JustDate'; import { justTime } from '../domain/JustTime'; import { BookingRequestRepositoryInMemory } from '../infrastructure/in-memory/BookingRequestRepositoryInMemory'; import { FreeSpotRepositoryInMemory } from '../infrastructure/in-memory/FreeSpotRepositoryInMemory'; +import { UserRepositoryInMemory } from '../infrastructure/in-memory/UserRepositoryInMemory'; import { book } from './book'; import * as E from 'fp-ts/Either'; +import * as TE from 'fp-ts/TaskEither'; +import { pipe } from 'fp-ts/lib/function'; describe(`book`, () => { + const jane = { + firstname: 'Jane', + lastname: 'Doe', + email: 'jane.doe@example.com', + phone: '0123456789', + }; + + const jon = { + firstname: 'Jon', + lastname: 'Doe', + email: 'jon.doe@example.com', + phone: '0123456789', + }; + + const userRepository = new UserRepositoryInMemory([jane, jon]); + it(`books the first available spot for each booking request`, async () => { let freeSpots = [ { id: 1, date: justDate(2020, 1, 1), time: justTime(18, 30) }, @@ -19,7 +38,7 @@ describe(`book`, () => { const freeSpotRepository = new FreeSpotRepositoryInMemory(freeSpots); const bookingRequestRepository = new BookingRequestRepositoryInMemory(bookingRequests); - const bookUseCase = book(bookingRequestRepository, freeSpotRepository); + const bookUseCase = book(bookingRequestRepository, freeSpotRepository, userRepository); const booked = await bookUseCase(); @@ -27,11 +46,11 @@ describe(`book`, () => { E.right([ [ { date: justDate(2020, 1, 1), from: justTime(18), to: justTime(20), chat: 123 }, - { id: 1, date: justDate(2020, 1, 1), time: justTime(18, 30) }, + { id: 1, date: justDate(2020, 1, 1), time: justTime(18, 30), user: jane }, ], [ { date: justDate(2020, 1, 1), from: justTime(18), to: justTime(21), chat: 123 }, - { id: 1, date: justDate(2020, 1, 1), time: justTime(19, 30) }, + { id: 1, date: justDate(2020, 1, 1), time: justTime(19, 30), user: jane }, ], ]), ); @@ -54,7 +73,7 @@ describe(`book`, () => { const freeSpotRepository = new FreeSpotRepositoryInMemory(freeSpots); const bookingRequestRepository = new BookingRequestRepositoryInMemory(bookingRequests); - const bookUseCase = book(bookingRequestRepository, freeSpotRepository); + const bookUseCase = book(bookingRequestRepository, freeSpotRepository, userRepository); await bookUseCase(); @@ -71,7 +90,7 @@ describe(`book`, () => { const freeSpotRepository = new FreeSpotRepositoryInMemory(freeSpots); const bookingRequestRepository = new BookingRequestRepositoryInMemory(bookingRequests); - const bookUseCase = book(bookingRequestRepository, freeSpotRepository); + const bookUseCase = book(bookingRequestRepository, freeSpotRepository, userRepository); await bookUseCase(); const spots = freeSpotRepository.get({ @@ -83,4 +102,29 @@ describe(`book`, () => { expect(spots()).resolves.toEqual(E.right([])); }); + + it(`gets user`, async () => { + let freeSpots = [{ id: 1, date: justDate(2020, 1, 1), time: justTime(18, 30) }]; + let bookingRequests = [ + { date: justDate(2020, 1, 1), from: justTime(18), to: justTime(20), chat: 123, user: 'Jon' }, + ]; + + const freeSpotRepository = new FreeSpotRepositoryInMemory(freeSpots); + const bookingRequestRepository = new BookingRequestRepositoryInMemory(bookingRequests); + const bookUseCase = book(bookingRequestRepository, freeSpotRepository, userRepository); + + const booked = await pipe( + bookUseCase, + TE.map(([[_, freeSpot]]) => freeSpot), + )(); + + expect(booked).toEqual( + E.right({ + id: 1, + date: justDate(2020, 1, 1), + time: justTime(18, 30), + user: jon, + }), + ); + }); }); diff --git a/src/application/book.ts b/src/application/book.ts index 3f38fc0..eb6b35c 100644 --- a/src/application/book.ts +++ b/src/application/book.ts @@ -1,32 +1,28 @@ import { BookingRequest, BookingRequestRepository } from '../domain/BookingRequest'; import { FreeSpot, FreeSpotRepository } from '../domain/FreeSpot'; +import { UserRepository } from '../domain/User'; import * as O from 'fp-ts/Option'; import * as A from 'fp-ts/ReadonlyArray'; import * as TE from 'fp-ts/TaskEither'; +import { sequenceT } from 'fp-ts/lib/Apply'; import { pipe } from 'fp-ts/lib/function'; export const book = ( bookingRequestRepository: BookingRequestRepository, freeSpotRepository: FreeSpotRepository, + userRepository: UserRepository, ): TE.TaskEither => { const tryBooking = (request: BookingRequest): TE.TaskEither> => { - const user = { - firstname: 'Jane', - lastname: 'Doe', - email: 'jane.doe@example.com', - phone: '0123456789', - }; - return pipe( - freeSpotRepository.get(request), - TE.flatMap((spots) => { + sequenceT(TE.ApplyPar)(userRepository.get(request.user || 'Jane'), freeSpotRepository.get(request)), + TE.flatMap(([user, spots]) => { if (spots.length === 0) { return TE.right(O.none); } return pipe( freeSpotRepository.book(spots[0], user), TE.flatMap((_) => bookingRequestRepository.delete(request)), - TE.map((_) => O.some([request, spots[0]])), + TE.map((_) => O.some([request, { ...spots[0], user }])), ); }), ); diff --git a/src/domain/FreeSpot.ts b/src/domain/FreeSpot.ts index 4e78b43..ac82d32 100644 --- a/src/domain/FreeSpot.ts +++ b/src/domain/FreeSpot.ts @@ -7,6 +7,7 @@ export type FreeSpot = { id: number; date: JustDate; time: JustTime; + user?: User; }; export type User = { diff --git a/src/domain/User.ts b/src/domain/User.ts new file mode 100644 index 0000000..214672d --- /dev/null +++ b/src/domain/User.ts @@ -0,0 +1,6 @@ +import { User } from './FreeSpot'; +import * as TE from 'fp-ts/lib/TaskEither'; + +export interface UserRepository { + get(name: string): TE.TaskEither; +} diff --git a/src/infrastructure/in-memory/UserRepositoryInMemory.ts b/src/infrastructure/in-memory/UserRepositoryInMemory.ts new file mode 100644 index 0000000..89df78c --- /dev/null +++ b/src/infrastructure/in-memory/UserRepositoryInMemory.ts @@ -0,0 +1,9 @@ +import { User } from '../../domain/FreeSpot'; +import { UserRepository } from '../../domain/User'; +import * as TE from 'fp-ts/TaskEither'; + +export class UserRepositoryInMemory implements UserRepository { + constructor(private state: User[] = []) {} + + get = (name: string): TE.TaskEither => TE.of(this.state.find((s) => s.firstname === name)!); +}