add devices by type endpoint

- update DevicesController

  - update DevicesEndpoint
  - update DevicesControllerTest
  - add getDevicesByType to DevicesController
  - update devices.http

- add getDevicesByType to DeviceService

- add findAllByType to DeviceRepository
This commit is contained in:
2025-08-17 19:16:26 +02:00
committed by swordsteel
parent 6f44c05330
commit 14d36f21db
6 changed files with 213 additions and 64 deletions

View File

@@ -6,3 +6,12 @@ GET {{hostname}}/devices/page-1
### get all types ### get all types
GET {{hostname}}/devices/page-1/show-2 GET {{hostname}}/devices/page-1/show-2
### get all types
GET {{hostname}}/devices/type-00000000-0000-0000-0000-000000000000
### get all types
GET {{hostname}}/devices/type-00000000-0000-0000-0000-000000000000/page-1
### get all types
GET {{hostname}}/devices/type-00000000-0000-0000-0000-000000000000/page-1/show-2

View File

@@ -1,6 +1,7 @@
package ltd.hlaeja.controller package ltd.hlaeja.controller
import jakarta.validation.constraints.Min import jakarta.validation.constraints.Min
import java.util.UUID
import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.map
import ltd.hlaeja.library.deviceRegistry.Devices import ltd.hlaeja.library.deviceRegistry.Devices
@@ -30,4 +31,16 @@ class DevicesController(
@PathVariable(required = false) @Min(1) show: Int = DEFAULT_SIZE, @PathVariable(required = false) @Min(1) show: Int = DEFAULT_SIZE,
): Flow<Devices.Response> = deviceService.getDevices((page - 1) * show, show) ): Flow<Devices.Response> = deviceService.getDevices((page - 1) * show, show)
.map { it.toDevicesResponse() } .map { it.toDevicesResponse() }
@GetMapping(
"/devices/type-{type}",
"/devices/type-{type}/page-{page}",
"/devices/type-{type}/page-{page}/show-{show}",
)
suspend fun getDevicesByType(
@PathVariable type: UUID,
@PathVariable(required = false) @Min(1) page: Int = DEFAULT_PAGE,
@PathVariable(required = false) @Min(1) show: Int = DEFAULT_SIZE,
): Flow<Devices.Response> = deviceService.getDevicesByType(type, (page - 1) * show, show)
.map { it.toDevicesResponse() }
} }

View File

@@ -16,4 +16,11 @@ interface DeviceRepository : CoroutineCrudRepository<DeviceEntity, UUID> {
@Param("offset") offset: Int, @Param("offset") offset: Int,
@Param("limit") limit: Int, @Param("limit") limit: Int,
): Flow<DeviceEntity> ): Flow<DeviceEntity>
@Query("SELECT * FROM devices WHERE type = :type LIMIT :limit OFFSET :offset")
fun findAllByType(
@Param("type") type: UUID,
@Param("offset") offset: Int,
@Param("limit") limit: Int,
): Flow<DeviceEntity>
} }

View File

@@ -37,4 +37,10 @@ class DeviceService(
page: Int, page: Int,
show: Int, show: Int,
): Flow<DeviceEntity> = deviceRepository.findAll(page, show) ): Flow<DeviceEntity> = deviceRepository.findAll(page, show)
suspend fun getDevicesByType(
type: UUID,
page: Int,
show: Int,
): Flow<DeviceEntity> = deviceRepository.findAllByType(type, page, show)
} }

View File

@@ -1,9 +1,11 @@
package ltd.hlaeja.controller package ltd.hlaeja.controller
import java.util.UUID
import ltd.hlaeja.library.deviceRegistry.Devices import ltd.hlaeja.library.deviceRegistry.Devices
import ltd.hlaeja.test.container.PostgresTestContainer import ltd.hlaeja.test.container.PostgresTestContainer
import org.assertj.core.api.Assertions.assertThat import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Nested
import org.junit.jupiter.api.Test import org.junit.jupiter.api.Test
import org.junit.jupiter.params.ParameterizedTest import org.junit.jupiter.params.ParameterizedTest
import org.junit.jupiter.params.provider.CsvSource import org.junit.jupiter.params.provider.CsvSource
@@ -27,6 +29,9 @@ class DevicesEndpoint {
webClient = WebTestClient.bindToServer().baseUrl("http://localhost:$port").build() webClient = WebTestClient.bindToServer().baseUrl("http://localhost:$port").build()
} }
@Nested
inner class GetDevices {
@Test @Test
fun `get devices default - success`() { fun `get devices default - success`() {
// when // when
@@ -103,3 +108,94 @@ class DevicesEndpoint {
result.expectStatus().isBadRequest result.expectStatus().isBadRequest
} }
} }
@Nested
inner class GetDevicesByType {
@Test
fun `get devices for type default - success`() {
// when
val result = webClient.get()
.uri("/devices/type-00000000-0000-0000-0001-000000000001")
.exchange()
// then
result.expectStatus().isOk()
.expectBody<List<Devices.Response>>()
.consumeWith {
assertThat(it.responseBody?.size).isEqualTo(2)
}
}
@ParameterizedTest
@CsvSource(
value = [
"00000000-0000-0000-0001-000000000001,1,2",
"00000000-0000-0000-0001-000000000001,2,0",
],
)
fun `get devices for type by page - success`(type: UUID, page: Int, expected: Int) {
// when
val result = webClient.get()
.uri("/devices/type-$type/page-$page")
.exchange()
// then
result.expectStatus().isOk()
.expectBody<List<Devices.Response>>()
.consumeWith {
assertThat(it.responseBody?.size).isEqualTo(expected)
}
}
@Test
fun `get devices for type by pages - fail`() {
// when
val result = webClient.get()
.uri("/devices/type-00000000-0000-0000-0001-000000000001/page-0")
.exchange()
// then
result.expectStatus().isBadRequest
}
@ParameterizedTest
@CsvSource(
value = [
"00000000-0000-0000-0001-000000000001,1,1,1",
"00000000-0000-0000-0001-000000000001,2,1,1",
"00000000-0000-0000-0001-000000000001,3,1,0",
],
)
fun `get devices for type by page and show - success`(type: UUID, page: Int, show: Int, expected: Int) {
// when
val result = webClient.get()
.uri("/devices/type-$type/page-$page/show-$show")
.exchange()
// then
result.expectStatus().isOk()
.expectBody<List<Devices.Response>>()
.consumeWith {
assertThat(it.responseBody?.size).isEqualTo(expected)
}
}
@ParameterizedTest
@CsvSource(
value = [
"0,1",
"1,0",
],
)
fun `get devices for type by page and show - fail`(page: Int, show: Int) {
// when
val result = webClient.get()
.uri("/devices/type-00000000-0000-0000-0001-000000000001/page-$page/show-$show")
.exchange()
// then
result.expectStatus().isBadRequest
}
}
}

View File

@@ -51,4 +51,22 @@ class DevicesControllerTest {
assertThat(response.type).isEqualToUuid(NIL_UUID) assertThat(response.type).isEqualToUuid(NIL_UUID)
assertThat(response.timestamp).isEqualTo(timestamp) assertThat(response.timestamp).isEqualTo(timestamp)
} }
@Test
fun `get all devices for type`() = runTest {
// given
coEvery {
service.getDevicesByType(any(), any(), any())
} returns flowOf(DeviceEntity(id, timestamp, type))
// when
val response = controller.getDevicesByType(type).single()
// then
coVerify(exactly = 1) { service.getDevicesByType(type, 0, 25) }
assertThat(response.id).isEqualToUuid(NIL_UUID)
assertThat(response.type).isEqualToUuid(NIL_UUID)
assertThat(response.timestamp).isEqualTo(timestamp)
}
} }