Skip to content

Commit 1c9f331

Browse files
authored
feature: [ANDROSDK-2309] support isEmpty/isNotEmpty filter operators (#2657)
2 parents 7313086 + 5f38523 commit 1c9f331

20 files changed

Lines changed: 208 additions & 44 deletions

File tree

core/api/core.api

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2494,6 +2494,7 @@ public final class org/hisp/dhis/android/core/arch/repositories/filters/internal
24942494
public final fun gt (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
24952495
public final fun in (Ljava/util/Set;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
24962496
public final fun inRelativePeriod (Lorg/hisp/dhis/android/core/common/RelativePeriod;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
2497+
public final fun isEmpty (Z)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
24972498
public final fun le (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
24982499
public final fun like (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
24992500
public final fun lt (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
@@ -2627,6 +2628,8 @@ public final class org/hisp/dhis/android/core/arch/repositories/filters/internal
26272628
public final fun ge (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
26282629
public final fun gt (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
26292630
public final fun in (Ljava/util/Collection;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
2631+
public final fun isNotNullAndIsNotBlank ()Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
2632+
public final fun isNullOrBlank ()Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
26302633
public final fun le (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
26312634
public final fun like (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
26322635
public final fun lt (Ljava/lang/String;)Lorg/hisp/dhis/android/core/arch/repositories/collection/BaseRepository;
@@ -2887,6 +2890,8 @@ public final class org/hisp/dhis/android/core/arch/repositories/scope/internal/F
28872890
public static final field LT Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator;
28882891
public static final field NOT_EQ Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator;
28892892
public static final field NOT_IN Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator;
2893+
public static final field NOT_NULL_AND_NOT_BLANK Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator;
2894+
public static final field NULL_OR_BLANK Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator;
28902895
public static final field SW Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator;
28912896
public static final field VOID Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator;
28922897
public final fun getApiOperator ()Ljava/lang/String;
@@ -2977,7 +2982,6 @@ public class org/hisp/dhis/android/core/arch/repositories/scope/internal/Reposit
29772982
public static final field Companion Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/RepositoryScopeFilterItemBuilder$Companion;
29782983
protected field key Ljava/lang/String;
29792984
protected field operator Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator;
2980-
protected field value Ljava/lang/String;
29812985
public fun <init> ()V
29822986
public fun build ()Lorg/hisp/dhis/android/core/arch/repositories/scope/internal/RepositoryScopeFilterItem;
29832987
protected final fun getKey ()Ljava/lang/String;

core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStoreIntegrationShould.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ class EventDataFilterStoreIntegrationShould : ObjectStoreAbstractIntegrationShou
5555
.eq(null)
5656
.like(null)
5757
.dateFilter(null)
58+
.isEmpty(null)
5859
.build()
5960
}
6061
}

core/src/androidTest/java/org/hisp/dhis/android/core/programstageworkinglist/ProgramStageWorkingListAttributeValueFilterStoreIntegrationShould.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ class ProgramStageWorkingListAttributeValueFilterStoreIntegrationShould :
5656
.lt(null)
5757
.like(null)
5858
.dateFilter(null)
59+
.isEmpty(null)
5960
.build()
6061
}
6162
}

core/src/androidTest/java/org/hisp/dhis/android/core/programstageworkinglist/ProgramStageWorkingListEventDataFilterStoreIntegrationShould.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,7 @@ class ProgramStageWorkingListEventDataFilterStoreIntegrationShould :
5454
.lt(null)
5555
.like(null)
5656
.dateFilter(null)
57+
.isEmpty(null)
5758
.build()
5859
}
5960
}

core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterStoreIntegrationShould.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class AttributeValueFilterStoreIntegrationShould : ObjectStoreAbstractIntegratio
5757
.eq(null)
5858
.like(null)
5959
.dateFilter(null)
60+
.isEmpty(null)
6061
.build()
6162
}
6263
}

core/src/main/java/org/hisp/dhis/android/core/arch/repositories/filters/internal/EventDataFilterConnector.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ class EventDataFilterConnector<R : BaseRepository> internal constructor(
7474
return repositoryFactory.updated(filter)
7575
}
7676

77+
fun isEmpty(empty: Boolean): R {
78+
val filter = EventDataFilter.builder().dataItem(key).isEmpty(empty).build()
79+
return repositoryFactory.updated(filter)
80+
}
81+
7782
fun inRelativePeriod(period: RelativePeriod): R {
7883
val dateFilter = DateFilterPeriod.builder().type(DatePeriodType.RELATIVE).period(period).build()
7984
val filter = EventDataFilter.builder().dataItem(key).dateFilter(dateFilter).build()

core/src/main/java/org/hisp/dhis/android/core/arch/repositories/filters/internal/ValueSubQueryFilterConnector.kt

Lines changed: 38 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import org.hisp.dhis.android.core.arch.repositories.scope.RepositoryScope
3434
import org.hisp.dhis.android.core.arch.repositories.scope.internal.FilterItemOperator
3535
import org.hisp.dhis.android.persistence.common.querybuilders.WhereClauseBuilder
3636

37+
@Suppress("TooManyFunctions")
3738
class ValueSubQueryFilterConnector<R : BaseRepository> internal constructor(
3839
repositoryFactory: BaseRepositoryFactory<R>,
3940
scope: RepositoryScope,
@@ -50,7 +51,7 @@ class ValueSubQueryFilterConnector<R : BaseRepository> internal constructor(
5051

5152
/**
5253
* Returns a new repository whose scope is the one of the current repository plus the new filter being applied.
53-
* The like filter checks if the given field has a value equal to the value provided.
54+
* The eq filter checks if the given field has a value equal to the value provided.
5455
* @param value value to compare with the target field
5556
* @return the new repository
5657
*/
@@ -60,7 +61,7 @@ class ValueSubQueryFilterConnector<R : BaseRepository> internal constructor(
6061

6162
/**
6263
* Returns a new repository whose scope is the one of the current repository plus the new filter being applied.
63-
* The like filter checks if the given field has a value lower or equal than the value provided.
64+
* The le filter checks if the given field has a value lower or equal than the value provided.
6465
* @param value value to compare with the target field
6566
* @return the new repository
6667
*/
@@ -70,7 +71,7 @@ class ValueSubQueryFilterConnector<R : BaseRepository> internal constructor(
7071

7172
/**
7273
* Returns a new repository whose scope is the one of the current repository plus the new filter being applied.
73-
* The like filter checks if the given field has a value strictly lower than the value provided.
74+
* The lt filter checks if the given field has a value strictly lower than the value provided.
7475
* @param value value to compare with the target field
7576
* @return the new repository
7677
*/
@@ -80,7 +81,7 @@ class ValueSubQueryFilterConnector<R : BaseRepository> internal constructor(
8081

8182
/**
8283
* Returns a new repository whose scope is the one of the current repository plus the new filter being applied.
83-
* The like filter checks if the given field has a value strictly greater or equal than the value provided.
84+
* The ge filter checks if the given field has a value strictly greater or equal than the value provided.
8485
* @param value value to compare with the target field
8586
* @return the new repository
8687
*/
@@ -90,7 +91,7 @@ class ValueSubQueryFilterConnector<R : BaseRepository> internal constructor(
9091

9192
/**
9293
* Returns a new repository whose scope is the one of the current repository plus the new filter being applied.
93-
* The like filter checks if the given field has a value strictly greater than the value provided.
94+
* The gt filter checks if the given field has a value strictly greater than the value provided.
9495
* @param value value to compare with the target field
9596
* @return the new repository
9697
*/
@@ -100,7 +101,7 @@ class ValueSubQueryFilterConnector<R : BaseRepository> internal constructor(
100101

101102
/**
102103
* Returns a new repository whose scope is the one of the current repository plus the new filter being applied.
103-
* The like filter checks if the given field has a value included in the list provided.
104+
* The in filter checks if the given field has a value included in the list provided.
104105
* @param values value list to compare with the target field
105106
* @return the new repository
106107
*/
@@ -119,6 +120,37 @@ class ValueSubQueryFilterConnector<R : BaseRepository> internal constructor(
119120
return inLinkTable(FilterItemOperator.LIKE, wrapValue("%$value%"))
120121
}
121122

123+
/**
124+
* Returns a new repository whose scope is the one of the current repository plus the new filter being applied.
125+
* The isNullOrBlank filter checks if the given field is null or blank.
126+
* @return the new repository
127+
*/
128+
fun isNullOrBlank(): R {
129+
val whereClause = WhereClauseBuilder()
130+
.appendIsNullOrValue(linkChild, "")
131+
.appendKeyStringValue(dataElementColumn, dataElementId)
132+
.build()
133+
return inTableWhere(whereClause)
134+
}
135+
136+
/**
137+
* Returns a new repository whose scope is the one of the current repository plus the new filter being applied.
138+
* The isNotNullAndIsNotBlank filter checks if the given field is not null and not blank.
139+
* @return the new repository
140+
*/
141+
fun isNotNullAndIsNotBlank(): R {
142+
val whereClause = WhereClauseBuilder()
143+
.appendComplexQuery(
144+
WhereClauseBuilder()
145+
.appendIsNotNullValue(linkChild)
146+
.appendNotKeyStringValue(linkChild, "")
147+
.build(),
148+
)
149+
.appendKeyStringValue(dataElementColumn, dataElementId)
150+
.build()
151+
return inTableWhere(whereClause)
152+
}
153+
122154
private fun inLinkTable(operator: FilterItemOperator, value: String): R {
123155
val whereClause = WhereClauseBuilder()
124156
.appendKeyOperatorValue(linkChild, operator.sqlOperator, value)

core/src/main/java/org/hisp/dhis/android/core/arch/repositories/scope/internal/FilterItemOperator.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,4 +40,19 @@ enum class FilterItemOperator(val sqlOperator: String, val apiOperator: String,
4040
SW("LIKE", "sw", "SW"),
4141
EW("LIKE", "ew", "EW"),
4242
VOID("", "", ""),
43+
NULL_OR_BLANK("", "null", "NULL"),
44+
NOT_NULL_AND_NOT_BLANK("", "!null", "!NULL"),
45+
;
46+
47+
/**
48+
* Builds the full SQL condition for this operator. NULL_OR_BLANK and NOT_NULL_AND_NOT_BLANK cannot be expressed
49+
* as "column sqlOperator value" because they need the column name in both sides of the OR/AND condition.
50+
*/
51+
internal fun getSqlCondition(column: String, valueStr: String? = null): String {
52+
return when (this) {
53+
NULL_OR_BLANK -> "($column IS NULL OR $column = '')"
54+
NOT_NULL_AND_NOT_BLANK -> "($column IS NOT NULL AND $column != '')"
55+
else -> "$column $sqlOperator $valueStr"
56+
}
57+
}
4358
}

core/src/main/java/org/hisp/dhis/android/core/arch/repositories/scope/internal/RepositoryScopeFilterItem.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,11 @@ import org.hisp.dhis.android.annotations.ModelBuilder
3333
data class RepositoryScopeFilterItem(
3434
val key: String,
3535
val operator: FilterItemOperator,
36-
val value: String,
36+
val value: String?,
3737
) {
3838
fun key(): String = key
3939
fun operator(): FilterItemOperator = operator
40-
fun value(): String = value
40+
fun value(): String? = value
4141

4242
fun toBuilder(): Builder = RepositoryScopeFilterItemBuilder.from(this)
4343

core/src/main/java/org/hisp/dhis/android/core/arch/repositories/scope/internal/WhereClauseFromScopeBuilder.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ internal class WhereClauseFromScopeBuilder(private val builder: WhereClauseBuild
3636
return "1"
3737
}
3838
for (item in scope.filters()) {
39-
builder.appendKeyOperatorValue(item.key(), item.operator().sqlOperator, item.value())
39+
builder.appendComplexQuery(item.operator().getSqlCondition(item.key(), item.value() ?: ""))
4040
}
4141
for (item in scope.complexFilters()) {
4242
builder.appendComplexQuery(item.whereQuery())

0 commit comments

Comments
 (0)