Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CDPS-112: Fix pagination page and move to new class #14

Merged
merged 1 commit into from
Jan 31, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import uk.gov.justice.digital.hmpps.healthandmedication.resource.requests.PageMe
import uk.gov.justice.digital.hmpps.healthandmedication.resource.responses.HealthAndMedicationForPrisonDto
import uk.gov.justice.digital.hmpps.healthandmedication.resource.responses.HealthAndMedicationForPrisonResponse
import uk.gov.justice.digital.hmpps.healthandmedication.utils.AuthenticationFacade
import uk.gov.justice.digital.hmpps.healthandmedication.utils.Pagination
import uk.gov.justice.digital.hmpps.healthandmedication.utils.toReferenceDataCode
import uk.gov.justice.digital.hmpps.healthandmedication.utils.validatePrisonerNumber
import java.time.Clock
Expand Down Expand Up @@ -65,40 +66,33 @@ class PrisonerHealthService(
)

// This maintains the order from the prisoner search API so that we're able to have sorting
val overlappingIds = prisonerNumbers.intersect(healthData.map { it.prisonerNumber }.toSet()).toList()

// Pagination specific code to be moved out
val startIndex = (request.page - 1) * request.size
val lastIndex = (startIndex + request.size - 1).coerceAtMost(overlappingIds.size - 1)
val idsForPage = overlappingIds.slice(startIndex..lastIndex)
// End pagination specific code

return HealthAndMedicationForPrisonResponse(
content = idsForPage.map { id ->
val health = healthData.find { it.prisonerNumber == id }!!
val prisoner = prisoners.find { prisoner -> prisoner.prisonerNumber == health.prisonerNumber }!!
val healthForPrison =
prisonerNumbers.intersect(healthData.map { it.prisonerNumber }.toSet()).toList().map { prisonerNumber ->
val health = healthData.find { it.prisonerNumber == prisonerNumber }!!
val prisoner = prisoners.find { prisoner -> prisoner.prisonerNumber == prisonerNumber }!!
HealthAndMedicationForPrisonDto(
firstName = prisoner.firstName,
lastName = prisoner.lastName,
location = prisoner.cellLocation,
prisonerNumber = health.prisonerNumber,
prisonerNumber = prisonerNumber,
health = health.toHealthDto(),
)
}.toList(),
}

val (content, metadata) = Pagination.paginateCollection(request.page, request.size, healthForPrison)

return HealthAndMedicationForPrisonResponse(
content = content,
// Pagination metadata, should be returned from the same class that returns the IDs calculated
metadata = PageMeta(
first = startIndex == 0,
last = (lastIndex + 1) >= overlappingIds.size,
numberOfElements = idsForPage.size,
offset = startIndex,
pageNumber = if (idsForPage.isNotEmpty()) {
Math.ceilDiv(startIndex, idsForPage.size) + 1
} else {
1
},
size = request.size,
totalElements = overlappingIds.size,
totalPages = Math.ceilDiv(overlappingIds.size, request.size).coerceAtLeast(1),
first = metadata.first,
last = metadata.last,
numberOfElements = metadata.numberOfElements,
offset = metadata.offset,
pageNumber = metadata.pageNumber,
size = metadata.size,
totalElements = metadata.totalElements,
totalPages = metadata.totalPages,
),
)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package uk.gov.justice.digital.hmpps.healthandmedication.utils

class Pagination {
data class PaginationMetadata(
val first: Boolean,
val last: Boolean,
val numberOfElements: Int,
val offset: Int,
val pageNumber: Int,
val size: Int,
val totalElements: Int,
val totalPages: Int,
)

data class PaginatedCollection<TCollection>(
val content: List<TCollection>,
val metadata: PaginationMetadata,
)

companion object {
fun <TCollection> paginateCollection(
page: Int,
pageSize: Int,
collection: List<TCollection>,
): PaginatedCollection<TCollection> {
val startIndex = (page - 1) * pageSize
val lastIndex = (startIndex + pageSize - 1).coerceAtMost(collection.size - 1)
val content = collection.slice(startIndex..lastIndex)

return PaginatedCollection(
content,
PaginationMetadata(
first = startIndex == 0,
last = (lastIndex + 1) >= collection.size,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just wondered why the > needed if you've got the coerceAtMost(collection.size - 1) guaranteeing it can't be greater

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't really matter though

numberOfElements = content.size,
offset = startIndex,
pageNumber = page,
size = pageSize,
totalElements = collection.size,
totalPages = Math.ceilDiv(collection.size, pageSize).coerceAtLeast(1),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ceilDiv should in theory give you something at least 1, but no harm enforcing that I guess

),
)
}
}
}