This commit is contained in:
@@ -3,10 +3,93 @@ package patient
|
||||
import (
|
||||
"api-service/internal/models"
|
||||
"database/sql"
|
||||
"database/sql/driver"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
type Date time.Time
|
||||
|
||||
func (d *Date) UnmarshalJSON(b []byte) error {
|
||||
s := strings.Trim(string(b), "\"")
|
||||
if s == "" || s == "null" {
|
||||
*d = Date(time.Time{})
|
||||
return nil
|
||||
}
|
||||
t, err := time.Parse("2006-01-02", s)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid date format, expected YYYY-MM-DD: %w", err)
|
||||
}
|
||||
*d = Date(t)
|
||||
return nil
|
||||
}
|
||||
|
||||
// new: MarshalJSON so responses use "YYYY-MM-DD"
|
||||
func (d Date) MarshalJSON() ([]byte, error) {
|
||||
t := time.Time(d)
|
||||
if t.IsZero() {
|
||||
return []byte("null"), nil
|
||||
}
|
||||
return []byte("\"" + t.Format("2006-01-02") + "\""), nil
|
||||
}
|
||||
|
||||
// new: database/sql/driver.Valuer implementation so DB driver can encode Date
|
||||
func (d Date) Value() (driver.Value, error) {
|
||||
t := time.Time(d)
|
||||
if t.IsZero() {
|
||||
return nil, nil
|
||||
}
|
||||
// return time.Time so pq/pgx has an encode plan for date/timestamp types
|
||||
return t, nil
|
||||
}
|
||||
|
||||
// new: sql.Scanner implementation so DB rows decode into Date
|
||||
func (d *Date) Scan(src interface{}) error {
|
||||
if src == nil {
|
||||
*d = Date(time.Time{})
|
||||
return nil
|
||||
}
|
||||
switch v := src.(type) {
|
||||
case time.Time:
|
||||
*d = Date(v)
|
||||
return nil
|
||||
case []byte:
|
||||
s := string(v)
|
||||
if t, err := time.Parse("2006-01-02", s); err == nil {
|
||||
*d = Date(t)
|
||||
return nil
|
||||
}
|
||||
if t, err := time.Parse(time.RFC3339, s); err == nil {
|
||||
*d = Date(t)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("cannot parse date from []byte: %s", s)
|
||||
case string:
|
||||
s := v
|
||||
if s == "" {
|
||||
*d = Date(time.Time{})
|
||||
return nil
|
||||
}
|
||||
if t, err := time.Parse("2006-01-02", s); err == nil {
|
||||
*d = Date(t)
|
||||
return nil
|
||||
}
|
||||
if t, err := time.Parse(time.RFC3339, s); err == nil {
|
||||
*d = Date(t)
|
||||
return nil
|
||||
}
|
||||
return fmt.Errorf("cannot parse date from string: %s", s)
|
||||
default:
|
||||
return fmt.Errorf("unsupported scan type for Date: %T", src)
|
||||
}
|
||||
}
|
||||
|
||||
func (d Date) ToTime() time.Time {
|
||||
return time.Time(d)
|
||||
}
|
||||
|
||||
// Patient represents the data structure for the patient table
|
||||
// with proper null handling and optimized JSON marshaling
|
||||
type Patient struct {
|
||||
@@ -15,7 +98,7 @@ type Patient struct {
|
||||
MedicalRecordNumber sql.NullString `json:"medical_record_number,omitempty" db:"medical_record_number"`
|
||||
PhoneNumber sql.NullString `json:"phone_number,omitempty" db:"phone_number"`
|
||||
Gender sql.NullString `json:"gender,omitempty" db:"gender"`
|
||||
BirthDate sql.NullTime `json:"birth_date,omitempty" db:"birth_date"`
|
||||
BirthDate Date `json:"birth_date,omitempty" db:"birth_date"`
|
||||
Address sql.NullString `json:"address,omitempty" db:"address"`
|
||||
Active sql.NullBool `json:"active,omitempty" db:"active"`
|
||||
FKSdProvinsiID models.NullableInt32 `json:"fk_sd_provinsi_id,omitempty" db:"fk_sd_provinsi_id"`
|
||||
@@ -32,21 +115,20 @@ type Patient struct {
|
||||
func (r Patient) MarshalJSON() ([]byte, error) {
|
||||
type Alias Patient
|
||||
aux := &struct {
|
||||
Name *string `json:"name,omitempty"`
|
||||
MedicalRecordNumber *string `json:"medical_record_number,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
Gender *string `json:"gender,omitempty"`
|
||||
BirthDate *time.Time `json:"birth_date,omitempty"`
|
||||
Address *string `json:"address,omitempty"`
|
||||
Active *bool `json:"active,omitempty"`
|
||||
FKSdProvinsiID *int32 `json:"fk_sd_provinsi_id,omitempty"`
|
||||
FKSdKabupatenKotaID *int32 `json:"fk_sd_kabupaten_kota_id,omitempty"`
|
||||
FKSdKecamatanID *int32 `json:"fk_sd_kecamatan_id,omitempty"`
|
||||
FKSdKelurahanID *int32 `json:"fk_sd_kelurahan_id,omitempty"`
|
||||
DsSdProvinsi *string `json:"ds_sd_provinsi,omitempty"`
|
||||
DsSdKabupatenKota *string `json:"ds_sd_kabupaten_kota,omitempty"`
|
||||
DsSdKecamatan *string `json:"ds_sd_kecamatan,omitempty"`
|
||||
DsSdKelurahan *string `json:"ds_sd_kelurahan,omitempty"`
|
||||
Name *string `json:"name,omitempty"`
|
||||
MedicalRecordNumber *string `json:"medical_record_number,omitempty"`
|
||||
PhoneNumber *string `json:"phone_number,omitempty"`
|
||||
Gender *string `json:"gender,omitempty"`
|
||||
Address *string `json:"address,omitempty"`
|
||||
Active *bool `json:"active,omitempty"`
|
||||
FKSdProvinsiID *int32 `json:"fk_sd_provinsi_id,omitempty"`
|
||||
FKSdKabupatenKotaID *int32 `json:"fk_sd_kabupaten_kota_id,omitempty"`
|
||||
FKSdKecamatanID *int32 `json:"fk_sd_kecamatan_id,omitempty"`
|
||||
FKSdKelurahanID *int32 `json:"fk_sd_kelurahan_id,omitempty"`
|
||||
DsSdProvinsi *string `json:"ds_sd_provinsi,omitempty"`
|
||||
DsSdKabupatenKota *string `json:"ds_sd_kabupaten_kota,omitempty"`
|
||||
DsSdKecamatan *string `json:"ds_sd_kecamatan,omitempty"`
|
||||
DsSdKelurahan *string `json:"ds_sd_kelurahan,omitempty"`
|
||||
*Alias
|
||||
}{
|
||||
Alias: (*Alias)(&r),
|
||||
@@ -64,9 +146,6 @@ func (r Patient) MarshalJSON() ([]byte, error) {
|
||||
if r.Gender.Valid {
|
||||
aux.Gender = &r.Gender.String
|
||||
}
|
||||
if r.BirthDate.Valid {
|
||||
aux.BirthDate = &r.BirthDate.Time
|
||||
}
|
||||
if r.Address.Valid {
|
||||
aux.Address = &r.Address.String
|
||||
}
|
||||
@@ -129,21 +208,21 @@ type PatientGetResponse struct {
|
||||
|
||||
// Request struct untuk create
|
||||
type PatientCreateRequest struct {
|
||||
Name string `json:"name" validate:"min=1,max=100"`
|
||||
MedicalRecordNumber string `json:"medical_record_number" validate:"min=1,max=20"`
|
||||
PhoneNumber string `json:"phone_number" validate:"min=1,max=20"`
|
||||
Gender string `json:"gender" validate:"min=1,max=20"`
|
||||
BirthDate time.Time `json:"birth_date"`
|
||||
Address string `json:"address" validate:"min=1,max=255"`
|
||||
Active bool `json:"active"`
|
||||
FKSdProvinsiID int32 `json:"fk_sd_provinsi_id"`
|
||||
FKSdKabupatenKotaID int32 `json:"fk_sd_kabupaten_kota_id"`
|
||||
FKSdKecamatanID int32 `json:"fk_sd_kecamatan_id"`
|
||||
FKSdKelurahanID int32 `json:"fk_sd_kelurahan_id"`
|
||||
DsSdProvinsi string `json:"ds_sd_provinsi" validate:"min=1,max=255"`
|
||||
DsSdKabupatenKota string `json:"ds_sd_kabupaten_kota" validate:"min=1,max=255"`
|
||||
DsSdKecamatan string `json:"ds_sd_kecamatan" validate:"min=1,max=255"`
|
||||
DsSdKelurahan string `json:"ds_sd_kelurahan" validate:"min=1,max=255"`
|
||||
Name string `json:"name" validate:"min=1,max=100"`
|
||||
MedicalRecordNumber string `json:"medical_record_number" validate:"min=1,max=20"`
|
||||
PhoneNumber string `json:"phone_number" validate:"min=1,max=20"`
|
||||
Gender string `json:"gender" validate:"max=1"`
|
||||
BirthDate Date `json:"birth_date"`
|
||||
Address string `json:"address" validate:"min=1,max=255"`
|
||||
Active bool `json:"active"`
|
||||
FKSdProvinsiID int32 `json:"fk_sd_provinsi_id"`
|
||||
FKSdKabupatenKotaID int32 `json:"fk_sd_kabupaten_kota_id"`
|
||||
FKSdKecamatanID int32 `json:"fk_sd_kecamatan_id"`
|
||||
FKSdKelurahanID int32 `json:"fk_sd_kelurahan_id"`
|
||||
DsSdProvinsi string `json:"ds_sd_provinsi" validate:"min=1,max=255"`
|
||||
DsSdKabupatenKota string `json:"ds_sd_kabupaten_kota" validate:"min=1,max=255"`
|
||||
DsSdKecamatan string `json:"ds_sd_kecamatan" validate:"min=1,max=255"`
|
||||
DsSdKelurahan string `json:"ds_sd_kelurahan" validate:"min=1,max=255"`
|
||||
}
|
||||
|
||||
type PatientPostRequest struct {
|
||||
@@ -158,22 +237,22 @@ type PatientCreateResponse struct {
|
||||
|
||||
// Update request
|
||||
type PatientUpdateRequest struct {
|
||||
ID int `json:"id" validate:"required,min=1"`
|
||||
Name string `json:"name" validate:"min=1,max=100"`
|
||||
MedicalRecordNumber string `json:"medical_record_number" validate:"min=1,max=20"`
|
||||
PhoneNumber string `json:"phone_number" validate:"min=1,max=20"`
|
||||
Gender string `json:"gender" validate:"min=1,max=20"`
|
||||
BirthDate time.Time `json:"birth_date"`
|
||||
Address string `json:"address" validate:"min=1,max=255"`
|
||||
Active bool `json:"active"`
|
||||
FKSdProvinsiID int32 `json:"fk_sd_provinsi_id"`
|
||||
FKSdKabupatenKotaID int32 `json:"fk_sd_kabupaten_kota_id"`
|
||||
FKSdKecamatanID int32 `json:"fk_sd_kecamatan_id"`
|
||||
FKSdKelurahanID int32 `json:"fk_sd_kelurahan_id"`
|
||||
DsSdProvinsi string `json:"ds_sd_provinsi" validate:"max=255"`
|
||||
DsSdKabupatenKota string `json:"ds_sd_kabupaten_kota" validate:"max=255"`
|
||||
DsSdKecamatan string `json:"ds_sd_kecamatan" validate:"max=255"`
|
||||
DsSdKelurahan string `json:"ds_sd_kelurahan" validate:"max=255"`
|
||||
ID int `json:"id" validate:"required,min=1"`
|
||||
Name string `json:"name" validate:"min=1,max=100"`
|
||||
MedicalRecordNumber string `json:"medical_record_number" validate:"min=1,max=20"`
|
||||
PhoneNumber string `json:"phone_number" validate:"min=1,max=20"`
|
||||
Gender string `json:"gender" validate:"max=1"`
|
||||
BirthDate Date `json:"birth_date"`
|
||||
Address string `json:"address" validate:"min=1,max=255"`
|
||||
Active bool `json:"active"`
|
||||
FKSdProvinsiID int32 `json:"fk_sd_provinsi_id"`
|
||||
FKSdKabupatenKotaID int32 `json:"fk_sd_kabupaten_kota_id"`
|
||||
FKSdKecamatanID int32 `json:"fk_sd_kecamatan_id"`
|
||||
FKSdKelurahanID int32 `json:"fk_sd_kelurahan_id"`
|
||||
DsSdProvinsi string `json:"ds_sd_provinsi" validate:"max=255"`
|
||||
DsSdKabupatenKota string `json:"ds_sd_kabupaten_kota" validate:"max=255"`
|
||||
DsSdKecamatan string `json:"ds_sd_kecamatan" validate:"max=255"`
|
||||
DsSdKelurahan string `json:"ds_sd_kelurahan" validate:"max=255"`
|
||||
}
|
||||
|
||||
// Response struct untuk update
|
||||
|
||||
Reference in New Issue
Block a user