Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion internal/models/province_case_response.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,17 @@ type ProvinceCaseStatistics struct {

// TransformToResponse converts a ProvinceCase model to the response format
func (pc *ProvinceCase) TransformToResponse(date time.Time) ProvinceCaseResponse {
return pc.transformToResponseWithOptions(date, true)
}

// TransformToResponseWithoutProvince converts a ProvinceCase model to the response format without province information
func (pc *ProvinceCase) TransformToResponseWithoutProvince(date time.Time) ProvinceCaseResponse {
return pc.transformToResponseWithOptions(date, false)
}

// transformToResponseWithOptions is a helper method that converts a ProvinceCase model to the response format
// with the option to include or exclude province information
func (pc *ProvinceCase) transformToResponseWithOptions(date time.Time, includeProvince bool) ProvinceCaseResponse {
// Calculate active cases
dailyActive := pc.Positive - pc.Recovered - pc.Deceased
cumulativeActive := pc.CumulativePositive - pc.CumulativeRecovered - pc.CumulativeDeceased
Expand Down Expand Up @@ -111,7 +122,11 @@ func (pc *ProvinceCase) TransformToResponse(date time.Time) ProvinceCaseResponse
Statistics: ProvinceCaseStatistics{
Percentages: calculatePercentages(pc.CumulativePositive, pc.CumulativeRecovered, pc.CumulativeDeceased, cumulativeActive),
},
Province: pc.Province,
}

// Include province information only if requested
if includeProvince {
response.Province = pc.Province
}

// Always include reproduction rate structure, even when values are null
Expand All @@ -129,6 +144,11 @@ func (pcd *ProvinceCaseWithDate) TransformToResponse() ProvinceCaseResponse {
return pcd.ProvinceCase.TransformToResponse(pcd.Date)
}

// TransformToResponseWithoutProvince converts a ProvinceCaseWithDate model to the response format without province information
func (pcd *ProvinceCaseWithDate) TransformToResponseWithoutProvince() ProvinceCaseResponse {
return pcd.ProvinceCase.TransformToResponseWithoutProvince(pcd.Date)
}

// TransformProvinceCaseSliceToResponse converts a slice of ProvinceCaseWithDate models to response format
func TransformProvinceCaseSliceToResponse(cases []ProvinceCaseWithDate) []ProvinceCaseResponse {
responses := make([]ProvinceCaseResponse, len(cases))
Expand Down
133 changes: 133 additions & 0 deletions internal/models/province_case_response_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,139 @@ func TestTransformProvinceCaseSliceToResponse_EmptySlice(t *testing.T) {
assert.Empty(t, result)
}

func TestProvinceCase_TransformToResponseWithoutProvince(t *testing.T) {
testDate := time.Date(2023, 10, 15, 0, 0, 0, 0, time.UTC)
rt := 1.5
rtUpper := 1.8
rtLower := 1.2

provinceCase := ProvinceCase{
ID: 1,
Day: 100,
ProvinceID: "ID-JK",
Positive: 150,
Recovered: 120,
Deceased: 10,
PersonUnderObservation: 25,
FinishedPersonUnderObservation: 20,
PersonUnderSupervision: 30,
FinishedPersonUnderSupervision: 25,
CumulativePositive: 5000,
CumulativeRecovered: 4500,
CumulativeDeceased: 300,
CumulativePersonUnderObservation: 800,
CumulativeFinishedPersonUnderObservation: 750,
CumulativePersonUnderSupervision: 600,
CumulativeFinishedPersonUnderSupervision: 580,
Rt: &rt,
RtUpper: &rtUpper,
RtLower: &rtLower,
Province: &Province{
ID: "ID-JK",
Name: "DKI Jakarta",
},
}

result := provinceCase.TransformToResponseWithoutProvince(testDate)

expectedResult := ProvinceCaseResponse{
Day: 100,
Date: testDate,
Daily: ProvinceDailyCases{
Positive: 150,
Recovered: 120,
Deceased: 10,
Active: 20, // 150 - 120 - 10
ODP: DailyObservationData{
Active: 5, // 25 - 20
Finished: 20,
},
PDP: DailySupervisionData{
Active: 5, // 30 - 25
Finished: 25,
},
},
Cumulative: ProvinceCumulativeCases{
Positive: 5000,
Recovered: 4500,
Deceased: 300,
Active: 200, // 5000 - 4500 - 300
ODP: ObservationData{
Active: 50, // 800 - 750
Finished: 750,
Total: 800,
},
PDP: SupervisionData{
Active: 20, // 600 - 580
Finished: 580,
Total: 600,
},
},
Statistics: ProvinceCaseStatistics{
Percentages: CasePercentages{
Active: 4.0, // (200 / 5000) * 100
Recovered: 90.0, // (4500 / 5000) * 100
Deceased: 6.0, // (300 / 5000) * 100
},
ReproductionRate: &ReproductionRate{
Value: &[]float64{1.5}[0],
UpperBound: &[]float64{1.8}[0],
LowerBound: &[]float64{1.2}[0],
},
},
// Province should be nil in this case
Province: nil,
}

assert.Equal(t, expectedResult, result)
assert.Nil(t, result.Province, "Province should be nil when using TransformToResponseWithoutProvince")
}

func TestProvinceCaseWithDate_TransformToResponseWithoutProvince(t *testing.T) {
testDate := time.Date(2023, 10, 15, 0, 0, 0, 0, time.UTC)
rt := 1.2

provinceCaseWithDate := ProvinceCaseWithDate{
ProvinceCase: ProvinceCase{
ID: 1,
Day: 200,
ProvinceID: "ID-JT",
Positive: 50,
Recovered: 40,
Deceased: 2,
PersonUnderObservation: 10,
FinishedPersonUnderObservation: 8,
PersonUnderSupervision: 12,
FinishedPersonUnderSupervision: 10,
CumulativePositive: 3000,
CumulativeRecovered: 2700,
CumulativeDeceased: 200,
CumulativePersonUnderObservation: 500,
CumulativeFinishedPersonUnderObservation: 450,
CumulativePersonUnderSupervision: 350,
CumulativeFinishedPersonUnderSupervision: 320,
Rt: &rt,
RtUpper: nil,
RtLower: nil,
Province: &Province{
ID: "ID-JT",
Name: "Jawa Tengah",
},
},
Date: testDate,
}

result := provinceCaseWithDate.TransformToResponseWithoutProvince()

assert.Equal(t, int64(200), result.Day)
assert.Equal(t, testDate, result.Date)
assert.Equal(t, int64(50), result.Daily.Positive)
assert.Equal(t, int64(8), result.Daily.Active) // 50 - 40 - 2
assert.Equal(t, int64(3000), result.Cumulative.Positive)
assert.Equal(t, int64(100), result.Cumulative.Active) // 3000 - 2700 - 200
assert.Nil(t, result.Province, "Province should be nil when using TransformToResponseWithoutProvince")
}

func TestProvinceCaseResponse_JSONStructure(t *testing.T) {
// This test verifies that the JSON structure matches the expected format
testDate := time.Date(2023, 10, 15, 0, 0, 0, 0, time.UTC)
Expand Down
4 changes: 2 additions & 2 deletions internal/service/covid_service.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,8 +142,8 @@ func (s *covidService) GetProvincesWithLatestCase() ([]models.ProvinceWithLatest
}

if latestCase != nil {
// Transform to response format
caseResponse := latestCase.TransformToResponse()
// Transform to response format without province information to avoid redundancy
caseResponse := latestCase.TransformToResponseWithoutProvince()
result[i].LatestCase = &caseResponse
}
}
Expand Down