From 4c25bdf8dbd53e533c23794c5df377d8e48fd2a6 Mon Sep 17 00:00:00 2001 From: dpurbosakti Date: Wed, 20 Aug 2025 13:40:25 +0700 Subject: [PATCH] feat (crud): add installation, unit --- cmd/migration/migrations/20250820061823.sql | 11 + cmd/migration/migrations/20250820062943.sql | 12 + cmd/migration/migrations/atlas.sum | 4 +- .../domain/main-entities/installation/dto.go | 69 +++ .../main-entities/installation/entity.go | 13 + internal/domain/main-entities/unit/dto.go | 68 +++ internal/domain/main-entities/unit/entity.go | 14 + .../domain/references/encounter/encounter.go | 2 +- .../main-handler/installation/handler.go | 71 +++ .../interface/main-handler/main-handler.go | 6 + .../interface/main-handler/unit/handler.go | 71 +++ internal/interface/migration/migration.go | 4 + .../main-use-case/division-position/case.go | 11 +- .../use-case/main-use-case/division/case.go | 11 +- .../main-use-case/installation/case.go | 459 +++++++++++++++++ .../main-use-case/installation/helper.go | 23 + .../main-use-case/installation/lib.go | 98 ++++ .../main-use-case/installation/tycovar.go | 32 ++ internal/use-case/main-use-case/unit/case.go | 460 ++++++++++++++++++ .../use-case/main-use-case/unit/helper.go | 23 + internal/use-case/main-use-case/unit/lib.go | 98 ++++ .../use-case/main-use-case/unit/tycovar.go | 32 ++ internal/use-case/main-use-case/user/case.go | 11 +- 23 files changed, 1595 insertions(+), 8 deletions(-) create mode 100644 cmd/migration/migrations/20250820061823.sql create mode 100644 cmd/migration/migrations/20250820062943.sql create mode 100644 internal/domain/main-entities/installation/dto.go create mode 100644 internal/domain/main-entities/installation/entity.go create mode 100644 internal/domain/main-entities/unit/dto.go create mode 100644 internal/domain/main-entities/unit/entity.go create mode 100644 internal/interface/main-handler/installation/handler.go create mode 100644 internal/interface/main-handler/unit/handler.go create mode 100644 internal/use-case/main-use-case/installation/case.go create mode 100644 internal/use-case/main-use-case/installation/helper.go create mode 100644 internal/use-case/main-use-case/installation/lib.go create mode 100644 internal/use-case/main-use-case/installation/tycovar.go create mode 100644 internal/use-case/main-use-case/unit/case.go create mode 100644 internal/use-case/main-use-case/unit/helper.go create mode 100644 internal/use-case/main-use-case/unit/lib.go create mode 100644 internal/use-case/main-use-case/unit/tycovar.go diff --git a/cmd/migration/migrations/20250820061823.sql b/cmd/migration/migrations/20250820061823.sql new file mode 100644 index 00000000..cd50b42b --- /dev/null +++ b/cmd/migration/migrations/20250820061823.sql @@ -0,0 +1,11 @@ +-- Create "Installation" table +CREATE TABLE "public"."Installation" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + "EncounterClass_Code" character varying(10) NULL, + PRIMARY KEY ("Id") +); diff --git a/cmd/migration/migrations/20250820062943.sql b/cmd/migration/migrations/20250820062943.sql new file mode 100644 index 00000000..36a3046b --- /dev/null +++ b/cmd/migration/migrations/20250820062943.sql @@ -0,0 +1,12 @@ +-- Create "Unit" table +CREATE TABLE "public"."Unit" ( + "Id" serial NOT NULL, + "CreatedAt" timestamptz NULL, + "UpdatedAt" timestamptz NULL, + "DeletedAt" timestamptz NULL, + "Installation_Id" integer NULL, + "Code" character varying(10) NULL, + "Name" character varying(50) NULL, + PRIMARY KEY ("Id"), + CONSTRAINT "fk_Unit_Installation" FOREIGN KEY ("Installation_Id") REFERENCES "public"."Installation" ("Id") ON UPDATE NO ACTION ON DELETE NO ACTION +); diff --git a/cmd/migration/migrations/atlas.sum b/cmd/migration/migrations/atlas.sum index d9bda753..a6638e1e 100644 --- a/cmd/migration/migrations/atlas.sum +++ b/cmd/migration/migrations/atlas.sum @@ -1,3 +1,5 @@ -h1:RD9Yp8yQFfSKnSkmgYm47Q47Dn3FmZvYDCeNIiVKU1w= +h1:sflrLy3WNiI1HdFXmrmyufKJOFz2lUT1ElPaNRU+uCo= 20250820052409.sql h1:W2zifi3eF+hG0fHvIrY15dH82WO/4QPGdZOEUkgKlAg= 20250820055632.sql h1:sPoDUmT4aZV4qiaq63ssIcoevr3N2WAjRcU1c+Kz6kc= +20250820061823.sql h1:mj37CorTCwngLSo5PRKGC3Wy4I4IapmNXaJGgGxU6y4= +20250820062943.sql h1:Cr8vZGsdJ8Bh+ZKGVAmEh+4rnsjgt5eIy3lExpE4etc= diff --git a/internal/domain/main-entities/installation/dto.go b/internal/domain/main-entities/installation/dto.go new file mode 100644 index 00000000..e4f806b1 --- /dev/null +++ b/internal/domain/main-entities/installation/dto.go @@ -0,0 +1,69 @@ +package installation + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ere "simrs-vx/internal/domain/references/encounter" +) + +type CreateDto struct { + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` +} + +type ReadListDto struct { + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Code string `json:"code"` + Name string `json:"name"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code"` +} + +func (i Installation) ToResponse() ResponseDto { + resp := ResponseDto{ + Code: i.Code, + Name: i.Name, + EncounterClass_Code: i.EncounterClass_Code, + } + resp.SmallMain = i.SmallMain + return resp +} + +func ToResponseList(users []Installation) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/installation/entity.go b/internal/domain/main-entities/installation/entity.go new file mode 100644 index 00000000..84159810 --- /dev/null +++ b/internal/domain/main-entities/installation/entity.go @@ -0,0 +1,13 @@ +package installation + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ere "simrs-vx/internal/domain/references/encounter" +) + +type Installation struct { + ecore.SmallMain // adjust this according to the needs + Code string `json:"code" gorm:"size:10"` + Name string `json:"name" gorm:"size:50"` + EncounterClass_Code ere.EncounterClass `json:"encounterClass_code" gorm:"size:10"` +} diff --git a/internal/domain/main-entities/unit/dto.go b/internal/domain/main-entities/unit/dto.go new file mode 100644 index 00000000..0a5e8b51 --- /dev/null +++ b/internal/domain/main-entities/unit/dto.go @@ -0,0 +1,68 @@ +package unit + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" +) + +type CreateDto struct { + Installation_Id *uint16 `json:"installation_id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type ReadListDto struct { + Installation_Id *uint16 `json:"installation_id"` + Code string `json:"code"` + Name string `json:"name"` + + Page int `json:"page"` + PageSize int `json:"page_size"` + NoPagination int `json:"no_pagination"` +} + +type ReadDetailDto struct { + Installation_Id *uint16 `json:"installation_id"` + Id uint16 `json:"id"` + Code string `json:"code"` + Name string `json:"name"` +} + +type UpdateDto struct { + Id uint16 `json:"id"` + CreateDto +} + +type DeleteDto struct { + Id uint16 `json:"id"` +} + +type MetaDto struct { + PageNumber int `json:"page_number"` + PageSize int `json:"page_size"` + Count int `json:"count"` +} + +type ResponseDto struct { + ecore.SmallMain + Installation_Id *uint16 `json:"installation_id"` + Code string `json:"code"` + Name string `json:"name"` +} + +func (u Unit) ToResponse() ResponseDto { + resp := ResponseDto{ + Installation_Id: u.Installation_Id, + Code: u.Code, + Name: u.Name, + } + resp.SmallMain = u.SmallMain + return resp +} + +func ToResponseList(users []Unit) []ResponseDto { + resp := make([]ResponseDto, len(users)) + for i, u := range users { + resp[i] = u.ToResponse() + } + return resp +} diff --git a/internal/domain/main-entities/unit/entity.go b/internal/domain/main-entities/unit/entity.go new file mode 100644 index 00000000..3953692f --- /dev/null +++ b/internal/domain/main-entities/unit/entity.go @@ -0,0 +1,14 @@ +package unit + +import ( + ecore "simrs-vx/internal/domain/base-entities/core" + ei "simrs-vx/internal/domain/main-entities/installation" +) + +type Unit struct { + ecore.SmallMain // adjust this according to the needs + Installation_Id *uint16 `json:"installation_id"` + Installation *ei.Installation `json:"installation" gorm:"foreignKey:Installation_Id"` + Code string `json:"code" gorm:"size:10"` + Name string `json:"name" gorm:"size:50"` +} diff --git a/internal/domain/references/encounter/encounter.go b/internal/domain/references/encounter/encounter.go index b7e4c1d8..941b0cae 100644 --- a/internal/domain/references/encounter/encounter.go +++ b/internal/domain/references/encounter/encounter.go @@ -28,7 +28,7 @@ const ( func (ec EncounterClass) Code() string { switch ec { - case ECAmbulatory: + case ECAmbulatory, ECOutpatient: return "AMB" case ECInpatient: return "IMP" diff --git a/internal/interface/main-handler/installation/handler.go b/internal/interface/main-handler/installation/handler.go new file mode 100644 index 00000000..dd5903f8 --- /dev/null +++ b/internal/interface/main-handler/installation/handler.go @@ -0,0 +1,71 @@ +package installation + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/installation" + u "simrs-vx/internal/use-case/main-use-case/installation" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/main-handler/main-handler.go b/internal/interface/main-handler/main-handler.go index 22f8453b..6659b264 100644 --- a/internal/interface/main-handler/main-handler.go +++ b/internal/interface/main-handler/main-handler.go @@ -24,6 +24,8 @@ import ( /******************** sources ********************/ division "simrs-vx/internal/interface/main-handler/division" divisionposition "simrs-vx/internal/interface/main-handler/division-position" + installation "simrs-vx/internal/interface/main-handler/installation" + unit "simrs-vx/internal/interface/main-handler/unit" ///// Internal "simrs-vx/internal/interface/main-handler/home" @@ -46,8 +48,12 @@ func SetRoutes() http.Handler { hk.Route("POST /v1/authentication/logout", r, auth.GuardMW, auth.Logout) hc.RegCrud(r, "/v1/user", user.O) + + /******************** sources ********************/ hc.RegCrud(r, "/v1/division", division.O) hc.RegCrud(r, "/v1/division-position", divisionposition.O) + hc.RegCrud(r, "/v1/installation", installation.O) + hc.RegCrud(r, "/v1/unit", unit.O) ///// return cmw.SetCors(handlerlogger.SetLog(r)) diff --git a/internal/interface/main-handler/unit/handler.go b/internal/interface/main-handler/unit/handler.go new file mode 100644 index 00000000..0abc9a21 --- /dev/null +++ b/internal/interface/main-handler/unit/handler.go @@ -0,0 +1,71 @@ +package unit + +import ( + "net/http" + + rw "github.com/karincake/risoles" + sf "github.com/karincake/semprit" + + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/unit" + u "simrs-vx/internal/use-case/main-use-case/unit" +) + +type myBase struct{} + +var O myBase + +func (obj myBase) Create(w http.ResponseWriter, r *http.Request) { + dto := e.CreateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.Create(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetList(w http.ResponseWriter, r *http.Request) { + dto := e.ReadListDto{} + sf.UrlQueryParam(&dto, *r.URL) + res, err := u.ReadList(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) GetDetail(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + dto := e.ReadDetailDto{} + dto.Id = uint16(id) + res, err := u.ReadDetail(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Update(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.UpdateDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + dto.Id = uint16(id) + res, err := u.Update(dto) + rw.DataResponse(w, res, err) +} + +func (obj myBase) Delete(w http.ResponseWriter, r *http.Request) { + id := rw.ValidateInt(w, "id", r.PathValue("id")) + if id <= 0 { + return + } + + dto := e.DeleteDto{} + dto.Id = uint16(id) + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/migration/migration.go b/internal/interface/migration/migration.go index 8396c8a6..723d097e 100644 --- a/internal/interface/migration/migration.go +++ b/internal/interface/migration/migration.go @@ -7,6 +7,8 @@ import ( "os/exec" ed "simrs-vx/internal/domain/main-entities/division" edp "simrs-vx/internal/domain/main-entities/division-position" + ei "simrs-vx/internal/domain/main-entities/installation" + eun "simrs-vx/internal/domain/main-entities/unit" eu "simrs-vx/internal/domain/main-entities/user" "ariga.io/atlas-provider-gorm/gormschema" @@ -45,6 +47,8 @@ func GetEntities() []any { &eu.User{}, &ed.Division{}, &edp.DivisionPosition{}, + &ei.Installation{}, + &eun.Unit{}, } } diff --git a/internal/use-case/main-use-case/division-position/case.go b/internal/use-case/main-use-case/division-position/case.go index 46d5d80f..2749ca1b 100644 --- a/internal/use-case/main-use-case/division-position/case.go +++ b/internal/use-case/main-use-case/division-position/case.go @@ -1,6 +1,7 @@ package divisionposition import ( + "errors" "fmt" e "simrs-vx/internal/domain/main-entities/division-position" "strconv" @@ -213,14 +214,20 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-read-detail-fail", Detail: "Database read detail failed", Raw: err, } - return pl.SetLogError(event, input) } pl.SetLogInfo(&event, nil, "complete") diff --git a/internal/use-case/main-use-case/division/case.go b/internal/use-case/main-use-case/division/case.go index 9b0aa8b5..dfd9d985 100644 --- a/internal/use-case/main-use-case/division/case.go +++ b/internal/use-case/main-use-case/division/case.go @@ -1,6 +1,7 @@ package division import ( + "errors" "fmt" e "simrs-vx/internal/domain/main-entities/division" "strconv" @@ -213,14 +214,20 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-read-detail-fail", Detail: "Database read detail failed", Raw: err, } - return pl.SetLogError(event, input) } pl.SetLogInfo(&event, nil, "complete") diff --git a/internal/use-case/main-use-case/installation/case.go b/internal/use-case/main-use-case/installation/case.go new file mode 100644 index 00000000..9a2689ec --- /dev/null +++ b/internal/use-case/main-use-case/installation/case.go @@ -0,0 +1,459 @@ +package installation + +import ( + "errors" + "fmt" + e "simrs-vx/internal/domain/main-entities/installation" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +const source = "installation" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Installation{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Installation + var dataList []e.Installation + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Installation + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Installation + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Installation + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/installation/helper.go b/internal/use-case/main-use-case/installation/helper.go new file mode 100644 index 00000000..3ad22892 --- /dev/null +++ b/internal/use-case/main-use-case/installation/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package installation + +import ( + e "simrs-vx/internal/domain/main-entities/installation" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Installation) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Code = inputSrc.Code + data.Name = inputSrc.Name + data.EncounterClass_Code = inputSrc.EncounterClass_Code +} diff --git a/internal/use-case/main-use-case/installation/lib.go b/internal/use-case/main-use-case/installation/lib.go new file mode 100644 index 00000000..30129aa3 --- /dev/null +++ b/internal/use-case/main-use-case/installation/lib.go @@ -0,0 +1,98 @@ +package installation + +import ( + e "simrs-vx/internal/domain/main-entities/installation" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.Installation, dbx ...*gorm.DB) (*e.Installation, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Installation, *e.MetaDto, error) { + data := []e.Installation{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.Installation{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Installation, error) { + data := e.Installation{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Installation, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.Installation, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/installation/tycovar.go b/internal/use-case/main-use-case/installation/tycovar.go new file mode 100644 index 00000000..072372e0 --- /dev/null +++ b/internal/use-case/main-use-case/installation/tycovar.go @@ -0,0 +1,32 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package installation + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/installation" +) + +type createMw func(input *e.CreateDto, data *e.Installation, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.Installation, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.Installation, tx *gorm.DB) error + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/unit/case.go b/internal/use-case/main-use-case/unit/case.go new file mode 100644 index 00000000..37082abf --- /dev/null +++ b/internal/use-case/main-use-case/unit/case.go @@ -0,0 +1,460 @@ +package unit + +import ( + "errors" + "fmt" + e "simrs-vx/internal/domain/main-entities/unit" + "strconv" + + dg "github.com/karincake/apem/db-gorm-pg" + d "github.com/karincake/dodol" + + pl "simrs-vx/pkg/logger" + + "gorm.io/gorm" +) + +const source = "unit" + +func Create(input e.CreateDto) (*d.Data, error) { + data := e.Unit{} + + setData(&input, &data) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err := dg.I.Transaction(func(tx *gorm.DB) error { + for i := range createPreMw { + mwName := fmt.Sprintf("createPreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := createPreMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBCreate") + _, err := CreateData(&data, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-create-fail", + Detail: "Database insert failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range createPostMw { + mwName := fmt.Sprintf("createPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + if err := createPostMw[i](&input, &data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + Data: data.ToResponse(), + }, nil +} + +func ReadList(input e.ReadListDto) (*d.Data, error) { + var data *e.Unit + var dataList []e.Unit + var metaList *e.MetaDto + var err error + + event := pl.Event{ + Feature: "ReadList", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readList") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + for i := range readListPreMw { + mwName := fmt.Sprintf("readListPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadList") + dataList, metaList, err = ReadListData(input, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-list-fail", + Detail: "Database read list failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readListPostMw { + mwName := fmt.Sprintf("readListPostMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readListPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "list-data", + "status": "fetched", + "page_number": strconv.Itoa(metaList.PageNumber), + "page_size": strconv.Itoa(metaList.PageSize), + "record_totalCount": strconv.Itoa(metaList.Count), + }, + Data: e.ToResponseList(dataList), + }, nil +} + +func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { + var data *e.Unit + var err error + + event := pl.Event{ + Feature: "ReadDetail", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "readDetail") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + for i := range readDetailPreMw { + mwName := fmt.Sprintf("readDetailPreMw[%d]", i) + + pl.SetLogInfo(&event, input, "started", mwName) + + if err := readDetailPreMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, input, "started", "DBReadDetail") + data, err = ReadDetailData(input, tx) + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + } + return pl.SetLogError(event, input) + + pl.SetLogInfo(&event, nil, "complete") + + for i := range readDetailPostMw { + mwName := fmt.Sprintf("readDetailPostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := readDetailPostMw[i](&input, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "fetched", + }, + Data: data.ToResponse(), + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Unit + var err error + + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, input, "started", "setUpdate") + setData(&input, data) + + for i := range updatePreMw { + mwName := fmt.Sprintf("updatePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBUpdate") + if err := UpdateData(*data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range updatePostMw { + mwName := fmt.Sprintf("updatePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := updatePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + Data: data.ToResponse(), + }, nil + +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + rdDto := e.ReadDetailDto{Id: input.Id} + var data *e.Unit + var err error + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + err = dg.I.Transaction(func(tx *gorm.DB) error { + pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") + data, err = ReadDetailData(rdDto, tx) + if err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-read-detail-fail", + Detail: "Database read detail failed", + Raw: err, + } + return pl.SetLogError(event, rdDto) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePreMw { + mwName := fmt.Sprintf("deletePreMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePreMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_PRE_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Pre-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + pl.SetLogInfo(&event, data, "started", "DBDelete") + if err := DeleteData(data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-delete-fail", + Detail: "Database delete failed", + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + + for i := range deletePostMw { + mwName := fmt.Sprintf("deletePostMw[%d]", i) + + pl.SetLogInfo(&event, data, "started", mwName) + + if err := deletePostMw[i](&rdDto, data, tx); err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "MW_POST_FAILED", // TODO: add to lang json + Detail: fmt.Sprintf("Post-middleware %s failed", mwName), + Raw: err, + } + return pl.SetLogError(event, data) + } + + pl.SetLogInfo(&event, nil, "complete") + } + + return nil + }) + + if err != nil { + return nil, err + } + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + Data: data.ToResponse(), + }, nil + +} diff --git a/internal/use-case/main-use-case/unit/helper.go b/internal/use-case/main-use-case/unit/helper.go new file mode 100644 index 00000000..f7729ec9 --- /dev/null +++ b/internal/use-case/main-use-case/unit/helper.go @@ -0,0 +1,23 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package unit + +import ( + e "simrs-vx/internal/domain/main-entities/unit" +) + +func setData[T *e.CreateDto | *e.UpdateDto](input T, data *e.Unit) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Installation_Id = inputSrc.Installation_Id + data.Code = inputSrc.Code + data.Name = inputSrc.Name +} diff --git a/internal/use-case/main-use-case/unit/lib.go b/internal/use-case/main-use-case/unit/lib.go new file mode 100644 index 00000000..a185ebb9 --- /dev/null +++ b/internal/use-case/main-use-case/unit/lib.go @@ -0,0 +1,98 @@ +package unit + +import ( + e "simrs-vx/internal/domain/main-entities/unit" + + dg "github.com/karincake/apem/db-gorm-pg" + gh "github.com/karincake/getuk" + "gorm.io/gorm" +) + +func CreateData(input *e.Unit, dbx ...*gorm.DB) (*e.Unit, error) { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&input).Error; err != nil { + return nil, err + } + + return input, nil +} + +func ReadListData(input e.ReadListDto, dbx ...*gorm.DB) ([]e.Unit, *e.MetaDto, error) { + data := []e.Unit{} + pagination := gh.Pagination{} + count := int64(0) + meta := e.MetaDto{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + tx = tx. + Model(&e.Unit{}). + // Joins("Patient"). // if needed + // Preload("Patient"). // if needed + Scopes(gh.Filter(input)). + Count(&count). + Scopes(gh.Paginate(input, &pagination)). + Order("\"CreatedAt\" DESC") + + if err := tx.Debug().Find(&data).Error; err != nil { + if err == gorm.ErrRecordNotFound { + return nil, &meta, nil + } + return nil, nil, err + + } + meta.Count = int(count) + meta.PageNumber = pagination.PageNumber + meta.PageSize = pagination.PageSize + return data, &meta, nil +} + +func ReadDetailData(input e.ReadDetailDto, dbx ...*gorm.DB) (*e.Unit, error) { + data := e.Unit{} + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.First(&data, input.Id).Error; err != nil { + return nil, err + } + + return &data, nil +} + +func UpdateData(input e.Unit, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Save(&input).Error +} + +func DeleteData(input *e.Unit, dbx ...*gorm.DB) error { + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + return tx.Delete(input).Error +} diff --git a/internal/use-case/main-use-case/unit/tycovar.go b/internal/use-case/main-use-case/unit/tycovar.go new file mode 100644 index 00000000..410328d3 --- /dev/null +++ b/internal/use-case/main-use-case/unit/tycovar.go @@ -0,0 +1,32 @@ +/* +DESCRIPTION: +A sample, part of the package that contains type, constants, and/or variables. + +In this sample it also provides type and variable regarding the needs of the +middleware to separate from main use-case which has the basic CRUD +functionality. The purpose of this is to make the code more maintainable. +*/ +package unit + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/unit" +) + +type createMw func(input *e.CreateDto, data *e.Unit, tx *gorm.DB) error +type readListMw func(input *e.ReadListDto, data *e.Unit, tx *gorm.DB) error +type readDetailMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error +type updateMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error +type deleteMw func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error + +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var readListPreMw []readListMw // .. +var readListPostMw []readListMw // .. +var readDetailPreMw []readDetailMw +var readDetailPostMw []readDetailMw +var updatePreMw []readDetailMw +var updatePostMw []readDetailMw +var deletePreMw []readDetailMw +var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/user/case.go b/internal/use-case/main-use-case/user/case.go index 0086fa32..fbcb65f3 100644 --- a/internal/use-case/main-use-case/user/case.go +++ b/internal/use-case/main-use-case/user/case.go @@ -1,6 +1,7 @@ package user import ( + "errors" "fmt" e "simrs-vx/internal/domain/main-entities/user" "strconv" @@ -213,14 +214,20 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "DBReadDetail") data, err = ReadDetailData(input, tx) - if err != nil { + if errors.Is(err, gorm.ErrRecordNotFound) { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-notFound", + Detail: fmt.Sprintf("Data with ID %v not found", input.Id), + Raw: err, + } + } else { event.Status = "failed" event.ErrInfo = pl.ErrorInfo{ Code: "data-read-detail-fail", Detail: "Database read detail failed", Raw: err, } - return pl.SetLogError(event, input) } pl.SetLogInfo(&event, nil, "complete")