Skip to content

Commit 8fcf7b5

Browse files
refactor(client): deduplicate page response classes (#401)
feat(client): make pagination robust to missing data docs: add comments for page methods
1 parent 206c69e commit 8fcf7b5

File tree

112 files changed

+9896
-6152
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

112 files changed

+9896
-6152
lines changed

orb-java-core/src/main/kotlin/com/withorb/api/models/AlertListPage.kt

Lines changed: 31 additions & 140 deletions
Original file line numberDiff line numberDiff line change
@@ -2,17 +2,7 @@
22

33
package com.withorb.api.models
44

5-
import com.fasterxml.jackson.annotation.JsonAnyGetter
6-
import com.fasterxml.jackson.annotation.JsonAnySetter
7-
import com.fasterxml.jackson.annotation.JsonCreator
8-
import com.fasterxml.jackson.annotation.JsonProperty
9-
import com.withorb.api.core.ExcludeMissing
10-
import com.withorb.api.core.JsonField
11-
import com.withorb.api.core.JsonMissing
12-
import com.withorb.api.core.JsonValue
13-
import com.withorb.api.errors.OrbInvalidDataException
145
import com.withorb.api.services.blocking.AlertService
15-
import java.util.Collections
166
import java.util.Objects
177
import java.util.Optional
188
import java.util.stream.Stream
@@ -34,14 +24,26 @@ class AlertListPage
3424
private constructor(
3525
private val alertsService: AlertService,
3626
private val params: AlertListParams,
37-
private val response: Response,
27+
private val response: AlertListPageResponse,
3828
) {
3929

40-
fun response(): Response = response
30+
/** Returns the response that this page was parsed from. */
31+
fun response(): AlertListPageResponse = response
4132

42-
fun data(): List<Alert> = response().data()
33+
/**
34+
* Delegates to [AlertListPageResponse], but gracefully handles missing data.
35+
*
36+
* @see [AlertListPageResponse.data]
37+
*/
38+
fun data(): List<Alert> = response._data().getOptional("data").getOrNull() ?: emptyList()
4339

44-
fun paginationMetadata(): PaginationMetadata = response().paginationMetadata()
40+
/**
41+
* Delegates to [AlertListPageResponse], but gracefully handles missing data.
42+
*
43+
* @see [AlertListPageResponse.paginationMetadata]
44+
*/
45+
fun paginationMetadata(): Optional<PaginationMetadata> =
46+
response._paginationMetadata().getOptional("pagination_metadata")
4547

4648
override fun equals(other: Any?): Boolean {
4749
if (this === other) {
@@ -56,23 +58,23 @@ private constructor(
5658
override fun toString() =
5759
"AlertListPage{alertsService=$alertsService, params=$params, response=$response}"
5860

59-
fun hasNextPage(): Boolean {
60-
if (data().isEmpty()) {
61-
return false
62-
}
63-
64-
return paginationMetadata().nextCursor().isPresent
65-
}
61+
fun hasNextPage(): Boolean =
62+
data().isNotEmpty() &&
63+
paginationMetadata().flatMap { it._nextCursor().getOptional("next_cursor") }.isPresent
6664

6765
fun getNextPageParams(): Optional<AlertListParams> {
6866
if (!hasNextPage()) {
6967
return Optional.empty()
7068
}
7169

7270
return Optional.of(
73-
AlertListParams.builder()
74-
.from(params)
75-
.apply { paginationMetadata().nextCursor().ifPresent { this.cursor(it) } }
71+
params
72+
.toBuilder()
73+
.apply {
74+
paginationMetadata()
75+
.flatMap { it._nextCursor().getOptional("next_cursor") }
76+
.ifPresent { cursor(it) }
77+
}
7678
.build()
7779
)
7880
}
@@ -86,122 +88,11 @@ private constructor(
8688
companion object {
8789

8890
@JvmStatic
89-
fun of(alertsService: AlertService, params: AlertListParams, response: Response) =
90-
AlertListPage(alertsService, params, response)
91-
}
92-
93-
class Response(
94-
private val data: JsonField<List<Alert>>,
95-
private val paginationMetadata: JsonField<PaginationMetadata>,
96-
private val additionalProperties: MutableMap<String, JsonValue>,
97-
) {
98-
99-
@JsonCreator
100-
private constructor(
101-
@JsonProperty("data") data: JsonField<List<Alert>> = JsonMissing.of(),
102-
@JsonProperty("pagination_metadata")
103-
paginationMetadata: JsonField<PaginationMetadata> = JsonMissing.of(),
104-
) : this(data, paginationMetadata, mutableMapOf())
105-
106-
fun data(): List<Alert> = data.getOptional("data").getOrNull() ?: listOf()
107-
108-
fun paginationMetadata(): PaginationMetadata =
109-
paginationMetadata.getRequired("pagination_metadata")
110-
111-
@JsonProperty("data")
112-
fun _data(): Optional<JsonField<List<Alert>>> = Optional.ofNullable(data)
113-
114-
@JsonProperty("pagination_metadata")
115-
fun _paginationMetadata(): Optional<JsonField<PaginationMetadata>> =
116-
Optional.ofNullable(paginationMetadata)
117-
118-
@JsonAnySetter
119-
private fun putAdditionalProperty(key: String, value: JsonValue) {
120-
additionalProperties.put(key, value)
121-
}
122-
123-
@JsonAnyGetter
124-
@ExcludeMissing
125-
fun _additionalProperties(): Map<String, JsonValue> =
126-
Collections.unmodifiableMap(additionalProperties)
127-
128-
private var validated: Boolean = false
129-
130-
fun validate(): Response = apply {
131-
if (validated) {
132-
return@apply
133-
}
134-
135-
data().map { it.validate() }
136-
paginationMetadata().validate()
137-
validated = true
138-
}
139-
140-
fun isValid(): Boolean =
141-
try {
142-
validate()
143-
true
144-
} catch (e: OrbInvalidDataException) {
145-
false
146-
}
147-
148-
fun toBuilder() = Builder().from(this)
149-
150-
override fun equals(other: Any?): Boolean {
151-
if (this === other) {
152-
return true
153-
}
154-
155-
return /* spotless:off */ other is Response && data == other.data && paginationMetadata == other.paginationMetadata && additionalProperties == other.additionalProperties /* spotless:on */
156-
}
157-
158-
override fun hashCode(): Int = /* spotless:off */ Objects.hash(data, paginationMetadata, additionalProperties) /* spotless:on */
159-
160-
override fun toString() =
161-
"Response{data=$data, paginationMetadata=$paginationMetadata, additionalProperties=$additionalProperties}"
162-
163-
companion object {
164-
165-
/** Returns a mutable builder for constructing an instance of [AlertListPage]. */
166-
@JvmStatic fun builder() = Builder()
167-
}
168-
169-
class Builder {
170-
171-
private var data: JsonField<List<Alert>> = JsonMissing.of()
172-
private var paginationMetadata: JsonField<PaginationMetadata> = JsonMissing.of()
173-
private var additionalProperties: MutableMap<String, JsonValue> = mutableMapOf()
174-
175-
@JvmSynthetic
176-
internal fun from(page: Response) = apply {
177-
this.data = page.data
178-
this.paginationMetadata = page.paginationMetadata
179-
this.additionalProperties.putAll(page.additionalProperties)
180-
}
181-
182-
fun data(data: List<Alert>) = data(JsonField.of(data))
183-
184-
fun data(data: JsonField<List<Alert>>) = apply { this.data = data }
185-
186-
fun paginationMetadata(paginationMetadata: PaginationMetadata) =
187-
paginationMetadata(JsonField.of(paginationMetadata))
188-
189-
fun paginationMetadata(paginationMetadata: JsonField<PaginationMetadata>) = apply {
190-
this.paginationMetadata = paginationMetadata
191-
}
192-
193-
fun putAdditionalProperty(key: String, value: JsonValue) = apply {
194-
this.additionalProperties.put(key, value)
195-
}
196-
197-
/**
198-
* Returns an immutable instance of [Response].
199-
*
200-
* Further updates to this [Builder] will not mutate the returned instance.
201-
*/
202-
fun build(): Response =
203-
Response(data, paginationMetadata, additionalProperties.toMutableMap())
204-
}
91+
fun of(
92+
alertsService: AlertService,
93+
params: AlertListParams,
94+
response: AlertListPageResponse,
95+
) = AlertListPage(alertsService, params, response)
20596
}
20697

20798
class AutoPager(private val firstPage: AlertListPage) : Iterable<Alert> {

0 commit comments

Comments
 (0)