diff --git a/cmd/main-api/config.yml-example b/cmd/main-api/config.yml-example index 22fdf651..30351abf 100644 --- a/cmd/main-api/config.yml-example +++ b/cmd/main-api/config.yml-example @@ -69,6 +69,7 @@ bpjsCfg: baseUrl: syncUrlCfg: + enable: false host: prefix: new-to-old diff --git a/internal/domain/main-entities/division/dto.go b/internal/domain/main-entities/division/dto.go index 30f0b238..d74b54f7 100644 --- a/internal/domain/main-entities/division/dto.go +++ b/internal/domain/main-entities/division/dto.go @@ -6,6 +6,7 @@ import ( ) type CreateDto struct { + Id *uint `json:"id"` Code string `json:"code" validate:"maxLength=10"` Name string `json:"name" validate:"maxLength=50"` Parent_Code *string `json:"parent_code"` diff --git a/internal/domain/main-entities/specialist/dto.go b/internal/domain/main-entities/specialist/dto.go index a67a830f..2d656556 100644 --- a/internal/domain/main-entities/specialist/dto.go +++ b/internal/domain/main-entities/specialist/dto.go @@ -8,6 +8,7 @@ import ( ) type CreateDto struct { + Id *uint `json:"id"` Code string `json:"code" validate:"maxLength=10"` Name string `json:"name" validate:"maxLength=50"` Unit_Code *string `json:"unit_code"` diff --git a/internal/domain/main-entities/subspecialist/dto.go b/internal/domain/main-entities/subspecialist/dto.go index 6e10b573..72959023 100644 --- a/internal/domain/main-entities/subspecialist/dto.go +++ b/internal/domain/main-entities/subspecialist/dto.go @@ -7,6 +7,7 @@ import ( ) type CreateDto struct { + Id *uint `json:"id"` Code string `json:"code" validate:"maxLength=10"` Name string `json:"name" validate:"maxLength=50"` Specialist_Code *string `json:"specialist_code"` diff --git a/internal/domain/main-entities/unit/dto.go b/internal/domain/main-entities/unit/dto.go index f272ecec..7b071a84 100644 --- a/internal/domain/main-entities/unit/dto.go +++ b/internal/domain/main-entities/unit/dto.go @@ -7,6 +7,7 @@ import ( ) type CreateDto struct { + Id *uint `json:"id"` Installation_Code *string `json:"installation_code"` Code string `json:"code" validate:"maxLength=10"` Name string `json:"name" validate:"maxLength=50"` diff --git a/internal/infra/sync-cfg/tycovar.go b/internal/infra/sync-cfg/tycovar.go index fdcda00b..6ae230fb 100644 --- a/internal/infra/sync-cfg/tycovar.go +++ b/internal/infra/sync-cfg/tycovar.go @@ -5,4 +5,5 @@ var O SyncUrlCfg = SyncUrlCfg{} type SyncUrlCfg struct { Prefix string `yaml:"prefix"` Host string `yaml:"host"` + Enable bool `yaml:"enable"` } diff --git a/internal/interface/simgos-sync-handler/division/handler.go b/internal/interface/simgos-sync-handler/division/handler.go new file mode 100644 index 00000000..0f87ca8a --- /dev/null +++ b/internal/interface/simgos-sync-handler/division/handler.go @@ -0,0 +1,66 @@ +package division + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/division" + esync "simrs-vx/internal/domain/sync-entities/log" + u "simrs-vx/internal/use-case/simgos-sync-use-case/division" +) + +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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/simgos-sync-handler.go b/internal/interface/simgos-sync-handler/simgos-sync-handler.go index aebcc9bb..6b63e1d6 100644 --- a/internal/interface/simgos-sync-handler/simgos-sync-handler.go +++ b/internal/interface/simgos-sync-handler/simgos-sync-handler.go @@ -2,6 +2,7 @@ package simgossynchandler import ( "net/http" + hc "simrs-vx/pkg/handler-crud-helper" /******************** infra ********************/ gs "simrs-vx/internal/infra/gorm-setting" @@ -14,11 +15,13 @@ import ( /******************** external ********************/ a "github.com/karincake/apem" - hk "github.com/karincake/hongkue" - /******************** internal ********************/ "simrs-vx/internal/interface/main-handler/home" + division "simrs-vx/internal/interface/simgos-sync-handler/division" installation "simrs-vx/internal/interface/simgos-sync-handler/installation" + specialist "simrs-vx/internal/interface/simgos-sync-handler/specialist" + subspecialist "simrs-vx/internal/interface/simgos-sync-handler/subspecialist" + unit "simrs-vx/internal/interface/simgos-sync-handler/unit" ) func SetRoutes() http.Handler { @@ -35,12 +38,11 @@ func SetRoutes() http.Handler { /******************** Source ******************/ prefix := "/new-to-old" - hk.GroupRoutes(prefix+"/v1/installation", r, hk.MapHandlerFunc{ - "POST /": installation.O.Create, - "POST /log": installation.O.CreateLog, - "PATCH /{id}": installation.O.Update, - "DELETE /{id}": installation.O.Delete, - }) + hc.SyncCrud(r, prefix+"/v1/installation", installation.O) + hc.SyncCrud(r, prefix+"/v1/unit", unit.O) + hc.SyncCrud(r, prefix+"/v1/division", division.O) + hc.SyncCrud(r, prefix+"/v1/specialist", specialist.O) + hc.SyncCrud(r, prefix+"/v1/subspecialist", subspecialist.O) return cmw.SetCors(handlerlogger.SetLog(r)) } diff --git a/internal/interface/simgos-sync-handler/specialist/handler.go b/internal/interface/simgos-sync-handler/specialist/handler.go new file mode 100644 index 00000000..79289472 --- /dev/null +++ b/internal/interface/simgos-sync-handler/specialist/handler.go @@ -0,0 +1,66 @@ +package specialist + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/specialist" + esync "simrs-vx/internal/domain/sync-entities/log" + u "simrs-vx/internal/use-case/simgos-sync-use-case/specialist" +) + +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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/subspecialist/handler.go b/internal/interface/simgos-sync-handler/subspecialist/handler.go new file mode 100644 index 00000000..fcd03c6b --- /dev/null +++ b/internal/interface/simgos-sync-handler/subspecialist/handler.go @@ -0,0 +1,66 @@ +package subspecialist + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/subspecialist" + esync "simrs-vx/internal/domain/sync-entities/log" + u "simrs-vx/internal/use-case/simgos-sync-use-case/subspecialist" +) + +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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/interface/simgos-sync-handler/unit/handler.go b/internal/interface/simgos-sync-handler/unit/handler.go new file mode 100644 index 00000000..b1cac1c5 --- /dev/null +++ b/internal/interface/simgos-sync-handler/unit/handler.go @@ -0,0 +1,66 @@ +package unit + +import ( + "net/http" + + rw "github.com/karincake/risoles" + // ua "github.com/karincake/tumpeng/auth/svc" + + e "simrs-vx/internal/domain/main-entities/unit" + esync "simrs-vx/internal/domain/sync-entities/log" + u "simrs-vx/internal/use-case/simgos-sync-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) CreateLog(w http.ResponseWriter, r *http.Request) { + dto := esync.SimxLogDto{} + if res := rw.ValidateStructByIOR(w, r.Body, &dto); !res { + return + } + res, err := u.CreateSimxLog(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 + } + + val := uint16(id) + dto.Id = &val + + 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{} + val := uint16(id) + dto.Id = &val + + res, err := u.Delete(dto) + rw.DataResponse(w, res, err) +} diff --git a/internal/use-case/main-use-case/division/case.go b/internal/use-case/main-use-case/division/case.go index c955aed7..8f2e8488 100644 --- a/internal/use-case/main-use-case/division/case.go +++ b/internal/use-case/main-use-case/division/case.go @@ -1,16 +1,19 @@ package division import ( - e "simrs-vx/internal/domain/main-entities/division" "strconv" dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" + "gorm.io/gorm" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" - "gorm.io/gorm" + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/division" + esync "simrs-vx/internal/domain/sync-entities/log" ) const source = "division" @@ -25,36 +28,32 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event) err := dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { - return err - } - if resData, err := CreateData(input, &event, tx); err != nil { return err } else { data = *resData + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -80,7 +79,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { @@ -131,7 +130,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { @@ -177,6 +176,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +184,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +227,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +235,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +265,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/division/middleware-runner.go b/internal/use-case/main-use-case/division/middleware-runner.go index 915cce28..51c90d77 100644 --- a/internal/use-case/main-use-case/division/middleware-runner.go +++ b/internal/use-case/main-use-case/division/middleware-runner.go @@ -1,35 +1,64 @@ package division import ( - e "simrs-vx/internal/domain/main-entities/division" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + sync "simrs-vx/internal/infra/sync-cfg" + + e "simrs-vx/internal/domain/main-entities/division" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Division) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +// ExecuteCreateMiddleware executes createlog middleware +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +68,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Division) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +87,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +105,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +124,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/division/middleware.go b/internal/use-case/main-use-case/division/middleware.go index f066ffb8..317b137a 100644 --- a/internal/use-case/main-use-case/division/middleware.go +++ b/internal/use-case/main-use-case/division/middleware.go @@ -1,9 +1,20 @@ package division +import ( + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/division" +) + // example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +func init() { + createPreMw = append(createPreMw, + createMw{Name: "create-unit", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "update-unit", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "delete-unit", Func: plugin.Delete}) +} diff --git a/internal/use-case/main-use-case/division/tycovar.go b/internal/use-case/main-use-case/division/tycovar.go index c7733117..cef873ee 100644 --- a/internal/use-case/main-use-case/division/tycovar.go +++ b/internal/use-case/main-use-case/division/tycovar.go @@ -12,11 +12,27 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/division" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Division, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +45,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/installation/middleware-runner.go b/internal/use-case/main-use-case/installation/middleware-runner.go index 5a8e2ad0..b85e3236 100644 --- a/internal/use-case/main-use-case/installation/middleware-runner.go +++ b/internal/use-case/main-use-case/installation/middleware-runner.go @@ -6,6 +6,8 @@ import ( "gorm.io/gorm" + sync "simrs-vx/internal/infra/sync-cfg" + e "simrs-vx/internal/domain/main-entities/installation" esync "simrs-vx/internal/domain/sync-entities/log" ) @@ -14,17 +16,23 @@ type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, nil) @@ -41,6 +49,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e // ExecuteCreateMiddleware executes create middleware func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, nil) @@ -56,6 +68,10 @@ func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, in } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Installation) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -71,6 +87,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Installation) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -86,6 +106,10 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, } func (me *middlewareRunner) RunUpdateMiddleware(middlewares []UpdateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, nil) @@ -101,6 +125,10 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []UpdateMw, input *e } func (me *middlewareRunner) RunDeleteMiddleware(middlewares []DeleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, nil) diff --git a/internal/use-case/main-use-case/installation/middleware.go b/internal/use-case/main-use-case/installation/middleware.go index dd4b0b42..b8dfa4c8 100644 --- a/internal/use-case/main-use-case/installation/middleware.go +++ b/internal/use-case/main-use-case/installation/middleware.go @@ -7,12 +7,10 @@ import ( // example of middleware func init() { createPreMw = append(createPreMw, - createMw{Name: "create-installation", Func: plugin.Create}, - ) + createMw{Name: "create-installation", Func: plugin.Create}) createSimxLogMw = append(createSimxLogMw, - createLogMw{Name: "create-log", Func: plugin.CreateLog}, - ) + createLogMw{Name: "create-log", Func: plugin.CreateLog}) updatePreMw = append(updatePreMw, updateMw{Name: "update-installation", Func: plugin.Update}) diff --git a/internal/use-case/main-use-case/specialist/case.go b/internal/use-case/main-use-case/specialist/case.go index c51a0002..f9f5442b 100644 --- a/internal/use-case/main-use-case/specialist/case.go +++ b/internal/use-case/main-use-case/specialist/case.go @@ -1,7 +1,6 @@ package specialist import ( - e "simrs-vx/internal/domain/main-entities/specialist" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -11,6 +10,11 @@ import ( pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/specialist" + esync "simrs-vx/internal/domain/sync-entities/log" ) const source = "specialist" @@ -25,36 +29,32 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event) err := dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { - return err - } - if resData, err := CreateData(input, &event, tx); err != nil { return err } else { data = *resData + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -80,7 +80,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { @@ -131,7 +131,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { @@ -177,6 +177,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +185,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +228,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +236,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +266,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/specialist/middleware-runner.go b/internal/use-case/main-use-case/specialist/middleware-runner.go index 4aa6cdd4..9a10d624 100644 --- a/internal/use-case/main-use-case/specialist/middleware-runner.go +++ b/internal/use-case/main-use-case/specialist/middleware-runner.go @@ -1,35 +1,64 @@ package specialist import ( - e "simrs-vx/internal/domain/main-entities/specialist" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + sync "simrs-vx/internal/infra/sync-cfg" + + e "simrs-vx/internal/domain/main-entities/specialist" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Specialist) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +// ExecuteCreateMiddleware executes createlog middleware +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +68,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Specialist) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +87,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +105,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +124,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/specialist/middleware.go b/internal/use-case/main-use-case/specialist/middleware.go index 298e51a8..5d119b01 100644 --- a/internal/use-case/main-use-case/specialist/middleware.go +++ b/internal/use-case/main-use-case/specialist/middleware.go @@ -1,9 +1,20 @@ package specialist +import ( + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/specialist" +) + // example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +func init() { + createPreMw = append(createPreMw, + createMw{Name: "create-unit", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "update-unit", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "delete-unit", Func: plugin.Delete}) +} diff --git a/internal/use-case/main-use-case/specialist/tycovar.go b/internal/use-case/main-use-case/specialist/tycovar.go index 16fa50b0..d0755799 100644 --- a/internal/use-case/main-use-case/specialist/tycovar.go +++ b/internal/use-case/main-use-case/specialist/tycovar.go @@ -12,11 +12,27 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/specialist" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Specialist, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +45,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Specialist, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/main-use-case/subspecialist/case.go b/internal/use-case/main-use-case/subspecialist/case.go index 51509c47..ca99750d 100644 --- a/internal/use-case/main-use-case/subspecialist/case.go +++ b/internal/use-case/main-use-case/subspecialist/case.go @@ -2,6 +2,8 @@ package subspecialist import ( e "simrs-vx/internal/domain/main-entities/subspecialist" + erc "simrs-vx/internal/domain/references/common" + esync "simrs-vx/internal/domain/sync-entities/log" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -25,36 +27,32 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event) err := dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { - return err - } - if resData, err := CreateData(input, &event, tx); err != nil { return err } else { data = *resData + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -80,7 +78,7 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { @@ -131,7 +129,7 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) + mwRunner := newMiddlewareRunner(&event) mwRunner.setMwType(pu.MWTPre) // Run pre-middleware if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { @@ -177,6 +175,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +183,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +226,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +234,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } - mwRunner.setMwType(pu.MWTPost) + mwRunner.setMwType(pu.MWTPre) // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +264,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/subspecialist/middleware-runner.go b/internal/use-case/main-use-case/subspecialist/middleware-runner.go index c7e5f285..ad1eba08 100644 --- a/internal/use-case/main-use-case/subspecialist/middleware-runner.go +++ b/internal/use-case/main-use-case/subspecialist/middleware-runner.go @@ -1,35 +1,63 @@ package subspecialist import ( - e "simrs-vx/internal/domain/main-entities/subspecialist" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + sync "simrs-vx/internal/infra/sync-cfg" + + e "simrs-vx/internal/domain/main-entities/subspecialist" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Subspecialist) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +67,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Subspecialist) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +86,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +104,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +123,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/subspecialist/tycovar.go b/internal/use-case/main-use-case/subspecialist/tycovar.go index ed4540b8..cd26e517 100644 --- a/internal/use-case/main-use-case/subspecialist/tycovar.go +++ b/internal/use-case/main-use-case/subspecialist/tycovar.go @@ -9,6 +9,8 @@ functionality. The purpose of this is to make the code more maintainable. package subspecialist import ( + elog "simrs-vx/internal/domain/sync-entities/log" + "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/subspecialist" @@ -16,7 +18,22 @@ import ( type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Subspecialist, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +46,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Subspecialist, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw 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 index 650c4511..75b1c4ab 100644 --- a/internal/use-case/main-use-case/unit/case.go +++ b/internal/use-case/main-use-case/unit/case.go @@ -2,6 +2,8 @@ package unit import ( e "simrs-vx/internal/domain/main-entities/unit" + erc "simrs-vx/internal/domain/references/common" + esync "simrs-vx/internal/domain/sync-entities/log" "strconv" dg "github.com/karincake/apem/db-gorm-pg" @@ -25,36 +27,32 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") + mwRunner := newMiddlewareRunner(&event) err := dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunCreateMiddleware(createPreMw, &input, &data); err != nil { - return err - } - if resData, err := CreateData(input, &event, tx); err != nil { return err } else { data = *resData + id := uint(data.Id) + input.Id = &id } - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunCreateMiddleware(createPostMw, &input, &data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunCreateMiddleware(createPreMw, &input); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.II{ "source": source, @@ -66,7 +64,6 @@ func Create(input e.CreateDto) (*d.Data, error) { } func ReadList(input e.ReadListDto) (*d.Data, error) { - var data *e.Unit var dataList []e.Unit var metaList *e.MetaDto var err error @@ -80,23 +77,9 @@ func ReadList(input e.ReadListDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readList") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunReadListMiddleware(readListPreMw, &input, data); err != nil { - return err - } - if dataList, metaList, err = ReadListData(input, &event, tx); err != nil { return err } - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunReadListMiddleware(readListPostMw, &input, data); err != nil { - return err - } - return nil }) @@ -131,23 +114,9 @@ func ReadDetail(input e.ReadDetailDto) (*d.Data, error) { pl.SetLogInfo(&event, input, "started", "readDetail") err = dg.I.Transaction(func(tx *gorm.DB) error { - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunReadDetailMiddleware(readDetailPreMw, &input, data); err != nil { - return err - } - if data, err = ReadDetailData(input, &event, tx); err != nil { return err } - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunReadDetailMiddleware(readDetailPostMw, &input, data); err != nil { - return err - } - return nil }) @@ -177,6 +146,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -184,32 +154,26 @@ func Update(input e.UpdateDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := UpdateData(input, data, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - - mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunUpdateMiddleware(readDetailPostMw, &rdDto, data); err != nil { + mwRunner.setMwType(pu.MWTPre) + // Run pre-middleware + if err := mwRunner.RunUpdateMiddleware(updatePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -233,6 +197,7 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") + mwRunner := newMiddlewareRunner(&event) err = dg.I.Transaction(func(tx *gorm.DB) error { pl.SetLogInfo(&event, rdDto, "started", "DBReadDetail") @@ -240,30 +205,26 @@ func Delete(input e.DeleteDto) (*d.Data, error) { return err } - mwRunner := newMiddlewareRunner(&event, tx) - mwRunner.setMwType(pu.MWTPre) - // Run pre-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPreMw, &rdDto, data); err != nil { - return err - } - + input.Id = &data.Id if err := DeleteData(data, &event, tx); err != nil { return err } mwRunner.setMwType(pu.MWTPost) - // Run post-middleware - if err := mwRunner.RunDeleteMiddleware(readDetailPostMw, &rdDto, data); err != nil { + // Run pre-middleware + if err := mwRunner.RunDeleteMiddleware(deletePreMw, &input); err != nil { return err } return nil }) - if err != nil { + if err = runLogMiddleware(err, input, mwRunner); err != nil { return nil, err } + pl.SetLogInfo(&event, nil, "complete") + return &d.Data{ Meta: d.IS{ "source": source, @@ -274,3 +235,32 @@ func Delete(input e.DeleteDto) (*d.Data, error) { }, nil } + +func runLogMiddleware(err error, input any, mwRunner *middlewareRunner) error { + var errMsg string + inputLog := esync.SimxLogDto{ + Payload: input, + Method: erc.CCCreate, + } + + if err != nil { + // Run log-middleware + errMsg = err.Error() + inputLog.ErrMessage = &errMsg + inputLog.IsSuccess = false + + // create log failed + if errMiddleware := mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); errMiddleware != nil { + return errMiddleware + } + return err + } + + // create log success + inputLog.IsSuccess = true + if err = mwRunner.RunCreateLogMiddleware(createSimxLogMw, &inputLog); err != nil { + return err + } + + return nil +} diff --git a/internal/use-case/main-use-case/unit/middleware-runner.go b/internal/use-case/main-use-case/unit/middleware-runner.go index fdce9d02..979548bc 100644 --- a/internal/use-case/main-use-case/unit/middleware-runner.go +++ b/internal/use-case/main-use-case/unit/middleware-runner.go @@ -1,35 +1,64 @@ package unit import ( - e "simrs-vx/internal/domain/main-entities/unit" pl "simrs-vx/pkg/logger" pu "simrs-vx/pkg/use-case-helper" "gorm.io/gorm" + + sync "simrs-vx/internal/infra/sync-cfg" + + e "simrs-vx/internal/domain/main-entities/unit" + esync "simrs-vx/internal/domain/sync-entities/log" ) type middlewareRunner struct { Event *pl.Event Tx *gorm.DB MwType pu.MWType + SyncOn bool } // NewMiddlewareExecutor creates a new middleware executor -func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { +func newMiddlewareRunner(event *pl.Event) *middlewareRunner { return &middlewareRunner{ - Event: event, - Tx: tx, + Event: event, + SyncOn: sync.O.Enable, } } // ExecuteCreateMiddleware executes create middleware -func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Unit) error { +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateLogMiddleware(middlewares []createLogMw, input *esync.SimxLogDto) error { + if !me.SyncOn { + return nil + } + + for _, middleware := range middlewares { + logData := pu.GetLogData(input, nil) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -39,6 +68,10 @@ func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e } func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Unit) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -54,6 +87,10 @@ func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, inpu } func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { logData := pu.GetLogData(input, data) @@ -68,13 +105,17 @@ func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, return nil } -func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []updateMw, input *e.UpdateDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } @@ -83,13 +124,17 @@ func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, inpu return nil } -func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []deleteMw, input *e.DeleteDto) error { + if !me.SyncOn { + return nil + } + for _, middleware := range middlewares { - logData := pu.GetLogData(input, data) + logData := pu.GetLogData(input, nil) pl.SetLogInfo(me.Event, logData, "started", middleware.Name) - if err := middleware.Func(input, data, me.Tx); err != nil { + if err := middleware.Func(input); err != nil { return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) } diff --git a/internal/use-case/main-use-case/unit/middleware.go b/internal/use-case/main-use-case/unit/middleware.go index bac48f4d..e3144448 100644 --- a/internal/use-case/main-use-case/unit/middleware.go +++ b/internal/use-case/main-use-case/unit/middleware.go @@ -1,9 +1,20 @@ package unit +import ( + plugin "simrs-vx/internal/use-case/simgos-sync-plugin/unit" +) + // example of middleware -// func init() { -// createPreMw = append(createPreMw, -// CreateMw{Name: "modif-input", Func: pm.ModifInput}, -// CreateMw{Name: "check-data", Func: pm.CheckData}, -// ) -// } +func init() { + createPreMw = append(createPreMw, + createMw{Name: "create-unit", Func: plugin.Create}) + + createSimxLogMw = append(createSimxLogMw, + createLogMw{Name: "create-log", Func: plugin.CreateLog}) + + updatePreMw = append(updatePreMw, + updateMw{Name: "update-unit", Func: plugin.Update}) + + deletePreMw = append(deletePreMw, + deleteMw{Name: "delete-unit", Func: plugin.Delete}) +} diff --git a/internal/use-case/main-use-case/unit/tycovar.go b/internal/use-case/main-use-case/unit/tycovar.go index e1a7c69f..bf717333 100644 --- a/internal/use-case/main-use-case/unit/tycovar.go +++ b/internal/use-case/main-use-case/unit/tycovar.go @@ -12,11 +12,27 @@ import ( "gorm.io/gorm" e "simrs-vx/internal/domain/main-entities/unit" + elog "simrs-vx/internal/domain/sync-entities/log" ) type createMw struct { Name string - Func func(input *e.CreateDto, data *e.Unit, tx *gorm.DB) error + Func func(input *e.CreateDto) error +} + +type createLogMw struct { + Name string + Func func(input *elog.SimxLogDto) error +} + +type updateMw struct { + Name string + Func func(input *e.UpdateDto) error +} + +type deleteMw struct { + Name string + Func func(input *e.DeleteDto) error } type readListMw struct { @@ -29,16 +45,17 @@ type readDetailMw struct { Func func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error } -type UpdateMw = readDetailMw -type DeleteMw = readDetailMw +type UpdateMw = updateMw +type DeleteMw = deleteMw -var createPreMw []createMw // preprocess middleware -var createPostMw []createMw // postprocess middleware +var createPreMw []createMw // preprocess middleware +var createPostMw []createMw // postprocess middleware +var createSimxLogMw []createLogMw var readListPreMw []readListMw // .. var readListPostMw []readListMw // .. var readDetailPreMw []readDetailMw var readDetailPostMw []readDetailMw -var updatePreMw []readDetailMw +var updatePreMw []updateMw var updatePostMw []readDetailMw -var deletePreMw []readDetailMw +var deletePreMw []deleteMw var deletePostMw []readDetailMw diff --git a/internal/use-case/simgos-sync-plugin/division/plugin.go b/internal/use-case/simgos-sync-plugin/division/plugin.go new file mode 100644 index 00000000..54c1403c --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/division/plugin.go @@ -0,0 +1,167 @@ +package division + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + sync "simrs-vx/internal/infra/sync-cfg" + + e "simrs-vx/internal/domain/main-entities/division" + elog "simrs-vx/internal/domain/sync-entities/log" + + d "github.com/karincake/dodol" +) + +func Create(input *e.CreateDto) error { + endpoint := getPrefixEndpoint() + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("PATCH", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("DELETE", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/division", sync.O.Host, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/installation/plugin.go b/internal/use-case/simgos-sync-plugin/installation/plugin.go index 06c9bebe..f2495139 100644 --- a/internal/use-case/simgos-sync-plugin/installation/plugin.go +++ b/internal/use-case/simgos-sync-plugin/installation/plugin.go @@ -11,6 +11,8 @@ import ( e "simrs-vx/internal/domain/main-entities/installation" elog "simrs-vx/internal/domain/sync-entities/log" + + d "github.com/karincake/dodol" ) func Create(input *e.CreateDto) error { @@ -34,15 +36,18 @@ func Create(input *e.CreateDto) error { } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf(resp.Status) - } - - _, err = io.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return err } + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + return nil } @@ -68,15 +73,18 @@ func CreateLog(input *elog.SimxLogDto) error { } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf(resp.Status) - } - - _, err = io.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return err } + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + return nil } @@ -102,15 +110,18 @@ func Update(input *e.UpdateDto) error { } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf(resp.Status) - } - - _, err = io.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return err } + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + return nil } @@ -136,15 +147,18 @@ func Delete(input *e.DeleteDto) error { } defer resp.Body.Close() - if resp.StatusCode != http.StatusOK { - return fmt.Errorf(resp.Status) - } - - _, err = io.ReadAll(resp.Body) + bodyBytes, err := io.ReadAll(resp.Body) if err != nil { return err } + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + return nil } diff --git a/internal/use-case/simgos-sync-plugin/specialist/plugin.go b/internal/use-case/simgos-sync-plugin/specialist/plugin.go new file mode 100644 index 00000000..892d7a17 --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/specialist/plugin.go @@ -0,0 +1,167 @@ +package specialist + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + sync "simrs-vx/internal/infra/sync-cfg" + + e "simrs-vx/internal/domain/main-entities/specialist" + elog "simrs-vx/internal/domain/sync-entities/log" + + d "github.com/karincake/dodol" +) + +func Create(input *e.CreateDto) error { + endpoint := getPrefixEndpoint() + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("PATCH", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("DELETE", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/specialist", sync.O.Host, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/subspecialist/plugin.go b/internal/use-case/simgos-sync-plugin/subspecialist/plugin.go new file mode 100644 index 00000000..15d6f650 --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/subspecialist/plugin.go @@ -0,0 +1,167 @@ +package subspecialist + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + sync "simrs-vx/internal/infra/sync-cfg" + + e "simrs-vx/internal/domain/main-entities/subspecialist" + elog "simrs-vx/internal/domain/sync-entities/log" + + d "github.com/karincake/dodol" +) + +func Create(input *e.CreateDto) error { + endpoint := getPrefixEndpoint() + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("PATCH", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("DELETE", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/subspecialist", sync.O.Host, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-plugin/unit/plugin.go b/internal/use-case/simgos-sync-plugin/unit/plugin.go new file mode 100644 index 00000000..e854d898 --- /dev/null +++ b/internal/use-case/simgos-sync-plugin/unit/plugin.go @@ -0,0 +1,167 @@ +package unit + +import ( + "bytes" + "encoding/json" + "fmt" + "io" + "net/http" + + sync "simrs-vx/internal/infra/sync-cfg" + + e "simrs-vx/internal/domain/main-entities/unit" + elog "simrs-vx/internal/domain/sync-entities/log" + + d "github.com/karincake/dodol" +) + +func Create(input *e.CreateDto) error { + endpoint := getPrefixEndpoint() + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func CreateLog(input *elog.SimxLogDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := prefixEndpoint + "/log" + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func Update(input *e.UpdateDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("PATCH", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func Delete(input *e.DeleteDto) error { + prefixEndpoint := getPrefixEndpoint() + endpoint := fmt.Sprintf("%s/%v", prefixEndpoint, *input.Id) + + jsonData, err := json.Marshal(input) + if err != nil { + return fmt.Errorf("failed to encode JSON: %w", err) + } + + req, err := http.NewRequest("DELETE", endpoint, bytes.NewReader(jsonData)) + if err != nil { + return err + } + + req.Header.Set("Content-Type", "application/json") + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return err + } + defer resp.Body.Close() + + bodyBytes, err := io.ReadAll(resp.Body) + if err != nil { + return err + } + + if resp.StatusCode != http.StatusOK { + errors := d.FieldError{} + _ = json.Unmarshal(bodyBytes, &errors) + + return fmt.Errorf(errors.Message) + } + + return nil +} + +func getPrefixEndpoint() string { + return fmt.Sprintf("%s%s/v1/unit", sync.O.Host, sync.O.Prefix) +} diff --git a/internal/use-case/simgos-sync-use-case/division/case.go b/internal/use-case/simgos-sync-use-case/division/case.go new file mode 100644 index 00000000..62c04143 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/division/case.go @@ -0,0 +1,197 @@ +package division + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/division" + esimgos "simrs-vx/internal/domain/simgos-entities/division" + esync "simrs-vx/internal/domain/sync-entities/division" + elog "simrs-vx/internal/domain/sync-entities/log" +) + +const source = "division" + +func Create(input e.CreateDto) (*d.Data, error) { + var ( + sgData *esimgos.MUnit + syncLink *esync.DivisionLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(*input.Id, sgData.KodeUnit, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // Step 2: Update Simgos + if err = UpdateSimgosData(input, syncLink, &event, tx); err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete Simgos + err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(uint(*input.Id), sgData.KodeUnit, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/division/helper.go b/internal/use-case/simgos-sync-use-case/division/helper.go new file mode 100644 index 00000000..e180d771 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/division/helper.go @@ -0,0 +1,56 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package division + +import ( + "encoding/json" + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/division" + esimgos "simrs-vx/internal/domain/simgos-entities/division" + esync "simrs-vx/internal/domain/sync-entities/division" + esyncLog "simrs-vx/internal/domain/sync-entities/log" +) + +func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MUnit) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.NamaUnit = inputSrc.Name + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.DivisionSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.DivisionLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/division/lib.go b/internal/use-case/simgos-sync-use-case/division/lib.go new file mode 100644 index 00000000..681be276 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/division/lib.go @@ -0,0 +1,188 @@ +package division + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/division" + esimgos "simrs-vx/internal/domain/simgos-entities/division" + esync "simrs-vx/internal/domain/sync-entities/division" + esynclog "simrs-vx/internal/domain/sync-entities/log" +) + +var now = time.Now() + +func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MUnit, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setDataSimgos(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MUnit, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MUnit{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"kode_unit\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.DivisionLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := setDataSimgos(&input) + data.KodeUnit = dataSimgos.Simgos_Id + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func HardDeleteSimgosData(data *esimgos.MUnit, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx. + Delete(&data).Error; 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") + return nil +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.DivisionLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.DivisionLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.DivisionLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.DivisionLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; 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") + return nil +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/division/middleware-runner.go b/internal/use-case/simgos-sync-use-case/division/middleware-runner.go new file mode 100644 index 00000000..dad68114 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/division/middleware-runner.go @@ -0,0 +1,104 @@ +package division + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/division" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Division) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Division) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Division) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/simgos-sync-use-case/division/middleware.go b/internal/use-case/simgos-sync-use-case/division/middleware.go new file mode 100644 index 00000000..f066ffb8 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/division/middleware.go @@ -0,0 +1,9 @@ +package division + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/simgos-sync-use-case/division/tycovar.go b/internal/use-case/simgos-sync-use-case/division/tycovar.go new file mode 100644 index 00000000..c7733117 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/division/tycovar.go @@ -0,0 +1,44 @@ +/* +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 division + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/division" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Division, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Division, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Division, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +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/simgos-sync-use-case/installation/case.go b/internal/use-case/simgos-sync-use-case/installation/case.go index 6c3a79bd..edbf709d 100644 --- a/internal/use-case/simgos-sync-use-case/installation/case.go +++ b/internal/use-case/simgos-sync-use-case/installation/case.go @@ -1,26 +1,27 @@ package installation import ( - "errors" - esimgos "simrs-vx/internal/domain/simgos-entities/installation" - esync "simrs-vx/internal/domain/sync-entities/log" - - dg "github.com/karincake/apem/db-gorm-pg" d "github.com/karincake/dodol" pl "simrs-vx/pkg/logger" "gorm.io/gorm" + db "simrs-vx/pkg/dualtrx-helper" + e "simrs-vx/internal/domain/main-entities/installation" + esimgos "simrs-vx/internal/domain/simgos-entities/installation" + esync "simrs-vx/internal/domain/sync-entities/installation" + elog "simrs-vx/internal/domain/sync-entities/log" ) const source = "installation" func Create(input e.CreateDto) (*d.Data, error) { var ( - txSync = dg.I.Begin() - txSimgos = dg.IS["simrs"].Begin() + sgData *esimgos.MInstalasi + syncLink *esync.InstallationLink + err error ) event := pl.Event{ @@ -31,30 +32,26 @@ func Create(input e.CreateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") - // STEP 1: Insert to simgos - sgData, err := CreateSimgosData(input, &event, txSimgos) + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(*input.Id, sgData.No_Instalasi, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + if err != nil { - return nil, err - } - - // STEP 2: Insert to Link - if err = CreateLinkData(*input.Id, sgData.No_Instalasi, &event, txSync); err != nil { - txSimgos.Rollback() - return nil, err - } - - // STEP 3: Commit two trx - if err = txSimgos.Commit().Error; err != nil { - txSimgos.Rollback() - txSync.Rollback() - return nil, err - } - - if err = txSync.Commit().Error; err != nil { - // STEP 4: Rollback Partial - go func() { - _ = DeleteSimgosData(sgData, &event) - }() + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } return nil, err } @@ -69,7 +66,7 @@ func Create(input e.CreateDto) (*d.Data, error) { }, nil } -func CreateSimxLog(input esync.SimxLogDto) (*d.Data, error) { +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { event := pl.Event{ Feature: "Create", Source: source, @@ -78,14 +75,13 @@ func CreateSimxLog(input esync.SimxLogDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "create") - err := dg.I.Transaction(func(tx *gorm.DB) error { - // InsertSimxLog + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log if err := CreateLogData(input, &event, tx); err != nil { return err } - pl.SetLogInfo(&event, nil, "complete") - return nil }) @@ -105,13 +101,6 @@ func CreateSimxLog(input esync.SimxLogDto) (*d.Data, error) { } func Update(input e.UpdateDto) (*d.Data, error) { - var ( - txSync = dg.I.Begin() - txSimgos = dg.IS["simrs"].Begin() - sgData *esimgos.MInstalasi - err error - ) - event := pl.Event{ Feature: "Update", Source: source, @@ -120,51 +109,21 @@ func Update(input e.UpdateDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "update") - // STEP 1: Get Installation Link - syncLink, errGetLink := ReadDetailLinkData(*input.Id, &event) - if errGetLink != nil { - if !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, err - } - } - - if errGetLink != nil && errors.Is(errGetLink, gorm.ErrRecordNotFound) { - // STEP 2.1: Insert to simgos - sgData, err = CreateSimgosData(input.CreateDto, &event, txSimgos) - if err != nil { - return nil, err - } - - // STEP 2.2: Insert to Link - simxId := uint(*input.Id) - if err = CreateLinkData(simxId, sgData.No_Instalasi, &event, txSync); err != nil { - txSimgos.Rollback() - return nil, err - } - } else { - // Step 3.1: Update Simgos - err = UpdateSimgosData(input, syncLink, &event, txSimgos) - if err != nil { - return nil, err - } - } - - // STEP 4: Commit two trx - if err = txSimgos.Commit().Error; err != nil { - txSimgos.Rollback() - txSync.Rollback() + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { return nil, err } - if errGetLink != nil { - if err = txSync.Commit().Error; err != nil { - // STEP 5.1: Rollback Partial - go func() { - _ = DeleteSimgosData(sgData, &event) - }() - return nil, err + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // Step 2: Update Simgos + if err = UpdateSimgosData(input, syncLink, &event, tx); err != nil { + return err } - } + + return nil + }) pl.SetLogInfo(&event, nil, "complete") @@ -178,12 +137,7 @@ func Update(input e.UpdateDto) (*d.Data, error) { } func Delete(input e.DeleteDto) (*d.Data, error) { - var ( - txSync = dg.I.Begin() - txSimgos = dg.IS["simrs"].Begin() - sgData *esimgos.MInstalasi - err error - ) + var isLinkDeleted bool event := pl.Event{ Feature: "Delete", @@ -193,53 +147,43 @@ func Delete(input e.DeleteDto) (*d.Data, error) { // Start log pl.SetLogInfo(&event, input, "started", "delete") - // STEP 1: Get Installation Link - syncLink, errGetLink := ReadDetailLinkData(*input.Id, &event) - if errGetLink != nil { - if !errors.Is(err, gorm.ErrRecordNotFound) { - return nil, err - } + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err } - if errGetLink == nil { - // STEP 2: Get Simgos - sgData, err = ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete Simgos + err = SoftDeleteSimgosData(sgData, &event, tx.Simgos) if err != nil { - return nil, err + return err } - // STEP 3: Delete M_Instalation Simgos - err = DeleteSimgosData(sgData, &event, txSimgos) + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) if err != nil { - return nil, err + return err } - // STEP 4: Delete Installation Link - err = DeleteLinkData(syncLink, &event, txSync) - if err != nil { - txSimgos.Rollback() - return nil, err - } + isLinkDeleted = true + return nil + }) - // STEP 4: Commit two trx - if err = txSimgos.Commit().Error; err != nil { - txSimgos.Rollback() - txSync.Rollback() - return nil, err - } - - if err = txSync.Commit().Error; err != nil { - // STEP 5: Rollback Partial + if err != nil { + if isLinkDeleted { go func() { - inputRollback := e.UpdateDto{ - CreateDto: e.CreateDto{ - Name: sgData.Nama_Instalasi, - }, - } - _ = UpdateSimgosData(inputRollback, syncLink, &event) + _, _ = CreateLinkData(uint(*input.Id), sgData.No_Instalasi, &event) }() - return nil, err } + + return nil, err } pl.SetLogInfo(&event, nil, "complete") diff --git a/internal/use-case/simgos-sync-use-case/installation/helper.go b/internal/use-case/simgos-sync-use-case/installation/helper.go index 51316d79..aa33ef4b 100644 --- a/internal/use-case/simgos-sync-use-case/installation/helper.go +++ b/internal/use-case/simgos-sync-use-case/installation/helper.go @@ -10,7 +10,7 @@ import ( erc "simrs-vx/internal/domain/references/common" esimgos "simrs-vx/internal/domain/simgos-entities/installation" esync "simrs-vx/internal/domain/sync-entities/installation" - "simrs-vx/internal/domain/sync-entities/log" + esyncLog "simrs-vx/internal/domain/sync-entities/log" ) func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MInstalasi) { @@ -29,7 +29,7 @@ func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MInstal return } -func setDataSimxLog(input *log.SimxLogDto) (data esync.InstallationSimxLog) { +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.InstallationSimxLog) { // encode to JSON jsonData, _ := json.MarshalIndent(input.Payload, "", " ") jsonString := string(jsonData) diff --git a/internal/use-case/simgos-sync-use-case/installation/lib.go b/internal/use-case/simgos-sync-use-case/installation/lib.go index 3e7ca854..9b057ece 100644 --- a/internal/use-case/simgos-sync-use-case/installation/lib.go +++ b/internal/use-case/simgos-sync-use-case/installation/lib.go @@ -1,9 +1,9 @@ package installation import ( - esynclog "simrs-vx/internal/domain/sync-entities/log" plh "simrs-vx/pkg/lib-helper" pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" "time" dg "github.com/karincake/apem/db-gorm-pg" @@ -12,6 +12,7 @@ import ( e "simrs-vx/internal/domain/main-entities/installation" esimgos "simrs-vx/internal/domain/simgos-entities/installation" esync "simrs-vx/internal/domain/sync-entities/installation" + esynclog "simrs-vx/internal/domain/sync-entities/log" ) var now = time.Now() @@ -45,7 +46,9 @@ func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MInstalasi if err := tx. Where("\"no_instalasi\" = ?", simgosId). First(&data).Error; err != nil { - return nil, err + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } } pl.SetLogInfo(event, nil, "complete") @@ -79,7 +82,32 @@ func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.InstallationLink, eve return nil } -func DeleteSimgosData(data *esimgos.MInstalasi, event *pl.Event, dbx ...*gorm.DB) error { +func HardDeleteSimgosData(data *esimgos.MInstalasi, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx. + Delete(&data).Error; 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") + return nil +} + +func SoftDeleteSimgosData(data *esimgos.MInstalasi, event *pl.Event, dbx ...*gorm.DB) error { pl.SetLogInfo(event, data, "started", "DBDelete") var tx *gorm.DB @@ -105,7 +133,7 @@ func DeleteSimgosData(data *esimgos.MInstalasi, event *pl.Event, dbx ...*gorm.DB return nil } -func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) error { +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.InstallationLink, error) { pl.SetLogInfo(event, nil, "started", "DBCreate") data := setDataSimxLink(simxId, simgosId) @@ -117,11 +145,11 @@ func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) err } if err := tx.Create(&data).Error; err != nil { - return plh.HandleCreateError(data, event, err) + return nil, plh.HandleCreateError(data, event, err) } pl.SetLogInfo(event, nil, "complete") - return nil + return &data, nil } func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.InstallationLink, error) { @@ -133,7 +161,9 @@ func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.InstallationLink if err := tx. Where("\"Simx_Id\" = ?", simxId). First(&data).Error; err != nil { - return nil, err + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } } pl.SetLogInfo(event, nil, "complete") diff --git a/internal/use-case/simgos-sync-use-case/specialist/case.go b/internal/use-case/simgos-sync-use-case/specialist/case.go new file mode 100644 index 00000000..cf76771c --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/specialist/case.go @@ -0,0 +1,197 @@ +package specialist + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/specialist" + esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + elog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +const source = "specialist" + +func Create(input e.CreateDto) (*d.Data, error) { + var ( + sgData *esimgos.MPolihfis + syncLink *esync.SpecialistLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(*input.Id, sgData.Id, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Installation Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // Step 2: Update Simgos + err = UpdateSimgosData(input, syncLink, &event, tx) + if err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete Simgos + err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(uint(*input.Id), sgData.Id, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/specialist/helper.go b/internal/use-case/simgos-sync-use-case/specialist/helper.go new file mode 100644 index 00000000..95839354 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/specialist/helper.go @@ -0,0 +1,60 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package specialist + +import ( + "encoding/json" + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/specialist" + esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + esyncLog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MPolihfis) { + 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.Poliklinik = inputSrc.Name + data.Active = 1 + data.Status = 1 + + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.SpecialistSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.SpecialistLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/specialist/lib.go b/internal/use-case/simgos-sync-use-case/specialist/lib.go new file mode 100644 index 00000000..c7123f0b --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/specialist/lib.go @@ -0,0 +1,188 @@ +package specialist + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/specialist" + esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + esynclog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +var now = time.Now() + +func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MPolihfis, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setDataSimgos(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MPolihfis, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MPolihfis{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"id\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.SpecialistLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := setDataSimgos(&input) + data.Id = dataSimgos.Simgos_Id + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func HardDeleteSimgosData(data *esimgos.MPolihfis, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx. + Delete(&data).Error; 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") + return nil +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.SpecialistLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.SpecialistLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.SpecialistLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.SpecialistLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; 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") + return nil +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/specialist/middleware-runner.go b/internal/use-case/simgos-sync-use-case/specialist/middleware-runner.go new file mode 100644 index 00000000..938c1f92 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/specialist/middleware-runner.go @@ -0,0 +1,104 @@ +package specialist + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/specialist" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Specialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/simgos-sync-use-case/specialist/middleware.go b/internal/use-case/simgos-sync-use-case/specialist/middleware.go new file mode 100644 index 00000000..298e51a8 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/specialist/middleware.go @@ -0,0 +1,9 @@ +package specialist + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/simgos-sync-use-case/specialist/tycovar.go b/internal/use-case/simgos-sync-use-case/specialist/tycovar.go new file mode 100644 index 00000000..16fa50b0 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/specialist/tycovar.go @@ -0,0 +1,44 @@ +/* +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 specialist + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/specialist" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Specialist, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Specialist, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Specialist, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +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/simgos-sync-use-case/subspecialist/case.go b/internal/use-case/simgos-sync-use-case/subspecialist/case.go new file mode 100644 index 00000000..2c633101 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/subspecialist/case.go @@ -0,0 +1,199 @@ +package subspecialist + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/subspecialist" + //esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + elog "simrs-vx/internal/domain/sync-entities/log" + //esync "simrs-vx/internal/domain/sync-entities/subspecialist" +) + +const source = "subspecialist" + +func Create(input e.CreateDto) (*d.Data, error) { + //var ( + // sgData *esimgos.MUnit + // syncLink *esync.SubspecialistLink + // err error + //) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + //err = db.WithDualTx(func(tx *db.Dualtx) error { + // // STEP 1: Insert to simgos + // sgData, err = CreateSimgosData(input, &event, tx.Simgos) + // if err != nil { + // return err + // } + // + // // STEP 2: Insert to Link + // syncLink, err = CreateLinkData(*input.Id, sgData.KodeUnit, &event, tx.Sync) + // if err != nil { + // return err + // } + // + // return nil + //}) + // + //if err != nil { + // if syncLink != nil { + // go func() { _ = DeleteLinkData(syncLink, &event) }() + // } + // return nil, err + //} + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + pl.SetLogInfo(&event, nil, "complete") + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + //// STEP 1: Get Link + //syncLink, err := ReadDetailLinkData(*input.Id, &event) + //if err != nil { + // return nil, err + //} + // + //tx := db.NewTx() + //err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // // Step 2: Update Simgos + // if err = UpdateSimgosData(input, syncLink, &event, tx); err != nil { + // return err + // } + // + // return nil + //}) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + //var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + //// STEP 1: Get Link + //syncLink, err := ReadDetailLinkData(*input.Id, &event) + //if err != nil { + // return nil, err + //} + // + //// STEP 2: Get Simgos + //sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + //if err != nil { + // return nil, err + //} + // + //err = db.WithDualTx(func(tx *db.Dualtx) error { + // // STEP 3: Delete Simgos + // err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + // if err != nil { + // return err + // } + // + // // STEP 4: Delete Link + // err = DeleteLinkData(syncLink, &event, tx.Sync) + // if err != nil { + // return err + // } + // + // isLinkDeleted = true + // return nil + //}) + // + //if err != nil { + // if isLinkDeleted { + // go func() { + // _, _ = CreateLinkData(uint(*input.Id), sgData.KodeUnit, &event) + // }() + // } + // return nil, err + //} + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/subspecialist/helper.go b/internal/use-case/simgos-sync-use-case/subspecialist/helper.go new file mode 100644 index 00000000..898f161c --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/subspecialist/helper.go @@ -0,0 +1,59 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package subspecialist + +import ( + "encoding/json" + erc "simrs-vx/internal/domain/references/common" + //esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + esyncLog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +//func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MPolihfis) { +// 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.Poliklinik = inputSrc.Name +// data.CodePolirs = *inputSrc.Unit_Code +// data.Active = 1 +// data.Status = 1 +// +// return +//} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.SpecialistSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.SpecialistLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/subspecialist/lib.go b/internal/use-case/simgos-sync-use-case/subspecialist/lib.go new file mode 100644 index 00000000..781e899d --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/subspecialist/lib.go @@ -0,0 +1,187 @@ +package subspecialist + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + //esimgos "simrs-vx/internal/domain/simgos-entities/specialist" + esynclog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/specialist" +) + +var now = time.Now() + +//func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MPolihfis, error) { +// pl.SetLogInfo(event, nil, "started", "DBCreate") +// +// data := setDataSimgos(&input) +// +// var tx *gorm.DB +// if len(dbx) > 0 { +// tx = dbx[0] +// } else { +// tx = dg.IS["simrs"] +// } +// +// if err := tx.Create(&data).Error; err != nil { +// return nil, plh.HandleCreateError(input, event, err) +// } +// +// pl.SetLogInfo(event, nil, "complete") +// return &data, nil +//} + +//func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MPolihfis, error) { +// pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") +// data := esimgos.MPolihfis{} +// +// var tx = dg.IS["simrs"] +// +// if err := tx. +// Where("\"kode_unit\" = ?", simgosId). +// First(&data).Error; err != nil { +// if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { +// return nil, processedErr +// } +// } +// +// pl.SetLogInfo(event, nil, "complete") +// return &data, nil +//} + +//func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.SpecialistLink, event *pl.Event, dbx ...*gorm.DB) error { +// pl.SetLogInfo(event, input, "started", "DBUpdate") +// +// data := setDataSimgos(&input) +// data.Id = dataSimgos.Simgos_Id +// +// var tx *gorm.DB +// if len(dbx) > 0 { +// tx = dbx[0] +// } else { +// tx = dg.IS["simrs"] +// } +// +// if err := tx.Save(&data).Error; err != nil { +// event.Status = "failed" +// event.ErrInfo = pl.ErrorInfo{ +// Code: "data-update-fail", +// Detail: "Database update failed", +// Raw: err, +// } +// return pl.SetLogError(event, input) +// } +// +// pl.SetLogInfo(event, nil, "complete") +// return nil +//} + +//func HardDeleteSimgosData(data *esimgos.MPolihfis, event *pl.Event, dbx ...*gorm.DB) error { +// pl.SetLogInfo(event, data, "started", "DBDelete") +// +// var tx *gorm.DB +// if len(dbx) > 0 { +// tx = dbx[0] +// } else { +// tx = dg.IS["simrs"] +// } +// +// if err := tx. +// Delete(&data).Error; 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") +// return nil +//} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.SpecialistLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.SpecialistLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.SpecialistLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.SpecialistLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; 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") + return nil +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/subspecialist/middleware-runner.go b/internal/use-case/simgos-sync-use-case/subspecialist/middleware-runner.go new file mode 100644 index 00000000..134041f1 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/subspecialist/middleware-runner.go @@ -0,0 +1,104 @@ +package subspecialist + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/subspecialist" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Subspecialist) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/simgos-sync-use-case/subspecialist/middleware.go b/internal/use-case/simgos-sync-use-case/subspecialist/middleware.go new file mode 100644 index 00000000..ad2ba452 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/subspecialist/middleware.go @@ -0,0 +1,9 @@ +package subspecialist + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/simgos-sync-use-case/subspecialist/tycovar.go b/internal/use-case/simgos-sync-use-case/subspecialist/tycovar.go new file mode 100644 index 00000000..ed4540b8 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/subspecialist/tycovar.go @@ -0,0 +1,44 @@ +/* +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 subspecialist + +import ( + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/subspecialist" +) + +type createMw struct { + Name string + Func func(input *e.CreateDto, data *e.Subspecialist, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Subspecialist, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Subspecialist, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +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/simgos-sync-use-case/unit/case.go b/internal/use-case/simgos-sync-use-case/unit/case.go new file mode 100644 index 00000000..e17a8b22 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/unit/case.go @@ -0,0 +1,198 @@ +package unit + +import ( + pl "simrs-vx/pkg/logger" + + d "github.com/karincake/dodol" + "gorm.io/gorm" + + db "simrs-vx/pkg/dualtrx-helper" + + e "simrs-vx/internal/domain/main-entities/unit" + esimgos "simrs-vx/internal/domain/simgos-entities/unit" + elog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/unit" +) + +const source = "unit" + +func Create(input e.CreateDto) (*d.Data, error) { + var ( + sgData *esimgos.MPloy + syncLink *esync.UnitLink + err error + ) + + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 1: Insert to simgos + sgData, err = CreateSimgosData(input, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 2: Insert to Link + syncLink, err = CreateLinkData(*input.Id, sgData.Kode, &event, tx.Sync) + if err != nil { + return err + } + + return nil + }) + + if err != nil { + if syncLink != nil { + go func() { _ = DeleteLinkData(syncLink, &event) }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func CreateSimxLog(input elog.SimxLogDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Create", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "create") + + tx := db.NewTx() + err := tx.Sync.Transaction(func(tx *gorm.DB) error { + // Insert to Log + if err := CreateLogData(input, &event, tx); err != nil { + return err + } + + return nil + }) + + if err != nil { + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.II{ + "source": source, + "structure": "single-data", + "status": "created", + }, + }, nil +} + +func Update(input e.UpdateDto) (*d.Data, error) { + event := pl.Event{ + Feature: "Update", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "update") + + // STEP 1: Get Installation Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + tx := db.NewTx() + err = tx.Simgos.Transaction(func(tx *gorm.DB) error { + // Step 2: Update Simgos + err = UpdateSimgosData(input, syncLink, &event, tx) + if err != nil { + return err + } + + return nil + }) + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "updated", + }, + }, nil +} + +func Delete(input e.DeleteDto) (*d.Data, error) { + var isLinkDeleted bool + + event := pl.Event{ + Feature: "Delete", + Source: source, + } + + // Start log + pl.SetLogInfo(&event, input, "started", "delete") + + // STEP 1: Get Installation Link + syncLink, err := ReadDetailLinkData(*input.Id, &event) + if err != nil { + return nil, err + } + + // STEP 2: Get Simgos + sgData, err := ReadDetailSimgosData(uint16(syncLink.Simgos_Id), &event) + if err != nil { + return nil, err + } + + err = db.WithDualTx(func(tx *db.Dualtx) error { + // STEP 3: Delete M_Poly Simgos + err = HardDeleteSimgosData(sgData, &event, tx.Simgos) + if err != nil { + return err + } + + // STEP 4: Delete Installation Link + err = DeleteLinkData(syncLink, &event, tx.Sync) + if err != nil { + return err + } + + isLinkDeleted = true + return nil + }) + + if err != nil { + if isLinkDeleted { + go func() { + _, _ = CreateLinkData(uint(*input.Id), sgData.Kode, &event) + }() + } + return nil, err + } + + pl.SetLogInfo(&event, nil, "complete") + + return &d.Data{ + Meta: d.IS{ + "source": source, + "structure": "single-data", + "status": "deleted", + }, + }, nil + +} diff --git a/internal/use-case/simgos-sync-use-case/unit/helper.go b/internal/use-case/simgos-sync-use-case/unit/helper.go new file mode 100644 index 00000000..a499958c --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/unit/helper.go @@ -0,0 +1,59 @@ +/* +DESCRIPTION: +Any functions that are used internally by the use-case +*/ +package unit + +import ( + "encoding/json" + erc "simrs-vx/internal/domain/references/common" + + e "simrs-vx/internal/domain/main-entities/unit" + + esimgos "simrs-vx/internal/domain/simgos-entities/unit" + esyncLog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/unit" +) + +func setDataSimgos[T *e.CreateDto | *e.UpdateDto](input T) (data esimgos.MPloy) { + var inputSrc *e.CreateDto + if inputT, ok := any(input).(*e.CreateDto); ok { + inputSrc = inputT + } else { + inputTemp := any(input).(*e.UpdateDto) + inputSrc = &inputTemp.CreateDto + } + + data.Nama = inputSrc.Name + data.Jenispoly = 0 + + return +} + +func setDataSimxLog(input *esyncLog.SimxLogDto) (data esync.UnitSimxLog) { + // encode to JSON + jsonData, _ := json.MarshalIndent(input.Payload, "", " ") + jsonString := string(jsonData) + + var status erc.ProcessStatusCode + if input.IsSuccess { + status = erc.PSCSuccess + } else { + status = erc.PSCFailed + if input.ErrMessage != nil { + data.ErrMessage = input.ErrMessage + } + } + + data.Value = &jsonString + data.Date = &now + data.Status = status + + return +} + +func setDataSimxLink(simxId, simgosId uint) (data esync.UnitLink) { + data.Simx_Id = simxId + data.Simgos_Id = simgosId + return +} diff --git a/internal/use-case/simgos-sync-use-case/unit/lib.go b/internal/use-case/simgos-sync-use-case/unit/lib.go new file mode 100644 index 00000000..720bd413 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/unit/lib.go @@ -0,0 +1,188 @@ +package unit + +import ( + plh "simrs-vx/pkg/lib-helper" + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + "time" + + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/unit" + esimgos "simrs-vx/internal/domain/simgos-entities/unit" + esynclog "simrs-vx/internal/domain/sync-entities/log" + esync "simrs-vx/internal/domain/sync-entities/unit" +) + +var now = time.Now() + +func CreateSimgosData(input e.CreateDto, event *pl.Event, dbx ...*gorm.DB) (*esimgos.MPloy, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + + data := setDataSimgos(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailSimgosData(simgosId uint16, event *pl.Event) (*esimgos.MPloy, error) { + pl.SetLogInfo(event, simgosId, "started", "DBReadDetail") + data := esimgos.MPloy{} + + var tx = dg.IS["simrs"] + + if err := tx. + Where("\"kode\" = ?", simgosId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simgosId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func UpdateSimgosData(input e.UpdateDto, dataSimgos *esync.UnitLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, input, "started", "DBUpdate") + + data := setDataSimgos(&input) + data.Kode = dataSimgos.Simgos_Id + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx.Save(&data).Error; err != nil { + event.Status = "failed" + event.ErrInfo = pl.ErrorInfo{ + Code: "data-update-fail", + Detail: "Database update failed", + Raw: err, + } + return pl.SetLogError(event, input) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} + +func HardDeleteSimgosData(data *esimgos.MPloy, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.IS["simrs"] + } + + if err := tx. + Delete(&data).Error; 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") + return nil +} + +func CreateLinkData(simxId, simgosId uint, event *pl.Event, dbx ...*gorm.DB) (*esync.UnitLink, error) { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLink(simxId, simgosId) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return nil, plh.HandleCreateError(data, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func ReadDetailLinkData(simxId uint16, event *pl.Event) (*esync.UnitLink, error) { + pl.SetLogInfo(event, simxId, "started", "DBReadDetail") + data := esync.UnitLink{} + + var tx = dg.I + + if err := tx. + Where("\"Simx_Id\" = ?", simxId). + First(&data).Error; err != nil { + if processedErr := pu.HandleReadError(err, event, source, simxId, data); processedErr != nil { + return nil, processedErr + } + } + + pl.SetLogInfo(event, nil, "complete") + return &data, nil +} + +func DeleteLinkData(data *esync.UnitLink, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, data, "started", "DBDelete") + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Delete(&data).Error; 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") + return nil +} + +func CreateLogData(input esynclog.SimxLogDto, event *pl.Event, dbx ...*gorm.DB) error { + pl.SetLogInfo(event, nil, "started", "DBCreate") + data := setDataSimxLog(&input) + + var tx *gorm.DB + if len(dbx) > 0 { + tx = dbx[0] + } else { + tx = dg.I + } + + if err := tx.Create(&data).Error; err != nil { + return plh.HandleCreateError(input, event, err) + } + + pl.SetLogInfo(event, nil, "complete") + return nil +} diff --git a/internal/use-case/simgos-sync-use-case/unit/middleware-runner.go b/internal/use-case/simgos-sync-use-case/unit/middleware-runner.go new file mode 100644 index 00000000..64426eb9 --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/unit/middleware-runner.go @@ -0,0 +1,104 @@ +package unit + +import ( + pl "simrs-vx/pkg/logger" + pu "simrs-vx/pkg/use-case-helper" + + "gorm.io/gorm" + + e "simrs-vx/internal/domain/main-entities/unit" +) + +type middlewareRunner struct { + Event *pl.Event + Tx *gorm.DB + MwType pu.MWType +} + +// NewMiddlewareExecutor creates a new middleware executor +func newMiddlewareRunner(event *pl.Event, tx *gorm.DB) *middlewareRunner { + return &middlewareRunner{ + Event: event, + Tx: tx, + } +} + +// ExecuteCreateMiddleware executes create middleware +func (me *middlewareRunner) RunCreateMiddleware(middlewares []createMw, input *e.CreateDto, data *e.Unit) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadListMiddleware(middlewares []readListMw, input *e.ReadListDto, data *e.Unit) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunReadDetailMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunUpdateMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) RunDeleteMiddleware(middlewares []readDetailMw, input *e.ReadDetailDto, data *e.Unit) error { + for _, middleware := range middlewares { + logData := pu.GetLogData(input, data) + + pl.SetLogInfo(me.Event, logData, "started", middleware.Name) + + if err := middleware.Func(input, data, me.Tx); err != nil { + return pu.HandleMiddlewareError(me.Event, string(me.MwType), middleware.Name, logData, err) + } + + pl.SetLogInfo(me.Event, nil, "complete") + } + return nil +} + +func (me *middlewareRunner) setMwType(mwType pu.MWType) { + me.MwType = mwType +} diff --git a/internal/use-case/simgos-sync-use-case/unit/middleware.go b/internal/use-case/simgos-sync-use-case/unit/middleware.go new file mode 100644 index 00000000..bac48f4d --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/unit/middleware.go @@ -0,0 +1,9 @@ +package unit + +// example of middleware +// func init() { +// createPreMw = append(createPreMw, +// CreateMw{Name: "modif-input", Func: pm.ModifInput}, +// CreateMw{Name: "check-data", Func: pm.CheckData}, +// ) +// } diff --git a/internal/use-case/simgos-sync-use-case/unit/tycovar.go b/internal/use-case/simgos-sync-use-case/unit/tycovar.go new file mode 100644 index 00000000..e1a7c69f --- /dev/null +++ b/internal/use-case/simgos-sync-use-case/unit/tycovar.go @@ -0,0 +1,44 @@ +/* +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 struct { + Name string + Func func(input *e.CreateDto, data *e.Unit, tx *gorm.DB) error +} + +type readListMw struct { + Name string + Func func(input *e.ReadListDto, data *e.Unit, tx *gorm.DB) error +} + +type readDetailMw struct { + Name string + Func func(input *e.ReadDetailDto, data *e.Unit, tx *gorm.DB) error +} + +type UpdateMw = readDetailMw +type DeleteMw = readDetailMw + +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/pkg/dualtrx-helper/dualtrx-helper.go b/pkg/dualtrx-helper/dualtrx-helper.go new file mode 100644 index 00000000..2f16203c --- /dev/null +++ b/pkg/dualtrx-helper/dualtrx-helper.go @@ -0,0 +1,66 @@ +package dualtrx_helper + +import ( + dg "github.com/karincake/apem/db-gorm-pg" + "gorm.io/gorm" +) + +type Dualtx struct { + Sync *gorm.DB + Simgos *gorm.DB +} + +func NewDualtx() *Dualtx { + return &Dualtx{ + Sync: dg.I.Begin(), + Simgos: dg.IS["simrs"].Begin(), + } +} + +func NewTx() *Dualtx { + return &Dualtx{ + Sync: dg.I, + Simgos: dg.IS["simrs"], + } +} + +func (t *Dualtx) Commit() error { + if err := t.Sync.Commit().Error; err != nil { + return err + } + + if err := t.Simgos.Commit().Error; err != nil { + return err + } + return nil +} + +func (t *Dualtx) Rollback() { + t.Sync.Rollback() + t.Simgos.Rollback() +} + +type DualTxFunc func(tx *Dualtx) error + +func WithDualTx(fn DualTxFunc) error { + var ( + tx = NewDualtx() + err error + ) + + defer func() { + if err != nil { + tx.Rollback() + } + }() + + if err = fn(tx); err != nil { + return err + } + + if err = tx.Commit(); err != nil { + return err + } + + return nil +} diff --git a/pkg/handler-crud-helper/handler-crud-helper.go b/pkg/handler-crud-helper/handler-crud-helper.go index df475094..3003e812 100644 --- a/pkg/handler-crud-helper/handler-crud-helper.go +++ b/pkg/handler-crud-helper/handler-crud-helper.go @@ -74,3 +74,36 @@ func RegCrudByCode(r *http.ServeMux, path string, mwAndRouter ...any) { "DELETE /{code}": c.Delete, }) } + +func SyncCrud(r *http.ServeMux, path string, mwAndRouter ...any) { + sLength := len(mwAndRouter) + + mwCandidates := mwAndRouter[:sLength-1] + mwList := []hk.HandlerMw{} + for i := range mwCandidates { + // have to do it manually, since casting directly results unexpected result + myType := reflect.TypeOf(mwCandidates[i]) + if myType.String() != "func(http.Handler) http.Handler" { + panic("non middleware included as middleware") + } + mwList = append(mwList, mwCandidates[i].(func(http.Handler) http.Handler)) + + // if g, okHandler := mwCandidates[i].(func(http.Handler) http.Handler); !okHandler { + // panic("non middleware included") + // } else { + // mwList = append(mwList, g) + // } + } + + c, ok := mwAndRouter[sLength-1].(SyncCrudBase) + if !ok { + panic("non CrudBase used in the last paramter") + } + + hk.GroupRoutes(path, r, mwList, hk.MapHandlerFunc{ + "POST /": c.Create, + "POST /log": c.CreateLog, + "PATCH /{id}": c.Update, + "DELETE /{id}": c.Delete, + }) +} diff --git a/pkg/handler-crud-helper/types.go b/pkg/handler-crud-helper/types.go index e85f22fc..891af38e 100644 --- a/pkg/handler-crud-helper/types.go +++ b/pkg/handler-crud-helper/types.go @@ -9,3 +9,10 @@ type CrudBase interface { Update(w http.ResponseWriter, r *http.Request) Delete(w http.ResponseWriter, r *http.Request) } + +type SyncCrudBase interface { + Create(w http.ResponseWriter, r *http.Request) + CreateLog(w http.ResponseWriter, r *http.Request) + Update(w http.ResponseWriter, r *http.Request) + Delete(w http.ResponseWriter, r *http.Request) +}