From 7046c5adc99ecf90a0ae89e1e4cdeae35a8a74fb Mon Sep 17 00:00:00 2001 From: behnam Date: Sat, 2 Nov 2024 14:57:23 +0300 Subject: [PATCH] Add demo logics for using fp-ts in feature layer --- .../latest-invoices-controller.ts | 4 +- .../latest-invoices/latest-invoices.tsx | 5 ++- src/feature/common/failures/params-failure.ts | 12 ++++++ .../data/repo/customer-invoice-db-repo.ts | 37 +++++++++++-------- .../domain/i-repo/customer-invoice-repo.ts | 3 +- .../fetch-customer-invoices-usecase.ts | 6 +-- .../customer/domain/i-repo/customer-repo.ts | 3 +- .../invoice/domain/i-repo/invoice-repo.ts | 3 +- .../domain/usecase/create-invoice-usecase.ts | 25 ++++++++----- 9 files changed, 64 insertions(+), 34 deletions(-) create mode 100644 src/feature/common/failures/params-failure.ts diff --git a/src/app/dashboard/components/server/latest-invoices/latest-invoices-controller.ts b/src/app/dashboard/components/server/latest-invoices/latest-invoices-controller.ts index 45bde22..8fbbde9 100644 --- a/src/app/dashboard/components/server/latest-invoices/latest-invoices-controller.ts +++ b/src/app/dashboard/components/server/latest-invoices/latest-invoices-controller.ts @@ -1,5 +1,5 @@ import fetchCustomerInvoicesUsecase from "@/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase"; -export default function latestInvoicesController() { - return fetchCustomerInvoicesUsecase() +export default async function latestInvoicesController() { + return await fetchCustomerInvoicesUsecase() } \ No newline at end of file diff --git a/src/app/dashboard/components/server/latest-invoices/latest-invoices.tsx b/src/app/dashboard/components/server/latest-invoices/latest-invoices.tsx index 09396cd..696af73 100644 --- a/src/app/dashboard/components/server/latest-invoices/latest-invoices.tsx +++ b/src/app/dashboard/components/server/latest-invoices/latest-invoices.tsx @@ -2,12 +2,15 @@ import CreateRandomInvoiceContainer from '@/app/dashboard/components/client/crea import latestInvoicesController from '@/app/dashboard/components/server/latest-invoices/latest-invoices-controller'; import { ArrowPathIcon } from '@heroicons/react/24/outline'; import clsx from 'clsx'; +import { isLeft } from 'fp-ts/lib/Either'; import Image from 'next/image'; export default async function LatestInvoices() { const latestInvoices = await latestInvoicesController(); - const invoices = latestInvoices.map((invoice, i) => { + if (isLeft(latestInvoices)) return
Error
+ + const invoices = latestInvoices.right.map((invoice, i) => { return (
{ - try { - const data = await sql` - SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id - FROM invoices - JOIN customers ON invoices.customer_id = customers.id - ORDER BY invoices.date DESC - LIMIT 20 ` as postgres.RowList; - - return this.customerInvoicesDto(data) - } catch (error) { - console.error('Database Error:', error); - throw new Error('Failed to fetch the latest invoices.'); - } + fetchList(): ApiTask { + + return pipe( + tryCatch( + async () => { + const response = await sql` + SELECT invoices.amount, customers.name, customers.image_url, customers.email, invoices.id + FROM invoices + JOIN customers ON invoices.customer_id = customers.id + ORDER BY invoices.date DESC + LIMIT 20 ` as postgres.RowList; + + return this.customerInvoicesDto(response) + }, + (l) => failureOr(l, new NetworkFailure()) + ) + ) } - private customerInvoicesDto(dbCustomers: customerInvoiceDbResponse[]): CustomerInvoice[] { return dbCustomers.map((customer) => this.customerInvoiceDto(customer)); } diff --git a/src/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo.ts b/src/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo.ts index 0a8c993..ab4b486 100644 --- a/src/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo.ts +++ b/src/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo.ts @@ -1,7 +1,8 @@ +import ApiTask from "@/feature/common/data/api-task" import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice" export default interface CustomerInvoiceRepo { - fetchList(): Promise + fetchList(): ApiTask } export const customerInvoiceRepoKey = "customerInvoiceRepoKey" \ No newline at end of file diff --git a/src/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase.ts b/src/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase.ts index 5947553..5d2df55 100644 --- a/src/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase.ts +++ b/src/feature/core/customer-invoice/domain/usecase/fetch-customer-invoices-usecase.ts @@ -1,12 +1,12 @@ -"use server" +import { ApiEither } from "@/feature/common/data/api-task"; import serverDi from "@/feature/common/server-di"; import CustomerInvoice from "@/feature/core/customer-invoice/domain/entity/customer-invoice"; import CustomerInvoiceRepo, { customerInvoiceRepoKey } from "@/feature/core/customer-invoice/domain/i-repo/customer-invoice-repo"; import { customerInvoiceModuleKey } from "@/feature/core/customer-invoice/invoice-module-key"; import { connection } from "next/server"; -export default async function fetchCustomerInvoicesUsecase(): Promise { +export default async function fetchCustomerInvoicesUsecase(): Promise> { connection() const repo = serverDi(customerInvoiceModuleKey).resolve(customerInvoiceRepoKey) - return repo.fetchList() + return repo.fetchList()() } \ No newline at end of file diff --git a/src/feature/core/customer/domain/i-repo/customer-repo.ts b/src/feature/core/customer/domain/i-repo/customer-repo.ts index d48fdde..86b890e 100644 --- a/src/feature/core/customer/domain/i-repo/customer-repo.ts +++ b/src/feature/core/customer/domain/i-repo/customer-repo.ts @@ -1,7 +1,8 @@ +import ApiTask from "@/feature/common/data/api-task" import Customer from "@/feature/core/customer/domain/entity/customer" export default interface CustomerRepo { - fetchList(query: string): Promise + fetchList(query: string): ApiTask fetchCustomersAmount(): Promise } diff --git a/src/feature/core/invoice/domain/i-repo/invoice-repo.ts b/src/feature/core/invoice/domain/i-repo/invoice-repo.ts index 983ac3f..ca5096d 100644 --- a/src/feature/core/invoice/domain/i-repo/invoice-repo.ts +++ b/src/feature/core/invoice/domain/i-repo/invoice-repo.ts @@ -1,10 +1,11 @@ +import ApiTask from "@/feature/common/data/api-task" import { InvoiceParam } from "@/feature/core/invoice/domain/param/invoice-param" import InvoiceStatusSummary from "@/feature/core/invoice/domain/value-object/invoice-status" export default interface InvoiceRepo { fetchAllInvoicesAmount(): Promise fetchInvoicesStatusSummary(): Promise - createInvoice(params: InvoiceParam): Promise + createInvoice(params: InvoiceParam): ApiTask } export const invoiceRepoKey = "invoiceRepoKey" \ No newline at end of file diff --git a/src/feature/core/invoice/domain/usecase/create-invoice-usecase.ts b/src/feature/core/invoice/domain/usecase/create-invoice-usecase.ts index 73a0106..9cfc63d 100644 --- a/src/feature/core/invoice/domain/usecase/create-invoice-usecase.ts +++ b/src/feature/core/invoice/domain/usecase/create-invoice-usecase.ts @@ -1,19 +1,24 @@ "use server" +import { ApiEither } from "@/feature/common/data/api-task"; +import ParamsFailure from "@/feature/common/failures/params-failure"; import serverDi from "@/feature/common/server-di"; import InvoiceRepo, { invoiceRepoKey } from "@/feature/core/invoice/domain/i-repo/invoice-repo"; import { InvoiceParam, invoiceSchema } from "@/feature/core/invoice/domain/param/invoice-param"; import { invoiceModuleKey } from "@/feature/core/invoice/invoice-module-key"; +import { pipe } from "fp-ts/lib/function"; +import { chain, fromNullable, left, map, right } from "fp-ts/lib/TaskEither"; -export default async function createInvoiceUsecase(params: InvoiceParam): Promise { - const isParamsValid = invoiceSchema.safeParse(params) - - if (!isParamsValid) { - return { - errorMessage: "Please pass correct params" - } - } +export default async function createInvoiceUsecase(params: InvoiceParam): Promise> { const repo = serverDi(invoiceModuleKey).resolve(invoiceRepoKey) - return repo.createInvoice(params) - + return pipe( + fromNullable(new ParamsFailure())(params), + map((params) => invoiceSchema.safeParse(params)), + chain((params) => { + const isParamsValid = invoiceSchema.safeParse(params) + if (!isParamsValid.success) left(new ParamsFailure()) + return right(params.data as InvoiceParam) + }), + chain((params) => repo.createInvoice(params)) + )() } \ No newline at end of file