Skip to content

Commit 8530822

Browse files
authored
Merge pull request #13 from ctrl-hub/fix/filter-options-in-request
fix: rename filterOptions to filters and implement filter expression …
2 parents 7f88637 + e090f59 commit 8530822

File tree

6 files changed

+98
-17
lines changed

6 files changed

+98
-17
lines changed

src/main/kotlin/com/ctrlhub/core/datacapture/FormSchemasRouter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,12 +27,12 @@ enum class FormSchemaIncludes(val value: String) : JsonApiIncludes {
2727
class FormSchemaRequestParameters(
2828
offset: Int = 0,
2929
limit: Int = 100,
30-
filterOptions: List<FilterOption> = emptyList(),
30+
filters: List<FilterOption> = emptyList(),
3131
includes: List<FormSchemaIncludes> = emptyList()
3232
) : RequestParametersWithIncludes<FormSchemaIncludes>(
3333
offset = offset,
3434
limit = limit,
35-
filterOptions = filterOptions,
35+
filters = filters,
3636
includes = includes,
3737
)
3838

src/main/kotlin/com/ctrlhub/core/datacapture/FormSubmissionVersionsRouter.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -34,12 +34,12 @@ enum class FormSubmissionVersionIncludes(val key: String) : JsonApiIncludes {
3434
class FormSubmissionVersionRequestParameters(
3535
offset: Int = 0,
3636
limit: Int = 100,
37-
filterOptions: List<FilterOption> = emptyList(),
37+
filters: List<FilterOption> = emptyList(),
3838
includes: List<FormSubmissionVersionIncludes> = emptyList()
3939
) : RequestParametersWithIncludes<FormSubmissionVersionIncludes>(
4040
offset = offset,
4141
limit = limit,
42-
filterOptions = filterOptions,
42+
filters = filters,
4343
includes = includes,
4444
)
4545

src/main/kotlin/com/ctrlhub/core/datacapture/FormSubmissionsRouter.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ class FormSubmissionsRouter(httpClient: HttpClient) : Router(httpClient) {
1818
suspend fun all(organisationId: String, formId: String): PaginatedList<FormSubmission> {
1919
return fetchPaginatedJsonApiResources(
2020
"/v3/orgs/$organisationId/data-capture/forms/$formId/submissions",
21-
queryParameters = emptyMap<String, String>(),
21+
queryParameters = emptyMap(),
2222
FormSubmission::class.java,
2323
User::class.java,
2424
Form::class.java,
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package com.ctrlhub.core.router.request
2+
3+
sealed interface FilterOption {
4+
fun format(): String
5+
}
6+
7+
class FieldFilterExpression(val field: String, val values: List<String>) : FilterOption {
8+
override fun format(): String {
9+
val quoted = values.joinToString(",") { "'${it}'" }
10+
return "${field}($quoted)"
11+
}
12+
}
13+
14+
class ValueFilterExpression(val value: String) : FilterOption {
15+
override fun format(): String = value
16+
}
17+
18+
class AndExpression(val parts: List<FilterOption>) : FilterOption {
19+
override fun format(): String = "and(${parts.joinToString(",") { it.format() }})"
20+
}
21+
22+
class OrExpression(val parts: List<FilterOption>) : FilterOption {
23+
override fun format(): String = "or(${parts.joinToString(",") { it.format() }})"
24+
}

src/main/kotlin/com/ctrlhub/core/router/request/RequestParameters.kt

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
package com.ctrlhub.core.router.request
22

3-
data class FilterOption(
4-
val field: String,
5-
val value: String
6-
)
7-
83
abstract class AbstractRequestParameters(
94
val offset: Int? = null,
105
val limit: Int? = null,
11-
val filterOptions: List<FilterOption>
6+
val filters: List<FilterOption> = emptyList()
127
) {
138
open fun toMap(): Map<String, String> {
149
val queryParams = mutableMapOf<String, String>()
1510
offset?.let { queryParams["offset"] = it.toString() }
1611
limit?.let { queryParams["limit"] = it.toString() }
1712

18-
filterOptions.forEach { queryParams["filter"] = "${it.field}('${it.value}')" }
13+
val parts = mutableListOf<String>()
14+
15+
for (expr in filters) {
16+
parts += expr.format()
17+
}
18+
19+
if (parts.isNotEmpty()) {
20+
queryParams["filter"] = parts.joinToString(",")
21+
}
1922

2023
return queryParams
2124
}
@@ -30,10 +33,11 @@ class RequestParameters(
3033
open class RequestParametersWithIncludes<TIncludes>(
3134
offset: Int? = null,
3235
limit: Int? = null,
33-
filterOptions: List<FilterOption> = emptyList(),
36+
filters: List<FilterOption> = emptyList(),
3437
val includes: List<TIncludes> = emptyList()
35-
) : AbstractRequestParameters(offset, limit, filterOptions) where TIncludes : JsonApiIncludes {
38+
) : AbstractRequestParameters(offset, limit, filters) where TIncludes : JsonApiIncludes {
3639

40+
@Suppress("unused")
3741
fun withIncludes(vararg includes: TIncludes): RequestParametersWithIncludes<TIncludes> {
3842
return copy(includes = this.includes + includes)
3943
}
@@ -53,7 +57,7 @@ open class RequestParametersWithIncludes<TIncludes>(
5357
}
5458

5559
private fun copy(
56-
filterOptions: List<FilterOption> = this.filterOptions,
57-
includes: List<TIncludes> = this.includes
58-
) = RequestParametersWithIncludes(offset, limit, filterOptions, includes)
60+
includes: List<TIncludes> = this.includes,
61+
filters: List<FilterOption> = this.filters
62+
) = RequestParametersWithIncludes(offset, limit, filters, includes)
5963
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package com.ctrlhub.core.router.request
2+
3+
import org.junit.jupiter.api.Assertions.assertEquals
4+
import org.junit.jupiter.api.Test
5+
6+
class RequestParametersFiltersTest {
7+
8+
@Test
9+
fun `and of two field expressions formats correctly`() {
10+
val expr = AndExpression(
11+
listOf(
12+
FieldFilterExpression("status", listOf("open")),
13+
FieldFilterExpression("category", listOf("news"))
14+
)
15+
)
16+
17+
val params = RequestParameters(filterOptions = listOf(expr))
18+
val map = params.toMap()
19+
20+
assertEquals("and(status('open'),category('news'))", map["filter"])
21+
}
22+
23+
@Test
24+
fun `and of functions formats correctly`() {
25+
val expr = AndExpression(
26+
listOf(
27+
ValueFilterExpression("is_latest()"),
28+
ValueFilterExpression("no_start()"),
29+
)
30+
)
31+
32+
val params = RequestParameters(filterOptions = listOf(expr))
33+
val map = params.toMap()
34+
35+
assertEquals("and(is_latest(),no_start())", map["filter"])
36+
}
37+
38+
@Test
39+
fun `mixed and expression with field and function`() {
40+
val expr = AndExpression(
41+
listOf(
42+
FieldFilterExpression("status", listOf("active")),
43+
ValueFilterExpression("is_latest()")
44+
)
45+
)
46+
47+
val params = RequestParameters(filterOptions = listOf(expr))
48+
val map = params.toMap()
49+
50+
assertEquals("and(status('active'),is_latest())", map["filter"])
51+
}
52+
}
53+

0 commit comments

Comments
 (0)