From 2b04906dd7956db66751bc81dcb7e609d4a9c237 Mon Sep 17 00:00:00 2001 From: Alexander Ungar Date: Fri, 31 Mar 2023 17:41:30 +0200 Subject: [PATCH] Add missing DELETE endpoint for Budgets --- src/repository/budget/budgetRepository.ts | 3 ++- .../budget/mongo/budgetMongoRepository.ts | 6 ++++++ src/routes/budget/budgetRouter.ts | 14 ++++++++++++++ src/routes/toExpressPath.ts | 5 +++++ src/usecase/budget/budgetService.ts | 9 +++++++++ src/usecase/budget/budgetUseCases.ts | 1 + 6 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/repository/budget/budgetRepository.ts b/src/repository/budget/budgetRepository.ts index 1f5a05a..18563a1 100644 --- a/src/repository/budget/budgetRepository.ts +++ b/src/repository/budget/budgetRepository.ts @@ -1,7 +1,8 @@ -import { type Budget } from "../../domain/budget"; +import { type Budget, type BudgetId } from "../../domain/budget"; interface BudgetRepository { findAll: () => Promise; + delete: (id: BudgetId) => Promise<{ deleted: boolean }>; } export default BudgetRepository; diff --git a/src/repository/budget/mongo/budgetMongoRepository.ts b/src/repository/budget/mongo/budgetMongoRepository.ts index 7d54240..542a114 100644 --- a/src/repository/budget/mongo/budgetMongoRepository.ts +++ b/src/repository/budget/mongo/budgetMongoRepository.ts @@ -7,8 +7,14 @@ export const findBudgets: BudgetRepository["findAll"] = async () => { return found.map(BudgetEntityConverter.toDomain); }; +export const deleteBudget: BudgetRepository["delete"] = async (budgetId) => { + const deleted = await BudgetSummaryModel.deleteOne({ id: budgetId.value }); + return { deleted: deleted.deletedCount > 0 }; +}; + const BudgetMongoRepository = (): BudgetRepository => ({ findAll: findBudgets, + delete: deleteBudget, }); export default BudgetMongoRepository; diff --git a/src/routes/budget/budgetRouter.ts b/src/routes/budget/budgetRouter.ts index 844be4e..200132d 100644 --- a/src/routes/budget/budgetRouter.ts +++ b/src/routes/budget/budgetRouter.ts @@ -45,6 +45,16 @@ export const getBudgetSummary = } }; +export const deleteBudget = + (deleteBudget: BudgetUseCases["deleteBudget"]) => + async (req: Request, res: Response): Promise => { + const budgetId = new UUID(req.params.budgetId); + const deleteResult = await deleteBudget(budgetId); + res.status( + deleteResult.deleted ? StatusCodes.NO_CONTENT : StatusCodes.NOT_FOUND + ); + }; + const BudgetRouter = (budgetUseCases: BudgetUseCases): Router => { const router = Router(); router.post( @@ -59,6 +69,10 @@ const BudgetRouter = (budgetUseCases: BudgetUseCases): Router => { toExpressPath(apiPaths.getBudgetSummary), asyncHandler(getBudgetSummary(budgetUseCases.getBudgetSummary)) ); + router.delete( + toExpressPath(apiPaths.deleteBudget), + asyncHandler(deleteBudget(budgetUseCases.deleteBudget)) + ); return router; }; diff --git a/src/routes/toExpressPath.ts b/src/routes/toExpressPath.ts index 9bd4c85..777b64d 100644 --- a/src/routes/toExpressPath.ts +++ b/src/routes/toExpressPath.ts @@ -1,3 +1,8 @@ +/** + * Reformats an OpenAPI defined path to a by Express readable path + * I.e. rewrites path param notation from OpenAPI format to Express format + * @param openApiPath The in the OpenAPI spec defined path + */ const toExpressPath = (openApiPath: string): string => openApiPath.replaceAll(/({)(.*)(})/g, ":$2"); diff --git a/src/usecase/budget/budgetService.ts b/src/usecase/budget/budgetService.ts index c59e403..217e5e5 100644 --- a/src/usecase/budget/budgetService.ts +++ b/src/usecase/budget/budgetService.ts @@ -3,6 +3,7 @@ import type BudgetSummaryRepository from "../../repository/budget/budgetSummaryR import type BudgetUseCases from "./budgetUseCases"; import UUID from "../../domain/uuid"; import type BudgetRepository from "../../repository/budget/budgetRepository"; +import budgetRepository from "../../repository/budget/budgetRepository"; export const createBudget: ( insertBudget: BudgetSummaryRepository["insert"] @@ -28,6 +29,13 @@ export const getBudgets: ( return await findAll(); }; +export const deleteBudget: ( + deleteFromPersistence: BudgetRepository["delete"] +) => BudgetUseCases["deleteBudget"] = + (deleteFromPersistence) => async (budgetId) => { + return await deleteFromPersistence(budgetId); + }; + const BudgetService: ( budgetSummaryRepo: BudgetSummaryRepository, budgetRepo: BudgetRepository @@ -35,6 +43,7 @@ const BudgetService: ( createBudget: createBudget(budgetSummaryRepo.insert), getBudgetSummary: getBudgetSummary(budgetSummaryRepo.find), getBudgets: getBudgets(budgetRepo.findAll), + deleteBudget: deleteBudget(budgetRepo.delete), }); export default BudgetService; diff --git a/src/usecase/budget/budgetUseCases.ts b/src/usecase/budget/budgetUseCases.ts index 18ea1bc..231d251 100644 --- a/src/usecase/budget/budgetUseCases.ts +++ b/src/usecase/budget/budgetUseCases.ts @@ -9,6 +9,7 @@ interface BudgetUseCases { createBudget: (newBudget: NewBudget) => Promise; getBudgetSummary: (budgetId: BudgetId) => Promise; getBudgets: () => Promise; + deleteBudget: (budgetId: BudgetId) => Promise<{ deleted: boolean }>; } export default BudgetUseCases;