package controllers import ( "context" "fmt" "math" "net/http" "reflect" "time" "kemendagri/sipd/services/master-sipd/models" "kemendagri/sipd/services/master-sipd/utils" "github.com/google/uuid" "github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5/pgxpool" ) type DaerahController struct { contextTimeout time.Duration pgxConn *pgxpool.Pool } func NewDaerahController(conn *pgxpool.Pool, timeout time.Duration) (controller *DaerahController) { controller = &DaerahController{ pgxConn: conn, contextTimeout: timeout, } return } func getDaerahDetailFields() []string { var field []string v := reflect.ValueOf(models.MstDaerahModel{}) for i := 0; i < v.Type().NumField(); i++ { field = append(field, v.Type().Field(i).Tag.Get("json")) } // log.Println("fields: ", field) return field } // Index lists of daerah func (c *DaerahController) Index( page, limit int, filter string, ) ( resp []models.MstDaerahModel, totalCount int, pageCount int, err error, ) { var q string resp = make([]models.MstDaerahModel, 0) pageCount = 1 offset := limit * (page - 1) var filterCond string if filter != "" { var filterMap map[string]string filterMap, err = utils.ValidateAndReturnFilterMap(filter, getDaerahDetailFields()) if err != nil { return resp, totalCount, pageCount, err } // log.Println("filterMap: ", filterMap) var key, val string for k, v := range filterMap { key = k val = v } switch key { case "nama_daerah": filterCond = fmt.Sprintf(" AND dd.%s ILIKE '%s%s%s' ", key, "%", val, "%") case "kode_ddn", "jns_pemda": filterCond = fmt.Sprintf(" AND dd.%s = '%s' ", key, val) default: filterCond = "" } } // total data q = `SELECT COALESCE(COUNT(dd.id_daerah), 0) FROM "master_data"."mst_daerah" AS dd WHERE dd.deleted_by = 0 AND dd.deleted_at='0001-01-01 00:00:00'` + filterCond err = c.pgxConn.QueryRow(context.Background(), q).Scan(&totalCount) if err != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal mengambil total data. - " + err.Error(), } return resp, totalCount, pageCount, err } var rows pgx.Rows q = `SELECT dd.id_daerah, dd.kode_ddn, dd.nama_daerah, dd.nama_ibu_kota, dd.daerah_khusus, dd.jns_pemda, dd.logo_daerah FROM "master_data"."mst_daerah" AS dd WHERE dd.deleted_by = 0 AND dd.deleted_at='0001-01-01 00:00:00' ` q += filterCond q += ` LIMIT $1 OFFSET $2` rows, err = c.pgxConn.Query(context.Background(), q, limit, offset) if err != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal mengambil data. - " + err.Error(), } return resp, totalCount, pageCount, err } defer rows.Close() for rows.Next() { var m models.MstDaerahModel err = rows.Scan( &m.ID, &m.KodeDaerah, &m.NamaDaerah, &m.NamaIbuKota, &m.DaerahKhusus, &m.JnsPemda, &m.LogoDaerah, ) if err != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal iterasi data. - " + rows.Err().Error(), } return resp, totalCount, pageCount, err } resp = append(resp, m) } if rows.Err() != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal mengambil data (rows). - " + rows.Err().Error(), } return resp, totalCount, pageCount, err } rows.Close() if totalCount > 0 && totalCount > limit { pageCount = int(math.Ceil(float64(totalCount) / float64(limit))) } return resp, totalCount, pageCount, err } // View detail of daerah func (c *DaerahController) View(id int) (resp models.MstDaerahDetilModel, err error) { // log.Println("id: ", id) q := `SELECT dd.id_daerah, pv.id_daerah as id_provinsi, pv.kode_ddn as kode_provinsi, pv.nama_daerah as nama_provinsi , dd.kode_ddn, dd.nama_daerah, dd.nama_ibu_kota, dd.daerah_khusus, dd.jns_pemda, CASE WHEN dd.jns_pemda=1 THEN 'Provinsi' WHEN dd.jns_pemda=2 THEN 'Kabupaten' WHEN dd.jns_pemda=3 THEN 'Kota' ELSE '-' END AS jenis_pemda_alias , dd.zona_waktu, dd.zona_wilayah, dd.logo_daerah , dd.created_at, dd.created_by, dd.updated_at, dd.updated_by, dd.deleted_at, dd.deleted_by FROM "master_data"."mst_daerah" AS dd LEFT JOIN "master_data"."mst_daerah" AS pv ON pv.id_daerah=dd.id_prov WHERE dd.id_daerah=$1` err = c.pgxConn.QueryRow(context.Background(), q, id).Scan( &resp.ID, &resp.IDProv, &resp.KodeProv, &resp.NamaProv, &resp.KodeDaerah, &resp.NamaDaerah, &resp.NamaIbuKota, &resp.DaerahKhusus, &resp.JnsPemda, &resp.JnsPemdaAlias, &resp.ZonaWaktu, &resp.ZonaWilayah, &resp.LogoDaerah, &resp.CreatedAt, &resp.CreatedBy, &resp.UpdatedAt, &resp.UpdatedBy, &resp.DeletedAt, &resp.DeletedBy, ) if err != nil { if err.Error() == "no rows in result set" { err = utils.RequestError{ Code: http.StatusNotFound, Message: "Data tidak ditemukan", } } else { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal mengambil data. - " + err.Error(), } } return resp, err } if resp.DeletedBy > 0 && !resp.DeletedAt.IsZero() { err = utils.RequestError{ Code: http.StatusNotFound, Message: "Data sudah dihapus.", } return resp, err } return resp, err } // Create new daerah func (c *DaerahController) Create(payload models.MstDaerahPayloadModel) error { var err error var kodeUnik string kodeUnik = uuid.New().String() // mulai validasi duplikat unique key var exists bool q := `SELECT EXISTS ( SELECT dd.id_daerah FROM "master_data"."mst_daerah" AS dd WHERE dd.kode_ddn = $1 OR dd.nama_daerah = $2 )` err = c.pgxConn.QueryRow( context.Background(), q, payload.KodeDaerah, payload.NamaDaerah, ).Scan(&exists) if err != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal memeriksa duplikasi unique key. - " + err.Error(), } return err } if exists { err = utils.RequestError{ Code: http.StatusBadRequest, Message: "Data sudah ada", } return err } // selesai validasi duplikat unique key q = ` INSERT INTO "master_data"."mst_daerah" ( id_prov, kode_unik, kode_ddn, nama_daerah, nama_ibu_kota, daerah_khusus, jns_pemda, zona_waktu, zona_wilayah, logo_daerah ) VALUES ( $1, -- id_prov $2, -- kode_unik $3, -- kode_ddn $4, -- nama_daerah $5, -- nama_ibu_kota $6, -- daerah_khusus $7, -- jns_pemda $8, -- zona_waktu $9, -- zona_wilayah $10 -- logo_daerah ) ` _, err = c.pgxConn.Exec( context.Background(), q, &payload.IDProv, &kodeUnik, &payload.KodeDaerah, &payload.NamaDaerah, &payload.NamaIbuKota, &payload.DaerahKhusus, &payload.JnsPemda, &payload.ZonaWaktu, &payload.ZonaWilayah, &payload.LogoDaerah, ) if err != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal menyimpan data daerah. - " + err.Error(), } return err } return err } // Update daerah func (c *DaerahController) Update(id int, payload models.MstDaerahPayloadModel) error { var err error var q string // pastikan data dengan id tersebut ada, dengan cara mengambil datanya. var idDaerah int var kodeDaerah, namaDaerah string q = `SELECT dd.id_daerah, dd.kode_ddn, dd.nama_daerah FROM "master_data"."mst_daerah" AS dd WHERE dd.id_daerah=$1` err = c.pgxConn.QueryRow(context.Background(), q, id).Scan(&idDaerah, &kodeDaerah, &namaDaerah) if err != nil { { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal mengambil data daerah. - " + err.Error(), } return err } } if kodeDaerah != payload.KodeDaerah && namaDaerah != payload.NamaDaerah { // mulai validasi duplikat unique key var exists bool q = `SELECT EXISTS ( SELECT dd.id_daerah FROM "master_data"."mst_daerah" AS dd WHERE dd.kode_ddn = $1 OR dd.nama_daerah = $2 )` err = c.pgxConn.QueryRow( context.Background(), q, payload.KodeDaerah, payload.NamaDaerah, ).Scan(&exists) if err != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal memeriksa duplikasi unique key. - " + err.Error(), } return err } if exists { err = utils.RequestError{ Code: http.StatusBadRequest, Message: "Data sudah ada", } return err } // selesai validasi duplikat unique key } q = ` UPDATE "master_data"."mst_daerah" SET id_prov = $1, kode_ddn = $2, nama_daerah = $3, nama_ibu_kota = $4, daerah_khusus = $5, jenis_pemda = $6, zona_waktu = $7, zona_wilayah = $8, logo_daerah = $9, updated_at = NOW() WHERE id_daerah = $10 ` _, err = c.pgxConn.Exec( context.Background(), q, payload.IDProv, payload.KodeDaerah, payload.NamaDaerah, payload.NamaIbuKota, payload.DaerahKhusus, payload.JnsPemda, payload.ZonaWaktu, payload.ZonaWilayah, payload.LogoDaerah, id, // kondisi WHERE ) if err != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal mengupdate data daerah. - " + err.Error(), } return err } return err } func (c *DaerahController) Delete(id int) error { var err error var idDaerah, deletedBy int var deletedAt time.Time q := `SELECT id_daerah, deleted_by, deleted_at FROM "master_data"."mst_daerah" WHERE id_daerah=$1` err = c.pgxConn.QueryRow(context.Background(), q, id).Scan(&idDaerah, &deletedBy, &deletedAt) if err != nil { { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal mengambil data daerah. - " + err.Error(), } return err } } if deletedBy != 0 { err = utils.RequestError{ Code: http.StatusBadRequest, Message: "data sudah dihapus", } return err } q = ` UPDATE "master_data"."mst_daerah" SET deleted_by = $1, deleted_at = NOW() WHERE id = $2 ` _, err = c.pgxConn.Exec( context.Background(), q, id, id, ) if err != nil { err = utils.RequestError{ Code: http.StatusInternalServerError, Message: "gagal menghapus data daerah. - " + err.Error(), } return err } return err }