Skip to content

Commit 9c6e6bf

Browse files
committed
Introduce String & Boolean BinaryOperationFilter
1 parent 521c54a commit 9c6e6bf

File tree

4 files changed

+77
-25
lines changed

4 files changed

+77
-25
lines changed

stream-android-core/src/main/java/io/getstream/android/core/api/filter/Filter.kt

Lines changed: 47 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,23 +18,38 @@ package io.getstream.android.core.api.filter
1818
import io.getstream.android.core.annotations.StreamInternalApi
1919
import io.getstream.android.core.annotations.StreamPublishedApi
2020
import io.getstream.android.core.internal.filter.BinaryOperator
21+
import io.getstream.android.core.internal.filter.BooleanBinaryOperator
2122
import io.getstream.android.core.internal.filter.CollectionOperator
2223
import io.getstream.android.core.internal.filter.FilterOperations
24+
import io.getstream.android.core.internal.filter.StringBinaryOperator
2325

2426
/**
2527
* Base interface for filters used in Stream API operations.
2628
*
2729
* Filters are used to specify criteria for querying and retrieving data from Stream services. Each
2830
* filter implementation defines specific matching logic for different comparison operations.
2931
*/
30-
@StreamPublishedApi public sealed interface Filter<M, F : FilterField<M>>
32+
@StreamPublishedApi
33+
public sealed interface Filter<M, F : FilterField<M>>
3134

3235
internal data class BinaryOperationFilter<M, F : FilterField<M>>(
3336
val operator: BinaryOperator,
3437
val field: F,
3538
val value: Any,
3639
) : Filter<M, F>
3740

41+
internal data class BooleanBinaryOperationFilter<M, F : FilterField<M>>(
42+
val operator: BooleanBinaryOperator,
43+
val field: F,
44+
val value: Boolean,
45+
) : Filter<M, F>
46+
47+
internal data class StringBinaryOperationFilter<M, F : FilterField<M>>(
48+
val operator: StringBinaryOperator,
49+
val field: F,
50+
val value: String,
51+
) : Filter<M, F>
52+
3853
internal data class CollectionOperationFilter<M, F : FilterField<M>>(
3954
internal val operator: CollectionOperator,
4055
val filters: Set<Filter<M, F>>,
@@ -45,6 +60,12 @@ internal data class CollectionOperationFilter<M, F : FilterField<M>>(
4560
public fun Filter<*, *>.toRequest(): Map<String, Any> =
4661
when (this) {
4762
is BinaryOperationFilter<*, *> -> mapOf(field.remote to mapOf(operator.remote to value))
63+
is BooleanBinaryOperationFilter<*, *> ->
64+
mapOf(field.remote to mapOf(operator.remote to value))
65+
66+
is StringBinaryOperationFilter<*, *> ->
67+
mapOf(field.remote to mapOf(operator.remote to value))
68+
4869
is CollectionOperationFilter<*, *> ->
4970
mapOf(operator.remote to filters.map(Filter<*, *>::toRequest))
5071
}
@@ -67,15 +88,37 @@ public infix fun <M, F : FilterField<M>> Filter<M, F>.matches(item: M): Boolean
6788
notNull && fieldValue greaterOrEqual filterValue
6889
BinaryOperator.LESS_OR_EQUAL -> notNull && fieldValue lessOrEqual filterValue
6990
BinaryOperator.IN -> notNull && fieldValue `in` filterValue
70-
BinaryOperator.QUERY -> notNull && search(filterValue, where = fieldValue)
71-
BinaryOperator.AUTOCOMPLETE -> notNull && fieldValue autocompletes filterValue
72-
BinaryOperator.EXISTS -> fieldValue exists filterValue
7391
BinaryOperator.CONTAINS -> notNull && fieldValue contains filterValue
7492
BinaryOperator.PATH_EXISTS -> notNull && fieldValue containsPath filterValue
7593
}
7694
}
7795
}
7896

97+
is StringBinaryOperationFilter<M, F> -> {
98+
val fieldValue = field.localValue(item)
99+
val filterValue = value
100+
val notNull = fieldValue != null
101+
102+
with(FilterOperations) {
103+
when (operator) {
104+
StringBinaryOperator.QUERY -> notNull && search(filterValue, where = fieldValue)
105+
StringBinaryOperator.AUTOCOMPLETE ->
106+
notNull && fieldValue autocompletes filterValue
107+
}
108+
}
109+
}
110+
111+
is BooleanBinaryOperationFilter<M, F> -> {
112+
val fieldValue = field.localValue(item)
113+
val filterValue = value
114+
115+
with(FilterOperations) {
116+
when (operator) {
117+
BooleanBinaryOperator.EXISTS -> fieldValue exists filterValue
118+
}
119+
}
120+
}
121+
79122
is CollectionOperationFilter<M, F> -> {
80123
when (operator) {
81124
CollectionOperator.AND -> filters.all { it.matches(item) }

stream-android-core/src/main/java/io/getstream/android/core/api/filter/Filters.kt

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ package io.getstream.android.core.api.filter
1717

1818
import io.getstream.android.core.annotations.StreamPublishedApi
1919
import io.getstream.android.core.internal.filter.BinaryOperator
20+
import io.getstream.android.core.internal.filter.BooleanBinaryOperator
2021
import io.getstream.android.core.internal.filter.CollectionOperator
22+
import io.getstream.android.core.internal.filter.StringBinaryOperator
2123

2224
/** Utility class for building filters. */
2325
public object Filters {
@@ -120,7 +122,7 @@ public fun <M, F : FilterField<M>> F.`in`(vararg values: Any): Filter<M, F> =
120122
*/
121123
@StreamPublishedApi
122124
public fun <M, F : FilterField<M>> F.query(value: String): Filter<M, F> =
123-
BinaryOperationFilter(BinaryOperator.QUERY, this, value)
125+
StringBinaryOperationFilter(StringBinaryOperator.QUERY, this, value)
124126

125127
/**
126128
* Creates a filter that performs autocomplete matching on this field.
@@ -130,7 +132,7 @@ public fun <M, F : FilterField<M>> F.query(value: String): Filter<M, F> =
130132
*/
131133
@StreamPublishedApi
132134
public fun <M, F : FilterField<M>> F.autocomplete(value: String): Filter<M, F> =
133-
BinaryOperationFilter(BinaryOperator.AUTOCOMPLETE, this, value)
135+
StringBinaryOperationFilter(StringBinaryOperator.AUTOCOMPLETE, this, value)
134136

135137
/**
136138
* Creates a filter that checks if this field exists.
@@ -139,7 +141,7 @@ public fun <M, F : FilterField<M>> F.autocomplete(value: String): Filter<M, F> =
139141
*/
140142
@StreamPublishedApi
141143
public fun <M, F : FilterField<M>> F.exists(): Filter<M, F> =
142-
BinaryOperationFilter(BinaryOperator.EXISTS, this, true)
144+
BooleanBinaryOperationFilter(BooleanBinaryOperator.EXISTS, this, true)
143145

144146
/**
145147
* Creates a filter that checks if this field does not exist.
@@ -148,7 +150,7 @@ public fun <M, F : FilterField<M>> F.exists(): Filter<M, F> =
148150
*/
149151
@StreamPublishedApi
150152
public fun <M, F : FilterField<M>> F.doesNotExist(): Filter<M, F> =
151-
BinaryOperationFilter(BinaryOperator.EXISTS, this, false)
153+
BooleanBinaryOperationFilter(BooleanBinaryOperator.EXISTS, this, false)
152154

153155
/**
154156
* Creates a filter that checks if this field contains a specific value.

stream-android-core/src/main/java/io/getstream/android/core/internal/filter/FilterOperations.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ internal object FilterOperations {
3737
}
3838
}
3939

40-
infix fun Any?.exists(that: Any): Boolean = (that is Boolean) && (this != null) == that
40+
infix fun Any?.exists(that: Boolean): Boolean = (this != null) == that
4141

4242
infix fun Any.`in`(that: Any): Boolean =
4343
when (that) {
@@ -65,20 +65,17 @@ internal object FilterOperations {
6565

6666
private val whitespaceAndPunctuation = Regex("[\\s\\p{Punct}]+")
6767

68-
infix fun Any.autocompletes(that: Any): Boolean {
69-
if (this !is String || that !is String || that.isEmpty()) {
68+
infix fun Any.autocompletes(that: String): Boolean {
69+
if (this !is String || that.isEmpty()) {
7070
return false
7171
}
7272

7373
// Split the text into words using whitespace and punctuation as delimiters
7474
return this.split(whitespaceAndPunctuation).any { word -> word.startsWith(that, true) }
7575
}
7676

77-
fun search(what: Any, where: Any): Boolean =
78-
what is String &&
79-
where is String &&
80-
what.isNotEmpty() &&
81-
where.contains(what, ignoreCase = true)
77+
fun search(what: String, where: Any): Boolean =
78+
where is String && what.isNotEmpty() && where.contains(what, ignoreCase = true)
8279

8380
infix fun Any.containsPath(that: Any): Boolean {
8481
if (this !is Map<*, *> || that !is String) return false

stream-android-core/src/main/java/io/getstream/android/core/internal/filter/FilterOperator.kt

Lines changed: 19 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,32 @@ internal enum class BinaryOperator(
4040
/** Matches any of the values specified in an array. */
4141
IN("\$in"),
4242

43-
/** Matches values by performing text search with the specified value. */
44-
QUERY("\$q"),
45-
46-
/** Matches values with the specified text. */
47-
AUTOCOMPLETE("\$autocomplete"),
48-
49-
/** Matches values that exist/don't exist based on the specified boolean value. */
50-
EXISTS("\$exists"),
51-
5243
/** Matches if the key array contains the given value. */
5344
CONTAINS("\$contains"),
5445

5546
/** Matches if the value contains JSON with the given path. */
5647
PATH_EXISTS("\$path_exists"),
5748
}
5849

50+
internal enum class BooleanBinaryOperator(
51+
/** The name of this operator as expected by the Stream API. */
52+
val remote: String
53+
) {
54+
/** Matches values that exist/don't exist based on the specified boolean value. */
55+
EXISTS("\$exists")
56+
}
57+
58+
internal enum class StringBinaryOperator(
59+
/** The name of this operator as expected by the Stream API. */
60+
val remote: String
61+
) {
62+
/** Matches values by performing text search with the specified value. */
63+
QUERY("\$q"),
64+
65+
/** Matches values with the specified text. */
66+
AUTOCOMPLETE("\$autocomplete"),
67+
}
68+
5969
internal enum class CollectionOperator(
6070
/** The name of this operator as expected by the Stream API. */
6171
val remote: String

0 commit comments

Comments
 (0)