diff --git a/core/build.gradle b/core/build.gradle index e5ff971c50..0c12c710e2 100644 --- a/core/build.gradle +++ b/core/build.gradle @@ -42,8 +42,8 @@ ext { buildToolsVersion: "30.0.2", minSdkVersion : 21, targetSdkVersion : 31, - versionCode : 261, - versionName : "1.6.1" + versionCode : 262, + versionName : "1.6.2" ] libraries = [ diff --git a/core/gradle.properties b/core/gradle.properties index bbd36100c1..b61b39df03 100644 --- a/core/gradle.properties +++ b/core/gradle.properties @@ -29,8 +29,8 @@ # Properties which are consumed by plugins/gradle-mvn-push.gradle plugin. # They are used for publishing artifact to snapshot repository. -VERSION_NAME=1.6.1 -VERSION_CODE=261 +VERSION_NAME=1.6.2 +VERSION_CODE=262 GROUP=org.hisp.dhis diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/MetadataCallRealIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/MetadataCallRealIntegrationShould.java index 890fd8de90..dd478590d0 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/MetadataCallRealIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/MetadataCallRealIntegrationShould.java @@ -32,6 +32,7 @@ import org.junit.Before; + import java.io.IOException; import io.reactivex.schedulers.Schedulers; diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/EventDataItemSQLEvaluatorIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/EventDataItemSQLEvaluatorIntegrationShould.kt new file mode 100644 index 0000000000..8fa866b6e6 --- /dev/null +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/EventDataItemSQLEvaluatorIntegrationShould.kt @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator + +import com.google.common.truth.Truth.assertThat +import org.hisp.dhis.android.core.analytics.aggregated.DimensionItem +import org.hisp.dhis.android.core.analytics.aggregated.MetadataItem +import org.hisp.dhis.android.core.analytics.aggregated.internal.AnalyticsServiceEvaluationItem +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.attribute1 +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.dataElement1 +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.firstNovember2019 +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.generator +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.orgunitChild1 +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.program +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.programStage1 +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.trackedEntity1 +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.trackedEntity2 +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.BaseEvaluatorSamples.trackedEntityType +import org.hisp.dhis.android.core.common.RelativePeriod +import org.hisp.dhis.android.core.dataelement.DataElement +import org.hisp.dhis.android.core.program.Program +import org.hisp.dhis.android.core.program.programindicatorengine.BaseTrackerDataIntegrationHelper +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(D2JunitRunner::class) +internal class EventDataItemSQLEvaluatorIntegrationShould : BaseEvaluatorIntegrationShould() { + + private val eventDataItemEvaluator = EventDataItemSQLEvaluator(databaseAdapter) + + private val helper = BaseTrackerDataIntegrationHelper(databaseAdapter) + + @Test + fun should_aggregate_data_from_multiple_teis() { + helper.createTrackedEntity(trackedEntity1.uid(), orgunitChild1.uid(), trackedEntityType.uid()) + val enrollment1 = generator.generate() + helper.createEnrollment(trackedEntity1.uid(), enrollment1, program.uid(), orgunitChild1.uid()) + val event1 = generator.generate() + helper.createTrackerEvent( + event1, enrollment1, program.uid(), programStage1.uid(), orgunitChild1.uid(), + eventDate = firstNovember2019 + ) + + helper.createTrackedEntity(trackedEntity2.uid(), orgunitChild1.uid(), trackedEntityType.uid()) + val enrollment2 = generator.generate() + helper.createEnrollment(trackedEntity2.uid(), enrollment2, program.uid(), orgunitChild1.uid()) + val event2 = generator.generate() + helper.createTrackerEvent( + event2, enrollment2, program.uid(), programStage1.uid(), orgunitChild1.uid(), + eventDate = firstNovember2019 + ) + + helper.insertTrackedEntityDataValue(event1, dataElement1.uid(), "10") + helper.insertTrackedEntityDataValue(event2, dataElement1.uid(), "20") + + val eventDataValue = evaluateEventDataElement(program, dataElement1) + assertThat(eventDataValue).isEqualTo("30") + + helper.insertTrackedEntityAttributeValue(trackedEntity1.uid(), attribute1.uid(), "5") + helper.insertTrackedEntityAttributeValue(trackedEntity2.uid(), attribute1.uid(), "3") + + val attributeValue = evaluateEventAttribute(program, attribute1) + assertThat(attributeValue).isEqualTo("8") + } + + private fun evaluateEventDataElement(program: Program, dataElement: DataElement): String? { + val evaluationItem = AnalyticsServiceEvaluationItem( + dimensionItems = listOf( + DimensionItem.DataItem.EventDataItem.DataElement(program.uid(), dataElement.uid()) + ), + filters = listOf( + DimensionItem.OrganisationUnitItem.Absolute(BaseEvaluatorSamples.orgunitParent.uid()), + DimensionItem.PeriodItem.Relative(RelativePeriod.LAST_MONTH) + ) + ) + + val metadataItem = MetadataItem.EventDataElementItem(dataElement, program) + + return eventDataItemEvaluator.evaluate( + evaluationItem, + metadata + (metadataItem.id to metadataItem) + ) + } + + private fun evaluateEventAttribute(program: Program, attribute: TrackedEntityAttribute): String? { + val evaluationItem = AnalyticsServiceEvaluationItem( + dimensionItems = listOf( + DimensionItem.DataItem.EventDataItem.Attribute(program.uid(), attribute.uid()) + ), + filters = listOf( + DimensionItem.OrganisationUnitItem.Absolute(BaseEvaluatorSamples.orgunitParent.uid()), + DimensionItem.PeriodItem.Relative(RelativePeriod.LAST_MONTH) + ) + ) + + val metadataItem = MetadataItem.EventAttributeItem(attribute, program) + + return eventDataItemEvaluator.evaluate( + evaluationItem, + metadata + (metadataItem.id to metadataItem) + ) + } +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/analytics/eventlinelist/EventLineListIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/analytics/eventlinelist/EventLineListIntegrationShould.kt index a1ce7c7ed7..78ad8e609e 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/analytics/eventlinelist/EventLineListIntegrationShould.kt +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/analytics/eventlinelist/EventLineListIntegrationShould.kt @@ -132,7 +132,8 @@ class EventLineListIntegrationShould : BaseMockIntegrationTestEmptyDispatcher() dataElementRepository = d2.dataElementModule().dataElements(), programIndicatorRepository = d2.programModule().programIndicators(), legendRepository = d2.legendSetModule().legends(), - indicatorRepository = d2.indicatorModule().indicators() + indicatorRepository = d2.indicatorModule().indicators(), + trackedEntityAttributeCollectionRepository = d2.trackedEntityModule().trackedEntityAttributes(), ) ) diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/category/internal/CategoryCategoryComboLinkStoreIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/category/internal/CategoryCategoryComboLinkStoreIntegrationShould.kt similarity index 57% rename from core/src/androidTest/java/org/hisp/dhis/android/core/category/internal/CategoryCategoryComboLinkStoreIntegrationShould.java rename to core/src/androidTest/java/org/hisp/dhis/android/core/category/internal/CategoryCategoryComboLinkStoreIntegrationShould.kt index d136b89256..d94be6ef2a 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/category/internal/CategoryCategoryComboLinkStoreIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/category/internal/CategoryCategoryComboLinkStoreIntegrationShould.kt @@ -25,55 +25,48 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.category.internal -package org.hisp.dhis.android.core.category.internal; +import com.google.common.truth.Truth.assertThat +import org.hisp.dhis.android.core.category.CategoryCategoryComboLink +import org.hisp.dhis.android.core.category.CategoryCategoryComboLinkTableInfo +import org.hisp.dhis.android.core.category.internal.CategoryCategoryComboLinkStore.create +import org.hisp.dhis.android.core.data.category.CategoryCategoryComboLinkSamples +import org.hisp.dhis.android.core.data.database.LinkStoreAbstractIntegrationShould +import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.Test +import org.junit.runner.RunWith -import org.hisp.dhis.android.core.category.CategoryCategoryComboLink; -import org.hisp.dhis.android.core.category.CategoryCategoryComboLinkTableInfo; -import org.hisp.dhis.android.core.data.category.CategoryCategoryComboLinkSamples; -import org.hisp.dhis.android.core.data.database.LinkStoreAbstractIntegrationShould; -import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory; -import org.hisp.dhis.android.core.utils.runner.D2JunitRunner; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.Map; - -import static com.google.common.truth.Truth.assertThat; - -@RunWith(D2JunitRunner.class) -public class CategoryCategoryComboLinkStoreIntegrationShould - extends LinkStoreAbstractIntegrationShould { - - public CategoryCategoryComboLinkStoreIntegrationShould() { - super(CategoryCategoryComboLinkStore.create(TestDatabaseAdapterFactory.get()), - CategoryCategoryComboLinkTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get()); +@RunWith(D2JunitRunner::class) +class CategoryCategoryComboLinkStoreIntegrationShould : LinkStoreAbstractIntegrationShould( + create(TestDatabaseAdapterFactory.get()), + CategoryCategoryComboLinkTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get() +) { + override fun addMasterUid(): String { + return CategoryCategoryComboLinkSamples.getCategoryCategoryComboLink().categoryCombo()!! } - @Override - protected String addMasterUid() { - return CategoryCategoryComboLinkSamples.getCategoryCategoryComboLink().categoryCombo(); + override fun buildObject(): CategoryCategoryComboLink { + return CategoryCategoryComboLinkSamples.getCategoryCategoryComboLink() } - @Override - protected CategoryCategoryComboLink buildObject() { - return CategoryCategoryComboLinkSamples.getCategoryCategoryComboLink(); - } - - @Override - protected CategoryCategoryComboLink buildObjectWithOtherMasterUid() { + override fun buildObjectWithOtherMasterUid(): CategoryCategoryComboLink { return buildObject().toBuilder() - .categoryCombo("new_category_combo") - .build(); + .categoryCombo("new_category_combo") + .build() } @Test - public void count_by_master_column() { - store.insert(buildObjectWithOtherMasterUid()); - store.insert(buildObject()); - Map count = store.groupAndGetCountBy(CategoryCategoryComboLinkTableInfo.Columns.CATEGORY_COMBO); - assertThat(count.keySet().size()).isEqualTo(2); - assertThat(count.get(buildObjectWithOtherMasterUid().categoryCombo())).isEqualTo(1); - assertThat(count.get(buildObject().categoryCombo())).isEqualTo(1); + fun count_by_master_column() { + store.insert(buildObjectWithOtherMasterUid()) + store.insert(buildObject()) + + val count: Map = + store.groupAndGetCountBy(CategoryCategoryComboLinkTableInfo.Columns.CATEGORY_COMBO) + + assertThat(count.keys.size).isEqualTo(2) + assertThat(count[buildObjectWithOtherMasterUid().categoryCombo()]).isEqualTo(1) + assertThat(count[buildObject().categoryCombo()]).isEqualTo(1) } -} \ No newline at end of file +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableDataObjectStoreAbstractIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableDataObjectStoreAbstractIntegrationShould.java deleted file mode 100644 index 5e40715255..0000000000 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableDataObjectStoreAbstractIntegrationShould.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.data.database; - -import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter; -import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore; -import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo; -import org.hisp.dhis.android.core.common.CoreObject; -import org.hisp.dhis.android.core.common.DataObject; -import org.hisp.dhis.android.core.common.ObjectWithDeleteInterface; -import org.hisp.dhis.android.core.common.ObjectWithUidInterface; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; - -import static com.google.common.truth.Truth.assertThat; - -public abstract class IdentifiableDataObjectStoreAbstractIntegrationShould extends IdentifiableObjectStoreAbstractIntegrationShould { - - private M objectWithToDeleteState; - private M objectWithSyncedState; - - public IdentifiableDataObjectStoreAbstractIntegrationShould(IdentifiableObjectStore store, - TableInfo tableInfo, - DatabaseAdapter databaseAdapter) { - super(store, tableInfo, databaseAdapter); - this.objectWithToDeleteState = buildObjectWithToDeleteState(); - this.objectWithSyncedState = buildObjectWithSyncedState(); - } - - protected abstract M buildObjectWithToDeleteState(); - - protected abstract M buildObjectWithSyncedState(); - - @Before - public void setUp() throws IOException { - super.setUp(); - } - - @Test - public void return_a_deleted_object_if_state_set_as_to_delete() { - store.insert(objectWithToDeleteState); - M object = store.selectFirst(); - assertThat(object.deleted()).isEqualTo(Boolean.TRUE); - } - - @Test - public void return_a_not_deleted_object_if_state_set_as_synced() { - store.insert(objectWithSyncedState); - M object = store.selectFirst(); - assertThat(object.deleted()).isEqualTo(Boolean.FALSE); - } -} \ No newline at end of file diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableDataObjectStoreAbstractIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableDataObjectStoreAbstractIntegrationShould.kt new file mode 100644 index 0000000000..70778331e0 --- /dev/null +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableDataObjectStoreAbstractIntegrationShould.kt @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.data.database + +import com.google.common.truth.Truth.assertThat +import java.io.IOException +import java.lang.Boolean +import kotlin.Throws +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore +import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo +import org.hisp.dhis.android.core.common.CoreObject +import org.hisp.dhis.android.core.common.DataObject +import org.hisp.dhis.android.core.common.ObjectWithDeleteInterface +import org.hisp.dhis.android.core.common.ObjectWithUidInterface +import org.junit.Before +import org.junit.Test + +abstract class IdentifiableDataObjectStoreAbstractIntegrationShould internal constructor( + store: IdentifiableObjectStore, + tableInfo: TableInfo, + databaseAdapter: DatabaseAdapter +) : IdentifiableObjectStoreAbstractIntegrationShould( + store, tableInfo, databaseAdapter +) where M : ObjectWithUidInterface, M : CoreObject, M : DataObject, M : ObjectWithDeleteInterface { + + private val objectWithToDeleteState: M + private val objectWithSyncedState: M + + protected abstract fun buildObjectWithToDeleteState(): M + protected abstract fun buildObjectWithSyncedState(): M + + @Before + @Throws(IOException::class) + override fun setUp() { + super.setUp() + } + + @Test + fun return_a_deleted_object_if_state_set_as_to_delete() { + store.insert(objectWithToDeleteState) + val obj = store.selectFirst() + assertThat(obj!!.deleted()).isEqualTo(Boolean.TRUE) + } + + @Test + fun return_a_not_deleted_object_if_state_set_as_synced() { + store.insert(objectWithSyncedState) + val obj = store.selectFirst() + assertThat(obj!!.deleted()).isEqualTo(Boolean.FALSE) + } + + init { + objectWithToDeleteState = buildObjectWithToDeleteState() + objectWithSyncedState = buildObjectWithSyncedState() + } +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableObjectStoreAbstractIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableObjectStoreAbstractIntegrationShould.java deleted file mode 100644 index 27fcebf556..0000000000 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableObjectStoreAbstractIntegrationShould.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.data.database; - -import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter; -import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore; -import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo; -import org.hisp.dhis.android.core.arch.handlers.internal.HandleAction; -import org.hisp.dhis.android.core.common.CoreObject; -import org.hisp.dhis.android.core.common.ObjectWithUidInterface; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.util.Collections; -import java.util.List; - -import static com.google.common.truth.Truth.assertThat; - -public abstract class IdentifiableObjectStoreAbstractIntegrationShould - extends ObjectStoreAbstractIntegrationShould { - - private M objectToUpdate; - IdentifiableObjectStore store; - - public IdentifiableObjectStoreAbstractIntegrationShould(IdentifiableObjectStore store, TableInfo tableInfo, DatabaseAdapter databaseAdapter) { - super(store, tableInfo, databaseAdapter); - this.store = store; - this.objectToUpdate = buildObjectToUpdate(); - } - - protected abstract M buildObjectToUpdate(); - - @Before - public void setUp() throws IOException { - super.setUp(); - } - - @Test - public void insert_and_select_by_uid() { - store.insert(object); - M objectFromDb = store.selectByUid(object.uid()); - assertEqualsIgnoreId(objectFromDb); - } - - @Test - public void insert_and_select_by_uid_list() { - store.insert(object); - List listFromDb = store.selectByUids(Collections.singletonList(object.uid())); - assertThat(listFromDb.size()).isEqualTo(1); - assertEqualsIgnoreId(listFromDb.get(0)); - } - - @Test - public void select_inserted_object_uid() { - store.insert(object); - String objectUidFromDb = store.selectUids().iterator().next(); - assertThat(objectUidFromDb).isEqualTo(object.uid()); - } - - @Test - public void delete_inserted_object_by_uid() { - store.insert(object); - store.delete(object.uid()); - assertThat(store.selectFirst()).isEqualTo(null); - } - - @Test(expected = RuntimeException.class) - public void throw_exception_if_try_to_delete_an_object_which_does_not_exists() { - store.delete(object.uid()); - } - - @Test - public void not_throw_exception_if_try_to_delete_an_object_which_does_not_exists() { - store.deleteIfExists(object.uid()); - } - - @Test - public void delete_if_exists_inserted_object_by_uid() { - store.insert(object); - store.deleteIfExists(object.uid()); - assertThat(store.selectFirst()).isEqualTo(null); - } - - @Test - public void update_inserted_object() { - store.insert(object); - store.update(objectToUpdate); - M updatedObjectFromDb = store.selectFirst(); - assertEqualsIgnoreId(updatedObjectFromDb, objectToUpdate); - } - - @Test - public void insert_object_if_object_does_not_exists() { - HandleAction handleAction = store.updateOrInsert(objectToUpdate); - assertThat(handleAction).isEqualTo(HandleAction.Insert); - } - - @Test - public void update_inserted_object_if_object_exists() { - store.insert(object); - HandleAction handleAction = store.updateOrInsert(objectToUpdate); - assertThat(handleAction).isEqualTo(HandleAction.Update); - } - - @Test - public void select_inserted_object_uids_where() { - // TODO Implement test for store.selectUidsWhere() method - } -} \ No newline at end of file diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableObjectStoreAbstractIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableObjectStoreAbstractIntegrationShould.kt new file mode 100644 index 0000000000..df112b0047 --- /dev/null +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/IdentifiableObjectStoreAbstractIntegrationShould.kt @@ -0,0 +1,146 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.data.database + +import com.google.common.truth.Truth.assertThat +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers +import java.io.IOException +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore +import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo +import org.hisp.dhis.android.core.arch.handlers.internal.HandleAction +import org.hisp.dhis.android.core.common.CoreObject +import org.hisp.dhis.android.core.common.ObjectWithUidInterface +import org.junit.Before +import org.junit.Test + +abstract class IdentifiableObjectStoreAbstractIntegrationShould internal constructor( + internal var store: IdentifiableObjectStore, + tableInfo: TableInfo, + databaseAdapter: DatabaseAdapter? +) : ObjectStoreAbstractIntegrationShould( + store, tableInfo, databaseAdapter!! +) where M : ObjectWithUidInterface, M : CoreObject { + private val objectToUpdate: M + protected abstract fun buildObjectToUpdate(): M + + @Before + @Throws(IOException::class) + override fun setUp() { + super.setUp() + } + + @Test + fun insert_and_select_by_uid() { + store.insert(`object`) + val objectFromDb = store.selectByUid(`object`.uid()) + assertEqualsIgnoreId(objectFromDb) + } + + @Test + fun insert_and_select_by_uid_list() { + store.insert(`object`) + val listFromDb = store.selectByUids(listOf(`object`.uid())) + assertThat(listFromDb.size).isEqualTo(1) + assertEqualsIgnoreId(listFromDb[0]) + } + + @Test + fun select_inserted_object_uid() { + store.insert(`object`) + val objectUidFromDb = store.selectUids().iterator().next() + assertThat(objectUidFromDb).isEqualTo(`object`.uid()) + } + + @Test + fun delete_inserted_object_by_uid() { + store.insert(`object`) + store.delete(`object`.uid()) + assertThat(store.selectFirst()).isEqualTo(null) + } + + @Test(expected = RuntimeException::class) + fun throw_exception_if_try_to_delete_an_object_which_does_not_exists() { + store.delete(`object`.uid()) + } + + @Test + fun not_throw_exception_if_try_to_delete_an_object_which_does_not_exists() { + store.deleteIfExists(`object`.uid()) + } + + @Test + fun delete_if_exists_inserted_object_by_uid() { + store.insert(`object`) + store.deleteIfExists(`object`.uid()) + assertThat(store.selectFirst()).isEqualTo(null) + } + + @Test + fun update_inserted_object() { + store.insert(`object`) + store.update(objectToUpdate) + val updatedObjectFromDb = store.selectFirst() + assertEqualsIgnoreId(updatedObjectFromDb, objectToUpdate) + } + + @Test + fun insert_object_if_object_does_not_exists() { + val handleAction = store.updateOrInsert(objectToUpdate) + assertThat(handleAction).isEqualTo(HandleAction.Insert) + } + + @Test + fun update_inserted_object_if_object_exists() { + store.insert(`object`) + val handleAction = store.updateOrInsert(objectToUpdate) + assertThat(handleAction).isEqualTo(HandleAction.Update) + } + + @Test + fun insert_same_object_simultaneously_and_transactionally() { + val s1 = Single.fromCallable { store.updateOrInsert(`object`) }.subscribeOn(Schedulers.io()) + val s2 = Single.fromCallable { store.updateOrInsert(`object`) }.subscribeOn(Schedulers.io()) + + s1.mergeWith(s2).blockingSubscribe() + + val objects = store.selectAll() + + assertThat(objects.size).isEqualTo(1) + } + + @Test + fun select_inserted_object_uids_where() { + // TODO Implement test for store.selectUidsWhere() method + } + + init { + objectToUpdate = buildObjectToUpdate() + } +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/LinkStoreAbstractIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/LinkStoreAbstractIntegrationShould.kt similarity index 53% rename from core/src/androidTest/java/org/hisp/dhis/android/core/data/database/LinkStoreAbstractIntegrationShould.java rename to core/src/androidTest/java/org/hisp/dhis/android/core/data/database/LinkStoreAbstractIntegrationShould.kt index 248c8720a7..940fa46a77 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/LinkStoreAbstractIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/LinkStoreAbstractIntegrationShould.kt @@ -25,58 +25,54 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.data.database -package org.hisp.dhis.android.core.data.database; +import com.google.common.truth.Truth.assertThat +import java.io.IOException +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.LinkStore +import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo +import org.hisp.dhis.android.core.common.CoreObject +import org.junit.Before +import org.junit.Test -import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter; -import org.hisp.dhis.android.core.arch.db.stores.internal.LinkStore; -import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo; -import org.hisp.dhis.android.core.common.CoreObject; -import org.junit.Before; -import org.junit.Test; +abstract class LinkStoreAbstractIntegrationShould internal constructor( + internal var store: LinkStore, + tableInfo: TableInfo, + databaseAdapter: DatabaseAdapter +) : ObjectStoreAbstractIntegrationShould(store, tableInfo, databaseAdapter) { -import java.io.IOException; + private val objectWithOtherMasterUid: M + private val masterUid: String -import static com.google.common.truth.Truth.assertThat; - -public abstract class LinkStoreAbstractIntegrationShould - extends ObjectStoreAbstractIntegrationShould { - - private M objectWithOtherMasterUid; - private String masterUid; - protected LinkStore store; - - public LinkStoreAbstractIntegrationShould(LinkStore store, - TableInfo tableInfo, - DatabaseAdapter databaseAdapter) { - super(store, tableInfo, databaseAdapter); - this.store = store; - this.objectWithOtherMasterUid = buildObjectWithOtherMasterUid(); - this.masterUid = addMasterUid(); - } - - protected abstract M buildObjectWithOtherMasterUid(); - protected abstract String addMasterUid(); + protected abstract fun buildObjectWithOtherMasterUid(): M + protected abstract fun addMasterUid(): String @Before - public void setUp() throws IOException { - super.setUp(); + @Throws(IOException::class) + override fun setUp() { + super.setUp() } @Test - public void delete_link_for_master_uid() { - store.insert(object); - store.deleteLinksForMasterUid(masterUid); - M objectFromDb = store.selectFirst(); - assertThat(objectFromDb).isEqualTo(null); + fun delete_link_for_master_uid() { + store.insert(`object`) + store.deleteLinksForMasterUid(masterUid) + val objectFromDb = store.selectFirst() + assertThat(objectFromDb).isEqualTo(null) } @Test - public void delete_links_for_master_should_delete_only_objects_with_the_master_key() { - store.insert(object); - store.insert(objectWithOtherMasterUid); - store.deleteLinksForMasterUid(masterUid); - M objectFromDb = store.selectFirst(); - assertEqualsIgnoreId(objectFromDb, objectWithOtherMasterUid); + fun delete_links_for_master_should_delete_only_objects_with_the_master_key() { + store.insert(`object`) + store.insert(objectWithOtherMasterUid) + store.deleteLinksForMasterUid(masterUid) + val objectFromDb = store.selectFirst() + assertEqualsIgnoreId(objectFromDb, objectWithOtherMasterUid) + } + + init { + objectWithOtherMasterUid = buildObjectWithOtherMasterUid() + masterUid = addMasterUid() } -} \ No newline at end of file +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectStoreAbstractIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectStoreAbstractIntegrationShould.java deleted file mode 100644 index cf84adcda8..0000000000 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectStoreAbstractIntegrationShould.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.data.database; - -import android.content.ContentValues; - -import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter; -import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectStore; -import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo; -import org.hisp.dhis.android.core.common.CoreObject; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; -import java.util.List; - -import static com.google.common.truth.Truth.assertThat; - -public abstract class ObjectStoreAbstractIntegrationShould { - - final M object; - private final ObjectStore store; - protected final TableInfo tableInfo; - private final DatabaseAdapter databaseAdapter; - - public ObjectStoreAbstractIntegrationShould(ObjectStore store, - TableInfo tableInfo, - DatabaseAdapter databaseAdapter) { - this.store = store; - this.object = buildObject(); - this.tableInfo = tableInfo; - this.databaseAdapter = databaseAdapter; - } - - protected abstract M buildObject(); - - @Before - public void setUp() throws IOException { - store.delete(); - } - - @Test - public void insert_and_select_first_object() { - store.insert(object); - M objectFromDb = store.selectFirst(); - assertEqualsIgnoreId(objectFromDb); - } - - @Test - public void insert_as_content_values_and_select_first_object() { - databaseAdapter.insert(tableInfo.name(), null, object.toContentValues()); - M objectFromDb = store.selectFirst(); - assertEqualsIgnoreId(objectFromDb); - } - - @Test - public void insert_and_select_all_objects() { - store.insert(object); - List objectsFromDb = store.selectAll(); - assertEqualsIgnoreId(objectsFromDb.iterator().next()); - } - - @Test - public void delete_inserted_object_by_id() { - store.insert(object); - M m = store.selectFirst(); - store.deleteById(m); - assertThat(store.selectFirst()).isEqualTo(null); - } - - - void assertEqualsIgnoreId(M localObject) { - assertEqualsIgnoreId(localObject, object); - } - - void assertEqualsIgnoreId(M m1, M m2) { - ContentValues cv1 = m1.toContentValues(); - cv1.remove("_id"); - - ContentValues cv2 = m2.toContentValues(); - cv2.remove("_id"); - - assertThat(cv1).isEqualTo(cv2); - } -} \ No newline at end of file diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectStoreAbstractIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectStoreAbstractIntegrationShould.kt new file mode 100644 index 0000000000..cfaa708024 --- /dev/null +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectStoreAbstractIntegrationShould.kt @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.data.database + +import com.google.common.truth.Truth.assertThat +import java.io.IOException +import kotlin.jvm.Throws +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectStore +import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo +import org.hisp.dhis.android.core.common.CoreObject +import org.junit.Before +import org.junit.Test + +abstract class ObjectStoreAbstractIntegrationShould internal constructor( + private val store: ObjectStore, + tableInfo: TableInfo, + databaseAdapter: DatabaseAdapter +) { + val `object`: M + private val tableInfo: TableInfo + private val databaseAdapter: DatabaseAdapter + + protected abstract fun buildObject(): M + + @Before + @Throws(IOException::class) + open fun setUp() { + store.delete() + } + + @Test + fun insert_and_select_first_object() { + store.insert(`object`) + val objectFromDb = store.selectFirst() + assertEqualsIgnoreId(objectFromDb) + } + + @Test + fun insert_as_content_values_and_select_first_object() { + databaseAdapter.insert(tableInfo.name(), null, `object`.toContentValues()) + val objectFromDb = store.selectFirst() + assertEqualsIgnoreId(objectFromDb) + } + + @Test + fun insert_and_select_all_objects() { + store.insert(`object`) + val objectsFromDb = store.selectAll() + assertEqualsIgnoreId(objectsFromDb.iterator().next()) + } + + @Test + fun delete_inserted_object_by_id() { + store.insert(`object`) + val m = store.selectFirst()!! + store.deleteById(m) + assertThat(store.selectFirst()).isEqualTo(null) + } + + fun assertEqualsIgnoreId(localObject: M?) { + assertEqualsIgnoreId(localObject, `object`) + } + + fun assertEqualsIgnoreId(m1: M?, m2: M) { + val cv1 = m1!!.toContentValues() + cv1.remove("_id") + val cv2 = m2.toContentValues() + cv2.remove("_id") + assertThat(cv1).isEqualTo(cv2) + } + + init { + `object` = buildObject() + this.tableInfo = tableInfo + this.databaseAdapter = databaseAdapter + } +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectWithoutUidStoreAbstractIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectWithoutUidStoreAbstractIntegrationShould.java deleted file mode 100644 index bb5a5e9281..0000000000 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectWithoutUidStoreAbstractIntegrationShould.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.data.database; - -import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter; -import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectWithoutUidStore; -import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo; -import org.hisp.dhis.android.core.arch.handlers.internal.HandleAction; -import org.hisp.dhis.android.core.common.CoreObject; -import org.junit.Before; -import org.junit.Test; - -import java.io.IOException; - -import static com.google.common.truth.Truth.assertThat; - -public abstract class ObjectWithoutUidStoreAbstractIntegrationShould - extends ObjectStoreAbstractIntegrationShould { - - private M objectToUpdate; - protected ObjectWithoutUidStore store; - - public ObjectWithoutUidStoreAbstractIntegrationShould(ObjectWithoutUidStore store, - TableInfo tableInfo, - DatabaseAdapter databaseAdapter) { - super(store, tableInfo, databaseAdapter); - this.store = store; - this.objectToUpdate = buildObjectToUpdate(); - } - - protected abstract M buildObjectToUpdate(); - - @Before - public void setUp() throws IOException { - super.setUp(); - } - - @Test - public void insert_and_update_where() { - store.insert(object); - store.updateWhere(objectToUpdate); - M objectFromDb = store.selectFirst(); - assertEqualsIgnoreId(objectFromDb, objectToUpdate); - } - - @Test - public void insert_and_delete_where() { - store.insert(object); - assertThat(store.count()).isEqualTo(1); - store.deleteWhere(object); - assertThat(store.count()).isEqualTo(0); - } - - @Test - public void update_when_call_update_or_insert_where_and_there_is_a_previous_object() { - store.insert(object); - HandleAction handleAction = store.updateOrInsertWhere(objectToUpdate); - assertThat(handleAction).isEqualTo(HandleAction.Update); - M objectFromDb = store.selectFirst(); - assertEqualsIgnoreId(objectFromDb, objectToUpdate); - } - - @Test - public void insert_when_call_update_or_insert_where_and_there_is_no_previous_object() { - HandleAction handleAction = store.updateOrInsertWhere(objectToUpdate); - assertThat(handleAction).isEqualTo(HandleAction.Insert); - M objectFromDb = store.selectFirst(); - assertEqualsIgnoreId(objectFromDb, objectToUpdate); - } -} \ No newline at end of file diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectWithoutUidStoreAbstractIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectWithoutUidStoreAbstractIntegrationShould.kt new file mode 100644 index 0000000000..efcff6a6f7 --- /dev/null +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/data/database/ObjectWithoutUidStoreAbstractIntegrationShould.kt @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.data.database + +import com.google.common.truth.Truth.assertThat +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectWithoutUidStore +import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo +import org.hisp.dhis.android.core.arch.handlers.internal.HandleAction +import org.hisp.dhis.android.core.common.CoreObject +import org.junit.Before +import org.junit.Test + +abstract class ObjectWithoutUidStoreAbstractIntegrationShould internal constructor( + internal val store: ObjectWithoutUidStore, + tableInfo: TableInfo, + databaseAdapter: DatabaseAdapter +) : ObjectStoreAbstractIntegrationShould(store, tableInfo, databaseAdapter) { + + private val objectToUpdate: M + protected abstract fun buildObjectToUpdate(): M + + @Before + override fun setUp() { + super.setUp() + } + + @Test + fun insert_and_update_where() { + store.insert(`object`) + store.updateWhere(objectToUpdate) + val objectFromDb = store.selectFirst() + assertEqualsIgnoreId(objectFromDb, objectToUpdate) + } + + @Test + fun insert_and_delete_where() { + store.insert(`object`) + assertThat(store.count()).isEqualTo(1) + store.deleteWhere(`object`) + assertThat(store.count()).isEqualTo(0) + } + + @Test + fun update_when_call_update_or_insert_where_and_there_is_a_previous_object() { + store.insert(`object`) + val handleAction = store.updateOrInsertWhere(objectToUpdate) + assertThat(handleAction).isEqualTo(HandleAction.Update) + val objectFromDb = store.selectFirst() + assertEqualsIgnoreId(objectFromDb, objectToUpdate) + } + + @Test + fun insert_when_call_update_or_insert_where_and_there_is_no_previous_object() { + val handleAction = store.updateOrInsertWhere(objectToUpdate) + assertThat(handleAction).isEqualTo(HandleAction.Insert) + val objectFromDb = store.selectFirst() + assertEqualsIgnoreId(objectFromDb, objectToUpdate) + } + + @Test + fun insert_same_object_simultaneously_and_transactionally() { + val s1 = Single.fromCallable { store.updateOrInsertWhere(`object`) }.subscribeOn(Schedulers.io()) + val s2 = Single.fromCallable { store.updateOrInsertWhere(`object`) }.subscribeOn(Schedulers.io()) + + s1.mergeWith(s2).blockingSubscribe() + + val objects = store.selectAll() + + assertThat(objects.size).isEqualTo(1) + } + + init { + objectToUpdate = buildObjectToUpdate() + } +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/data/server/RealServerMother.java b/core/src/androidTest/java/org/hisp/dhis/android/core/data/server/RealServerMother.java index 6c1618a92b..4e0a14e585 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/data/server/RealServerMother.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/data/server/RealServerMother.java @@ -38,6 +38,7 @@ public class RealServerMother { public static String url2_35 = "https://play.dhis2.org/2.35/"; public static String url2_36 = "https://play.dhis2.org/2.36/"; public static String url2_37 = "https://play.dhis2.org/2.37/"; + public static String url2_38 = "https://play.dhis2.org/2.38/"; public static String url_dev = "https://play.dhis2.org/dev/"; public static String android_current = "https://play.dhis2.org/android-current/"; public static String android_previous1 = "https://play.dhis2.org/android-previous1/"; diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStoreIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStoreIntegrationShould.kt similarity index 69% rename from core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStoreIntegrationShould.java rename to core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStoreIntegrationShould.kt index 9a1aaf4c2c..a552d3a41f 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStoreIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStoreIntegrationShould.kt @@ -25,27 +25,24 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.event.internal -package org.hisp.dhis.android.core.event.internal; +import org.hisp.dhis.android.core.common.tableinfo.ItemFilterTableInfo +import org.hisp.dhis.android.core.data.database.ObjectStoreAbstractIntegrationShould +import org.hisp.dhis.android.core.data.event.EventDataFilterSamples +import org.hisp.dhis.android.core.event.EventDataFilter +import org.hisp.dhis.android.core.event.internal.EventDataFilterStore.create +import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.runner.RunWith -import org.hisp.dhis.android.core.data.database.ObjectStoreAbstractIntegrationShould; -import org.hisp.dhis.android.core.data.event.EventDataFilterSamples; -import org.hisp.dhis.android.core.event.EventDataFilter; -import org.hisp.dhis.android.core.event.EventDataFilterTableInfo; -import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory; -import org.hisp.dhis.android.core.utils.runner.D2JunitRunner; -import org.junit.runner.RunWith; - -@RunWith(D2JunitRunner.class) -public class EventDataFilterStoreIntegrationShould extends ObjectStoreAbstractIntegrationShould { - - public EventDataFilterStoreIntegrationShould() { - super(EventDataFilterStore.create(TestDatabaseAdapterFactory.get()), - EventDataFilterTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get()); - } - - @Override - protected EventDataFilter buildObject() { - return EventDataFilterSamples.get(); +@RunWith(D2JunitRunner::class) +class EventDataFilterStoreIntegrationShould : ObjectStoreAbstractIntegrationShould( + create(TestDatabaseAdapterFactory.get()), + ItemFilterTableInfo.TABLE_INFO, + TestDatabaseAdapterFactory.get() +) { + override fun buildObject(): EventDataFilter { + return EventDataFilterSamples.get() } -} \ No newline at end of file +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventFilterStoreIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventFilterStoreIntegrationShould.kt similarity index 64% rename from core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventFilterStoreIntegrationShould.java rename to core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventFilterStoreIntegrationShould.kt index 76a9fa1843..03aa1c0085 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventFilterStoreIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/event/internal/EventFilterStoreIntegrationShould.kt @@ -25,35 +25,28 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.event.internal -package org.hisp.dhis.android.core.event.internal; +import org.hisp.dhis.android.core.data.database.IdentifiableObjectStoreAbstractIntegrationShould +import org.hisp.dhis.android.core.data.event.EventFilterSamples +import org.hisp.dhis.android.core.event.EventFilter +import org.hisp.dhis.android.core.event.EventFilterTableInfo +import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.runner.RunWith -import org.hisp.dhis.android.core.data.database.IdentifiableObjectStoreAbstractIntegrationShould; -import org.hisp.dhis.android.core.data.event.EventFilterSamples; -import org.hisp.dhis.android.core.event.EventFilter; -import org.hisp.dhis.android.core.event.EventFilterTableInfo; -import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory; -import org.hisp.dhis.android.core.utils.runner.D2JunitRunner; -import org.junit.runner.RunWith; - -@RunWith(D2JunitRunner.class) -public class EventFilterStoreIntegrationShould - extends IdentifiableObjectStoreAbstractIntegrationShould { - - public EventFilterStoreIntegrationShould() { - super(EventFilterStore.create(TestDatabaseAdapterFactory.get()), - EventFilterTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get()); - } - - @Override - protected EventFilter buildObject() { - return EventFilterSamples.get(); +@RunWith(D2JunitRunner::class) +internal class EventFilterStoreIntegrationShould : IdentifiableObjectStoreAbstractIntegrationShould( + EventFilterStore.create(TestDatabaseAdapterFactory.get()), + EventFilterTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get() +) { + override fun buildObject(): EventFilter { + return EventFilterSamples.get() } - @Override - protected EventFilter buildObjectToUpdate() { + override fun buildObjectToUpdate(): EventFilter { return EventFilterSamples.get().toBuilder() - .description("new_description") - .build(); + .description("new_description") + .build() } -} \ No newline at end of file +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/period/internal/PeriodHelperIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/period/internal/PeriodHelperIntegrationShould.kt new file mode 100644 index 0000000000..11fcbe1441 --- /dev/null +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/period/internal/PeriodHelperIntegrationShould.kt @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.period.internal + +import com.google.common.truth.Truth.assertThat +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers +import java.util.* +import org.hisp.dhis.android.core.period.PeriodType +import org.hisp.dhis.android.core.utils.integration.mock.BaseMockIntegrationTestEmptyDispatcher +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(D2JunitRunner::class) +class PeriodHelperIntegrationShould : BaseMockIntegrationTestEmptyDispatcher() { + + @Test + fun should_not_crash_when_creating_same_period() { + val date = Date() + + val s1 = Single.fromCallable { + d2.periodModule().periodHelper().getPeriodForPeriodTypeAndDate(PeriodType.Daily, date) + }.subscribeOn(Schedulers.io()) + + val s2 = Single.fromCallable { + d2.periodModule().periodHelper().getPeriodForPeriodTypeAndDate(PeriodType.Daily, date) + }.subscribeOn(Schedulers.io()) + + s1.mergeWith(s2).blockingSubscribe() + + val periods = d2.periodModule().periods().blockingGet() + + assertThat(periods.size).isEqualTo(1) + + PeriodStoreImpl.create(databaseAdapter).delete() + } +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreIntegrationShould.kt similarity index 55% rename from core/src/androidTest/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreIntegrationShould.java rename to core/src/androidTest/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreIntegrationShould.kt index b2c4817852..f64e0e2149 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreIntegrationShould.kt @@ -25,36 +25,50 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.relationship.internal -package org.hisp.dhis.android.core.relationship.internal; +import com.google.common.truth.Truth.assertThat +import org.hisp.dhis.android.core.data.database.ObjectWithoutUidStoreAbstractIntegrationShould +import org.hisp.dhis.android.core.data.relationship.RelationshipItemSamples +import org.hisp.dhis.android.core.relationship.RelationshipItem +import org.hisp.dhis.android.core.relationship.RelationshipItemEvent +import org.hisp.dhis.android.core.relationship.RelationshipItemTableInfo +import org.hisp.dhis.android.core.relationship.internal.RelationshipItemStoreImpl.Companion.create +import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.Test +import org.junit.runner.RunWith -import org.hisp.dhis.android.core.data.database.ObjectWithoutUidStoreAbstractIntegrationShould; -import org.hisp.dhis.android.core.data.relationship.RelationshipItemSamples; -import org.hisp.dhis.android.core.relationship.RelationshipItem; -import org.hisp.dhis.android.core.relationship.RelationshipItemEvent; -import org.hisp.dhis.android.core.relationship.RelationshipItemTableInfo; -import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory; -import org.hisp.dhis.android.core.utils.runner.D2JunitRunner; -import org.junit.runner.RunWith; +@RunWith(D2JunitRunner::class) +class RelationshipItemStoreIntegrationShould : ObjectWithoutUidStoreAbstractIntegrationShould( + create(TestDatabaseAdapterFactory.get()), + RelationshipItemTableInfo.TABLE_INFO, + TestDatabaseAdapterFactory.get() +) { -@RunWith(D2JunitRunner.class) -public class RelationshipItemStoreIntegrationShould extends - ObjectWithoutUidStoreAbstractIntegrationShould { + private val relationshipItemStore = store as RelationshipItemStore - public RelationshipItemStoreIntegrationShould() { - super(RelationshipItemStoreImpl.create(TestDatabaseAdapterFactory.get()), - RelationshipItemTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get()); + override fun buildObject(): RelationshipItem { + return RelationshipItemSamples.getRelationshipItem() } - @Override - protected RelationshipItem buildObject() { - return RelationshipItemSamples.getRelationshipItem(); + override fun buildObjectToUpdate(): RelationshipItem { + return RelationshipItemSamples.getRelationshipItem().toBuilder() + .event(RelationshipItemEvent.builder().event("new_event").build()) + .build() } - @Override - protected RelationshipItem buildObjectToUpdate() { - return RelationshipItemSamples.getRelationshipItem().toBuilder() - .event(RelationshipItemEvent.builder().event("new_event").build()) - .build(); + @Test + fun getByEntityUid() { + val sample = RelationshipItemSamples.getRelationshipItem() + relationshipItemStore.insert(RelationshipItemSamples.getRelationshipItem()) + + val itemsByExistingEntityUid = relationshipItemStore.getByEntityUid(sample.event()!!.event()) + assertThat(itemsByExistingEntityUid.size).isEqualTo(1) + + val itemsByNonExistingEntityUid = relationshipItemStore.getByEntityUid("other_entity") + assertThat(itemsByNonExistingEntityUid).isEmpty() + + relationshipItemStore.delete() } -} \ No newline at end of file +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/systeminfo/SystemInfoModuleMockIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/systeminfo/SystemInfoModuleMockIntegrationShould.java index 49006395c4..2ad06b2023 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/systeminfo/SystemInfoModuleMockIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/systeminfo/SystemInfoModuleMockIntegrationShould.java @@ -28,20 +28,20 @@ package org.hisp.dhis.android.core.systeminfo; +import static com.google.common.truth.Truth.assertThat; + import org.hisp.dhis.android.core.utils.integration.mock.BaseMockIntegrationTestFullDispatcher; import org.hisp.dhis.android.core.utils.runner.D2JunitRunner; import org.junit.Test; import org.junit.runner.RunWith; -import static com.google.common.truth.Truth.assertThat; - @RunWith(D2JunitRunner.class) public class SystemInfoModuleMockIntegrationShould extends BaseMockIntegrationTestFullDispatcher { @Test public void allow_access_to_system_info_user() { SystemInfo systemInfo = d2.systemInfoModule().systemInfo().blockingGet(); - assertThat(systemInfo.version()).isEqualTo("2.37"); + assertThat(systemInfo.version()).isEqualTo("2.38"); assertThat(systemInfo.systemName()).isEqualTo("DHIS 2 Demo - Sierra Leone"); } } \ No newline at end of file diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterStoreIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterStoreIntegrationShould.kt new file mode 100644 index 0000000000..5f5745418c --- /dev/null +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterStoreIntegrationShould.kt @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.trackedentity.internal + +import org.hisp.dhis.android.core.common.tableinfo.ItemFilterTableInfo +import org.hisp.dhis.android.core.data.database.ObjectStoreAbstractIntegrationShould +import org.hisp.dhis.android.core.data.trackedentity.AttributeValueFilterSamples +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter +import org.hisp.dhis.android.core.trackedentity.internal.AttributeValueFilterStore.create +import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.runner.RunWith + +@RunWith(D2JunitRunner::class) +class AttributeValueFilterStoreIntegrationShould : ObjectStoreAbstractIntegrationShould( + create(TestDatabaseAdapterFactory.get()), + ItemFilterTableInfo.TABLE_INFO, + TestDatabaseAdapterFactory.get() +) { + override fun buildObject(): AttributeValueFilter { + return AttributeValueFilterSamples.get() + } +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStoreIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStoreIntegrationShould.kt similarity index 66% rename from core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStoreIntegrationShould.java rename to core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStoreIntegrationShould.kt index e0f350bb76..5295fa8191 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStoreIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStoreIntegrationShould.kt @@ -25,35 +25,30 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.trackedentity.internal -package org.hisp.dhis.android.core.trackedentity.internal; +import org.hisp.dhis.android.core.data.database.IdentifiableObjectStoreAbstractIntegrationShould +import org.hisp.dhis.android.core.data.trackedentity.TrackedEntityInstanceFilterSamples +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilterTableInfo +import org.hisp.dhis.android.core.trackedentity.internal.TrackedEntityInstanceFilterStore.create +import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.runner.RunWith -import org.hisp.dhis.android.core.data.database.IdentifiableObjectStoreAbstractIntegrationShould; -import org.hisp.dhis.android.core.data.trackedentity.TrackedEntityInstanceFilterSamples; -import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter; -import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilterTableInfo; -import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory; -import org.hisp.dhis.android.core.utils.runner.D2JunitRunner; -import org.junit.runner.RunWith; - -@RunWith(D2JunitRunner.class) -public class TrackedEntityInstanceFilterStoreIntegrationShould - extends IdentifiableObjectStoreAbstractIntegrationShould { - - public TrackedEntityInstanceFilterStoreIntegrationShould() { - super(TrackedEntityInstanceFilterStore.create(TestDatabaseAdapterFactory.get()), - TrackedEntityInstanceFilterTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get()); - } - - @Override - protected TrackedEntityInstanceFilter buildObject() { - return TrackedEntityInstanceFilterSamples.get(); +@RunWith(D2JunitRunner::class) +class TrackedEntityInstanceFilterStoreIntegrationShould : + IdentifiableObjectStoreAbstractIntegrationShould( + create(TestDatabaseAdapterFactory.get()), + TrackedEntityInstanceFilterTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get() + ) { + override fun buildObject(): TrackedEntityInstanceFilter { + return TrackedEntityInstanceFilterSamples.get() } - @Override - protected TrackedEntityInstanceFilter buildObjectToUpdate() { + override fun buildObjectToUpdate(): TrackedEntityInstanceFilter { return TrackedEntityInstanceFilterSamples.get().toBuilder() - .description("new_description") - .build(); + .description("new_description") + .build() } -} \ No newline at end of file +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/user/internal/UserOrganisationUnitLinkStoreIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/core/user/internal/UserOrganisationUnitLinkStoreIntegrationShould.java deleted file mode 100644 index 34dca03920..0000000000 --- a/core/src/androidTest/java/org/hisp/dhis/android/core/user/internal/UserOrganisationUnitLinkStoreIntegrationShould.java +++ /dev/null @@ -1,95 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.user.internal; - -import static com.google.common.truth.Truth.assertThat; -import static org.hisp.dhis.android.core.organisationunit.OrganisationUnit.Scope.SCOPE_DATA_CAPTURE; -import static org.hisp.dhis.android.core.organisationunit.OrganisationUnit.Scope.SCOPE_TEI_SEARCH; - -import org.hisp.dhis.android.core.data.database.LinkStoreAbstractIntegrationShould; -import org.hisp.dhis.android.core.data.user.UserOrganisationUnitLinkSamples; -import org.hisp.dhis.android.core.user.UserOrganisationUnitLink; -import org.hisp.dhis.android.core.user.UserOrganisationUnitLinkTableInfo; -import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory; -import org.hisp.dhis.android.core.utils.runner.D2JunitRunner; -import org.junit.Test; -import org.junit.runner.RunWith; - -import java.util.List; - -@RunWith(D2JunitRunner.class) -public class UserOrganisationUnitLinkStoreIntegrationShould - extends LinkStoreAbstractIntegrationShould { - - UserOrganisationUnitLinkStore linkStore; - - public UserOrganisationUnitLinkStoreIntegrationShould() { - super(UserOrganisationUnitLinkStoreImpl.create(TestDatabaseAdapterFactory.get()), - UserOrganisationUnitLinkTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get()); - - linkStore = (UserOrganisationUnitLinkStore) store; - } - - @Override - protected String addMasterUid() { - return UserOrganisationUnitLinkSamples.getUserOrganisationUnitLink().organisationUnitScope(); - } - - @Override - protected UserOrganisationUnitLink buildObject() { - return UserOrganisationUnitLinkSamples.getUserOrganisationUnitLink(); - } - - @Override - protected UserOrganisationUnitLink buildObjectWithOtherMasterUid() { - return buildObject().toBuilder() - .organisationUnitScope("other-scope") - .build(); - } - - @Test - public void assignedOrgUnitForDataCapture() { - linkStore.insert(UserOrganisationUnitLinkSamples.getUserOrganisationUnitLink()); - linkStore.insert(UserOrganisationUnitLinkSamples.getAssignedUserOrganisationUnitLink(SCOPE_DATA_CAPTURE)); - linkStore.insert(UserOrganisationUnitLinkSamples.getUnassignedUserOrganisationUnitLink(SCOPE_DATA_CAPTURE)); - List orgUnitUids = linkStore.queryAssignedOrganisationUnitUidsByScope(SCOPE_DATA_CAPTURE); - - assertThat(orgUnitUids.size()).isEqualTo(2); - } - - @Test - public void assignedOrgUnitForTEISearch() { - linkStore.insert(UserOrganisationUnitLinkSamples.getUserOrganisationUnitLink()); - linkStore.insert(UserOrganisationUnitLinkSamples.getAssignedUserOrganisationUnitLink(SCOPE_TEI_SEARCH)); - linkStore.insert(UserOrganisationUnitLinkSamples.getUnassignedUserOrganisationUnitLink(SCOPE_TEI_SEARCH)); - List orgUnitUids = linkStore.queryAssignedOrganisationUnitUidsByScope(SCOPE_TEI_SEARCH); - - assertThat(orgUnitUids.size()).isEqualTo(1); - } -} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/core/user/internal/UserOrganisationUnitLinkStoreIntegrationShould.kt b/core/src/androidTest/java/org/hisp/dhis/android/core/user/internal/UserOrganisationUnitLinkStoreIntegrationShould.kt new file mode 100644 index 0000000000..7ae27fbe9a --- /dev/null +++ b/core/src/androidTest/java/org/hisp/dhis/android/core/user/internal/UserOrganisationUnitLinkStoreIntegrationShould.kt @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.user.internal + +import com.google.common.truth.Truth.assertThat +import org.hisp.dhis.android.core.data.database.LinkStoreAbstractIntegrationShould +import org.hisp.dhis.android.core.data.user.UserOrganisationUnitLinkSamples +import org.hisp.dhis.android.core.organisationunit.OrganisationUnit +import org.hisp.dhis.android.core.user.UserOrganisationUnitLink +import org.hisp.dhis.android.core.user.UserOrganisationUnitLinkTableInfo +import org.hisp.dhis.android.core.user.internal.UserOrganisationUnitLinkStoreImpl.Companion.create +import org.hisp.dhis.android.core.utils.integration.mock.TestDatabaseAdapterFactory +import org.hisp.dhis.android.core.utils.runner.D2JunitRunner +import org.junit.Test +import org.junit.runner.RunWith + +@RunWith(D2JunitRunner::class) +class UserOrganisationUnitLinkStoreIntegrationShould : LinkStoreAbstractIntegrationShould( + create(TestDatabaseAdapterFactory.get()), + UserOrganisationUnitLinkTableInfo.TABLE_INFO, TestDatabaseAdapterFactory.get() +) { + private var linkStore: UserOrganisationUnitLinkStore = store as UserOrganisationUnitLinkStore + + override fun addMasterUid(): String { + return UserOrganisationUnitLinkSamples.getUserOrganisationUnitLink().organisationUnitScope() + } + + override fun buildObject(): UserOrganisationUnitLink { + return UserOrganisationUnitLinkSamples.getUserOrganisationUnitLink() + } + + override fun buildObjectWithOtherMasterUid(): UserOrganisationUnitLink { + return buildObject().toBuilder() + .organisationUnitScope("other-scope") + .build() + } + + @Test + fun assignedOrgUnitForDataCapture() { + linkStore.insert(UserOrganisationUnitLinkSamples.getUserOrganisationUnitLink()) + linkStore.insert( + UserOrganisationUnitLinkSamples + .getAssignedUserOrganisationUnitLink(OrganisationUnit.Scope.SCOPE_DATA_CAPTURE) + ) + linkStore.insert( + UserOrganisationUnitLinkSamples + .getUnassignedUserOrganisationUnitLink(OrganisationUnit.Scope.SCOPE_DATA_CAPTURE) + ) + val orgUnitUids = linkStore + .queryAssignedOrganisationUnitUidsByScope(OrganisationUnit.Scope.SCOPE_DATA_CAPTURE) + assertThat(orgUnitUids.size).isEqualTo(2) + } + + @Test + fun assignedOrgUnitForTEISearch() { + linkStore.insert(UserOrganisationUnitLinkSamples.getUserOrganisationUnitLink()) + linkStore.insert( + UserOrganisationUnitLinkSamples + .getAssignedUserOrganisationUnitLink(OrganisationUnit.Scope.SCOPE_TEI_SEARCH) + ) + linkStore.insert( + UserOrganisationUnitLinkSamples + .getUnassignedUserOrganisationUnitLink(OrganisationUnit.Scope.SCOPE_TEI_SEARCH) + ) + + val orgUnitUids = linkStore.queryAssignedOrganisationUnitUidsByScope(OrganisationUnit.Scope.SCOPE_TEI_SEARCH) + + assertThat(orgUnitUids.size).isEqualTo(1) + } +} diff --git a/core/src/androidTest/java/org/hisp/dhis/android/testapp/trackedentity/TrackedEntityAttributeCollectionRepositoryMockIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/testapp/trackedentity/TrackedEntityAttributeCollectionRepositoryMockIntegrationShould.java index 84793c051e..6469c517ff 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/testapp/trackedentity/TrackedEntityAttributeCollectionRepositoryMockIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/testapp/trackedentity/TrackedEntityAttributeCollectionRepositoryMockIntegrationShould.java @@ -200,6 +200,16 @@ public void by_display_form_name() { assertThat(trackedEntityAttributes.size()).isEqualTo(1); } + @Test + public void withLegendSets() { + TrackedEntityAttribute trackedEntityAttribute = + d2.trackedEntityModule().trackedEntityAttributes() + .withLegendSets() + .one() + .blockingGet(); + assertThat(trackedEntityAttribute.legendSets().size()).isEqualTo(2); + } + @Test public void filter_by_field_color() { List trackedEntityAttributes = diff --git a/core/src/androidTest/java/org/hisp/dhis/android/testapp/trackedentity/TrackedEntityInstanceFilterCollectionRepositoryMockIntegrationShould.java b/core/src/androidTest/java/org/hisp/dhis/android/testapp/trackedentity/TrackedEntityInstanceFilterCollectionRepositoryMockIntegrationShould.java index ef25729c8b..2d25a78fe3 100644 --- a/core/src/androidTest/java/org/hisp/dhis/android/testapp/trackedentity/TrackedEntityInstanceFilterCollectionRepositoryMockIntegrationShould.java +++ b/core/src/androidTest/java/org/hisp/dhis/android/testapp/trackedentity/TrackedEntityInstanceFilterCollectionRepositoryMockIntegrationShould.java @@ -28,8 +28,12 @@ package org.hisp.dhis.android.testapp.trackedentity; +import static com.google.common.truth.Truth.assertThat; + +import org.hisp.dhis.android.core.common.AssignedUserMode; import org.hisp.dhis.android.core.enrollment.EnrollmentStatus; import org.hisp.dhis.android.core.event.EventStatus; +import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode; import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter; import org.hisp.dhis.android.core.utils.integration.mock.BaseMockIntegrationTestFullDispatcher; import org.hisp.dhis.android.core.utils.runner.D2JunitRunner; @@ -38,8 +42,6 @@ import java.util.List; -import static com.google.common.truth.Truth.assertThat; - @RunWith(D2JunitRunner.class) public class TrackedEntityInstanceFilterCollectionRepositoryMockIntegrationShould extends BaseMockIntegrationTestFullDispatcher { @@ -87,7 +89,7 @@ public void filter_by_sort_order() { public void filter_by_enrollment_status() { List trackedEntityInstanceFilters = d2.trackedEntityModule().trackedEntityInstanceFilters() - .byEnrollmentStatus().eq(EnrollmentStatus.COMPLETED) + .byEnrollmentStatus().eq(EnrollmentStatus.ACTIVE) .blockingGet(); assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); @@ -100,24 +102,124 @@ public void filter_by_follow_up() { .byFollowUp().eq(Boolean.TRUE) .blockingGet(); - assertThat(trackedEntityInstanceFilters.size()).isEqualTo(0); + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_organization_unit() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byOrganisationUnit().eq("orgUnitUid") + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_ou_mode() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byOuMode().eq(OrganisationUnitMode.ACCESSIBLE) + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_order_property() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byOrderProperty().eq("dueDate:asc,createdDate:desc") + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_display_column_order() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byDisplayColumnOrder().like("eventDate") + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_assigned_user_mode() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byAssignedUserMode().eq(AssignedUserMode.PROVIDED) + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_event_status() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byEventStatus().eq(EventStatus.COMPLETED) + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_event_date() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byEventDate().like("-5") + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_last_updated_date() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byLastUpdatedDate().like("RELATIVE") + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_program_stage() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byProgramStage().eq("uvMKOn1oWvd") + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); + } + + @Test + public void filter_by_teis() { + List trackedEntityInstanceFilters = + d2.trackedEntityModule().trackedEntityInstanceFilters() + .byTrackedEntityInstances().like("a3kGcGDCuk7") + .blockingGet(); + + assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); } @Test - public void filter_by_period_from() { + public void filter_by_enrollment_incident_date() { List trackedEntityInstanceFilters = d2.trackedEntityModule().trackedEntityInstanceFilters() - .byPeriodFrom().eq(-20) + .byEnrollmentIncidentDate().like("2014-05-01") .blockingGet(); assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); } @Test - public void filter_by_period_to() { + public void filter_by_enrollment_created_date() { List trackedEntityInstanceFilters = d2.trackedEntityModule().trackedEntityInstanceFilters() - .byPeriodTo().eq(20) + .byEnrollmentCreatedDate().like("TODAY") .blockingGet(); assertThat(trackedEntityInstanceFilters.size()).isEqualTo(1); diff --git a/core/src/main/assets/migrations/125.sql b/core/src/main/assets/migrations/125.sql new file mode 100644 index 0000000000..d6bd9cc4d6 --- /dev/null +++ b/core/src/main/assets/migrations/125.sql @@ -0,0 +1,3 @@ +# Add TrackedEntityAttributeLegendSetLink (ANDROSDK-1546); + +CREATE TABLE TrackedEntityAttributeLegendSetLink (_id INTEGER PRIMARY KEY AUTOINCREMENT, trackedEntityAttribute TEXT NOT NULL, legendSet TEXT NOT NULL, sortOrder INTEGER, FOREIGN KEY (trackedEntityAttribute) REFERENCES TrackedEntityAttribute (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (legendSet) REFERENCES LegendSet (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (trackedEntityAttribute, legendSet)); diff --git a/core/src/main/assets/migrations/126.sql b/core/src/main/assets/migrations/126.sql new file mode 100644 index 0000000000..5f29edb3b1 --- /dev/null +++ b/core/src/main/assets/migrations/126.sql @@ -0,0 +1,11 @@ +# Add restriction (ANDROSDK-1502); + +ALTER TABLE EventDataFilter RENAME TO EventDataFilter_Old; +CREATE TABLE ItemFilter (_id INTEGER PRIMARY KEY AUTOINCREMENT, eventFilter TEXT, dataItem TEXT, trackedEntityInstanceFilter TEXT, attribute TEXT, sw TEXT, ew TEXT, le TEXT, ge TEXT, gt TEXT, lt TEXT, eq TEXT, inProperty TEXT, like TEXT, dateFilter TEXT, FOREIGN KEY (eventFilter) REFERENCES EventFilter (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (trackedEntityInstanceFilter) REFERENCES TrackedEntityInstanceFilter (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); +INSERT INTO ItemFilter (_id, eventFilter, dataItem, le, ge, gt, lt, eq, inProperty, like, dateFilter) SELECT _id, eventFilter, dataItem, le, ge, gt, lt, eq, inProperty, like, dateFilter FROM EventDataFilter_Old; +DROP TABLE IF EXISTS EventDataFilter_Old; + +ALTER TABLE TrackedEntityInstanceFilter RENAME TO TrackedEntityInstanceFilter_Old; +CREATE TABLE TrackedEntityInstanceFilter (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, color TEXT, icon TEXT, program TEXT NOT NULL, description TEXT, sortOrder INTEGER, enrollmentStatus TEXT, followUp INTEGER, organisationUnit TEXT, ouMode TEXT, assignedUserMode TEXT, orderProperty TEXT, displayColumnOrder TEXT, eventStatus TEXT, eventDate TEXT, lastUpdatedDate TEXT, programStage TEXT, trackedEntityInstances TEXT, enrollmentIncidentDate TEXT, enrollmentCreatedDate TEXT, trackedEntityType TEXT, FOREIGN KEY (program) REFERENCES Program (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); +INSERT INTO TrackedEntityInstanceFilter (_id, uid, code, name, displayName, created, lastUpdated, color, icon, program, description, sortOrder, enrollmentStatus, followUp) SELECT _id, uid, code, name, displayName, created, lastUpdated, color, icon, program, description, sortOrder, enrollmentStatus, followUp FROM TrackedEntityInstanceFilter_Old; +DROP TABLE IF EXISTS TrackedEntityInstanceFilter_Old; diff --git a/core/src/main/assets/migrations/127.sql b/core/src/main/assets/migrations/127.sql new file mode 100644 index 0000000000..04e82c4dd9 --- /dev/null +++ b/core/src/main/assets/migrations/127.sql @@ -0,0 +1,6 @@ +# Add aggregationType (ANDROSDK-1547) to TrackedEntityAttribute; + +ALTER TABLE TrackedEntityAttribute RENAME TO TrackedEntityAttribute_Old; +CREATE TABLE TrackedEntityAttribute (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, shortName TEXT, displayShortName TEXT, description TEXT, displayDescription TEXT, pattern TEXT, sortOrderInListNoProgram INTEGER, optionSet TEXT, valueType TEXT, expression TEXT, programScope INTEGER, displayInListNoProgram INTEGER, generated INTEGER, displayOnVisitSchedule INTEGER, orgunitScope INTEGER, uniqueProperty INTEGER, inherit INTEGER, formName TEXT, fieldMask TEXT, color TEXT, icon TEXT, displayFormName TEXT, aggregationType TEXT, FOREIGN KEY (optionSet) REFERENCES OptionSet (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); +INSERT INTO TrackedEntityAttribute (_id, uid, code, name, displayName, created, lastUpdated, shortName, displayShortName, description, displayDescription, pattern, sortOrderInListNoProgram, optionSet, valueType, expression, programScope, displayInListNoProgram, generated, displayOnVisitSchedule, orgunitScope, uniqueProperty, inherit, formName, fieldMask, color, icon, displayFormName) SELECT _id, uid, code, name, displayName, created, lastUpdated, shortName, displayShortName, description, displayDescription, pattern, sortOrderInListNoProgram, optionSet, valueType, expression, programScope, displayInListNoProgram, generated, displayOnVisitSchedule, orgunitScope, uniqueProperty, inherit, formName, fieldMask, color, icon, displayFormName FROM TrackedEntityAttribute_Old; +DROP TABLE IF EXISTS TrackedEntityAttribute_Old diff --git a/core/src/main/assets/snapshots/124.sql b/core/src/main/assets/snapshots/127.sql similarity index 96% rename from core/src/main/assets/snapshots/124.sql rename to core/src/main/assets/snapshots/127.sql index fb9e1a6cc4..3fe9fc8da6 100644 --- a/core/src/main/assets/snapshots/124.sql +++ b/core/src/main/assets/snapshots/127.sql @@ -61,7 +61,7 @@ CREATE TABLE ProgramRuleAction (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT CREATE TABLE OrganisationUnitLevel (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, level INTEGER); CREATE TABLE ProgramSection (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, description TEXT, program TEXT, sortOrder INTEGER, formName TEXT, color TEXT, icon TEXT, desktopRenderType TEXT, mobileRenderType TEXT, FOREIGN KEY (program) REFERENCES Program (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); CREATE TABLE DataApproval (_id INTEGER PRIMARY KEY AUTOINCREMENT, workflow TEXT NOT NULL, organisationUnit TEXT NOT NULL, period TEXT NOT NULL, attributeOptionCombo TEXT NOT NULL, state TEXT, FOREIGN KEY (attributeOptionCombo) REFERENCES CategoryOptionCombo (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (period) REFERENCES Period (periodId), FOREIGN KEY (organisationUnit) REFERENCES OrganisationUnit (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (attributeOptionCombo, period, organisationUnit, workflow)); -CREATE TABLE TrackedEntityAttribute (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, shortName TEXT, displayShortName TEXT, description TEXT, displayDescription TEXT, pattern TEXT, sortOrderInListNoProgram INTEGER, optionSet TEXT, valueType TEXT, expression TEXT, programScope INTEGER, displayInListNoProgram INTEGER, generated INTEGER, displayOnVisitSchedule INTEGER, orgunitScope INTEGER, uniqueProperty INTEGER, inherit INTEGER, formName TEXT, fieldMask TEXT, color TEXT, icon TEXT, displayFormName TEXT, FOREIGN KEY (optionSet) REFERENCES OptionSet (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); +CREATE TABLE TrackedEntityAttribute (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, shortName TEXT, displayShortName TEXT, description TEXT, displayDescription TEXT, pattern TEXT, sortOrderInListNoProgram INTEGER, optionSet TEXT, valueType TEXT, expression TEXT, programScope INTEGER, displayInListNoProgram INTEGER, generated INTEGER, displayOnVisitSchedule INTEGER, orgunitScope INTEGER, uniqueProperty INTEGER, inherit INTEGER, formName TEXT, fieldMask TEXT, color TEXT, icon TEXT, displayFormName TEXT, aggregationType TEXT, FOREIGN KEY (optionSet) REFERENCES OptionSet (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); CREATE TABLE TrackerImportConflict (_id INTEGER PRIMARY KEY AUTOINCREMENT, conflict TEXT, value TEXT, trackedEntityInstance TEXT, enrollment TEXT, event TEXT, tableReference TEXT, errorCode TEXT, status TEXT, created TEXT, displayDescription TEXT, trackedEntityAttribute TEXT, dataElement TEXT, FOREIGN KEY (trackedEntityInstance) REFERENCES TrackedEntityInstance (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (enrollment) REFERENCES Enrollment (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (event) REFERENCES Event (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); CREATE TABLE DataSetOrganisationUnitLink (_id INTEGER PRIMARY KEY AUTOINCREMENT, dataSet TEXT NOT NULL, organisationUnit TEXT NOT NULL, FOREIGN KEY (dataSet) REFERENCES DataSet (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (organisationUnit) REFERENCES OrganisationUnit (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (organisationUnit, dataSet)); CREATE TABLE UserOrganisationUnit (_id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT NOT NULL, organisationUnit TEXT NOT NULL, organisationUnitScope TEXT NOT NULL, root INTEGER, userAssigned INTEGER, FOREIGN KEY (user) REFERENCES User (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (organisationUnit) REFERENCES OrganisationUnit (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (organisationUnitScope, user, organisationUnit)); @@ -98,10 +98,9 @@ CREATE TABLE AggregatedDataSync (_id INTEGER PRIMARY KEY AUTOINCREMENT, dataSet CREATE TABLE TrackedEntityInstanceSync (_id INTEGER PRIMARY KEY AUTOINCREMENT, program TEXT, organisationUnitIdsHash INTEGER, downloadLimit INTEGER NOT NULL, lastUpdated TEXT NOT NULL, FOREIGN KEY (program) REFERENCES Program (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (program, organisationUnitIdsHash)); CREATE TABLE EventSync (_id INTEGER PRIMARY KEY AUTOINCREMENT, program TEXT, organisationUnitIdsHash INTEGER, downloadLimit INTEGER NOT NULL, lastUpdated TEXT NOT NULL, FOREIGN KEY (program) REFERENCES Program (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (program, organisationUnitIdsHash)); CREATE TABLE CategoryOptionOrganisationUnitLink (_id INTEGER PRIMARY KEY AUTOINCREMENT, categoryOption TEXT NOT NULL, organisationUnit TEXT, restriction TEXT, FOREIGN KEY (categoryOption) REFERENCES CategoryOption (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (organisationUnit) REFERENCES OrganisationUnit (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (categoryOption, organisationUnit)); -CREATE TABLE TrackedEntityInstanceFilter (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, color TEXT, icon TEXT, program TEXT NOT NULL, description TEXT, sortOrder INTEGER, enrollmentStatus TEXT, followUp INTEGER, periodFrom INTEGER, periodTo INTEGER, FOREIGN KEY (program) REFERENCES Program (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); +CREATE TABLE TrackedEntityInstanceFilter (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, color TEXT, icon TEXT, program TEXT NOT NULL, description TEXT, sortOrder INTEGER, enrollmentStatus TEXT, followUp INTEGER, organisationUnit TEXT, ouMode TEXT, assignedUserMode TEXT, orderProperty TEXT, displayColumnOrder TEXT, eventStatus TEXT, eventDate TEXT, lastUpdatedDate TEXT, programStage TEXT, trackedEntityInstances TEXT, enrollmentIncidentDate TEXT, enrollmentCreatedDate TEXT, trackedEntityType TEXT, FOREIGN KEY (program) REFERENCES Program (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); CREATE TABLE TrackedEntityInstanceEventFilter (_id INTEGER PRIMARY KEY AUTOINCREMENT, trackedEntityInstanceFilter TEXT NOT NULL, programStage TEXT, eventStatus TEXT, periodFrom INTEGER, periodTo INTEGER, assignedUserMode TEXT, FOREIGN KEY (trackedEntityInstanceFilter) REFERENCES TrackedEntityInstanceFilter (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); CREATE TABLE EventFilter (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT NOT NULL UNIQUE, code TEXT, name TEXT, displayName TEXT, created TEXT, lastUpdated TEXT, program TEXT NOT NULL, programStage TEXT, description TEXT, followUp INTEGER, organisationUnit TEXT, ouMode TEXT, assignedUserMode TEXT, orderProperty TEXT, displayColumnOrder TEXT, events TEXT, eventStatus TEXT, eventDate TEXT, dueDate TEXT, lastUpdatedDate TEXT, completedDate TEXT, FOREIGN KEY (program) REFERENCES Program (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (programStage) REFERENCES ProgramStage (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (organisationUnit) REFERENCES OrganisationUnit (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); -CREATE TABLE EventDataFilter (_id INTEGER PRIMARY KEY AUTOINCREMENT, eventFilter TEXT NOT NULL, dataItem TEXT, le TEXT, ge TEXT, gt TEXT, lt TEXT, eq TEXT, inProperty TEXT, like TEXT, dateFilter TEXT, FOREIGN KEY (eventFilter) REFERENCES EventFilter (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); CREATE TABLE ReservedValueSetting (_id INTEGER PRIMARY KEY AUTOINCREMENT, uid TEXT UNIQUE, numberOfValuesToReserve INTEGER, FOREIGN KEY (uid) REFERENCES TrackedEntityAttribute (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); CREATE TABLE SectionIndicatorLink (_id INTEGER PRIMARY KEY AUTOINCREMENT, section TEXT NOT NULL, indicator TEXT NOT NULL, FOREIGN KEY (section) REFERENCES Section (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (indicator) REFERENCES Indicator (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (section, indicator)); CREATE TABLE DataElementLegendSetLink (_id INTEGER PRIMARY KEY AUTOINCREMENT, dataElement TEXT NOT NULL, legendSet TEXT NOT NULL, sortOrder INTEGER, FOREIGN KEY (dataElement) REFERENCES DataElement (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (legendSet) REFERENCES LegendSet (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (dataElement, legendSet)); @@ -121,4 +120,6 @@ CREATE TABLE IndicatorLegendSetLink(_id INTEGER PRIMARY KEY AUTOINCREMENT, indic CREATE TABLE ProgramTempOwner (_id INTEGER PRIMARY KEY AUTOINCREMENT, program TEXT NOT NULL, trackedEntityInstance TEXT NOT NULL, created TEXT NOT NULL, validUntil TEXT NOT NULL, reason TEXT NOT NULL, FOREIGN KEY (program) REFERENCES Program (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); CREATE TABLE SMSConfig (_id INTEGER PRIMARY KEY AUTOINCREMENT, key TEXT NOT NULL UNIQUE, value TEXT); CREATE TABLE SmsMetadataId (_id INTEGER PRIMARY KEY AUTOINCREMENT, type TEXT, uid TEXT); -CREATE TABLE SMSOngoingSubmission (_id INTEGER PRIMARY KEY AUTOINCREMENT, submissionId INTEGER, type TEXT); \ No newline at end of file +CREATE TABLE SMSOngoingSubmission (_id INTEGER PRIMARY KEY AUTOINCREMENT, submissionId INTEGER, type TEXT); +CREATE TABLE TrackedEntityAttributeLegendSetLink (_id INTEGER PRIMARY KEY AUTOINCREMENT, trackedEntityAttribute TEXT NOT NULL, legendSet TEXT NOT NULL, sortOrder INTEGER, FOREIGN KEY (trackedEntityAttribute) REFERENCES TrackedEntityAttribute (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (legendSet) REFERENCES LegendSet (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, UNIQUE (trackedEntityAttribute, legendSet)); +CREATE TABLE ItemFilter (_id INTEGER PRIMARY KEY AUTOINCREMENT, eventFilter TEXT, dataItem TEXT, trackedEntityInstanceFilter TEXT, attribute TEXT, sw TEXT, ew TEXT, le TEXT, ge TEXT, gt TEXT, lt TEXT, eq TEXT, inProperty TEXT, like TEXT, dateFilter TEXT, FOREIGN KEY (eventFilter) REFERENCES EventFilter (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED, FOREIGN KEY (trackedEntityInstanceFilter) REFERENCES TrackedEntityInstanceFilter (uid) ON DELETE CASCADE DEFERRABLE INITIALLY DEFERRED); diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/AnalyticsException.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/AnalyticsException.kt index dabe794764..119f3c95ab 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/AnalyticsException.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/AnalyticsException.kt @@ -36,12 +36,14 @@ sealed class AnalyticsException(message: String) : Throwable(message) { class InvalidDataElement(val uid: String) : AnalyticsException("Missing DataElement $uid") class InvalidDataElementOperand(val uid: String) : AnalyticsException("Missing DataElementOperand $uid") class InvalidProgramIndicator(val uid: String) : AnalyticsException("Missing ProgramIndicator $uid") + class InvalidProgram(val uid: String) : AnalyticsException("Missing Program $uid") class InvalidIndicator(val uid: String) : AnalyticsException("Missing Indicator $uid") class InvalidOrganisationUnit(val uid: String) : AnalyticsException("Missing organisation unit $uid") class InvalidOrganisationUnitGroup(val uid: String) : AnalyticsException("Missing organisation unit group $uid") class InvalidOrganisationUnitLevel(val id: String) : AnalyticsException("Missing organisation unit level $id") class InvalidCategory(val uid: String) : AnalyticsException("Missing category $uid") class InvalidCategoryOption(val uid: String) : AnalyticsException("Missing category option $uid") + class InvalidTrackedEntityAttribute(val uid: String) : AnalyticsException("Missing tracked entity attribute $uid") class ProgramIndicatorCustomBoundaries(val programIndicator: ProgramIndicator) : AnalyticsException( "Custom boundaries are not supported for program indicators: " + diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/LegendEvaluator.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/LegendEvaluator.kt index 20b4e49c91..0b4103d55e 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/LegendEvaluator.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/LegendEvaluator.kt @@ -33,13 +33,15 @@ import org.hisp.dhis.android.core.dataelement.DataElementCollectionRepository import org.hisp.dhis.android.core.indicator.IndicatorCollectionRepository import org.hisp.dhis.android.core.legendset.LegendCollectionRepository import org.hisp.dhis.android.core.program.ProgramIndicatorCollectionRepository +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeCollectionRepository @Suppress("TooGenericExceptionCaught") internal class LegendEvaluator @Inject constructor( private val dataElementRepository: DataElementCollectionRepository, private val programIndicatorRepository: ProgramIndicatorCollectionRepository, private val indicatorRepository: IndicatorCollectionRepository, - private val legendRepository: LegendCollectionRepository + private val legendRepository: LegendCollectionRepository, + private val trackedEntityAttributeCollectionRepository: TrackedEntityAttributeCollectionRepository, ) { fun getLegendByProgramIndicator( programIndicatorUid: String, @@ -81,6 +83,27 @@ internal class LegendEvaluator @Inject constructor( } } + @Suppress("UnusedPrivateMember", "FunctionOnlyReturningConstant") + fun getLegendByTrackedEntityAttribute( + trackedEntityAttributeUid: String, + value: String? + ): String? { + return if (value == null) { + null + } else try { + val trackedEntityAttribute = trackedEntityAttributeCollectionRepository + .byUid().eq(trackedEntityAttributeUid) + .withLegendSets() + .one().blockingGet() + + val legendSet = trackedEntityAttribute.legendSets()!![0] + + return getLegendByLegendSet(legendSet.uid(), value) + } catch (e: Exception) { + null + } + } + fun getLegendByIndicator( indicatorUid: String, value: String? diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/AnalyticsModel.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/AnalyticsModel.kt index 75beff5025..819cbff6a8 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/AnalyticsModel.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/AnalyticsModel.kt @@ -40,7 +40,9 @@ import org.hisp.dhis.android.core.organisationunit.OrganisationUnit import org.hisp.dhis.android.core.organisationunit.OrganisationUnitGroup import org.hisp.dhis.android.core.organisationunit.OrganisationUnitLevel import org.hisp.dhis.android.core.period.Period +import org.hisp.dhis.android.core.program.Program import org.hisp.dhis.android.core.program.ProgramIndicator +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute sealed class MetadataItem(val id: String, val displayName: String) { class DataElementItem(val item: DataElement) : MetadataItem(item.uid(), item.displayName()!!) @@ -49,6 +51,10 @@ sealed class MetadataItem(val id: String, val displayName: String) { class IndicatorItem(val item: Indicator) : MetadataItem(item.uid(), item.displayName()!!) class ProgramIndicatorItem(val item: ProgramIndicator) : MetadataItem(item.uid(), item.displayName()!!) + class EventDataElementItem(val item: DataElement, val program: Program) : + MetadataItem("${program.uid()}.${item.uid()}", "${program.displayName()} ${item.displayName()}") + class EventAttributeItem(val item: TrackedEntityAttribute, program: Program) : + MetadataItem("${program.uid()}.${item.uid()}", "${program.displayName()} ${item.displayName()}") class CategoryItem(val item: Category) : MetadataItem(item.uid(), item.displayName()!!) class CategoryOptionItem(val item: CategoryOption) : MetadataItem(item.uid(), item.displayName()!!) @@ -92,6 +98,12 @@ sealed class DimensionItem(val dimension: Dimension, val id: String) { data class IndicatorItem(val uid: String) : DataItem(uid) data class ProgramIndicatorItem(val uid: String) : DataItem(uid) + + sealed class EventDataItem(id: String) : DataItem(id) { + data class DataElement(val program: String, val dataElement: String) : + EventDataItem("$program.$dataElement") + data class Attribute(val program: String, val attribute: String) : EventDataItem("$program.$attribute") + } } sealed class PeriodItem(id: String) : DimensionItem(Dimension.Period, id) { diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceEvaluatorHelper.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceEvaluatorHelper.kt index db2d2fedc6..4e8592aa4d 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceEvaluatorHelper.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceEvaluatorHelper.kt @@ -37,6 +37,7 @@ import org.hisp.dhis.android.core.analytics.aggregated.DimensionalValue import org.hisp.dhis.android.core.analytics.aggregated.MetadataItem import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.AnalyticsEvaluator import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.DataElementSQLEvaluator +import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.EventDataItemSQLEvaluator import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.IndicatorEvaluator import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.ProgramIndicatorSQLEvaluator @@ -44,6 +45,7 @@ internal class AnalyticsServiceEvaluatorHelper @Inject constructor( private val dataElementEvaluator: DataElementSQLEvaluator, private val programIndicatorEvaluator: ProgramIndicatorSQLEvaluator, private val indicatorEvaluator: IndicatorEvaluator, + private val eventDataItemEvaluator: EventDataItemSQLEvaluator, private val legendEvaluator: LegendEvaluator ) { fun evaluate( @@ -105,6 +107,7 @@ internal class AnalyticsServiceEvaluatorHelper @Inject constructor( is DimensionItem.DataItem.DataElementOperandItem -> dataElementEvaluator is DimensionItem.DataItem.ProgramIndicatorItem -> programIndicatorEvaluator is DimensionItem.DataItem.IndicatorItem -> indicatorEvaluator + is DimensionItem.DataItem.EventDataItem -> eventDataItemEvaluator } } @@ -131,6 +134,14 @@ internal class AnalyticsServiceEvaluatorHelper @Inject constructor( dimensionDataItem.uid, value ) + is DimensionItem.DataItem.EventDataItem.DataElement -> legendEvaluator.getLegendByDataElement( + dimensionDataItem.dataElement, + value + ) + is DimensionItem.DataItem.EventDataItem.Attribute -> legendEvaluator.getLegendByTrackedEntityAttribute( + dimensionDataItem.attribute, + value + ) } } } diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceMetadataHelper.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceMetadataHelper.kt index 2e97135b86..d4b4e69e97 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceMetadataHelper.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceMetadataHelper.kt @@ -47,6 +47,8 @@ import org.hisp.dhis.android.core.organisationunit.OrganisationUnitLevel import org.hisp.dhis.android.core.period.internal.ParentPeriodGenerator import org.hisp.dhis.android.core.period.internal.PeriodHelper import org.hisp.dhis.android.core.program.ProgramIndicatorCollectionRepository +import org.hisp.dhis.android.core.program.internal.ProgramStoreInterface +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute @Suppress("LongParameterList") internal class AnalyticsServiceMetadataHelper @Inject constructor( @@ -59,6 +61,8 @@ internal class AnalyticsServiceMetadataHelper @Inject constructor( private val organisationUnitStore: IdentifiableObjectStore, private val organisationUnitGroupStore: IdentifiableObjectStore, private val organisationUnitLevelStore: IdentifiableObjectStore, + private val programStore: ProgramStoreInterface, + private val trackedEntityAttributeStore: IdentifiableObjectStore, private val programIndicatorRepository: ProgramIndicatorCollectionRepository, private val analyticsOrganisationUnitHelper: AnalyticsOrganisationUnitHelper, private val parentPeriodGenerator: ParentPeriodGenerator, @@ -99,7 +103,7 @@ internal class AnalyticsServiceMetadataHelper @Inject constructor( is DimensionItem.OrganisationUnitItem -> getOrganisationUnitItems(item) is DimensionItem.CategoryItem -> getCategoryItems(item) } - val metadataItemsMap = metadataItems.map { it.id to it }.toMap() + val metadataItemsMap = metadataItems.associateBy { it.id } metadata += metadataItemsMap } @@ -108,7 +112,7 @@ internal class AnalyticsServiceMetadataHelper @Inject constructor( return metadata } - @SuppressWarnings("ThrowsCount") + @SuppressWarnings("ThrowsCount", "ComplexMethod") private fun getDataItems(item: DimensionItem.DataItem): List { return listOf( when (item) { @@ -145,6 +149,24 @@ internal class AnalyticsServiceMetadataHelper @Inject constructor( programIndicatorRepository.withAnalyticsPeriodBoundaries().uid(item.uid).blockingGet() ?.let { programIndicator -> MetadataItem.ProgramIndicatorItem(programIndicator) } ?: throw AnalyticsException.InvalidProgramIndicator(item.uid) + + is DimensionItem.DataItem.EventDataItem.DataElement -> { + val dataElement = dataElementStore.selectByUid(item.dataElement) + ?: throw AnalyticsException.InvalidDataElement(item.id) + val program = programStore.selectByUid(item.program) + ?: throw AnalyticsException.InvalidProgram(item.id) + + MetadataItem.EventDataElementItem(dataElement, program) + } + + is DimensionItem.DataItem.EventDataItem.Attribute -> { + val attribute = trackedEntityAttributeStore.selectByUid(item.attribute) + ?: throw AnalyticsException.InvalidTrackedEntityAttribute(item.id) + val program = programStore.selectByUid(item.program) + ?: throw AnalyticsException.InvalidProgram(item.id) + + MetadataItem.EventAttributeItem(attribute, program) + } } ) } diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsVisualizationsServiceDimensionHelper.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsVisualizationsServiceDimensionHelper.kt index d984d4d423..9fa3149642 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsVisualizationsServiceDimensionHelper.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsVisualizationsServiceDimensionHelper.kt @@ -69,6 +69,7 @@ internal class AnalyticsVisualizationsServiceDimensionHelper @Inject constructor }?.flatten() ?: emptyList() } + @Suppress("ComplexMethod") private fun extractDataDimensionItems(visualization: Visualization): List { return visualization.dataDimensionItems()?.mapNotNull { item -> when (item.dataDimensionItemType()) { @@ -83,6 +84,22 @@ internal class AnalyticsVisualizationsServiceDimensionHelper @Inject constructor } DataDimensionItemType.PROGRAM_INDICATOR -> item.programIndicator()?.let { DimensionItem.DataItem.ProgramIndicatorItem(it.uid()) } + DataDimensionItemType.PROGRAM_DATA_ELEMENT -> + item.programDataElement()?.let { + it.program()?.uid()?.let { program -> + it.dataElement()?.uid()?.let { dataElement -> + DimensionItem.DataItem.EventDataItem.DataElement(program, dataElement) + } + } + } + DataDimensionItemType.PROGRAM_ATTRIBUTE -> + item.programAttribute()?.let { + it.program()?.uid()?.let { program -> + it.attribute()?.uid()?.let { attribute -> + DimensionItem.DataItem.EventDataItem.Attribute(program, attribute) + } + } + } else -> null } diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsDimensionHelper.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsDimensionHelper.kt new file mode 100644 index 0000000000..3360456b98 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsDimensionHelper.kt @@ -0,0 +1,62 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator + +import org.hisp.dhis.android.core.analytics.AnalyticsException +import org.hisp.dhis.android.core.analytics.aggregated.Dimension +import org.hisp.dhis.android.core.analytics.aggregated.DimensionItem +import org.hisp.dhis.android.core.analytics.aggregated.internal.AnalyticsServiceEvaluationItem + +internal object AnalyticsDimensionHelper { + + fun getItemsByDimension(evaluationItem: AnalyticsServiceEvaluationItem): Map> { + return (evaluationItem.dimensionItems + evaluationItem.filters) + .map { it as DimensionItem } + .groupBy { it.dimension } + } + + @Suppress("ThrowsCount") + inline fun getSingleItemByDimension( + item: AnalyticsServiceEvaluationItem + ): List { + val dimensionItems = item.dimensionItems.filterIsInstance() + + return when (dimensionItems.size) { + 0 -> { + val filterItems = item.filters.filterIsInstance() + when (filterItems.size) { + 0 -> throw AnalyticsException.InvalidArguments("Invalid arguments: no items for dimension.") + else -> filterItems + } + } + 1 -> dimensionItems + else -> throw AnalyticsException.InvalidArguments("Invalid arguments: more than one item as dimension.") + } + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsEvaluatorHelper.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsEvaluatorHelper.kt index 1235f2d5da..c7e8ac5419 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsEvaluatorHelper.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsEvaluatorHelper.kt @@ -28,15 +28,14 @@ package org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator -import org.hisp.dhis.android.core.analytics.aggregated.Dimension import org.hisp.dhis.android.core.analytics.aggregated.DimensionItem import org.hisp.dhis.android.core.analytics.aggregated.MetadataItem -import org.hisp.dhis.android.core.analytics.aggregated.internal.AnalyticsServiceEvaluationItem import org.hisp.dhis.android.core.arch.db.querybuilders.internal.WhereClauseBuilder import org.hisp.dhis.android.core.arch.helpers.DateUtils import org.hisp.dhis.android.core.category.CategoryCategoryComboLinkTableInfo as cToCcInfo import org.hisp.dhis.android.core.category.CategoryOptionComboCategoryOptionLinkTableInfo as cocToCoInfo import org.hisp.dhis.android.core.category.CategoryOptionComboTableInfo as cocInfo +import org.hisp.dhis.android.core.common.AggregationType import org.hisp.dhis.android.core.organisationunit.OrganisationUnitTableInfo import org.hisp.dhis.android.core.period.Period import org.hisp.dhis.android.core.period.PeriodTableInfo @@ -52,10 +51,9 @@ import org.hisp.dhis.android.core.period.PeriodTableInfo */ internal object AnalyticsEvaluatorHelper { - fun getItemsByDimension(evaluationItem: AnalyticsServiceEvaluationItem): Map> { - return (evaluationItem.dimensionItems + evaluationItem.filters) - .map { it as DimensionItem } - .groupBy { it.dimension } + fun getElementAggregator(aggregationType: String?): String { + return aggregationType?.let { AggregationType.valueOf(it).sql } + ?: AggregationType.SUM.sql!! } fun appendOrgunitWhereClause( diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/DataElementSQLEvaluator.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/DataElementSQLEvaluator.kt index 563102d880..edc1bba926 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/DataElementSQLEvaluator.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/DataElementSQLEvaluator.kt @@ -34,7 +34,6 @@ import org.hisp.dhis.android.core.analytics.aggregated.Dimension import org.hisp.dhis.android.core.analytics.aggregated.DimensionItem import org.hisp.dhis.android.core.analytics.aggregated.MetadataItem import org.hisp.dhis.android.core.analytics.aggregated.internal.AnalyticsServiceEvaluationItem -import org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator.AnalyticsEvaluatorHelper.getItemsByDimension import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter import org.hisp.dhis.android.core.arch.db.querybuilders.internal.WhereClauseBuilder import org.hisp.dhis.android.core.common.AggregationType @@ -60,7 +59,7 @@ internal class DataElementSQLEvaluator @Inject constructor( evaluationItem: AnalyticsServiceEvaluationItem, metadata: Map ): String { - val items = getItemsByDimension(evaluationItem) + val items = AnalyticsDimensionHelper.getItemsByDimension(evaluationItem) val whereClause = WhereClauseBuilder().apply { items.entries.forEach { entry -> @@ -148,43 +147,30 @@ internal class DataElementSQLEvaluator @Inject constructor( ) } - @Suppress("ThrowsCount") private fun getAggregator( evaluationItem: AnalyticsServiceEvaluationItem, metadata: Map ): String { - val dimensionDataItem = evaluationItem.dimensionItems.filterIsInstance() - - val dataItemList = when (dimensionDataItem.size) { - 0 -> evaluationItem.filters.filterIsInstance() - 1 -> dimensionDataItem - else -> - throw AnalyticsException.InvalidArguments("Invalid arguments: more than one data item as dimension.") - } - - return when (dataItemList.size) { - 0 -> throw AnalyticsException.InvalidArguments("Invalid arguments: no data dimension is specified.") - 1 -> { - val item = metadata[dataItemList.first().id] - val aggregationType = when (item) { - is MetadataItem.DataElementItem -> item.item.aggregationType() - is MetadataItem.DataElementOperandItem -> - metadata[item.item.dataElement()?.uid()]?.let { - (it as MetadataItem.DataElementItem).item.aggregationType() - } - else -> throw AnalyticsException.InvalidArguments( - "Invalid arguments: dimension is not " + - "dataelement or operand." - ) - } - getDataElementAggregator(aggregationType) + val itemList: List = AnalyticsDimensionHelper.getSingleItemByDimension(evaluationItem) + + return if (itemList.size > 1) { + AnalyticsEvaluatorHelper.getElementAggregator(AggregationType.SUM.name) + } else { + val item = itemList[0] + val metadataItem = metadata[item.id] + ?: throw AnalyticsException.InvalidArguments("Invalid arguments: ${item.id} not found in metadata.") + + val aggregationType = when (metadataItem) { + is MetadataItem.DataElementItem -> metadataItem.item.aggregationType() + is MetadataItem.DataElementOperandItem -> + metadata[metadataItem.item.dataElement()?.uid()]?.let { + (it as MetadataItem.DataElementItem).item.aggregationType() + } + else -> + throw AnalyticsException.InvalidArguments("Invalid arguments: invalid dataElement item ${item.id}.") } - else -> getDataElementAggregator(AggregationType.SUM.name) - } - } - private fun getDataElementAggregator(aggregationType: String?): String { - return aggregationType?.let { AggregationType.valueOf(it).sql } - ?: AggregationType.SUM.sql!! + AnalyticsEvaluatorHelper.getElementAggregator(aggregationType) + } } } diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/EventDataItemSQLEvaluator.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/EventDataItemSQLEvaluator.kt new file mode 100644 index 0000000000..23cc6869e4 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/EventDataItemSQLEvaluator.kt @@ -0,0 +1,226 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator + +import javax.inject.Inject +import org.hisp.dhis.android.core.analytics.AnalyticsException +import org.hisp.dhis.android.core.analytics.aggregated.Dimension +import org.hisp.dhis.android.core.analytics.aggregated.DimensionItem +import org.hisp.dhis.android.core.analytics.aggregated.MetadataItem +import org.hisp.dhis.android.core.analytics.aggregated.internal.AnalyticsServiceEvaluationItem +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.querybuilders.internal.WhereClauseBuilder +import org.hisp.dhis.android.core.enrollment.EnrollmentTableInfo +import org.hisp.dhis.android.core.event.EventTableInfo +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeValueTableInfo +import org.hisp.dhis.android.core.trackedentity.TrackedEntityDataValueTableInfo + +internal class EventDataItemSQLEvaluator @Inject constructor( + private val databaseAdapter: DatabaseAdapter +) : AnalyticsEvaluator { + + override fun evaluate( + evaluationItem: AnalyticsServiceEvaluationItem, + metadata: Map + ): String? { + val sqlQuery = getSql(evaluationItem, metadata) + + return databaseAdapter.rawQuery(sqlQuery)?.use { c -> + c.moveToFirst() + c.getString(0) + } + } + + override fun getSql( + evaluationItem: AnalyticsServiceEvaluationItem, + metadata: Map + ): String { + val items = AnalyticsDimensionHelper.getItemsByDimension(evaluationItem) + + val whereClause = WhereClauseBuilder().apply { + items.entries.forEach { entry -> + when (entry.key) { + is Dimension.Data -> appendDataWhereClause(entry.value, this) + is Dimension.Period -> appendPeriodWhereClause(entry.value, this, metadata) + is Dimension.OrganisationUnit -> appendOrgunitWhereClause(entry.value, this, metadata) + is Dimension.Category -> appendCategoryWhereClause(entry.value, this) + } + } + appendKeyNumberValue("$eventAlias.${EventTableInfo.Columns.DELETED}", 0) + }.build() + + val eventDataItem = getEventDataItems(evaluationItem)[0] + val aggregator = getAggregator(eventDataItem, metadata) + + return when (eventDataItem) { + is DimensionItem.DataItem.EventDataItem.DataElement -> + "SELECT $aggregator(${TrackedEntityDataValueTableInfo.Columns.VALUE}) " + + "FROM ${TrackedEntityDataValueTableInfo.TABLE_INFO.name()} $dataValueAlias " + + "INNER JOIN ${EventTableInfo.TABLE_INFO.name()} $eventAlias " + + "ON $dataValueAlias.${TrackedEntityDataValueTableInfo.Columns.EVENT} = " + + "$eventAlias.${EventTableInfo.Columns.UID} " + + "WHERE $whereClause" + + is DimensionItem.DataItem.EventDataItem.Attribute -> + "SELECT $aggregator(${TrackedEntityAttributeValueTableInfo.Columns.VALUE}) " + + "FROM ${TrackedEntityAttributeValueTableInfo.TABLE_INFO.name()} $attAlias " + + "INNER JOIN ${EnrollmentTableInfo.TABLE_INFO.name()} $enrollmentAlias " + + "ON $attAlias.${TrackedEntityAttributeValueTableInfo.Columns.TRACKED_ENTITY_INSTANCE} = " + + "$enrollmentAlias.${EnrollmentTableInfo.Columns.TRACKED_ENTITY_INSTANCE} " + + "INNER JOIN ${EventTableInfo.TABLE_INFO.name()} $eventAlias " + + "ON $enrollmentAlias.${EnrollmentTableInfo.Columns.UID} = " + + "$eventAlias.${EventTableInfo.Columns.ENROLLMENT} " + + "WHERE $whereClause" + } + } + + private fun appendDataWhereClause( + items: List, + builder: WhereClauseBuilder + ): WhereClauseBuilder { + val innerClause = items.map { it as DimensionItem.DataItem } + .foldRight(WhereClauseBuilder()) { item, innerBuilder -> + when (item) { + is DimensionItem.DataItem.EventDataItem.DataElement -> { + val operandClause = WhereClauseBuilder() + .appendKeyStringValue( + "$dataValueAlias.${TrackedEntityDataValueTableInfo.Columns.DATA_ELEMENT}", + item.dataElement + ) + .appendKeyStringValue( + "$eventAlias.${EventTableInfo.Columns.PROGRAM}", + item.program + ) + .build() + innerBuilder.appendOrComplexQuery(operandClause) + } + is DimensionItem.DataItem.EventDataItem.Attribute -> { + val operandClause = WhereClauseBuilder() + .appendKeyStringValue( + "$attAlias.${TrackedEntityAttributeValueTableInfo.Columns.TRACKED_ENTITY_ATTRIBUTE}", + item.attribute + ) + .appendKeyStringValue( + "$eventAlias.${EventTableInfo.Columns.PROGRAM}", + item.program + ) + .build() + innerBuilder.appendOrComplexQuery(operandClause) + } + else -> + throw AnalyticsException.InvalidArguments( + "Invalid arguments: unexpected " + + "dataItem ${item.javaClass.name} in EventDataItem Evaluator." + ) + } + }.build() + + return builder.appendComplexQuery(innerClause) + } + + private fun appendPeriodWhereClause( + items: List, + builder: WhereClauseBuilder, + metadata: Map + ): WhereClauseBuilder { + val reportingPeriods = AnalyticsEvaluatorHelper.getReportingPeriods(items, metadata) + + return if (reportingPeriods.isEmpty()) { + builder + } else { + val eventDateColumn = "$eventAlias.${EventTableInfo.Columns.EVENT_DATE}" + + val innerClause = reportingPeriods.joinToString(" OR ") { + "(${ + AnalyticsEvaluatorHelper.getPeriodWhereClause( + columnStart = eventDateColumn, + columnEnd = eventDateColumn, + period = it + ) + })" + } + + builder.appendComplexQuery(innerClause) + } + } + + private fun appendOrgunitWhereClause( + items: List, + builder: WhereClauseBuilder, + metadata: Map + ): WhereClauseBuilder { + return AnalyticsEvaluatorHelper.appendOrgunitWhereClause( + columnName = "$eventAlias.${EventTableInfo.Columns.ORGANISATION_UNIT}", + items = items, + builder = builder, + metadata = metadata + ) + } + + private fun appendCategoryWhereClause( + items: List, + builder: WhereClauseBuilder + ): WhereClauseBuilder { + return AnalyticsEvaluatorHelper.appendCategoryWhereClause( + columnName = "$eventAlias.${EventTableInfo.Columns.ATTRIBUTE_OPTION_COMBO}", + items = items, + builder = builder + ) + } + + private fun getEventDataItems( + evaluationItem: AnalyticsServiceEvaluationItem, + ): List { + return AnalyticsDimensionHelper.getSingleItemByDimension(evaluationItem) + } + + private fun getAggregator( + item: DimensionItem.DataItem.EventDataItem, + metadata: Map + ): String { + + val aggregationType = when (val metadataItem = metadata[item.id]) { + is MetadataItem.EventDataElementItem -> + metadataItem.item.aggregationType() + is MetadataItem.EventAttributeItem -> + metadataItem.item.aggregationType()?.name + else -> + throw AnalyticsException.InvalidArguments("Invalid arguments: invalid event data item ${item.id}.") + } + + return AnalyticsEvaluatorHelper.getElementAggregator(aggregationType) + } + + companion object { + private const val eventAlias = "ev" + private const val dataValueAlias = "tdv" + private const val attAlias = "av" + private const val enrollmentAlias = "en" + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/ProgramIndicatorEvaluatorHelper.kt b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/ProgramIndicatorEvaluatorHelper.kt index 94c301942c..d7f5cc9f02 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/ProgramIndicatorEvaluatorHelper.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/ProgramIndicatorEvaluatorHelper.kt @@ -103,7 +103,7 @@ internal object ProgramIndicatorEvaluatorHelper { evaluationItem: AnalyticsServiceEvaluationItem, metadata: Map ): String { - val items = AnalyticsEvaluatorHelper.getItemsByDimension(evaluationItem) + val items = AnalyticsDimensionHelper.getItemsByDimension(evaluationItem) return WhereClauseBuilder().apply { appendKeyNumberValue(EventTableInfo.Columns.DELETED, 0) @@ -157,7 +157,7 @@ internal object ProgramIndicatorEvaluatorHelper { evaluationItem: AnalyticsServiceEvaluationItem, metadata: Map ): String { - val items = AnalyticsEvaluatorHelper.getItemsByDimension(evaluationItem) + val items = AnalyticsDimensionHelper.getItemsByDimension(evaluationItem) return WhereClauseBuilder().apply { appendKeyStringValue(EnrollmentTableInfo.Columns.PROGRAM, programIndicator.program()?.uid()) diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/d2/internal/D2DIComponent.java b/core/src/main/java/org/hisp/dhis/android/core/arch/d2/internal/D2DIComponent.java index 977f0f45df..9e8743ce90 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/arch/d2/internal/D2DIComponent.java +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/d2/internal/D2DIComponent.java @@ -90,6 +90,7 @@ import org.hisp.dhis.android.core.trackedentity.TrackedEntityPackageDIModule; import org.hisp.dhis.android.core.trackedentity.TrackedEntityType; import org.hisp.dhis.android.core.trackedentity.internal.OldTrackerImporterPayloadGenerator; +import org.hisp.dhis.android.core.trackedentity.internal.TrackedEntityAttributeLegendSetDIModule; import org.hisp.dhis.android.core.tracker.importer.internal.TrackerImporterPackageDIModule; import org.hisp.dhis.android.core.tracker.importer.internal.interpreters.InterpreterSelector; import org.hisp.dhis.android.core.user.internal.UserPackageDIModule; @@ -139,6 +140,7 @@ OrganisationUnitPackageDIModule.class, PeriodPackageDIModule.class, ProgramPackageDIModule.class, + TrackedEntityAttributeLegendSetDIModule.class, RelationshipPackageDIModule.class, ResourcePackageDIModule.class, SystemInfoPackageDIModule.class, diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/BaseDatabaseOpenHelper.java b/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/BaseDatabaseOpenHelper.java index 4a5f29bea8..0a138e2e26 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/BaseDatabaseOpenHelper.java +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/BaseDatabaseOpenHelper.java @@ -36,7 +36,7 @@ class BaseDatabaseOpenHelper { - static final int VERSION = 124; + static final int VERSION = 127; private final AssetManager assetManager; private final int targetVersion; diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/EncryptedStatementWrapper.java b/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/EncryptedStatementWrapper.java index 8a923142d4..4a0242f93e 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/EncryptedStatementWrapper.java +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/EncryptedStatementWrapper.java @@ -43,6 +43,11 @@ public class EncryptedStatementWrapper implements StatementWrapper { this.s = s; } + @Override + public void bindNull(int index) { + s.bindNull(index); + } + @Override public void bind(int index, String arg) { if (arg == null) { diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/UnencryptedStatementWrapper.java b/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/UnencryptedStatementWrapper.java index 264d78f1ff..cc2fb8c3d1 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/UnencryptedStatementWrapper.java +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/db/access/internal/UnencryptedStatementWrapper.java @@ -44,6 +44,11 @@ class UnencryptedStatementWrapper implements StatementWrapper { this.s = s; } + @Override + public void bindNull(int index) { + s.bindNull(index); + } + @Override public void bind(int index, String arg) { if (arg == null) { diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/db/adapters/custom/internal/EntityQueryCriteriaColumnAdapter.kt b/core/src/main/java/org/hisp/dhis/android/core/arch/db/adapters/custom/internal/EntityQueryCriteriaColumnAdapter.kt new file mode 100644 index 0000000000..315337d694 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/db/adapters/custom/internal/EntityQueryCriteriaColumnAdapter.kt @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.arch.db.adapters.custom.internal + +import android.content.ContentValues +import android.database.Cursor +import com.gabrielittner.auto.value.cursor.ColumnTypeAdapter +import org.hisp.dhis.android.core.trackedentity.EntityQueryCriteria + +class EntityQueryCriteriaColumnAdapter : ColumnTypeAdapter { + override fun fromCursor(cursor: Cursor, columnName: String): EntityQueryCriteria? { + return EntityQueryCriteria.create(cursor) + } + + override fun toContentValues(values: ContentValues, columnName: String, value: EntityQueryCriteria?) { + value?.toContentValues() + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/db/adapters/ignore/internal/IgnoreAttributeValueFilterListColumnAdapter.java b/core/src/main/java/org/hisp/dhis/android/core/arch/db/adapters/ignore/internal/IgnoreAttributeValueFilterListColumnAdapter.java new file mode 100644 index 0000000000..15264ef253 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/db/adapters/ignore/internal/IgnoreAttributeValueFilterListColumnAdapter.java @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.arch.db.adapters.ignore.internal; + +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter; + +import java.util.List; + +public final class IgnoreAttributeValueFilterListColumnAdapter extends IgnoreColumnAdapter> { +} \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/binders/internal/StatementWrapper.java b/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/binders/internal/StatementWrapper.java index 869dd7c6e2..2ef2c52c46 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/binders/internal/StatementWrapper.java +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/binders/internal/StatementWrapper.java @@ -31,6 +31,13 @@ import java.util.Date; public interface StatementWrapper { + /** + * Bind an index using .bindNull(). + * A helper function to abstract/clean up boilerplate if/else bloat... + * @param index + */ + void bindNull(int index); + /** * Handle if String argument is null and bind it using .bindNull() if so. * A helper function to abstract/clean up boilerplate if/else bloat... diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/internal/IdentifiableObjectStoreImpl.kt b/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/internal/IdentifiableObjectStoreImpl.kt index 0b7c4878fa..a2226ad544 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/internal/IdentifiableObjectStoreImpl.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/internal/IdentifiableObjectStoreImpl.kt @@ -112,6 +112,7 @@ internal open class IdentifiableObjectStoreImpl( @Throws(RuntimeException::class) @Suppress("TooGenericExceptionCaught") + @Synchronized override fun updateOrInsert(o: O): HandleAction { return try { update(o) diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/internal/ObjectWithoutUidStoreImpl.kt b/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/internal/ObjectWithoutUidStoreImpl.kt index 38cc38a927..26321aba60 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/internal/ObjectWithoutUidStoreImpl.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/db/stores/internal/ObjectWithoutUidStoreImpl.kt @@ -103,6 +103,7 @@ internal open class ObjectWithoutUidStoreImpl( @Throws(RuntimeException::class) @Suppress("TooGenericExceptionCaught") + @Synchronized override fun updateOrInsertWhere(o: O): HandleAction { return try { updateWhere(o) diff --git a/core/src/main/java/org/hisp/dhis/android/core/arch/handlers/internal/IdentifiableDataHandlerImpl.kt b/core/src/main/java/org/hisp/dhis/android/core/arch/handlers/internal/IdentifiableDataHandlerImpl.kt index 5dca90c3f4..16494dba1f 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/arch/handlers/internal/IdentifiableDataHandlerImpl.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/arch/handlers/internal/IdentifiableDataHandlerImpl.kt @@ -151,11 +151,16 @@ internal abstract class IdentifiableDataHandlerImpl( } } + protected fun deleteLinkedRelationships(o: O) { + o.uid()?.let { relationshipHandler.deleteLinkedRelationships(it) } + } + protected abstract fun addRelationshipState(o: O): O protected abstract fun addSyncedState(o: O): O protected fun deleteOrPersist(o: O): HandleAction { val modelUid = o.uid() return if ((CollectionsHelper.isDeleted(o) || deleteIfCondition(o)) && modelUid != null) { + deleteLinkedRelationships(o) store.deleteIfExists(modelUid) HandleAction.Delete } else { diff --git a/core/src/main/java/org/hisp/dhis/android/core/common/FilterOperators.java b/core/src/main/java/org/hisp/dhis/android/core/common/FilterOperators.java new file mode 100644 index 0000000000..6dd3d4f314 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/common/FilterOperators.java @@ -0,0 +1,124 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.common; + +import androidx.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.gabrielittner.auto.value.cursor.ColumnAdapter; +import com.gabrielittner.auto.value.cursor.ColumnName; + +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DateFilterPeriodColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.StringSetColumnAdapter; +import org.hisp.dhis.android.core.common.tableinfo.ItemFilterTableInfo; + +import java.util.Set; + +public abstract class FilterOperators { + + /** + * Less than or equal to + */ + @Nullable + @JsonProperty() + public abstract String le(); + + /** + * Greater than or equal to + */ + @Nullable + @JsonProperty() + public abstract String ge(); + + /** + * Greater than + */ + @Nullable + @JsonProperty() + public abstract String gt(); + + /** + * Lesser than + */ + @Nullable + @JsonProperty() + public abstract String lt(); + + /** + * Equal to + */ + @Nullable + @JsonProperty() + public abstract String eq(); + + /** + * In a list + */ + @Nullable + @JsonProperty() + @ColumnAdapter(StringSetColumnAdapter.class) + @ColumnName(ItemFilterTableInfo.Columns.IN) + public abstract Set in(); + + /** + * Like + */ + @Nullable + @JsonProperty() + public abstract String like(); + + /** + * If the dataItem is of type date, then date filtering parameters are specified using this. + */ + @Nullable + @JsonProperty() + @ColumnAdapter(DateFilterPeriodColumnAdapter.class) + public abstract DateFilterPeriod dateFilter(); + + @JsonPOJOBuilder(withPrefix = "") + public static abstract class Builder { + + public abstract T le(String le); + + public abstract T ge(String ge); + + public abstract T gt(String gt); + + public abstract T lt(String lt); + + public abstract T eq(String eq); + + public abstract T in(Set in); + + public abstract T like(String like); + + public abstract T dateFilter(DateFilterPeriod dateFilter); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/common/FilterQueryCriteria.java b/core/src/main/java/org/hisp/dhis/android/core/common/FilterQueryCriteria.java new file mode 100644 index 0000000000..cd819492a4 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/common/FilterQueryCriteria.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.common; + +import androidx.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.gabrielittner.auto.value.cursor.ColumnAdapter; +import com.gabrielittner.auto.value.cursor.ColumnName; + +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DateFilterPeriodColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.StringListColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.AssignedUserModeColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.EventStatusColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.OrganisationUnitModeColumnAdapter; +import org.hisp.dhis.android.core.event.EventFilterTableInfo; +import org.hisp.dhis.android.core.event.EventStatus; +import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode; + +import java.util.List; + +public abstract class FilterQueryCriteria { + + @Nullable + public abstract Boolean followUp(); + + @Nullable + @JsonProperty() + public abstract String organisationUnit(); + + @Nullable + @JsonProperty() + @ColumnAdapter(OrganisationUnitModeColumnAdapter.class) + public abstract OrganisationUnitMode ouMode(); + + @Nullable + @JsonProperty() + @ColumnAdapter(AssignedUserModeColumnAdapter.class) + public abstract AssignedUserMode assignedUserMode(); + + @Nullable + @JsonProperty() + @ColumnName(EventFilterTableInfo.Columns.ORDER) + public abstract String order(); + + @Nullable + @JsonProperty() + @ColumnAdapter(StringListColumnAdapter.class) + public abstract List displayColumnOrder(); + + @Nullable + @JsonProperty() + @ColumnAdapter(EventStatusColumnAdapter.class) + public abstract EventStatus eventStatus(); + + @Nullable + @JsonProperty() + @ColumnAdapter(DateFilterPeriodColumnAdapter.class) + public abstract DateFilterPeriod eventDate(); + + @Nullable + @JsonProperty() + @ColumnAdapter(DateFilterPeriodColumnAdapter.class) + public abstract DateFilterPeriod lastUpdatedDate(); + + @JsonPOJOBuilder(withPrefix = "") + public static abstract class Builder { + + public abstract T followUp(Boolean followUp); + + public abstract T organisationUnit(String organisationUnit); + + public abstract T ouMode(OrganisationUnitMode ouMode); + + public abstract T assignedUserMode(AssignedUserMode assignedUserMode); + + public abstract T order(String order); + + public abstract T displayColumnOrder(List displayColumnOrder); + + public abstract T eventStatus(EventStatus eventStatus); + + public abstract T eventDate(DateFilterPeriod eventDate); + + public abstract T lastUpdatedDate(DateFilterPeriod lastUpdatedDate); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/event/EventDataFilterTableInfo.java b/core/src/main/java/org/hisp/dhis/android/core/common/tableinfo/ItemFilterTableInfo.java similarity index 84% rename from core/src/main/java/org/hisp/dhis/android/core/event/EventDataFilterTableInfo.java rename to core/src/main/java/org/hisp/dhis/android/core/common/tableinfo/ItemFilterTableInfo.java index 1a052074ab..2c677d2b2f 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/event/EventDataFilterTableInfo.java +++ b/core/src/main/java/org/hisp/dhis/android/core/common/tableinfo/ItemFilterTableInfo.java @@ -26,22 +26,22 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.hisp.dhis.android.core.event; +package org.hisp.dhis.android.core.common.tableinfo; import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo; import org.hisp.dhis.android.core.arch.helpers.CollectionsHelper; import org.hisp.dhis.android.core.common.CoreColumns; -public final class EventDataFilterTableInfo { +public final class ItemFilterTableInfo { - private EventDataFilterTableInfo() { + private ItemFilterTableInfo() { } public static final TableInfo TABLE_INFO = new TableInfo() { @Override public String name() { - return "EventDataFilter"; + return "ItemFilter"; } @Override @@ -53,6 +53,10 @@ public CoreColumns columns() { public static class Columns extends CoreColumns { public final static String EVENT_FILTER = "eventFilter"; public final static String DATA_ITEM = "dataItem"; + public final static String TRACKED_ENTITY_INSTANCE_FILTER = "trackedEntityInstanceFilter"; + public final static String ATTRIBUTE = "attribute"; + public static final String SW = "sw"; + public static final String EW = "ew"; public final static String LE = "le"; public static final String GE = "ge"; public static final String GT = "gt"; @@ -67,6 +71,10 @@ public String[] all() { return CollectionsHelper.appendInNewArray(super.all(), EVENT_FILTER, DATA_ITEM, + TRACKED_ENTITY_INSTANCE_FILTER, + ATTRIBUTE, + SW, + EW, LE, GE, GT, diff --git a/core/src/main/java/org/hisp/dhis/android/core/event/EventDataFilter.java b/core/src/main/java/org/hisp/dhis/android/core/event/EventDataFilter.java index 55fcd7c8ff..358a74a3b5 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/event/EventDataFilter.java +++ b/core/src/main/java/org/hisp/dhis/android/core/event/EventDataFilter.java @@ -35,20 +35,14 @@ import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; -import com.gabrielittner.auto.value.cursor.ColumnAdapter; -import com.gabrielittner.auto.value.cursor.ColumnName; import com.google.auto.value.AutoValue; -import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DateFilterPeriodColumnAdapter; -import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.StringSetColumnAdapter; import org.hisp.dhis.android.core.common.CoreObject; -import org.hisp.dhis.android.core.common.DateFilterPeriod; - -import java.util.Set; +import org.hisp.dhis.android.core.common.FilterOperators; @AutoValue @JsonDeserialize(builder = $$AutoValue_EventDataFilter.Builder.class) -public abstract class EventDataFilter implements CoreObject { +public abstract class EventDataFilter extends FilterOperators implements CoreObject { /** * The related event filter @@ -64,65 +58,6 @@ public abstract class EventDataFilter implements CoreObject { @JsonProperty() public abstract String dataItem(); - /** - * Less than or equal to - */ - @Nullable - @JsonProperty() - public abstract String le(); - - /** - * Greater than or equal to - */ - @Nullable - @JsonProperty() - public abstract String ge(); - - /** - * Greater than - */ - @Nullable - @JsonProperty() - public abstract String gt(); - - /** - * Lesser than - */ - @Nullable - @JsonProperty() - public abstract String lt(); - - /** - * Equal to - */ - @Nullable - @JsonProperty() - public abstract String eq(); - - /** - * In a list - */ - @Nullable - @JsonProperty() - @ColumnAdapter(StringSetColumnAdapter.class) - @ColumnName(EventDataFilterTableInfo.Columns.IN) - public abstract Set in(); - - /** - * Like - */ - @Nullable - @JsonProperty() - public abstract String like(); - - /** - * If the dataItem is of type date, then date filtering parameters are specified using this. - */ - @Nullable - @JsonProperty() - @ColumnAdapter(DateFilterPeriodColumnAdapter.class) - public abstract DateFilterPeriod dateFilter(); - public static Builder builder() { return new $$AutoValue_EventDataFilter.Builder(); } @@ -135,29 +70,13 @@ public static EventDataFilter create(Cursor cursor) { @AutoValue.Builder @JsonPOJOBuilder(withPrefix = "") - public static abstract class Builder { + public static abstract class Builder extends FilterOperators.Builder { public abstract Builder id(Long id); public abstract Builder eventFilter(String eventFilter); public abstract Builder dataItem(String dataItem); - public abstract Builder le(String le); - - public abstract Builder ge(String ge); - - public abstract Builder gt(String gt); - - public abstract Builder lt(String lt); - - public abstract Builder eq(String eq); - - public abstract Builder in(Set in); - - public abstract Builder like(String like); - - public abstract Builder dateFilter(DateFilterPeriod dateFilter); - public abstract EventDataFilter build(); } } \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/event/EventQueryCriteria.java b/core/src/main/java/org/hisp/dhis/android/core/event/EventQueryCriteria.java index 201283c154..e8154ef660 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/event/EventQueryCriteria.java +++ b/core/src/main/java/org/hisp/dhis/android/core/event/EventQueryCriteria.java @@ -36,53 +36,20 @@ import com.fasterxml.jackson.databind.annotation.JsonDeserialize; import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; import com.gabrielittner.auto.value.cursor.ColumnAdapter; -import com.gabrielittner.auto.value.cursor.ColumnName; import com.google.auto.value.AutoValue; import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DateFilterPeriodColumnAdapter; import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.StringListColumnAdapter; -import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.AssignedUserModeColumnAdapter; -import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.EventStatusColumnAdapter; -import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.OrganisationUnitModeColumnAdapter; import org.hisp.dhis.android.core.arch.db.adapters.ignore.internal.IgnoreEventDataFilterListColumnAdapter; -import org.hisp.dhis.android.core.common.AssignedUserMode; import org.hisp.dhis.android.core.common.CoreObject; import org.hisp.dhis.android.core.common.DateFilterPeriod; -import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode; +import org.hisp.dhis.android.core.common.FilterQueryCriteria; import java.util.List; @AutoValue @JsonDeserialize(builder = $$AutoValue_EventQueryCriteria.Builder.class) -public abstract class EventQueryCriteria implements CoreObject { - - @Nullable - @JsonProperty() - public abstract Boolean followUp(); - - @Nullable - @JsonProperty() - public abstract String organisationUnit(); - - @Nullable - @JsonProperty() - @ColumnAdapter(OrganisationUnitModeColumnAdapter.class) - public abstract OrganisationUnitMode ouMode(); - - @Nullable - @JsonProperty() - @ColumnAdapter(AssignedUserModeColumnAdapter.class) - public abstract AssignedUserMode assignedUserMode(); - - @Nullable - @JsonProperty() - @ColumnName(EventFilterTableInfo.Columns.ORDER) - public abstract String order(); - - @Nullable - @JsonProperty() - @ColumnAdapter(StringListColumnAdapter.class) - public abstract List displayColumnOrder(); +public abstract class EventQueryCriteria extends FilterQueryCriteria implements CoreObject { @Nullable @JsonProperty() @@ -94,26 +61,11 @@ public abstract class EventQueryCriteria implements CoreObject { @ColumnAdapter(StringListColumnAdapter.class) public abstract List events(); - @Nullable - @JsonProperty() - @ColumnAdapter(EventStatusColumnAdapter.class) - public abstract EventStatus eventStatus(); - - @Nullable - @JsonProperty() - @ColumnAdapter(DateFilterPeriodColumnAdapter.class) - public abstract DateFilterPeriod eventDate(); - @Nullable @JsonProperty() @ColumnAdapter(DateFilterPeriodColumnAdapter.class) public abstract DateFilterPeriod dueDate(); - @Nullable - @JsonProperty() - @ColumnAdapter(DateFilterPeriodColumnAdapter.class) - public abstract DateFilterPeriod lastUpdatedDate(); - @Nullable @JsonProperty() @ColumnAdapter(DateFilterPeriodColumnAdapter.class) @@ -131,33 +83,15 @@ public static EventQueryCriteria create(Cursor cursor) { @AutoValue.Builder @JsonPOJOBuilder(withPrefix = "") - public static abstract class Builder { + public static abstract class Builder extends FilterQueryCriteria.Builder { public abstract Builder id(Long id); - public abstract Builder followUp(Boolean followUp); - - public abstract Builder organisationUnit(String organisationUnit); - - public abstract Builder ouMode(OrganisationUnitMode ouMode); - - public abstract Builder assignedUserMode(AssignedUserMode assignedUserMode); - - public abstract Builder order(String order); - - public abstract Builder displayColumnOrder(List displayColumnOrder); - public abstract Builder dataFilters(List dataFilters); public abstract Builder events(List events); - public abstract Builder eventStatus(EventStatus eventStatus); - - public abstract Builder eventDate(DateFilterPeriod eventDate); - public abstract Builder dueDate(DateFilterPeriod dueDate); - public abstract Builder lastUpdatedDate(DateFilterPeriod lastUpdatedDate); - public abstract Builder completedDate(DateFilterPeriod completedDate); public abstract EventQueryCriteria build(); diff --git a/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterEntityDIModule.java b/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterEntityDIModule.kt similarity index 75% rename from core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterEntityDIModule.java rename to core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterEntityDIModule.kt index 1beef4357d..4973a9aa48 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterEntityDIModule.java +++ b/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterEntityDIModule.kt @@ -25,31 +25,29 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.event.internal -package org.hisp.dhis.android.core.event.internal; - -import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter; -import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectWithoutUidStore; -import org.hisp.dhis.android.core.arch.handlers.internal.HandlerWithTransformer; -import org.hisp.dhis.android.core.arch.handlers.internal.ObjectWithoutUidHandlerImpl; -import org.hisp.dhis.android.core.event.EventDataFilter; - -import dagger.Module; -import dagger.Provides; -import dagger.Reusable; +import dagger.Module +import dagger.Provides +import dagger.Reusable +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectWithoutUidStore +import org.hisp.dhis.android.core.arch.handlers.internal.HandlerWithTransformer +import org.hisp.dhis.android.core.arch.handlers.internal.ObjectWithoutUidHandlerImpl +import org.hisp.dhis.android.core.event.EventDataFilter +import org.hisp.dhis.android.core.event.internal.EventDataFilterStore.create @Module -public final class EventDataFilterEntityDIModule { - +internal class EventDataFilterEntityDIModule { @Provides @Reusable - ObjectWithoutUidStore store(DatabaseAdapter databaseAdapter) { - return EventDataFilterStore.create(databaseAdapter); + fun store(databaseAdapter: DatabaseAdapter): ObjectWithoutUidStore { + return create(databaseAdapter) } @Provides @Reusable - HandlerWithTransformer handler(ObjectWithoutUidStore store) { - return new ObjectWithoutUidHandlerImpl<>(store); + fun handler(store: ObjectWithoutUidStore): HandlerWithTransformer { + return ObjectWithoutUidHandlerImpl(store) } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterFields.java b/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterFields.java index 7e0ca88807..be77ed5f3e 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterFields.java +++ b/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterFields.java @@ -30,8 +30,8 @@ import org.hisp.dhis.android.core.arch.api.fields.internal.Fields; import org.hisp.dhis.android.core.arch.fields.internal.FieldsHelper; +import org.hisp.dhis.android.core.common.tableinfo.ItemFilterTableInfo.Columns; import org.hisp.dhis.android.core.event.EventDataFilter; -import org.hisp.dhis.android.core.event.EventDataFilterTableInfo.Columns; public final class EventDataFilterFields { diff --git a/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStore.kt b/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStore.kt index 7c1454505d..85f57bc15c 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStore.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/event/internal/EventDataFilterStore.kt @@ -36,22 +36,26 @@ import org.hisp.dhis.android.core.arch.db.stores.binders.internal.WhereStatement import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectWithoutUidStore import org.hisp.dhis.android.core.arch.db.stores.internal.StoreFactory.objectWithoutUidStore import org.hisp.dhis.android.core.arch.db.stores.projections.internal.SingleParentChildProjection +import org.hisp.dhis.android.core.common.tableinfo.ItemFilterTableInfo import org.hisp.dhis.android.core.event.EventDataFilter -import org.hisp.dhis.android.core.event.EventDataFilterTableInfo @Suppress("MagicNumber") internal object EventDataFilterStore { private val BINDER = StatementBinder { o: EventDataFilter, w: StatementWrapper -> w.bind(1, o.eventFilter()) w.bind(2, o.dataItem()) - w.bind(3, o.le()) - w.bind(4, o.ge()) - w.bind(5, o.gt()) - w.bind(6, o.lt()) - w.bind(7, o.eq()) - w.bind(8, StringSetColumnAdapter.serialize(o.`in`())) - w.bind(9, o.like()) - w.bind(10, DateFilterPeriodColumnAdapter.serialize(o.dateFilter())) + w.bindNull(3) + w.bindNull(4) + w.bindNull(5) + w.bindNull(6) + w.bind(7, o.le()) + w.bind(8, o.ge()) + w.bind(9, o.gt()) + w.bind(10, o.lt()) + w.bind(11, o.eq()) + w.bind(12, StringSetColumnAdapter.serialize(o.`in`())) + w.bind(13, o.like()) + w.bind(14, DateFilterPeriodColumnAdapter.serialize(o.dateFilter())) } private val WHERE_UPDATE_BINDER = WhereStatementBinder { _: EventDataFilter, _ -> } @@ -59,15 +63,15 @@ internal object EventDataFilterStore { @JvmField val CHILD_PROJECTION = SingleParentChildProjection( - EventDataFilterTableInfo.TABLE_INFO, - EventDataFilterTableInfo.Columns.EVENT_FILTER + ItemFilterTableInfo.TABLE_INFO, + ItemFilterTableInfo.Columns.EVENT_FILTER ) @JvmStatic fun create(databaseAdapter: DatabaseAdapter): ObjectWithoutUidStore { return objectWithoutUidStore( databaseAdapter, - EventDataFilterTableInfo.TABLE_INFO, + ItemFilterTableInfo.TABLE_INFO, BINDER, WHERE_UPDATE_BINDER, WHERE_DELETE_BINDER ) { EventDataFilter.create(it) } } diff --git a/core/src/main/java/org/hisp/dhis/android/core/legendset/internal/LegendSetUidsSeeker.kt b/core/src/main/java/org/hisp/dhis/android/core/legendset/internal/LegendSetUidsSeeker.kt index 3b5fc78ece..793d74b95b 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/legendset/internal/LegendSetUidsSeeker.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/legendset/internal/LegendSetUidsSeeker.kt @@ -35,6 +35,7 @@ import org.hisp.dhis.android.core.arch.db.querybuilders.internal.MultipleTableQu import org.hisp.dhis.android.core.indicator.IndicatorLegendSetLinkTableInfo import org.hisp.dhis.android.core.legendset.DataElementLegendSetLinkTableInfo import org.hisp.dhis.android.core.legendset.ProgramIndicatorLegendSetLinkTableInfo +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeLegendSetLinkTableInfo import org.hisp.dhis.android.core.visualization.VisualizationTableInfo @Reusable @@ -45,6 +46,7 @@ internal class LegendSetUidsSeeker @Inject constructor(private val databaseAdapt ProgramIndicatorLegendSetLinkTableInfo.TABLE_INFO.name(), IndicatorLegendSetLinkTableInfo.TABLE_INFO.name(), DataElementLegendSetLinkTableInfo.TABLE_INFO.name(), + TrackedEntityAttributeLegendSetLinkTableInfo.TABLE_INFO.name(), ) val query = MultipleTableQueryBuilder() .generateQuery(ProgramIndicatorLegendSetLinkTableInfo.Columns.LEGEND_SET, tableNames) diff --git a/core/src/main/java/org/hisp/dhis/android/core/period/internal/AbstractPeriodGenerator.java b/core/src/main/java/org/hisp/dhis/android/core/period/internal/AbstractPeriodGenerator.java index 890274a4d4..95222c17ec 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/period/internal/AbstractPeriodGenerator.java +++ b/core/src/main/java/org/hisp/dhis/android/core/period/internal/AbstractPeriodGenerator.java @@ -39,6 +39,7 @@ import java.util.List; import java.util.Locale; +@SuppressWarnings({"PMD.AvoidSynchronizedAtMethodLevel"}) abstract class AbstractPeriodGenerator implements PeriodGenerator { private final Calendar initialCalendar; protected Calendar calendar; @@ -54,7 +55,7 @@ abstract class AbstractPeriodGenerator implements PeriodGenerator { } @Override - public final List generatePeriods(int start, int end) throws RuntimeException { + synchronized public final List generatePeriods(int start, int end) throws RuntimeException { this.calendar = (Calendar) initialCalendar.clone(); if (start >= end) { @@ -77,7 +78,7 @@ public final List generatePeriods(int start, int end) throws RuntimeExce } @Override - public final Period generatePeriod(Date date, int periodOffset) { + synchronized public final Period generatePeriod(Date date, int periodOffset) { this.calendar = (Calendar) initialCalendar.clone(); moveToStartOfThePeriodOfADayWithOffset(date, periodOffset); @@ -99,7 +100,7 @@ public final Period generatePeriod(Date date, int periodOffset) { } @Override - public List generatePeriodsInYear(int yearOffset) { + synchronized public List generatePeriodsInYear(int yearOffset) { this.calendar = (Calendar) initialCalendar.clone(); int targetYear = calendar.get(Calendar.YEAR) + yearOffset; diff --git a/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipModule.java b/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipModule.java index dc431d9359..c368813001 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipModule.java +++ b/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipModule.java @@ -29,6 +29,6 @@ public interface RelationshipModule { RelationshipTypeCollectionRepository relationshipTypes(); - RelationshipCollectionRepository relationships(); + RelationshipService relationshipService(); } \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipService.kt b/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipService.kt new file mode 100644 index 0000000000..37714dcd53 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipService.kt @@ -0,0 +1,5 @@ +package org.hisp.dhis.android.core.relationship + +interface RelationshipService { + fun hasAccessPermission(relationshipType: RelationshipType): Boolean +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipServiceImpl.kt b/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipServiceImpl.kt new file mode 100644 index 0000000000..de57f624de --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/relationship/RelationshipServiceImpl.kt @@ -0,0 +1,46 @@ +package org.hisp.dhis.android.core.relationship + +import dagger.Reusable +import javax.inject.Inject +import org.hisp.dhis.android.core.program.ProgramCollectionRepository +import org.hisp.dhis.android.core.program.ProgramStageCollectionRepository +import org.hisp.dhis.android.core.trackedentity.TrackedEntityTypeCollectionRepository + +@Reusable +internal class RelationshipServiceImpl @Inject constructor( + private val programRepository: ProgramCollectionRepository, + private val programStageRepository: ProgramStageCollectionRepository, + private val trackedEntityTypeRepository: TrackedEntityTypeCollectionRepository +) : RelationshipService { + override fun hasAccessPermission(relationshipType: RelationshipType): Boolean { + + val fromAccess = relationshipType.fromConstraint()?.let { constraintAccess(it) } ?: false + val toAccess = relationshipType.toConstraint()?.let { constraintAccess(it) } ?: false + + val writeAccess = if (relationshipType.bidirectional() == true) { + fromAccess && toAccess + } else { + fromAccess + } + + return writeAccess + } + + private fun constraintAccess( + constraint: RelationshipConstraint + ): Boolean = when (constraint.relationshipEntity()) { + RelationshipEntityType.PROGRAM_INSTANCE -> { + val programUid = constraint.program()?.uid() + programRepository.uid(programUid).blockingGet()!!.access().data().write()!! + } + RelationshipEntityType.PROGRAM_STAGE_INSTANCE -> { + val programStageUid = constraint.programStage()?.uid() + programStageRepository.uid(programStageUid).blockingGet()?.access()!!.data().write() + } + RelationshipEntityType.TRACKED_ENTITY_INSTANCE -> { + val teTypeUid = constraint.trackedEntityType()?.uid() + trackedEntityTypeRepository.uid(teTypeUid).blockingGet().access().data().write() + } + else -> false + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandler.java b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandler.kt similarity index 77% rename from core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandler.java rename to core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandler.kt index c71be68800..c5c8b6b40e 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandler.java +++ b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandler.kt @@ -25,13 +25,14 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.hisp.dhis.android.core.relationship.internal; +package org.hisp.dhis.android.core.relationship.internal -import org.hisp.dhis.android.core.arch.handlers.internal.HandlerWithTransformer; -import org.hisp.dhis.android.core.relationship.Relationship; -import org.hisp.dhis.android.core.relationship.RelationshipItem; +import org.hisp.dhis.android.core.arch.handlers.internal.HandlerWithTransformer +import org.hisp.dhis.android.core.relationship.Relationship +import org.hisp.dhis.android.core.relationship.RelationshipItem -public interface RelationshipHandler extends HandlerWithTransformer { - boolean doesRelationshipExist(Relationship relationship); - boolean doesRelationshipItemExist(RelationshipItem item); -} \ No newline at end of file +internal interface RelationshipHandler : HandlerWithTransformer { + fun doesRelationshipExist(relationship: Relationship): Boolean + fun doesRelationshipItemExist(item: RelationshipItem): Boolean + fun deleteLinkedRelationships(entityUid: String) +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandlerImpl.kt b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandlerImpl.kt index c9749faf40..ff8b113725 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandlerImpl.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipHandlerImpl.kt @@ -66,6 +66,13 @@ internal class RelationshipHandlerImpl @Inject constructor( return storeSelector.getElementStore(item).exists(item.elementUid()) } + override fun deleteLinkedRelationships(entityUid: String) { + relationshipItemStore.getByEntityUid(entityUid) + .mapNotNull { it.relationship()?.uid() } + .distinct() + .forEach { store.deleteIfExists(it) } + } + private fun getExistingRelationshipUid(relationship: Relationship): String? { val existingRelationshipUidsForPair = relationshipItemStore.getRelationshipUidsForItems( relationship.from()!!, relationship.to()!! diff --git a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStore.kt b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStore.kt index cacde5bec8..f9a6c79606 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStore.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStore.kt @@ -45,4 +45,6 @@ internal interface RelationshipItemStore : ObjectWithoutUidStore): List fun getByItem(item: RelationshipItem): List + + fun getByEntityUid(entityUid: String): List } diff --git a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreImpl.kt b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreImpl.kt index a9399be4cc..a9b86f9313 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreImpl.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipItemStoreImpl.kt @@ -137,6 +137,16 @@ internal class RelationshipItemStoreImpl private constructor( return selectWhere(clauseBuilder.build()) } + override fun getByEntityUid(entityUid: String): List { + val clauseBuilder = WhereClauseBuilder().apply { + appendOrKeyStringValue(RelationshipItemTableInfo.Columns.TRACKED_ENTITY_INSTANCE, entityUid) + appendOrKeyStringValue(RelationshipItemTableInfo.Columns.ENROLLMENT, entityUid) + appendOrKeyStringValue(RelationshipItemTableInfo.Columns.EVENT, entityUid) + } + + return selectWhere(clauseBuilder.build()) + } + private fun getAllItemsOfSameType(from: RelationshipItem, to: RelationshipItem): Cursor { val query = "SELECT " + RelationshipItemTableInfo.Columns.RELATIONSHIP + ", " + "MAX(CASE WHEN " + RelationshipItemTableInfo.Columns.RELATIONSHIP_ITEM_TYPE + " = 'FROM' " + diff --git a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipModuleImpl.java b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipModuleImpl.java index 7b30c28402..b58af67277 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipModuleImpl.java +++ b/core/src/main/java/org/hisp/dhis/android/core/relationship/internal/RelationshipModuleImpl.java @@ -29,6 +29,8 @@ import org.hisp.dhis.android.core.relationship.RelationshipCollectionRepository; import org.hisp.dhis.android.core.relationship.RelationshipModule; +import org.hisp.dhis.android.core.relationship.RelationshipService; +import org.hisp.dhis.android.core.relationship.RelationshipServiceImpl; import org.hisp.dhis.android.core.relationship.RelationshipTypeCollectionRepository; import javax.inject.Inject; @@ -41,12 +43,16 @@ public final class RelationshipModuleImpl implements RelationshipModule { private final RelationshipTypeCollectionRepository relationshipTypes; private final RelationshipCollectionRepository relationships; + private final RelationshipService relationshipService; @Inject - RelationshipModuleImpl(RelationshipTypeCollectionRepository relationshipTypeRepository, - RelationshipCollectionRepository relationshipRepository) { + RelationshipModuleImpl( + RelationshipTypeCollectionRepository relationshipTypeRepository, + RelationshipCollectionRepository relationshipRepository, + RelationshipServiceImpl relationshipService) { this.relationshipTypes = relationshipTypeRepository; this.relationships = relationshipRepository; + this.relationshipService = relationshipService; } @Override @@ -58,4 +64,9 @@ public RelationshipTypeCollectionRepository relationshipTypes() { public RelationshipCollectionRepository relationships() { return relationships; } + + @Override + public RelationshipService relationshipService() { + return relationshipService; + } } \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISPatchVersion.java b/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISPatchVersion.kt similarity index 75% rename from core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISPatchVersion.java rename to core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISPatchVersion.kt index ee136e10b2..e99790b39d 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISPatchVersion.java +++ b/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISPatchVersion.kt @@ -25,11 +25,11 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.systeminfo -package org.hisp.dhis.android.core.systeminfo; - -public enum DHISPatchVersion { +enum class DHISPatchVersion(val majorVersion: DHISVersion, val strValue: String, val smsVersion: SMSVersion?) { V2_29(DHISVersion.V2_29, "2.29", null), + V2_30(DHISVersion.V2_30, "2.30", null), V2_31_0(DHISVersion.V2_31, "2.31.0", null), @@ -64,34 +64,10 @@ public enum DHISPatchVersion { V2_38_0(DHISVersion.V2_38, "2.38.0", SMSVersion.V2); - private String strValue; - private DHISVersion majorVersion; - private SMSVersion smsVersion; - - DHISPatchVersion(DHISVersion majorVersion, String strValue, SMSVersion smsVersion) { - this.majorVersion = majorVersion; - this.strValue = strValue; - this.smsVersion = smsVersion; - } - - public String getStrValue() { - return strValue; - } - - public DHISVersion getMajorVersion() { - return majorVersion; - } - - public SMSVersion getSmsVersion() { - return smsVersion; - } - - public static DHISPatchVersion getValue(String versionStr) { - for (DHISPatchVersion patchVersion : DHISPatchVersion.values()) { - if (versionStr.equals(patchVersion.strValue) || versionStr.startsWith(patchVersion.strValue + "-")) { - return patchVersion; - } + companion object { + @JvmStatic + fun getValue(versionStr: String): DHISPatchVersion? { + return values().find { versionStr == it.strValue || versionStr.startsWith(it.strValue + "-") } } - return null; } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISVersion.java b/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISVersion.java deleted file mode 100644 index 626f572c43..0000000000 --- a/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISVersion.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.systeminfo; - -public enum DHISVersion { - V2_29, - V2_30, - V2_31, - V2_32, - V2_33, - V2_34, - V2_35, - V2_36, - V2_37, - V2_38; - - private static final String V2_29_STR = "2.29"; - private static final String V2_30_STR = "2.30"; - private static final String V2_31_STR = "2.31"; - private static final String V2_32_STR = "2.32"; - private static final String V2_33_STR = "2.33"; - private static final String V2_34_STR = "2.34"; - private static final String V2_35_STR = "2.35"; - private static final String V2_36_STR = "2.36"; - private static final String V2_37_STR = "2.37"; - private static final String V2_38_STR = "2.38"; - - public static DHISVersion getValue(String versionStr) { - if (versionStr.startsWith(V2_29_STR)) { - return V2_29; - } else if (versionStr.startsWith(V2_30_STR)) { - return V2_30; - } else if (versionStr.startsWith(V2_31_STR)) { - return V2_31; - } else if (versionStr.startsWith(V2_32_STR)) { - return V2_32; - } else if (versionStr.startsWith(V2_33_STR)) { - return V2_33; - } else if (versionStr.startsWith(V2_34_STR)) { - return V2_34; - } else if (versionStr.startsWith(V2_35_STR)) { - return V2_35; - } else if (versionStr.startsWith(V2_36_STR)) { - return V2_36; - } else if (versionStr.startsWith(V2_37_STR)) { - return V2_37; - } else if (versionStr.startsWith(V2_38_STR)) { - return V2_38; - } else { - return null; - } - } - - public static boolean isAllowedVersion(String versionStr) { - return getValue(versionStr) != null; - } - - public static String[] allowedVersionsAsStr() { - return new String[]{V2_30_STR, V2_31_STR, V2_32_STR, V2_33_STR, V2_34_STR, V2_35_STR, - V2_36_STR, V2_37_STR, V2_38_STR}; - } -} \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISVersion.kt b/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISVersion.kt new file mode 100644 index 0000000000..90177e978f --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/systeminfo/DHISVersion.kt @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.systeminfo + +enum class DHISVersion(internal val prefix: String) { + V2_29("2.29"), + V2_30("2.30"), + V2_31("2.31"), + V2_32("2.32"), + V2_33("2.33"), + V2_34("2.34"), + V2_35("2.35"), + V2_36("2.36"), + V2_37("2.37"), + V2_38("2.38"); + + companion object { + @JvmStatic + fun getValue(versionStr: String): DHISVersion? { + return values().find { versionStr.startsWith(it.prefix) } + } + + @JvmStatic + fun isAllowedVersion(versionStr: String): Boolean { + return getValue(versionStr) != null + } + + @JvmStatic + fun allowedVersionsAsStr(): Array { + return listOf(V2_30, V2_31, V2_32, V2_33, V2_34, V2_35, V2_36, V2_37, V2_38) + .map { it.prefix } + .toTypedArray() + } + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/systeminfo/SMSVersion.kt b/core/src/main/java/org/hisp/dhis/android/core/systeminfo/SMSVersion.kt new file mode 100644 index 0000000000..ae7a98bfd2 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/systeminfo/SMSVersion.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.systeminfo + +enum class SMSVersion(val intValue: Int) { + V1(1), + V2(2); + + companion object { + @JvmStatic + fun getValue(versionStr: String): SMSVersion? { + val patchVersion = DHISPatchVersion.getValue(versionStr) + + return if (patchVersion == null) { + DHISVersion.getValue(versionStr)?.let { getLatestInDHISVersion(it) } + } else { + patchVersion.smsVersion + } + } + + private fun getLatestInDHISVersion(dhisVersion: DHISVersion): SMSVersion? { + return DHISPatchVersion.values() + .filter { it.majorVersion == dhisVersion && it.smsVersion != null } + .fold(null) { latest: SMSVersion?, version -> + if (latest == null || latest.intValue < version.smsVersion!!.intValue) { + version.smsVersion + } else { + latest + } + } + } + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/AttributeValueFilter.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/AttributeValueFilter.java new file mode 100644 index 0000000000..82c5dc51ce --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/AttributeValueFilter.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.trackedentity; + +import android.database.Cursor; + +import androidx.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.google.auto.value.AutoValue; + +import org.hisp.dhis.android.core.common.CoreObject; +import org.hisp.dhis.android.core.common.FilterOperators; + +@AutoValue +@JsonDeserialize(builder = $$AutoValue_AttributeValueFilter.Builder.class) +public abstract class AttributeValueFilter extends FilterOperators implements CoreObject { + + /** + * The related trackedEntityInstance filter + */ + @Nullable + @JsonProperty() + public abstract String trackedEntityInstanceFilter(); + + /** + * The attribute id + */ + @Nullable + @JsonProperty() + public abstract String attribute(); + + /** + * End with + */ + @Nullable + @JsonProperty() + public abstract String ew(); + + /** + * Starts with + */ + @Nullable + @JsonProperty() + public abstract String sw(); + + public static Builder builder() { + return new $$AutoValue_AttributeValueFilter.Builder(); + } + + public static AttributeValueFilter create(Cursor cursor) { + return $AutoValue_AttributeValueFilter.createFromCursor(cursor); + } + + public abstract Builder toBuilder(); + + @AutoValue.Builder + @JsonPOJOBuilder(withPrefix = "") + public static abstract class Builder extends FilterOperators.Builder { + public abstract Builder id(Long id); + + public abstract Builder trackedEntityInstanceFilter(String trackedEntityInstanceFilter); + + public abstract Builder attribute(String attribute); + + public abstract Builder ew(String ew); + + public abstract Builder sw(String sw); + + public abstract AttributeValueFilter build(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/EntityQueryCriteria.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/EntityQueryCriteria.java new file mode 100644 index 0000000000..c1262f88b2 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/EntityQueryCriteria.java @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.trackedentity; + +import android.database.Cursor; + +import androidx.annotation.Nullable; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.annotation.JsonDeserialize; +import com.fasterxml.jackson.databind.annotation.JsonPOJOBuilder; +import com.gabrielittner.auto.value.cursor.ColumnAdapter; +import com.google.auto.value.AutoValue; + +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DateFilterPeriodColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.StringListColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.EnrollmentStatusColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.ignore.internal.IgnoreAttributeValueFilterListColumnAdapter; +import org.hisp.dhis.android.core.common.CoreObject; +import org.hisp.dhis.android.core.common.DateFilterPeriod; +import org.hisp.dhis.android.core.common.FilterQueryCriteria; +import org.hisp.dhis.android.core.enrollment.EnrollmentStatus; + +import java.util.List; + +@AutoValue +@JsonDeserialize(builder = $$AutoValue_EntityQueryCriteria.Builder.class) +public abstract class EntityQueryCriteria extends FilterQueryCriteria implements CoreObject { + + @Nullable + @JsonProperty() + public abstract String programStage(); + + @Nullable + @JsonProperty() + @ColumnAdapter(StringListColumnAdapter.class) + public abstract List trackedEntityInstances(); + + @Nullable + @JsonProperty() + public abstract String trackedEntityType(); + + @Nullable + @JsonProperty() + @ColumnAdapter(EnrollmentStatusColumnAdapter.class) + public abstract EnrollmentStatus enrollmentStatus(); + + @Nullable + @JsonProperty() + @ColumnAdapter(DateFilterPeriodColumnAdapter.class) + public abstract DateFilterPeriod enrollmentIncidentDate(); + + @Nullable + @JsonProperty() + @ColumnAdapter(DateFilterPeriodColumnAdapter.class) + public abstract DateFilterPeriod enrollmentCreatedDate(); + + @Nullable + @JsonProperty() + @ColumnAdapter(IgnoreAttributeValueFilterListColumnAdapter.class) + public abstract List attributeValueFilters(); + + public static Builder builder() { + return new $$AutoValue_EntityQueryCriteria.Builder(); + } + + public abstract Builder toBuilder(); + + public static EntityQueryCriteria create(Cursor cursor) { + return $AutoValue_EntityQueryCriteria.createFromCursor(cursor); + } + + @AutoValue.Builder + @JsonPOJOBuilder(withPrefix = "") + public static abstract class Builder extends FilterQueryCriteria.Builder { + public abstract Builder id(Long id); + + public abstract Builder programStage(String programStage); + + public abstract Builder trackedEntityInstances(List trackedEntityInstances); + + public abstract Builder trackedEntityType(String trackedEntityType); + + public abstract Builder enrollmentStatus(EnrollmentStatus enrollmentStatus); + + public abstract Builder enrollmentIncidentDate(DateFilterPeriod enrollmentIncidentDate); + + public abstract Builder enrollmentCreatedDate(DateFilterPeriod enrollmentCreatedDate); + + public abstract Builder attributeValueFilters(List attributeValueFilters); + + public abstract EntityQueryCriteria build(); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttribute.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttribute.java index a80f527836..4d2d5d1598 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttribute.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttribute.java @@ -41,9 +41,12 @@ import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DbValueTypeColumnAdapter; import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DefaultAccessColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.AggregationTypeColumnAdapter; import org.hisp.dhis.android.core.arch.db.adapters.identifiable.internal.ObjectWithUidColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.ignore.internal.IgnoreObjectWithUidListColumnAdapter; import org.hisp.dhis.android.core.arch.helpers.AccessHelper; import org.hisp.dhis.android.core.common.Access; +import org.hisp.dhis.android.core.common.AggregationType; import org.hisp.dhis.android.core.common.BaseNameableObject; import org.hisp.dhis.android.core.common.CoreObject; import org.hisp.dhis.android.core.common.ObjectStyle; @@ -52,6 +55,8 @@ import org.hisp.dhis.android.core.common.ValueType; import org.hisp.dhis.android.core.trackedentity.internal.TrackedEntityAttributeFields; +import java.util.List; + @AutoValue @JsonDeserialize(builder = $$AutoValue_TrackedEntityAttribute.Builder.class) public abstract class TrackedEntityAttribute extends BaseNameableObject @@ -79,6 +84,11 @@ public abstract class TrackedEntityAttribute extends BaseNameableObject @JsonProperty() public abstract String expression(); + @Nullable + @JsonProperty() + @ColumnAdapter(AggregationTypeColumnAdapter.class) + public abstract AggregationType aggregationType(); + @Nullable @JsonProperty() public abstract Boolean programScope(); @@ -113,6 +123,11 @@ public abstract class TrackedEntityAttribute extends BaseNameableObject @JsonProperty() public abstract String fieldMask(); + @Nullable + @JsonProperty() + @ColumnAdapter(IgnoreObjectWithUidListColumnAdapter.class) + public abstract List legendSets(); + @JsonProperty() @ColumnAdapter(DefaultAccessColumnAdapter.class) public abstract Access access(); @@ -152,6 +167,8 @@ public abstract static class Builder extends BaseNameableObject.Builder public abstract Builder expression(String expression); + public abstract Builder aggregationType(AggregationType aggregationType); + public abstract Builder programScope(Boolean programScope); public abstract Builder displayInListNoProgram(Boolean displayInListNoProgram); @@ -173,6 +190,8 @@ public abstract static class Builder extends BaseNameableObject.Builder public abstract Builder access(Access access); + public abstract Builder legendSets(List legendSets); + public abstract Builder formName(String formName); public abstract Builder displayFormName(String displayFormName); diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeCollectionRepository.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeCollectionRepository.java index 5036ae9e47..bc217706cd 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeCollectionRepository.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeCollectionRepository.java @@ -127,4 +127,8 @@ public StringFilterConnector byColor public StringFilterConnector byIcon() { return cf.string(Columns.ICON); } + + public TrackedEntityAttributeCollectionRepository withLegendSets() { + return cf.withChild(TrackedEntityAttributeFields.LEGEND_SETS); + } } diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLink.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLink.java new file mode 100644 index 0000000000..0be5fc0624 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLink.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.trackedentity; + +import android.database.Cursor; + +import androidx.annotation.Nullable; + +import com.google.auto.value.AutoValue; + +import org.hisp.dhis.android.core.common.BaseObject; +import org.hisp.dhis.android.core.common.CoreObject; +import org.jetbrains.annotations.NotNull; + +@AutoValue +public abstract class TrackedEntityAttributeLegendSetLink implements CoreObject { + @NotNull + public abstract String trackedEntityAttribute(); + + @NotNull + public abstract String legendSet(); + + @Nullable + public abstract Integer sortOrder(); + + public static TrackedEntityAttributeLegendSetLink create(Cursor cursor) { + return AutoValue_TrackedEntityAttributeLegendSetLink.createFromCursor(cursor); + } + + public static Builder builder() { + return new $$AutoValue_TrackedEntityAttributeLegendSetLink.Builder(); + } + + public abstract Builder toBuilder(); + + @AutoValue.Builder + public static abstract class Builder extends BaseObject.Builder { + public abstract Builder id(Long id); + + public abstract Builder trackedEntityAttribute(String trackedEntityAttribute); + + public abstract Builder legendSet(String legendSet); + + public abstract Builder sortOrder(@Nullable Integer sortOrder); + + public abstract TrackedEntityAttributeLegendSetLink build(); + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLinkStore.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLinkStore.kt new file mode 100644 index 0000000000..dcfa07b7a9 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLinkStore.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.trackedentity + +import android.database.Cursor +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.binders.internal.StatementBinder +import org.hisp.dhis.android.core.arch.db.stores.binders.internal.StatementWrapper +import org.hisp.dhis.android.core.arch.db.stores.internal.LinkStore +import org.hisp.dhis.android.core.arch.db.stores.internal.StoreFactory.linkStore + +@Suppress("MagicNumber") +internal object TrackedEntityAttributeLegendSetLinkStore { + private val BINDER = StatementBinder { o: TrackedEntityAttributeLegendSetLink, w: StatementWrapper -> + w.bind(1, o.trackedEntityAttribute()) + w.bind(2, o.legendSet()) + w.bind(3, o.sortOrder()) + } + + fun create(databaseAdapter: DatabaseAdapter): LinkStore { + return linkStore( + databaseAdapter, TrackedEntityAttributeLegendSetLinkTableInfo.TABLE_INFO, + TrackedEntityAttributeLegendSetLinkTableInfo.Columns.TRACKED_ENTITY_ATTRIBUTE, + BINDER + ) { cursor: Cursor? -> TrackedEntityAttributeLegendSetLink.create(cursor) } + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLinkTableInfo.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLinkTableInfo.kt new file mode 100644 index 0000000000..0ef0afb0f2 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeLegendSetLinkTableInfo.kt @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.trackedentity + +import org.hisp.dhis.android.core.arch.db.stores.projections.internal.LinkTableChildProjection +import org.hisp.dhis.android.core.arch.db.tableinfos.TableInfo +import org.hisp.dhis.android.core.arch.helpers.CollectionsHelper +import org.hisp.dhis.android.core.common.CoreColumns +import org.hisp.dhis.android.core.legendset.LegendSetTableInfo + +class TrackedEntityAttributeLegendSetLinkTableInfo { + + companion object { + val TABLE_INFO: TableInfo = object : TableInfo() { + override fun name(): String { + return "TrackedEntityAttributeLegendSetLink" + } + + override fun columns(): CoreColumns { + return Columns() + } + } + + val CHILD_PROJECTION = LinkTableChildProjection( + LegendSetTableInfo.TABLE_INFO, + Columns.TRACKED_ENTITY_ATTRIBUTE, + Columns.LEGEND_SET + ) + } + + class Columns : CoreColumns() { + override fun all(): Array { + return CollectionsHelper.appendInNewArray( + super.all(), + TRACKED_ENTITY_ATTRIBUTE, + LEGEND_SET, + SORT_ORDER + ) + } + + override fun whereUpdate(): Array { + return CollectionsHelper.appendInNewArray( + super.all(), + TRACKED_ENTITY_ATTRIBUTE, + LEGEND_SET, + SORT_ORDER + ) + } + + companion object { + const val TRACKED_ENTITY_ATTRIBUTE = "trackedEntityAttribute" + const val LEGEND_SET = "legendSet" + const val SORT_ORDER = "sortOrder" + } + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeTableInfo.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeTableInfo.java index e0a2236648..9359c86430 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeTableInfo.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeTableInfo.java @@ -58,6 +58,7 @@ public static class Columns extends NameableWithStyleColumns { public static final String VALUE_TYPE = "valueType"; public static final String EXPRESSION = "expression"; public static final String PROGRAM_SCOPE = "programScope"; + public static final String AGGREGATION_TYPE = "aggregationType"; public static final String DISPLAY_IN_LIST_NO_PROGRAM = "displayInListNoProgram"; public static final String GENERATED = "generated"; public static final String DISPLAY_ON_VISIT_SCHEDULE = "displayOnVisitSchedule"; @@ -84,7 +85,8 @@ public String[] all() { INHERIT, FORM_NAME, DISPLAY_FORM_NAME, - FIELD_MASK + FIELD_MASK, + AGGREGATION_TYPE ); } } diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilter.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilter.java index 276c7d930a..93494838a6 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilter.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilter.java @@ -30,6 +30,7 @@ import android.database.Cursor; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.fasterxml.jackson.annotation.JsonProperty; @@ -38,18 +39,17 @@ import com.gabrielittner.auto.value.cursor.ColumnAdapter; import com.google.auto.value.AutoValue; -import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.FilterPeriodColumnAdapter; -import org.hisp.dhis.android.core.arch.db.adapters.enums.internal.EnrollmentStatusColumnAdapter; +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.EntityQueryCriteriaColumnAdapter; import org.hisp.dhis.android.core.arch.db.adapters.identifiable.internal.ObjectWithUidColumnAdapter; import org.hisp.dhis.android.core.arch.db.adapters.ignore.internal.IgnoreTrackedEntityInstanceEventFilterListColumnAdapter; import org.hisp.dhis.android.core.common.BaseIdentifiableObject; import org.hisp.dhis.android.core.common.CoreObject; +import org.hisp.dhis.android.core.common.DateFilterPeriod; import org.hisp.dhis.android.core.common.FilterPeriod; import org.hisp.dhis.android.core.common.ObjectStyle; import org.hisp.dhis.android.core.common.ObjectWithStyle; import org.hisp.dhis.android.core.common.ObjectWithUid; import org.hisp.dhis.android.core.enrollment.EnrollmentStatus; -import org.hisp.dhis.android.core.trackedentity.internal.TrackedEntityInstanceFilterFields; import java.util.List; @@ -71,19 +71,42 @@ public abstract class TrackedEntityInstanceFilter extends BaseIdentifiableObject @JsonProperty() public abstract Integer sortOrder(); + /** + * @deprecated since 2.37. Use {@link #entityQueryCriteria().enrollmentStatus()} instead. + */ + @Deprecated @Nullable - @JsonProperty() - @ColumnAdapter(EnrollmentStatusColumnAdapter.class) - public abstract EnrollmentStatus enrollmentStatus(); + public EnrollmentStatus enrollmentStatus() { + return entityQueryCriteria().enrollmentStatus(); + } + /** + * @deprecated since 2.37. Use {@link #entityQueryCriteria().followUp()} instead. + */ + @Deprecated @Nullable - @JsonProperty(TrackedEntityInstanceFilterFields.FOLLOW_UP) - public abstract Boolean followUp(); + public Boolean followUp() { + return entityQueryCriteria().followUp(); + } + /** + * @deprecated since 2.37. Use {@link #entityQueryCriteria().enrollmentCreatedDate()} instead. + */ + @Deprecated @Nullable + public FilterPeriod enrollmentCreatedPeriod() { + DateFilterPeriod dateFilterPeriod = entityQueryCriteria().enrollmentCreatedDate(); + return dateFilterPeriod == null ? null : + FilterPeriod.builder() + .periodFrom(dateFilterPeriod.startBuffer()) + .periodTo(dateFilterPeriod.endBuffer()) + .build(); + } + + @NonNull @JsonProperty() - @ColumnAdapter(FilterPeriodColumnAdapter.class) - public abstract FilterPeriod enrollmentCreatedPeriod(); + @ColumnAdapter(EntityQueryCriteriaColumnAdapter.class) + public abstract EntityQueryCriteria entityQueryCriteria(); @Nullable @JsonProperty() @@ -113,12 +136,7 @@ public static abstract class Builder extends BaseIdentifiableObject.Builder eventFilters); @@ -126,6 +144,7 @@ public static abstract class Builder extends BaseIdentifiableObject.Builder? +) { + fun toTrackedEntityInstanceFilter(): TrackedEntityInstanceFilter = + TrackedEntityInstanceFilter.builder() + .uid(id) + .code(code) + .name(name) + .displayName(displayName) + .created(created) + .lastUpdated(lastUpdated) + .deleted(deleted) + .program(program) + .description(description) + .sortOrder(sortOrder) + .entityQueryCriteria( + EntityQueryCriteria.builder() + .followUp(followup) + .enrollmentStatus(enrollmentStatus) + .enrollmentCreatedDate( + enrollmentCreatedPeriod?.let { + DateFilterPeriod.builder() + .startBuffer(it.periodFrom()) + .endBuffer(it.periodTo()) + .type(DatePeriodType.RELATIVE) + .build() + } + ) + .build() + ) + .eventFilters(eventFilters) + .build() +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterCollectionRepository.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterCollectionRepository.java index 01523acfbe..ff43fd283b 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterCollectionRepository.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterCollectionRepository.java @@ -37,7 +37,10 @@ import org.hisp.dhis.android.core.arch.repositories.filters.internal.IntegerFilterConnector; import org.hisp.dhis.android.core.arch.repositories.filters.internal.StringFilterConnector; import org.hisp.dhis.android.core.arch.repositories.scope.RepositoryScope; +import org.hisp.dhis.android.core.common.AssignedUserMode; import org.hisp.dhis.android.core.enrollment.EnrollmentStatus; +import org.hisp.dhis.android.core.event.EventStatus; +import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode; import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilterTableInfo.Columns; import org.hisp.dhis.android.core.trackedentity.internal.TrackedEntityInstanceFilterFields; @@ -81,12 +84,52 @@ public BooleanFilterConnector b return cf.bool(Columns.FOLLOW_UP); } - public IntegerFilterConnector byPeriodFrom() { - return cf.integer(Columns.PERIOD_FROM); + public StringFilterConnector byOrganisationUnit() { + return cf.string(Columns.ORGANISATION_UNIT); } - public IntegerFilterConnector byPeriodTo() { - return cf.integer(Columns.PERIOD_TO); + public EnumFilterConnector byOuMode() { + return cf.enumC(Columns.OU_MODE); + } + + public EnumFilterConnector byAssignedUserMode() { + return cf.enumC(Columns.ASSIGNED_USER_MODE); + } + + public StringFilterConnector byOrderProperty() { + return cf.string(Columns.ORDER); + } + + public StringFilterConnector byDisplayColumnOrder() { + return cf.string(Columns.DISPLAY_COLUMN_ORDER); + } + + public EnumFilterConnector byEventStatus() { + return cf.enumC(Columns.EVENT_STATUS); + } + + public StringFilterConnector byEventDate() { + return cf.string(Columns.EVENT_DATE); + } + + public StringFilterConnector byLastUpdatedDate() { + return cf.string(Columns.LAST_UPDATED_DATE); + } + + public StringFilterConnector byProgramStage() { + return cf.string(Columns.PROGRAM_STAGE); + } + + public StringFilterConnector byTrackedEntityInstances() { + return cf.string(Columns.TRACKED_ENTITY_INSTANCES); + } + + public StringFilterConnector byEnrollmentIncidentDate() { + return cf.string(Columns.ENROLLMENT_INCIDENT_DATE); + } + + public StringFilterConnector byEnrollmentCreatedDate() { + return cf.string(Columns.ENROLLMENT_CREATED_DATE); } public StringFilterConnector byColor() { diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterTableInfo.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterTableInfo.java index c9f25e68ba..698afccd52 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterTableInfo.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterTableInfo.java @@ -57,8 +57,19 @@ public static class Columns extends IdentifiableWithStyleColumns { public final static String SORT_ORDER = "sortOrder"; public final static String ENROLLMENT_STATUS = "enrollmentStatus"; public final static String FOLLOW_UP = "followUp"; - public static final String PERIOD_FROM = "periodFrom"; - public static final String PERIOD_TO = "periodTo"; + public final static String ORGANISATION_UNIT = "organisationUnit"; + public final static String OU_MODE = "ouMode"; + public final static String ASSIGNED_USER_MODE = "assignedUserMode"; + public final static String ORDER = "orderProperty"; + public final static String DISPLAY_COLUMN_ORDER = "displayColumnOrder"; + public final static String EVENT_STATUS = "eventStatus"; + public final static String EVENT_DATE = "eventDate"; + public final static String LAST_UPDATED_DATE = "lastUpdatedDate"; + public final static String PROGRAM_STAGE = "programStage"; + public final static String TRACKED_ENTITY_INSTANCES = "trackedEntityInstances"; + public final static String ENROLLMENT_INCIDENT_DATE = "enrollmentIncidentDate"; + public final static String ENROLLMENT_CREATED_DATE = "enrollmentCreatedDate"; + public final static String TRACKED_ENTITY_TYPE = "trackedEntityType"; @Override public String[] all() { @@ -68,8 +79,19 @@ public String[] all() { SORT_ORDER, ENROLLMENT_STATUS, FOLLOW_UP, - PERIOD_FROM, - PERIOD_TO + ORGANISATION_UNIT, + OU_MODE, + ASSIGNED_USER_MODE, + ORDER, + DISPLAY_COLUMN_ORDER, + EVENT_STATUS, + EVENT_DATE, + LAST_UPDATED_DATE, + PROGRAM_STAGE, + TRACKED_ENTITY_INSTANCES, + ENROLLMENT_INCIDENT_DATE, + ENROLLMENT_CREATED_DATE, + TRACKED_ENTITY_TYPE ); } } diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityPackageDIModule.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityPackageDIModule.java index aa6aaf1605..72519bdd69 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityPackageDIModule.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityPackageDIModule.java @@ -30,6 +30,7 @@ import org.hisp.dhis.android.core.arch.call.factories.internal.QueryCallFactory; import org.hisp.dhis.android.core.arch.call.factories.internal.UidsCall; +import org.hisp.dhis.android.core.trackedentity.internal.AttributeValueFilterEntityDIModule; import org.hisp.dhis.android.core.trackedentity.internal.ReservedValueSettingDIModule; import org.hisp.dhis.android.core.trackedentity.internal.TrackedEntityAttributeCall; import org.hisp.dhis.android.core.trackedentity.internal.TrackedEntityAttributeEntityDIModule; @@ -71,7 +72,8 @@ TrackedEntityInstanceQueryEntityDIModule.class, TrackedEntityInstanceSyncEntityDIModule.class, TrackedEntityTypeEntityDIModule.class, - TrackedEntityTypeAttributeEntityDIModule.class + TrackedEntityTypeAttributeEntityDIModule.class, + AttributeValueFilterEntityDIModule.class }) public final class TrackedEntityPackageDIModule { diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterEntityDIModule.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterEntityDIModule.kt new file mode 100644 index 0000000000..6efc33bb2d --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterEntityDIModule.kt @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.trackedentity.internal + +import dagger.Module +import dagger.Provides +import dagger.Reusable +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectWithoutUidStore +import org.hisp.dhis.android.core.arch.handlers.internal.HandlerWithTransformer +import org.hisp.dhis.android.core.arch.handlers.internal.ObjectWithoutUidHandlerImpl +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter +import org.hisp.dhis.android.core.trackedentity.internal.AttributeValueFilterStore.create + +@Module +internal class AttributeValueFilterEntityDIModule { + @Provides + @Reusable + fun store(databaseAdapter: DatabaseAdapter): ObjectWithoutUidStore { + return create(databaseAdapter) + } + + @Provides + @Reusable + fun handler(store: ObjectWithoutUidStore): HandlerWithTransformer { + return ObjectWithoutUidHandlerImpl(store) + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/systeminfo/SMSVersion.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterFields.java similarity index 55% rename from core/src/main/java/org/hisp/dhis/android/core/systeminfo/SMSVersion.java rename to core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterFields.java index d1b082fae8..8038165ff6 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/systeminfo/SMSVersion.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterFields.java @@ -26,45 +26,35 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.hisp.dhis.android.core.systeminfo; +package org.hisp.dhis.android.core.trackedentity.internal; -public enum SMSVersion { - V1(1), - V2(2); +import org.hisp.dhis.android.core.arch.api.fields.internal.Fields; +import org.hisp.dhis.android.core.arch.fields.internal.FieldsHelper; +import org.hisp.dhis.android.core.common.tableinfo.ItemFilterTableInfo.Columns; +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter; - private final static SMSVersion latestVersion = SMSVersion.V2; - private Integer intValue; +public final class AttributeValueFilterFields { - SMSVersion(Integer intValue) { - this.intValue = intValue; - } - - public Integer getIntValue() { - return intValue; - } + private static final String API_IN = "in"; - public static SMSVersion getValue(String versionStr) { - DHISPatchVersion patchVersion = DHISPatchVersion.getValue(versionStr); - if (patchVersion == null) { - DHISVersion dhisVersion = DHISVersion.getValue(versionStr); - return getLatestInDHISVersion(dhisVersion); - } else { - return patchVersion.getSmsVersion(); - } - } + private static final FieldsHelper fh = new FieldsHelper<>(); - private static SMSVersion getLatestInDHISVersion(DHISVersion dhisVersion) { - SMSVersion latest = null; - for (DHISPatchVersion patchVersion : DHISPatchVersion.values()) { - if (patchVersion.getMajorVersion().equals(dhisVersion) && patchVersion.getSmsVersion() != null) { - SMSVersion smsVersion = patchVersion.getSmsVersion(); + public static final Fields allFields = Fields.builder() + .fields( + fh.field(Columns.ATTRIBUTE), + fh.field(Columns.SW), + fh.field(Columns.EW), + fh.field(Columns.LE), + fh.field(Columns.GE), + fh.field(Columns.GT), + fh.field(Columns.LT), + fh.field(Columns.EQ), + fh.field(API_IN), + fh.field(Columns.LIKE), + fh.field(Columns.DATE_FILTER) + ).build(); - if (latest == null || latest.intValue < smsVersion.intValue) { - latest = smsVersion; - } - } - } - return latest; + private AttributeValueFilterFields() { } } \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterStore.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterStore.kt new file mode 100644 index 0000000000..745b48af0d --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/AttributeValueFilterStore.kt @@ -0,0 +1,78 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.trackedentity.internal + +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DateFilterPeriodColumnAdapter +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.StringSetColumnAdapter +import org.hisp.dhis.android.core.arch.db.stores.binders.internal.StatementBinder +import org.hisp.dhis.android.core.arch.db.stores.binders.internal.StatementWrapper +import org.hisp.dhis.android.core.arch.db.stores.binders.internal.WhereStatementBinder +import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectWithoutUidStore +import org.hisp.dhis.android.core.arch.db.stores.internal.StoreFactory.objectWithoutUidStore +import org.hisp.dhis.android.core.arch.db.stores.projections.internal.SingleParentChildProjection +import org.hisp.dhis.android.core.common.tableinfo.ItemFilterTableInfo +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter + +@Suppress("MagicNumber") +internal object AttributeValueFilterStore { + private val BINDER = StatementBinder { o: AttributeValueFilter, w: StatementWrapper -> + w.bindNull(1) + w.bindNull(2) + w.bind(3, o.trackedEntityInstanceFilter()) + w.bind(4, o.attribute()) + w.bind(5, o.sw()) + w.bind(6, o.ew()) + w.bind(7, o.le()) + w.bind(8, o.ge()) + w.bind(9, o.gt()) + w.bind(10, o.lt()) + w.bind(11, o.eq()) + w.bind(12, StringSetColumnAdapter.serialize(o.`in`())) + w.bind(13, o.like()) + w.bind(14, DateFilterPeriodColumnAdapter.serialize(o.dateFilter())) + } + + private val WHERE_UPDATE_BINDER = WhereStatementBinder { _: AttributeValueFilter, _ -> } + private val WHERE_DELETE_BINDER = WhereStatementBinder { _: AttributeValueFilter, _ -> } + + @JvmField + val CHILD_PROJECTION = SingleParentChildProjection( + ItemFilterTableInfo.TABLE_INFO, + ItemFilterTableInfo.Columns.TRACKED_ENTITY_INSTANCE_FILTER + ) + + @JvmStatic + fun create(databaseAdapter: DatabaseAdapter): ObjectWithoutUidStore { + return objectWithoutUidStore( + databaseAdapter, + ItemFilterTableInfo.TABLE_INFO, + BINDER, WHERE_UPDATE_BINDER, WHERE_DELETE_BINDER + ) { AttributeValueFilter.create(it) } + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/EntityQueryCriteriaFields.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/EntityQueryCriteriaFields.kt new file mode 100644 index 0000000000..e593862a57 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/EntityQueryCriteriaFields.kt @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.trackedentity.internal + +import org.hisp.dhis.android.core.arch.api.fields.internal.Fields +import org.hisp.dhis.android.core.arch.fields.internal.FieldsHelper +import org.hisp.dhis.android.core.common.AssignedUserMode +import org.hisp.dhis.android.core.common.DateFilterPeriod +import org.hisp.dhis.android.core.enrollment.EnrollmentStatus +import org.hisp.dhis.android.core.event.EventStatus +import org.hisp.dhis.android.core.event.internal.DateFilterPeriodFields +import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter +import org.hisp.dhis.android.core.trackedentity.EntityQueryCriteria +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilterTableInfo.Columns + +internal object EntityQueryCriteriaFields { + const val ATTRIBUTE_VALUE_FILTER = "attributeValueFilters" + private val fh = FieldsHelper() + val allFields: Fields = Fields.builder() + .fields( + fh.field(Columns.FOLLOW_UP), + fh.field(Columns.ORGANISATION_UNIT), + fh.field(Columns.OU_MODE), + fh.field(Columns.ASSIGNED_USER_MODE), + fh.field(Columns.ORDER), + fh.field(Columns.DISPLAY_COLUMN_ORDER), + fh.field(Columns.EVENT_STATUS), + fh.field(Columns.PROGRAM_STAGE), + fh.field(Columns.TRACKED_ENTITY_INSTANCES), + fh.field(Columns.TRACKED_ENTITY_TYPE), + fh.field(Columns.ENROLLMENT_STATUS), + fh.nestedField(Columns.EVENT_DATE) + .with(DateFilterPeriodFields.allFields), + fh.nestedField(Columns.LAST_UPDATED_DATE) + .with(DateFilterPeriodFields.allFields), + fh.nestedField(Columns.ENROLLMENT_INCIDENT_DATE) + .with(DateFilterPeriodFields.allFields), + fh.nestedField(Columns.ENROLLMENT_CREATED_DATE) + .with(DateFilterPeriodFields.allFields), + fh.nestedField(ATTRIBUTE_VALUE_FILTER).with(AttributeValueFilterFields.allFields) + ).build() +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeEntityDIModule.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeEntityDIModule.java index 3d4928e2b3..2974c752c7 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeEntityDIModule.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeEntityDIModule.java @@ -31,11 +31,8 @@ import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter; import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore; import org.hisp.dhis.android.core.arch.handlers.internal.Handler; -import org.hisp.dhis.android.core.arch.repositories.children.internal.ChildrenAppender; import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute; -import java.util.Collections; -import java.util.Map; import dagger.Module; import dagger.Provides; @@ -55,10 +52,4 @@ public IdentifiableObjectStore store(DatabaseAdapter dat public Handler handler(TrackedEntityAttributeHandler impl) { return impl; } - - @Provides - @Reusable - Map> childrenAppenders() { - return Collections.emptyMap(); - } } \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeFields.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeFields.java index b0af7a893d..98b8a6ab30 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeFields.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeFields.java @@ -32,15 +32,20 @@ import org.hisp.dhis.android.core.arch.api.fields.internal.Fields; import org.hisp.dhis.android.core.arch.fields.internal.FieldsHelper; import org.hisp.dhis.android.core.common.Access; +import org.hisp.dhis.android.core.common.AggregationType; import org.hisp.dhis.android.core.common.ObjectStyle; import org.hisp.dhis.android.core.common.ValueType; import org.hisp.dhis.android.core.common.internal.AccessFields; import org.hisp.dhis.android.core.common.objectstyle.internal.ObjectStyleFields; +import org.hisp.dhis.android.core.legendset.LegendSet; +import org.hisp.dhis.android.core.legendset.internal.LegendSetFields; import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute; +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeTableInfo; import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeTableInfo.Columns; public final class TrackedEntityAttributeFields { public static final String UNIQUE = "unique"; + public static final String LEGEND_SETS = "legendSets"; private static final String STYLE = "style"; private static final String ACCESS = "access"; public static final String ORG_UNIT_SCOPE = "orgunitScope"; @@ -59,6 +64,7 @@ public final class TrackedEntityAttributeFields { fh.field(Columns.VALUE_TYPE), fh.field(Columns.EXPRESSION), fh.field(Columns.PROGRAM_SCOPE), + fh.field(TrackedEntityAttributeTableInfo.Columns.AGGREGATION_TYPE), fh.field(Columns.DISPLAY_IN_LIST_NO_PROGRAM), fh.field(Columns.GENERATED), fh.field(Columns.DISPLAY_ON_VISIT_SCHEDULE), @@ -66,6 +72,7 @@ public final class TrackedEntityAttributeFields { fh.field(UNIQUE), fh.field(Columns.INHERIT), fh.field(Columns.FIELD_MASK), + fh.nestedField(LEGEND_SETS).with(LegendSetFields.uid), fh.nestedFieldWithUid(Columns.OPTION_SET), fh.nestedField(STYLE).with(ObjectStyleFields.allFields), fh.nestedField(ACCESS).with(AccessFields.read), diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeHandler.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeHandler.java index 1202d6a2fd..1f79270ae1 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeHandler.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeHandler.java @@ -28,9 +28,15 @@ package org.hisp.dhis.android.core.trackedentity.internal; +import androidx.annotation.NonNull; + import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore; +import org.hisp.dhis.android.core.arch.handlers.internal.HandleAction; import org.hisp.dhis.android.core.arch.handlers.internal.IdentifiableHandlerImpl; +import org.hisp.dhis.android.core.arch.handlers.internal.OrderedLinkHandler; +import org.hisp.dhis.android.core.common.ObjectWithUid; import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute; +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeLegendSetLink; import javax.inject.Inject; @@ -39,9 +45,17 @@ @Reusable final class TrackedEntityAttributeHandler extends IdentifiableHandlerImpl { + private final OrderedLinkHandler + trackedEntityAttributeLegendSetLinkHandler; + @Inject - TrackedEntityAttributeHandler(IdentifiableObjectStore trackedEntityAttributeStore) { + TrackedEntityAttributeHandler( + IdentifiableObjectStore trackedEntityAttributeStore, + OrderedLinkHandler + trackedEntityAttributeLegendSetLinkHandler + ) { super(trackedEntityAttributeStore); + this.trackedEntityAttributeLegendSetLinkHandler = trackedEntityAttributeLegendSetLinkHandler; } @Override @@ -59,6 +73,18 @@ protected TrackedEntityAttribute beforeObjectHandled(TrackedEntityAttribute o) { return builder.build(); } + @Override + protected void afterObjectHandled(TrackedEntityAttribute o, @NonNull HandleAction action) { + if (o.legendSets() != null) { + trackedEntityAttributeLegendSetLinkHandler.handleMany(o.uid(), o.legendSets(), + (legendSet, sortOrder) -> TrackedEntityAttributeLegendSetLink.builder() + .legendSet(legendSet.uid()) + .sortOrder(sortOrder) + .trackedEntityAttribute(o.uid()) + .build()); + } + } + @Override protected boolean deleteIfCondition(TrackedEntityAttribute trackedEntityAttribute) { return !trackedEntityAttribute.access().read(); diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeLegendSetChildrenAppender.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeLegendSetChildrenAppender.kt new file mode 100644 index 0000000000..c41d47fc1b --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeLegendSetChildrenAppender.kt @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.trackedentity.internal + +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.ObjectWithUidChildStore +import org.hisp.dhis.android.core.arch.db.stores.internal.StoreFactory +import org.hisp.dhis.android.core.arch.repositories.children.internal.ChildrenAppender +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeLegendSetLinkTableInfo + +internal class TrackedEntityAttributeLegendSetChildrenAppender( + private val linkChildStore: ObjectWithUidChildStore +) : ChildrenAppender() { + + override fun appendChildren(m: TrackedEntityAttribute): TrackedEntityAttribute { + val builder = m.toBuilder() + builder.legendSets(linkChildStore.getChildren(m)) + return builder.build() + } + + companion object { + fun create(databaseAdapter: DatabaseAdapter): TrackedEntityAttributeLegendSetChildrenAppender { + return TrackedEntityAttributeLegendSetChildrenAppender( + StoreFactory.objectWithUidChildStore( + databaseAdapter, + TrackedEntityAttributeLegendSetLinkTableInfo.TABLE_INFO, + TrackedEntityAttributeLegendSetLinkTableInfo.CHILD_PROJECTION, + ) + ) + } + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeLegendSetDIModule.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeLegendSetDIModule.kt new file mode 100644 index 0000000000..a8044afac5 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeLegendSetDIModule.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.trackedentity.internal + +import dagger.Module +import dagger.Provides +import dagger.Reusable +import java.util.Collections +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.stores.internal.LinkStore +import org.hisp.dhis.android.core.arch.handlers.internal.OrderedLinkHandler +import org.hisp.dhis.android.core.arch.handlers.internal.OrderedLinkHandlerImpl +import org.hisp.dhis.android.core.arch.repositories.children.internal.ChildrenAppender +import org.hisp.dhis.android.core.common.ObjectWithUid +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeLegendSetLink +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeLegendSetLinkStore + +@Module +internal class TrackedEntityAttributeLegendSetDIModule { + @Provides + @Reusable + fun store(databaseAdapter: DatabaseAdapter): LinkStore { + return TrackedEntityAttributeLegendSetLinkStore.create(databaseAdapter) + } + + @Provides + @Reusable + fun handler( + store: LinkStore + ): OrderedLinkHandler { + return OrderedLinkHandlerImpl(store) + } + + @Provides + @Reusable + fun childrenAppenders(databaseAdapter: DatabaseAdapter): Map> { + return Collections.singletonMap( + TrackedEntityAttributeFields.LEGEND_SETS, + TrackedEntityAttributeLegendSetChildrenAppender.create(databaseAdapter) + ) + } +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeStore.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeStore.java index 1b60832d48..7ff1ec2c6c 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeStore.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeStore.java @@ -65,6 +65,7 @@ public void bindToStatement(@NonNull TrackedEntityAttribute o, @NonNull Statemen w.bind(25, o.formName()); w.bind(26, o.displayFormName()); w.bind(27, o.fieldMask()); + w.bind(28, o.aggregationType()); } }; diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterAttributeValueFilterChildrenAppender.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterAttributeValueFilterChildrenAppender.java new file mode 100644 index 0000000000..1b36b342a0 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterAttributeValueFilterChildrenAppender.java @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.trackedentity.internal; + +import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter; +import org.hisp.dhis.android.core.arch.db.stores.internal.SingleParentChildStore; +import org.hisp.dhis.android.core.arch.db.stores.internal.StoreFactory; +import org.hisp.dhis.android.core.arch.repositories.children.internal.ChildrenAppender; +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter; +import org.hisp.dhis.android.core.trackedentity.EntityQueryCriteria; +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter; + +public final class TrackedEntityInstanceFilterAttributeValueFilterChildrenAppender + extends ChildrenAppender { + + private final SingleParentChildStore childStore; + + private TrackedEntityInstanceFilterAttributeValueFilterChildrenAppender( + SingleParentChildStore childStore) { + this.childStore = childStore; + } + + @Override + public TrackedEntityInstanceFilter appendChildren(TrackedEntityInstanceFilter trackedEntityInstanceFilter) { + if (trackedEntityInstanceFilter.entityQueryCriteria() != null) { + EntityQueryCriteria.Builder criteriaBuilder = trackedEntityInstanceFilter.entityQueryCriteria().toBuilder(); + criteriaBuilder.attributeValueFilters(childStore.getChildren(trackedEntityInstanceFilter)); + return trackedEntityInstanceFilter.toBuilder().entityQueryCriteria(criteriaBuilder.build()).build(); + } + return TrackedEntityInstanceFilter.builder().build(); + } + + public static ChildrenAppender create(DatabaseAdapter databaseAdapter) { + return new TrackedEntityInstanceFilterAttributeValueFilterChildrenAppender( + StoreFactory.singleParentChildStore( + databaseAdapter, + AttributeValueFilterStore.CHILD_PROJECTION, + AttributeValueFilter::create) + ); + } +} \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterCall.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterCall.kt similarity index 54% rename from core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterCall.java rename to core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterCall.kt index c18dd0f301..04b6dba7bf 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterCall.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterCall.kt @@ -25,49 +25,61 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +package org.hisp.dhis.android.core.trackedentity.internal -package org.hisp.dhis.android.core.trackedentity.internal; - -import org.hisp.dhis.android.core.arch.api.executors.internal.APIDownloader; -import org.hisp.dhis.android.core.arch.call.factories.internal.UidsCall; -import org.hisp.dhis.android.core.arch.handlers.internal.Handler; -import org.hisp.dhis.android.core.common.internal.DataAccessFields; -import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter; - -import java.util.List; -import java.util.Set; - -import javax.inject.Inject; - -import dagger.Reusable; -import io.reactivex.Single; +import dagger.Reusable +import io.reactivex.Single +import javax.inject.Inject +import org.hisp.dhis.android.core.arch.api.executors.internal.APIDownloader +import org.hisp.dhis.android.core.arch.call.factories.internal.UidsCall +import org.hisp.dhis.android.core.arch.handlers.internal.Handler +import org.hisp.dhis.android.core.common.internal.DataAccessFields +import org.hisp.dhis.android.core.systeminfo.DHISVersion +import org.hisp.dhis.android.core.systeminfo.DHISVersionManager +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter @Reusable -public final class TrackedEntityInstanceFilterCall implements UidsCall { - - private static final int MAX_UID_LIST_SIZE = 50; +class TrackedEntityInstanceFilterCall @Inject internal constructor( + private val service: TrackedEntityInstanceFilterService, + private val handler: Handler, + private val apiDownloader: APIDownloader, + private val versionManager: DHISVersionManager +) : UidsCall { + override fun download(uids: Set): Single> { + val accessDataReadFilter = "access." + DataAccessFields.read.eq(true).generateString() - private final TrackedEntityInstanceFilterService service; - private final Handler handler; - private final APIDownloader apiDownloader; - - @Inject - TrackedEntityInstanceFilterCall(TrackedEntityInstanceFilterService service, - Handler handler, - APIDownloader apiDownloader) { - this.service = service; - this.handler = handler; - this.apiDownloader = apiDownloader; - } - - @Override - public Single> download(Set programUids) { - String accessDataReadFilter = "access." + DataAccessFields.read.eq(true).generateString(); - return apiDownloader.downloadPartitioned(programUids, MAX_UID_LIST_SIZE, handler, partitionUids -> + return if (versionManager.isGreaterOrEqualThan(DHISVersion.V2_38)) { + apiDownloader.downloadPartitioned( + uids, + MAX_UID_LIST_SIZE, + handler + ) { partitionUids: Set -> service.getTrackedEntityInstanceFilters( - TrackedEntityInstanceFilterFields.programUid.in(partitionUids), + TrackedEntityInstanceFilterFields.programUid.`in`(partitionUids), + accessDataReadFilter, + TrackedEntityInstanceFilterFields.allFields, + false + ) + } + } else { + apiDownloader.downloadPartitioned( + uids, + MAX_UID_LIST_SIZE, + handler, + { partitionUids: Set -> + service.getTrackedEntityInstanceFiltersAPI37( + TrackedEntityInstanceFilterFields.programUid.`in`(partitionUids), accessDataReadFilter, - TrackedEntityInstanceFilterFields.allFields, - Boolean.FALSE)); + TrackedEntityInstanceFilterFields.allFieldsAPI37, + false + ) + }, + { it.toTrackedEntityInstanceFilter() } + ) + } + } + + companion object { + private const val MAX_UID_LIST_SIZE = 50 } -} \ No newline at end of file +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterFields.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterFields.java deleted file mode 100644 index 63825b1ad2..0000000000 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterFields.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.trackedentity.internal; - -import org.hisp.dhis.android.core.arch.api.fields.internal.Field; -import org.hisp.dhis.android.core.arch.api.fields.internal.Fields; -import org.hisp.dhis.android.core.arch.fields.internal.FieldsHelper; -import org.hisp.dhis.android.core.common.BaseIdentifiableObject; -import org.hisp.dhis.android.core.common.FilterPeriod; -import org.hisp.dhis.android.core.enrollment.EnrollmentStatus; -import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceEventFilter; -import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter; -import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilterTableInfo.Columns; - -public final class TrackedEntityInstanceFilterFields { - - public final static String ENROLLMENT_CREATED_PERIOD = "enrollmentCreatedPeriod"; - public final static String FOLLOW_UP = "followup"; - public final static String EVENT_FILTERS = "eventFilters"; - - private static final FieldsHelper fh = new FieldsHelper<>(); - - public static final Field programUid = - Field.create(Columns.PROGRAM + "." + BaseIdentifiableObject.UID); - - public static final Fields allFields = Fields.builder() - .fields(fh.getIdentifiableFields()) - .fields( - fh.nestedFieldWithUid(Columns.PROGRAM), - fh.field(Columns.DESCRIPTION), - fh.field(Columns.SORT_ORDER), - fh.field(Columns.ENROLLMENT_STATUS), - fh.field(FOLLOW_UP), - fh.field(ENROLLMENT_CREATED_PERIOD), - fh.nestedField(EVENT_FILTERS) - .with(TrackedEntityInstanceEventFilterFields.allFields) - ).build(); - - private TrackedEntityInstanceFilterFields() { - } -} \ No newline at end of file diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterFields.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterFields.kt new file mode 100644 index 0000000000..01878d0247 --- /dev/null +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterFields.kt @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.trackedentity.internal + +import org.hisp.dhis.android.core.arch.api.fields.internal.Field +import org.hisp.dhis.android.core.arch.api.fields.internal.Fields +import org.hisp.dhis.android.core.arch.fields.internal.FieldsHelper +import org.hisp.dhis.android.core.common.BaseIdentifiableObject +import org.hisp.dhis.android.core.common.FilterPeriod +import org.hisp.dhis.android.core.enrollment.EnrollmentStatus +import org.hisp.dhis.android.core.trackedentity.EntityQueryCriteria +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceEventFilter +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilterTableInfo + +object TrackedEntityInstanceFilterFields { + private const val ENROLLMENT_CREATED_PERIOD = "enrollmentCreatedPeriod" + const val FOLLOW_UP = "followup" + const val EVENT_FILTERS = "eventFilters" + const val ENTITY_QUERY_CRITERIA = "entityQueryCriteria" + + private val fh = FieldsHelper() + + val programUid: Field = + Field.create(TrackedEntityInstanceFilterTableInfo.Columns.PROGRAM + "." + BaseIdentifiableObject.UID) + + private val commonFields = Fields.builder() + .fields(fh.getIdentifiableFields()) + .fields( + fh.nestedFieldWithUid(TrackedEntityInstanceFilterTableInfo.Columns.PROGRAM), + fh.field(TrackedEntityInstanceFilterTableInfo.Columns.DESCRIPTION), + fh.field(TrackedEntityInstanceFilterTableInfo.Columns.SORT_ORDER), + fh.nestedField(EVENT_FILTERS) + .with(TrackedEntityInstanceEventFilterFields.allFields) + ) + + val allFields: Fields = commonFields + .fields( + fh.nestedField(ENTITY_QUERY_CRITERIA) + .with(EntityQueryCriteriaFields.allFields) + ).build() + + val allFieldsAPI37: Fields = commonFields + .fields( + fh.field(TrackedEntityInstanceFilterTableInfo.Columns.ENROLLMENT_STATUS), + fh.field(FOLLOW_UP), + fh.field(ENROLLMENT_CREATED_PERIOD) + ).build() +} diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterHandler.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterHandler.kt index 593b50846c..1988558c64 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterHandler.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterHandler.kt @@ -33,13 +33,15 @@ import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStor import org.hisp.dhis.android.core.arch.handlers.internal.HandleAction import org.hisp.dhis.android.core.arch.handlers.internal.HandlerWithTransformer import org.hisp.dhis.android.core.arch.handlers.internal.IdentifiableHandlerImpl +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceEventFilter import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter @Reusable internal class TrackedEntityInstanceFilterHandler @Inject constructor( trackedEntityInstanceFilterStore: IdentifiableObjectStore, - private val trackedEntityInstanceEventFilterHandler: HandlerWithTransformer + private val trackedEntityInstanceEventFilterHandler: HandlerWithTransformer, + private val attributeValueFilterHandler: HandlerWithTransformer ) : IdentifiableHandlerImpl(trackedEntityInstanceFilterStore) { override fun beforeCollectionHandled( @@ -51,9 +53,14 @@ internal class TrackedEntityInstanceFilterHandler @Inject constructor( override fun afterObjectHandled(o: TrackedEntityInstanceFilter, action: HandleAction) { if (action !== HandleAction.Delete) { - trackedEntityInstanceEventFilterHandler.handleMany(o.eventFilters()) { - ef: TrackedEntityInstanceEventFilter -> - ef.toBuilder().trackedEntityInstanceFilter(o.uid()).build() + trackedEntityInstanceEventFilterHandler + .handleMany(o.eventFilters()) { ef: TrackedEntityInstanceEventFilter -> + ef.toBuilder().trackedEntityInstanceFilter(o.uid()).build() + } + o.entityQueryCriteria().attributeValueFilters()?.let { + attributeValueFilterHandler.handleMany(it) { avf: AttributeValueFilter -> + avf.toBuilder().trackedEntityInstanceFilter(o.uid()).build() + } } } } diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterService.java b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterService.java index a30e15c934..6b601638cf 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterService.java +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterService.java @@ -33,12 +33,20 @@ import org.hisp.dhis.android.core.arch.api.filters.internal.Which; import org.hisp.dhis.android.core.arch.api.payload.internal.Payload; import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter; +import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilterAPI37; import io.reactivex.Single; import retrofit2.http.GET; import retrofit2.http.Query; public interface TrackedEntityInstanceFilterService { + @GET("trackedEntityInstanceFilters") + Single> getTrackedEntityInstanceFiltersAPI37( + @Query("filter") @Where Filter uids, + @Query("filter") String accessDataReadFilter, + @Query("fields") @Which Fields fields, + @Query("paging") Boolean paging); + @GET("trackedEntityInstanceFilters") Single> getTrackedEntityInstanceFilters( @Query("filter") @Where Filter uids, diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStore.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStore.kt index 2f2811572b..9715e7ac9e 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStore.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterStore.kt @@ -28,6 +28,8 @@ package org.hisp.dhis.android.core.trackedentity.internal import org.hisp.dhis.android.core.arch.db.access.DatabaseAdapter +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.DateFilterPeriodColumnAdapter +import org.hisp.dhis.android.core.arch.db.adapters.custom.internal.StringListColumnAdapter import org.hisp.dhis.android.core.arch.db.stores.binders.internal.IdentifiableWithStyleStatementBinder import org.hisp.dhis.android.core.arch.db.stores.binders.internal.StatementWrapper import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore @@ -44,10 +46,21 @@ internal object TrackedEntityInstanceFilterStore { w.bind(9, getUidOrNull(o.program())) w.bind(10, o.description()) w.bind(11, o.sortOrder()) - w.bind(12, o.enrollmentStatus()) - w.bind(13, o.followUp()) - w.bind(14, o.enrollmentCreatedPeriod()?.periodFrom()) - w.bind(15, o.enrollmentCreatedPeriod()?.periodTo()) + w.bind(12, o.entityQueryCriteria().enrollmentStatus()) + w.bind(13, o.entityQueryCriteria().followUp()) + w.bind(14, o.entityQueryCriteria().organisationUnit()) + w.bind(15, o.entityQueryCriteria().ouMode()) + w.bind(16, o.entityQueryCriteria().assignedUserMode()) + w.bind(17, o.entityQueryCriteria().order()) + w.bind(18, StringListColumnAdapter.serialize(o.entityQueryCriteria().displayColumnOrder())) + w.bind(19, o.entityQueryCriteria().eventStatus()) + w.bind(20, DateFilterPeriodColumnAdapter.serialize(o.entityQueryCriteria().eventDate())) + w.bind(21, DateFilterPeriodColumnAdapter.serialize(o.entityQueryCriteria().lastUpdatedDate())) + w.bind(22, o.entityQueryCriteria().programStage()) + w.bind(23, StringListColumnAdapter.serialize(o.entityQueryCriteria().trackedEntityInstances())) + w.bind(24, DateFilterPeriodColumnAdapter.serialize(o.entityQueryCriteria().enrollmentIncidentDate())) + w.bind(25, DateFilterPeriodColumnAdapter.serialize(o.entityQueryCriteria().enrollmentCreatedDate())) + w.bind(26, o.entityQueryCriteria().trackedEntityType()) } } diff --git a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/search/TrackedEntityInstanceQueryRepositoryScopeHelper.kt b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/search/TrackedEntityInstanceQueryRepositoryScopeHelper.kt index c5f9e227c2..fda8d88195 100644 --- a/core/src/main/java/org/hisp/dhis/android/core/trackedentity/search/TrackedEntityInstanceQueryRepositoryScopeHelper.kt +++ b/core/src/main/java/org/hisp/dhis/android/core/trackedentity/search/TrackedEntityInstanceQueryRepositoryScopeHelper.kt @@ -80,20 +80,9 @@ internal object TrackedEntityInstanceQueryRepositoryScopeHelper { val builder = scope.toBuilder() filter.program()?.let { builder.program(it.uid()) } - filter.enrollmentStatus()?.let { builder.enrollmentStatus(listOf(it)) } - filter.enrollmentCreatedPeriod()?.let { createPeriod -> - createPeriod.periodFrom()?.let { periodFrom -> - val fromFilter = DateFilterPeriod.builder().startBuffer(periodFrom).build() - val newFilter = DateFilterPeriodHelper.mergeDateFilterPeriods(builder.build().programDate(), fromFilter) - builder.programDate(newFilter) - } - createPeriod.periodTo()?. let { periodTo -> - val toFilter = DateFilterPeriod.builder().endBuffer(periodTo).build() - val newFilter = DateFilterPeriodHelper.mergeDateFilterPeriods(builder.build().programDate(), toFilter) - builder.programDate(newFilter) - } - } - filter.followUp()?.let { builder.followUp(it) } + filter.entityQueryCriteria().enrollmentStatus()?.let { builder.enrollmentStatus(listOf(it)) } + filter.entityQueryCriteria().enrollmentCreatedDate()?.let { builder.programDate(it) } + filter.entityQueryCriteria().followUp()?.let { builder.followUp(it) } filter.eventFilters()?.let { eventFilters -> val filters = eventFilters.map { eventFilter -> val eventBuilder = TrackedEntityInstanceQueryEventFilter.builder() diff --git a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventDataFilterSamples.java b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventDataFilterSamples.java deleted file mode 100644 index 329120683e..0000000000 --- a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventDataFilterSamples.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.data.event; - -import com.google.common.collect.Lists; -import com.google.common.collect.Sets; - -import org.hisp.dhis.android.core.arch.helpers.DateUtils; -import org.hisp.dhis.android.core.common.DateFilterPeriod; -import org.hisp.dhis.android.core.common.DatePeriodType; -import org.hisp.dhis.android.core.common.RelativePeriod; -import org.hisp.dhis.android.core.event.EventDataFilter; - -import java.text.ParseException; -import java.util.Date; -import java.util.List; - -public class EventDataFilterSamples { - - public static EventDataFilter get() { - return EventDataFilter.builder() - .id(1L) - .eventFilter("eventFilter") - .dataItem("abcDataElementUid") - .le("20") - .ge("10") - .gt("10") - .lt("20") - .eq("abc") - .in(Sets.newHashSet("India", "Norway")) - .like("abc") - .dateFilter(DateFilterPeriod.builder() - .startDate(getSimpleDate("2014-05-01")) - .endDate(getSimpleDate("2019-03-20")) - .type(DatePeriodType.ABSOLUTE) - .build()) - .build(); - } - - public static EventDataFilter get1() { - return EventDataFilter.builder() - .dataItem("abcDataElementUid") - .le("20") - .ge("10") - .gt("10") - .lt("20") - .in(Sets.newHashSet("India", "Norway")) - .like("abc") - .build(); - } - - public static EventDataFilter get2() { - return EventDataFilter.builder() - .dataItem("dateDataElementUid") - .dateFilter(DateFilterPeriod.builder() - .startDate(getSimpleDate("2014-05-01")) - .endDate(getSimpleDate("2019-03-20")) - .type(DatePeriodType.ABSOLUTE) - .build()) - .build(); - } - - public static EventDataFilter get3() { - return EventDataFilter.builder() - .dataItem("anotherDateDataElementUid") - .dateFilter(DateFilterPeriod.builder() - .startBuffer(-5) - .endBuffer(5) - .type(DatePeriodType.RELATIVE) - .build()) - .build(); - } - - public static EventDataFilter get4() { - return EventDataFilter.builder() - .dataItem("yetAnotherDateDataElementUid") - .dateFilter(DateFilterPeriod.builder() - .period(RelativePeriod.LAST_WEEK) - .type(DatePeriodType.RELATIVE) - .build()) - .build(); - } - - public static List getEventDataFilters() { - return Lists.newArrayList(get1(), get2(), get3(), get4()); - } - - private static Date getSimpleDate(String dateStr) { - try { - return DateUtils.SIMPLE_DATE_FORMAT.parse(dateStr); - } catch (ParseException e) { - e.printStackTrace(); - return null; - } - } -} \ No newline at end of file diff --git a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventDataFilterSamples.kt b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventDataFilterSamples.kt new file mode 100644 index 0000000000..227636f6b1 --- /dev/null +++ b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventDataFilterSamples.kt @@ -0,0 +1,122 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.data.event + +import java.text.ParseException +import java.util.* +import org.hisp.dhis.android.core.arch.helpers.DateUtils +import org.hisp.dhis.android.core.common.DateFilterPeriod +import org.hisp.dhis.android.core.common.DatePeriodType +import org.hisp.dhis.android.core.common.RelativePeriod +import org.hisp.dhis.android.core.event.EventDataFilter + +internal object EventDataFilterSamples { + fun get(): EventDataFilter { + return EventDataFilter.builder() + .id(1L) + .eventFilter("eventFilter") + .dataItem("abcDataElementUid") + .le("20") + .ge("10") + .gt("10") + .lt("20") + .eq("abc") + .`in`(setOf("Norway", "India")) + .like("abc") + .dateFilter( + DateFilterPeriod.builder() + .startDate(getSimpleDate("2014-05-01")) + .endDate(getSimpleDate("2019-03-20")) + .type(DatePeriodType.ABSOLUTE) + .build() + ) + .build() + } + + fun get1(): EventDataFilter { + return EventDataFilter.builder() + .dataItem("abcDataElementUid") + .le("20") + .ge("10") + .gt("10") + .lt("20") + .`in`(setOf("India", "Norway")) + .like("abc") + .build() + } + + fun get2(): EventDataFilter { + return EventDataFilter.builder() + .dataItem("dateDataElementUid") + .dateFilter( + DateFilterPeriod.builder() + .startDate(getSimpleDate("2014-05-01")) + .endDate(getSimpleDate("2019-03-20")) + .type(DatePeriodType.ABSOLUTE) + .build() + ) + .build() + } + + fun get3(): EventDataFilter { + return EventDataFilter.builder() + .dataItem("anotherDateDataElementUid") + .dateFilter( + DateFilterPeriod.builder() + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .build() + ) + .build() + } + + fun get4(): EventDataFilter { + return EventDataFilter.builder() + .dataItem("yetAnotherDateDataElementUid") + .dateFilter( + DateFilterPeriod.builder() + .period(RelativePeriod.LAST_WEEK) + .type(DatePeriodType.RELATIVE) + .build() + ) + .build() + } + + val eventDataFilters: List + get() = listOf(get1(), get2(), get3(), get4()) + + private fun getSimpleDate(dateStr: String): Date? { + return try { + DateUtils.SIMPLE_DATE_FORMAT.parse(dateStr) + } catch (e: ParseException) { + e.printStackTrace() + null + } + } +} diff --git a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventFilterSamples.java b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventFilterSamples.java deleted file mode 100644 index 9853015510..0000000000 --- a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventFilterSamples.java +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (c) 2004-2022, University of Oslo - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, this - * list of conditions and the following disclaimer. - * - * Redistributions in binary form must reproduce the above copyright notice, - * this list of conditions and the following disclaimer in the documentation - * and/or other materials provided with the distribution. - * Neither the name of the HISP project nor the names of its contributors may - * be used to endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR - * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON - * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -package org.hisp.dhis.android.core.data.event; - -import com.google.common.collect.Lists; - -import org.hisp.dhis.android.core.arch.helpers.DateUtils; -import org.hisp.dhis.android.core.common.AssignedUserMode; -import org.hisp.dhis.android.core.common.BaseIdentifiableObject; -import org.hisp.dhis.android.core.common.DateFilterPeriod; -import org.hisp.dhis.android.core.common.DatePeriodType; -import org.hisp.dhis.android.core.common.RelativePeriod; -import org.hisp.dhis.android.core.event.EventFilter; -import org.hisp.dhis.android.core.event.EventQueryCriteria; -import org.hisp.dhis.android.core.event.EventStatus; -import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode; - -import java.text.ParseException; -import java.util.Date; - -public class EventFilterSamples { - - public static EventFilter get() { - return EventFilter.builder() - .id(1L) - .uid("event_filter_uid") - .code("tb_events") - .name("TB events") - .displayName("TB events") - .created(getDate("2019-09-27T00:19:06.590")) - .lastUpdated(getDate("2019-09-27T00:19:06.590")) - .program("program_uid") - .programStage("program_stage_uid") - .description("Simple Filter for TB events") - .eventQueryCriteria(EventQueryCriteria.builder() - .followUp(Boolean.FALSE) - .organisationUnit("orgUnitUid") - .ouMode(OrganisationUnitMode.ACCESSIBLE) - .assignedUserMode(AssignedUserMode.CURRENT) - .order("dueDate:asc,createdDate:desc") - .displayColumnOrder(Lists.newArrayList( - "eventDate","status","assignedUser","qrur9Dvnyt5","oZg33kd9taw")) - .dataFilters(EventDataFilterSamples.getEventDataFilters()) - .events(Lists.newArrayList("event1Uid","event2Uid")) - .eventStatus(EventStatus.ACTIVE) - .eventDate(DateFilterPeriod.builder() - .startDate(getSimpleDate("2014-05-01")) - .endDate(getSimpleDate("2014-05-01")) - .type(DatePeriodType.ABSOLUTE) - .build()) - .dueDate(DateFilterPeriod.builder() - .period(RelativePeriod.LAST_2_SIXMONTHS) - .type(DatePeriodType.RELATIVE) - .build()) - .lastUpdatedDate(DateFilterPeriod.builder() - .startBuffer(-5) - .endBuffer(5) - .type(DatePeriodType.RELATIVE) - .build()) - .completedDate(DateFilterPeriod.builder() - .period(RelativePeriod.TODAY) - .type(DatePeriodType.RELATIVE) - .build()) - .build()) - .build(); - } - - private static Date getDate(String dateStr) { - try { - return DateUtils.DATE_FORMAT.parse(dateStr); - } catch (ParseException e) { - e.printStackTrace(); - return null; - } - } - - private static Date getSimpleDate(String dateStr) { - try { - return DateUtils.SIMPLE_DATE_FORMAT.parse(dateStr); - } catch (ParseException e) { - e.printStackTrace(); - return null; - } - } -} \ No newline at end of file diff --git a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventFilterSamples.kt b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventFilterSamples.kt new file mode 100644 index 0000000000..bd8fdaad86 --- /dev/null +++ b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/event/EventFilterSamples.kt @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.data.event + +import java.text.ParseException +import java.util.* +import org.hisp.dhis.android.core.arch.helpers.DateUtils +import org.hisp.dhis.android.core.common.AssignedUserMode +import org.hisp.dhis.android.core.common.DateFilterPeriod +import org.hisp.dhis.android.core.common.DatePeriodType +import org.hisp.dhis.android.core.common.RelativePeriod +import org.hisp.dhis.android.core.event.EventFilter +import org.hisp.dhis.android.core.event.EventQueryCriteria +import org.hisp.dhis.android.core.event.EventStatus +import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode + +internal object EventFilterSamples { + @JvmStatic + fun get(): EventFilter { + return EventFilter.builder() + .id(1L) + .uid("event_filter_uid") + .code("tb_events") + .name("TB events") + .displayName("TB events") + .created(getDate("2019-09-27T00:19:06.590")) + .lastUpdated(getDate("2019-09-27T00:19:06.590")) + .program("program_uid") + .programStage("program_stage_uid") + .description("Simple Filter for TB events") + .eventQueryCriteria( + EventQueryCriteria.builder() + .followUp(false) + .organisationUnit("orgUnitUid") + .ouMode(OrganisationUnitMode.ACCESSIBLE) + .assignedUserMode(AssignedUserMode.CURRENT) + .order("dueDate:asc,createdDate:desc") + .displayColumnOrder(listOf("eventDate", "status", "assignedUser", "qrur9Dvnyt5", "oZg33kd9taw")) + .dataFilters(EventDataFilterSamples.eventDataFilters) + .events(listOf("event1Uid", "event2Uid")) + .eventStatus(EventStatus.ACTIVE) + .eventDate( + DateFilterPeriod.builder() + .startDate(getSimpleDate("2014-05-01")) + .endDate(getSimpleDate("2014-05-01")) + .type(DatePeriodType.ABSOLUTE) + .build() + ) + .dueDate( + DateFilterPeriod.builder() + .period(RelativePeriod.LAST_2_SIXMONTHS) + .type(DatePeriodType.RELATIVE) + .build() + ) + .lastUpdatedDate( + DateFilterPeriod.builder() + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .build() + ) + .completedDate( + DateFilterPeriod.builder() + .period(RelativePeriod.TODAY) + .type(DatePeriodType.RELATIVE) + .build() + ) + .build() + ) + .build() + } + + private fun getDate(dateStr: String): Date? { + return try { + DateUtils.DATE_FORMAT.parse(dateStr) + } catch (e: ParseException) { + e.printStackTrace() + null + } + } + + private fun getSimpleDate(dateStr: String): Date? { + return try { + DateUtils.SIMPLE_DATE_FORMAT.parse(dateStr) + } catch (e: ParseException) { + e.printStackTrace() + null + } + } +} diff --git a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/systeminfo/SystemInfoSamples.java b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/systeminfo/SystemInfoSamples.java index 8c8abf988a..0f73ac6cfa 100644 --- a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/systeminfo/SystemInfoSamples.java +++ b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/systeminfo/SystemInfoSamples.java @@ -41,7 +41,7 @@ public static SystemInfo get1() { .id(1L) .serverDate(getDate("2017-11-29T11:27:46.935")) .dateFormat("yyyy-mm-dd") - .version("2.37") + .version("2.38") .contextPath("https://play.dhis2.org/android-current") .systemName("DHIS 2 Demo - Sierra Leone") .build(); diff --git a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/AttributeValueFilterSamples.kt b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/AttributeValueFilterSamples.kt new file mode 100644 index 0000000000..bc7c9e9707 --- /dev/null +++ b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/AttributeValueFilterSamples.kt @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.data.trackedentity + +import java.text.ParseException +import java.util.* +import org.hisp.dhis.android.core.arch.helpers.DateUtils +import org.hisp.dhis.android.core.common.DateFilterPeriod +import org.hisp.dhis.android.core.common.DatePeriodType +import org.hisp.dhis.android.core.common.RelativePeriod +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter + +internal object AttributeValueFilterSamples { + fun get(): AttributeValueFilter { + return AttributeValueFilter.builder() + .id(1L) + .trackedEntityInstanceFilter("trackedEntityInstanceFilter") + .attribute("attributeUid") + .sw("as") + .ew("sa") + .le("20") + .ge("10") + .gt("10") + .lt("20") + .eq("abc") + .`in`(setOf("Norway", "India")) + .like("abc") + .dateFilter( + DateFilterPeriod.builder() + .startDate(getSimpleDate("2014-05-01")) + .endDate(getSimpleDate("2019-03-20")) + .type(DatePeriodType.ABSOLUTE) + .build() + ) + .build() + } + + fun get1(): AttributeValueFilter { + return AttributeValueFilter.builder() + .attribute("abcAttributeUid") + .sw("as") + .ew("sa") + .le("20") + .ge("10") + .gt("10") + .lt("20") + .`in`(setOf("India", "Norway")) + .like("abc") + .build() + } + + fun get2(): AttributeValueFilter { + return AttributeValueFilter.builder() + .attribute("dateAttributeUid") + .dateFilter( + DateFilterPeriod.builder() + .startDate(getSimpleDate("2014-05-01")) + .endDate(getSimpleDate("2019-03-20")) + .type(DatePeriodType.ABSOLUTE) + .build() + ) + .build() + } + + fun get3(): AttributeValueFilter { + return AttributeValueFilter.builder() + .attribute("anotherDateAttributeUid") + .dateFilter( + DateFilterPeriod.builder() + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .build() + ) + .build() + } + + fun get4(): AttributeValueFilter { + return AttributeValueFilter.builder() + .attribute("yetAnotherDateAttributeUid") + .dateFilter( + DateFilterPeriod.builder() + .period(RelativePeriod.LAST_WEEK) + .type(DatePeriodType.RELATIVE) + .build() + ) + .build() + } + + val attributeValueFilters: List + get() = listOf(get1(), get2(), get3(), get4()) + + private fun getSimpleDate(dateStr: String): Date? { + return try { + DateUtils.SIMPLE_DATE_FORMAT.parse(dateStr) + } catch (e: ParseException) { + e.printStackTrace() + null + } + } +} diff --git a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/TrackedEntityAttributeSamples.java b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/TrackedEntityAttributeSamples.java index f26ebf47d4..bcfab271ef 100644 --- a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/TrackedEntityAttributeSamples.java +++ b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/TrackedEntityAttributeSamples.java @@ -29,6 +29,7 @@ package org.hisp.dhis.android.core.data.trackedentity; import org.hisp.dhis.android.core.arch.helpers.UidGeneratorImpl; +import org.hisp.dhis.android.core.common.AggregationType; import org.hisp.dhis.android.core.common.ObjectWithUid; import org.hisp.dhis.android.core.common.ValueType; import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute; @@ -52,6 +53,7 @@ public static TrackedEntityAttribute get() { .programScope(Boolean.TRUE) .displayInListNoProgram(Boolean.TRUE) .generated(Boolean.TRUE) + .aggregationType(AggregationType.DEFAULT) .displayOnVisitSchedule(Boolean.TRUE) .orgUnitScope(Boolean.TRUE) .unique(Boolean.TRUE) diff --git a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/TrackedEntityInstanceFilterSamples.java b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/TrackedEntityInstanceFilterSamples.java index 1782746e89..08c9cbcebd 100644 --- a/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/TrackedEntityInstanceFilterSamples.java +++ b/core/src/sharedTest/java/org/hisp/dhis/android/core/data/trackedentity/TrackedEntityInstanceFilterSamples.java @@ -25,17 +25,20 @@ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ - package org.hisp.dhis.android.core.data.trackedentity; import com.google.common.collect.Lists; +import org.hisp.dhis.android.core.common.AssignedUserMode; import org.hisp.dhis.android.core.common.BaseIdentifiableObject; -import org.hisp.dhis.android.core.common.FilterPeriod; +import org.hisp.dhis.android.core.common.DateFilterPeriod; +import org.hisp.dhis.android.core.common.DatePeriodType; import org.hisp.dhis.android.core.common.ObjectWithUid; +import org.hisp.dhis.android.core.common.RelativePeriod; import org.hisp.dhis.android.core.enrollment.EnrollmentStatus; import org.hisp.dhis.android.core.event.EventStatus; -import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceEventFilter; +import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode; +import org.hisp.dhis.android.core.trackedentity.EntityQueryCriteria; import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter; import java.text.ParseException; @@ -53,14 +56,47 @@ public static TrackedEntityInstanceFilter get() { .created(getDate("2019-09-27T00:19:06.590")) .lastUpdated(getDate("2019-09-27T00:19:06.590")) .description("Foci response assigned to someone, and the enrollment is still active") - .followUp(Boolean.FALSE) - .enrollmentStatus(EnrollmentStatus.ACTIVE) .sortOrder(2) .program(ObjectWithUid.create("M3xtLkYBlKI")) - .enrollmentCreatedPeriod(FilterPeriod.create(-20,20)) - .eventFilters(Lists.newArrayList(TrackedEntityInstanceEventFilter.builder() - .trackedEntityInstanceFilter("klhzVgls081") - .eventStatus(EventStatus.ACTIVE).build())) + .entityQueryCriteria(EntityQueryCriteria.builder() + .followUp(Boolean.FALSE) + .enrollmentStatus(EnrollmentStatus.ACTIVE) + .eventStatus(EventStatus.COMPLETED) + .programStage("uvMKOn1oWvd") + .enrollmentCreatedDate(DateFilterPeriod.builder() + .period(RelativePeriod.TODAY) + .startDate(getDate("2014-05-01T00:00:00.000")) + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .endDate(getDate("2019-03-20T00:00:00.000")) + .build()) + .enrollmentIncidentDate(DateFilterPeriod.builder() + .period(RelativePeriod.TODAY) + .startDate(getDate("2014-05-01T00:00:00.000")) + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .endDate(getDate("2019-03-20T00:00:00.000")) + .build()) + .ouMode(OrganisationUnitMode.SELECTED) + .trackedEntityType("trackedEntityTypeUid") + .assignedUserMode(AssignedUserMode.PROVIDED) + .trackedEntityInstances(Lists.newArrayList("a3kGcGDCuk7", "a3kGcGDCuk8")) + .displayColumnOrder(Lists.newArrayList("eventDate", "status")) + .order("dueDate:asc,createdDate:desc") + .organisationUnit("orgUnitUid") + .eventDate(DateFilterPeriod.builder() + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .build()) + .lastUpdatedDate(DateFilterPeriod.builder() + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .build()) + .build()) .build(); } diff --git a/core/src/sharedTest/resources/datavalueset/data_value_set_success.json b/core/src/sharedTest/resources/datavalueset/data_value_set_success.json index a36d88db9e..1883cfeb35 100644 --- a/core/src/sharedTest/resources/datavalueset/data_value_set_success.json +++ b/core/src/sharedTest/resources/datavalueset/data_value_set_success.json @@ -1,40 +1,46 @@ { - "responseType": "ImportSummary", - "status": "SUCCESS", - "importOptions": { - "idSchemes": {}, - "dryRun": false, - "async": false, - "importStrategy": "CREATE_AND_UPDATE", - "mergeMode": "REPLACE", - "reportMode": "FULL", - "skipExistingCheck": false, - "sharing": false, - "skipNotifications": false, - "skipAudit": false, - "datasetAllowsPeriods": false, - "strictPeriods": false, - "strictDataElements": false, - "strictCategoryOptionCombos": false, - "strictAttributeOptionCombos": false, - "strictOrganisationUnits": false, - "requireCategoryOptionCombo": false, - "requireAttributeOptionCombo": false, - "skipPatternValidation": false, - "ignoreEmptyCollection": false, - "force": false, - "firstRowIsHeader": true, - "skipLastUpdated": false, - "mergeDataValues": false, - "skipCache": false - }, - "description": "Import process completed successfully", - "importCount": { - "imported": 0, - "updated": 3, - "ignored": 0, - "deleted": 0 - }, - "conflicts": [], - "dataSetComplete": "false" + "httpStatus": "OK", + "httpStatusCode": 200, + "status": "OK", + "message": "Import was successful.", + "response": { + "responseType": "ImportSummary", + "status": "SUCCESS", + "importOptions": { + "idSchemes": {}, + "dryRun": false, + "async": false, + "importStrategy": "CREATE_AND_UPDATE", + "mergeMode": "REPLACE", + "reportMode": "FULL", + "skipExistingCheck": false, + "sharing": false, + "skipNotifications": false, + "skipAudit": false, + "datasetAllowsPeriods": false, + "strictPeriods": false, + "strictDataElements": false, + "strictCategoryOptionCombos": false, + "strictAttributeOptionCombos": false, + "strictOrganisationUnits": false, + "requireCategoryOptionCombo": false, + "requireAttributeOptionCombo": false, + "skipPatternValidation": false, + "ignoreEmptyCollection": false, + "force": false, + "firstRowIsHeader": true, + "skipLastUpdated": false, + "mergeDataValues": false, + "skipCache": false + }, + "description": "Import process completed successfully", + "importCount": { + "imported": 0, + "updated": 3, + "ignored": 0, + "deleted": 0 + }, + "conflicts": [], + "dataSetComplete": "false" + } } \ No newline at end of file diff --git a/core/src/sharedTest/resources/datavalueset/data_value_set_warning.json b/core/src/sharedTest/resources/datavalueset/data_value_set_warning.json index 29ceb60547..ad6e8fbadc 100644 --- a/core/src/sharedTest/resources/datavalueset/data_value_set_warning.json +++ b/core/src/sharedTest/resources/datavalueset/data_value_set_warning.json @@ -1,45 +1,51 @@ { - "responseType": "ImportSummary", + "httpStatus": "Conflict", + "httpStatusCode": 409, "status": "WARNING", - "importOptions": { - "idSchemes": {}, - "dryRun": false, - "async": false, - "importStrategy": "CREATE_AND_UPDATE", - "mergeMode": "REPLACE", - "reportMode": "FULL", - "skipExistingCheck": false, - "sharing": false, - "skipNotifications": false, - "skipAudit": false, - "datasetAllowsPeriods": false, - "strictPeriods": false, - "strictDataElements": false, - "strictCategoryOptionCombos": false, - "strictAttributeOptionCombos": false, - "strictOrganisationUnits": false, - "requireCategoryOptionCombo": false, - "requireAttributeOptionCombo": false, - "skipPatternValidation": false, - "ignoreEmptyCollection": false, - "force": false, - "firstRowIsHeader": true, - "skipLastUpdated": false, - "mergeDataValues": false, - "skipCache": false - }, - "description": "Import process completed successfully", - "importCount": { - "imported": 0, - "updated": 0, - "ignored": 1, - "deleted": 0 - }, - "conflicts": [ - { - "object": "40L", - "value": "Data value is not a positive integer, must match data element type: vANAXwtLwcT" - } - ], - "dataSetComplete": "false" + "message": "An error occurred, please check import summary.", + "response": { + "responseType": "ImportSummary", + "status": "WARNING", + "importOptions": { + "idSchemes": {}, + "dryRun": false, + "async": false, + "importStrategy": "CREATE_AND_UPDATE", + "mergeMode": "REPLACE", + "reportMode": "FULL", + "skipExistingCheck": false, + "sharing": false, + "skipNotifications": false, + "skipAudit": false, + "datasetAllowsPeriods": false, + "strictPeriods": false, + "strictDataElements": false, + "strictCategoryOptionCombos": false, + "strictAttributeOptionCombos": false, + "strictOrganisationUnits": false, + "requireCategoryOptionCombo": false, + "requireAttributeOptionCombo": false, + "skipPatternValidation": false, + "ignoreEmptyCollection": false, + "force": false, + "firstRowIsHeader": true, + "skipLastUpdated": false, + "mergeDataValues": false, + "skipCache": false + }, + "description": "Import process completed successfully", + "importCount": { + "imported": 0, + "updated": 0, + "ignored": 1, + "deleted": 0 + }, + "conflicts": [ + { + "object": "40L", + "value": "Data value is not a positive integer, must match data element type: vANAXwtLwcT" + } + ], + "dataSetComplete": "false" + } } \ No newline at end of file diff --git a/core/src/sharedTest/resources/systeminfo/system_info.json b/core/src/sharedTest/resources/systeminfo/system_info.json index 395d87156a..b029c3240f 100644 --- a/core/src/sharedTest/resources/systeminfo/system_info.json +++ b/core/src/sharedTest/resources/systeminfo/system_info.json @@ -7,7 +7,7 @@ "lastAnalyticsTableSuccess": "2017-11-29T03:32:45.861", "intervalSinceLastAnalyticsTableSuccess": "7 h, 55 m, 1 s", "lastAnalyticsTableRuntime": "7 m, 40 s", - "version": "2.37", + "version": "2.38", "revision": "585e4bd", "buildTime": "2017-10-12T06:22:05.000", "jasperReportsVersion": "6.3.1", diff --git a/core/src/sharedTest/resources/trackedentity/tracked_entity_attribute.json b/core/src/sharedTest/resources/trackedentity/tracked_entity_attribute.json index 548bea0679..06d12d6336 100644 --- a/core/src/sharedTest/resources/trackedentity/tracked_entity_attribute.json +++ b/core/src/sharedTest/resources/trackedentity/tracked_entity_attribute.json @@ -24,6 +24,7 @@ "unique": false, "inherit": false, "fieldMask": "XXXXX", + "aggregationType": "DEFAULT", "formName": "number", "displayFormName": "num", "optionSetValue": false, diff --git a/core/src/sharedTest/resources/trackedentity/tracked_entity_attributes.json b/core/src/sharedTest/resources/trackedentity/tracked_entity_attributes.json index 1007d24526..4a1059e0f6 100644 --- a/core/src/sharedTest/resources/trackedentity/tracked_entity_attributes.json +++ b/core/src/sharedTest/resources/trackedentity/tracked_entity_attributes.json @@ -22,7 +22,15 @@ "delete": true, "write": true, "manage": false - } + }, + "legendSets": [ + { + "id": "QiOkbpGEud4" + }, + { + "id": "rtOkbpGEud4" + } + ] }, { "id": "aejWyOfXge6", @@ -47,6 +55,11 @@ "optionSet": { "id": "VQ2lai3OfVG" }, + "legendSets": [ + { + "id": "rtOkbpGEud4" + } + ], "access": { "read": true, "updateWithSection": true, diff --git a/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filter.json b/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filter.json index 38c97390c9..7ade507aac 100644 --- a/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filter.json +++ b/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filter.json @@ -9,6 +9,7 @@ "externalAccess": false, "followup": false, "enrollmentStatus": "ACTIVE", + "organisationUnit": "orgUnitUid", "sortOrder": 2, "favorite": false, "access": { @@ -41,6 +42,7 @@ ], "eventFilters": [ { + "trackedEntityInstanceFilter": "klhzVgls081", "assignedUserMode": "ANY", "programStage": "uvMKOn1oWvd", "eventStatus": "OVERDUE", @@ -52,6 +54,75 @@ ] } ], + "entityQueryCriteria": { + "followUp": false, + "enrollmentStatus": "ACTIVE", + "eventStatus": "COMPLETED", + "programStage": "uvMKOn1oWvd", + "enrollmentCreatedDate": { + "period": "TODAY", + "endDate": "2019-03-20T00:00:00.000", + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE", + "startDate": "2014-05-01T00:00:00.000" + }, + "enrollmentIncidentDate": { + "period": "TODAY", + "endDate": "2019-03-20T00:00:00.000", + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE", + "startDate": "2014-05-01T00:00:00.000" + }, + "eventDate": { + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE" + }, + "lastUpdatedDate": { + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE" + }, + "ouMode": "SELECTED", + "organisationUnit": "orgUnitUid", + "trackedEntityType": "trackedEntityTypeUid", + "assignedUserMode": "PROVIDED", + "trackedEntityInstances": [ + "a3kGcGDCuk7", + "a3kGcGDCuk8" + ], + "displayColumnOrder": [ + "eventDate", + "status" + ], + "order": "dueDate:asc,createdDate:desc", + "attributeValueFilters": [ + { + "ew": "aa", + "sw": "ac", + "like": "abc", + "lt": "20", + "le": "20", + "attribute": "w75KJ2mc4zz", + "gt": "10", + "ge": "10", + "dateFilter": { + "period": "LAST_WEEK", + "endDate": "2019-03-20T00:00:00.000", + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE", + "startDate": "2014-05-01T00:00:00.000" + }, + "in": [ + "Norway", + "India" + ] + } + ] + }, "userAccesses": [ ] } \ No newline at end of file diff --git a/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filter_v_37.json b/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filter_v_37.json new file mode 100644 index 0000000000..ff3b46fe84 --- /dev/null +++ b/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filter_v_37.json @@ -0,0 +1,57 @@ +{ + "code": "assigned_none", + "lastUpdated": "2019-09-27T00:19:06.590", + "id": "klhzVgls081", + "created": "2019-09-27T00:19:06.590", + "name": "Ongoing foci responses", + "displayName": "Ongoing foci responses", + "description": "Foci response assigned to someone, and the enrollment is still active", + "externalAccess": false, + "followup": false, + "enrollmentStatus": "ACTIVE", + "sortOrder": 2, + "favorite": false, + "access": { + "read": true, + "update": true, + "externalize": false, + "delete": true, + "write": true, + "manage": true + }, + "program": { + "id": "M3xtLkYBlKI" + }, + "lastUpdatedBy": { + "displayName": "Tom Wakiki", + "id": "GOLswS44mh8", + "username": "system" + }, + "enrollmentCreatedPeriod": { + "periodFrom": -5, + "periodTo": 5 + }, + "favorites": [ + ], + "translations": [ + ], + "userGroupAccesses": [ + ], + "attributeValues": [ + ], + "eventFilters": [ + { + "assignedUserMode": "ANY", + "programStage": "uvMKOn1oWvd", + "eventStatus": "OVERDUE", + "eventCreatedPeriod": { + "periodFrom": -11, + "periodTo": 11 + }, + "assignedUsers": [ + ] + } + ], + "userAccesses": [ + ] +} \ No newline at end of file diff --git a/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filters.json b/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filters.json index c6a59b1cf0..003886c1e1 100644 --- a/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filters.json +++ b/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filters.json @@ -15,8 +15,6 @@ "displayName": "Ongoing foci responses", "description": "Foci response assigned to someone, and the enrollment is still active", "externalAccess": false, - "followup": false, - "enrollmentStatus": "ACTIVE", "sortOrder": 2, "favorite": false, "access": { @@ -35,10 +33,6 @@ "id": "GOLswS44mh8", "username": "system" }, - "enrollmentCreatedPeriod": { - "periodFrom": -15, - "periodTo": 15 - }, "favorites": [ ], "translations": [ @@ -61,7 +55,76 @@ } ], "userAccesses": [ - ] + ], + "entityQueryCriteria": { + "followUp": false, + "enrollmentStatus": "ACTIVE", + "eventStatus": "COMPLETED", + "programStage": "uvMKOn1oWvd", + "enrollmentCreatedDate": { + "period": "TODAY", + "endDate": "2019-03-20T00:00:00.000", + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE", + "startDate": "2014-05-01T00:00:00.000" + }, + "enrollmentIncidentDate": { + "period": "TODAY", + "endDate": "2019-03-20T00:00:00.000", + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE", + "startDate": "2014-05-01T00:00:00.000" + }, + "eventDate": { + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE" + }, + "lastUpdatedDate": { + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE" + }, + "ouMode": "SELECTED", + "organisationUnit": "orgUnitUid", + "trackedEntityType": "trackedEntityTypeUid", + "assignedUserMode": "PROVIDED", + "trackedEntityInstances": [ + "a3kGcGDCuk7", + "a3kGcGDCuk8" + ], + "displayColumnOrder": [ + "eventDate", + "status" + ], + "order": "dueDate:asc,createdDate:desc", + "attributeValueFilters": [ + { + "ew": "aa", + "sw": "ac", + "like": "abc", + "lt": "20", + "le": "20", + "attribute": "w75KJ2mc4zz", + "gt": "10", + "ge": "10", + "dateFilter": { + "period": "LAST_WEEK", + "endDate": "2019-03-20T00:00:00.000", + "startBuffer": -5, + "endBuffer": 5, + "type": "RELATIVE", + "startDate": "2014-05-01T00:00:00.000" + }, + "in": [ + "Norway", + "India" + ] + } + ] + } }, { "code": "assigned_to_me", @@ -72,8 +135,6 @@ "displayName": "Events assigned to me", "description": "All actve enrollmetns with events assigned to me", "externalAccess": false, - "followup": false, - "enrollmentStatus": "COMPLETED", "sortOrder": 1, "favorite": false, "access": { @@ -92,10 +153,6 @@ "id": "GOLswS44mh8", "username": "system" }, - "enrollmentCreatedPeriod": { - "periodFrom": -20, - "periodTo": 20 - }, "favorites": [ ], @@ -128,7 +185,11 @@ ], "userAccesses": [ - ] + ], + "entityQueryCriteria": { + "followUp": true, + "ouMode": "ACCESSIBLE" + } } ] } \ No newline at end of file diff --git a/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filters_v_37.json b/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filters_v_37.json new file mode 100644 index 0000000000..c6a59b1cf0 --- /dev/null +++ b/core/src/sharedTest/resources/trackedentity/tracked_entity_instance_filters_v_37.json @@ -0,0 +1,134 @@ +{ + "pager": { + "page": 1, + "pageCount": 1, + "total": 3, + "pageSize": 50 + }, + "trackedEntityInstanceFilters": [ + { + "code": "assigned_none", + "lastUpdated": "2019-09-27T00:19:06.590", + "id": "klhzVgls081", + "created": "2019-09-27T00:19:06.590", + "name": "Ongoing foci responses", + "displayName": "Ongoing foci responses", + "description": "Foci response assigned to someone, and the enrollment is still active", + "externalAccess": false, + "followup": false, + "enrollmentStatus": "ACTIVE", + "sortOrder": 2, + "favorite": false, + "access": { + "read": true, + "update": true, + "externalize": false, + "delete": true, + "write": true, + "manage": true + }, + "program": { + "id": "lxAQ7Zs9VYR" + }, + "lastUpdatedBy": { + "displayName": "Tom Wakiki", + "id": "GOLswS44mh8", + "username": "system" + }, + "enrollmentCreatedPeriod": { + "periodFrom": -15, + "periodTo": 15 + }, + "favorites": [ + ], + "translations": [ + ], + "userGroupAccesses": [ + ], + "attributeValues": [ + ], + "eventFilters": [ + { + "assignedUserMode": "ANY", + "programStage": "dBwrot7S420", + "eventStatus": "OVERDUE", + "eventCreatedPeriod": { + "periodFrom": -11, + "periodTo": 11 + }, + "assignedUsers": [ + ] + } + ], + "userAccesses": [ + ] + }, + { + "code": "assigned_to_me", + "lastUpdated": "2019-09-27T00:16:03.400", + "id": "PpGINOT00UX", + "created": "2019-09-27T00:16:03.400", + "name": "Events assigned to me", + "displayName": "Events assigned to me", + "description": "All actve enrollmetns with events assigned to me", + "externalAccess": false, + "followup": false, + "enrollmentStatus": "COMPLETED", + "sortOrder": 1, + "favorite": false, + "access": { + "read": true, + "update": true, + "externalize": false, + "delete": true, + "write": true, + "manage": true + }, + "program": { + "id": "IpHINAT79UW" + }, + "lastUpdatedBy": { + "displayName": "Tom Wakiki", + "id": "GOLswS44mh8", + "username": "system" + }, + "enrollmentCreatedPeriod": { + "periodFrom": -20, + "periodTo": 20 + }, + "favorites": [ + + ], + "translations": [ + + ], + "userGroupAccesses": [ + + ], + "attributeValues": [ + + ], + "eventFilters": [ + { + "assignedUserMode": "CURRENT", + "assignedUsers": [ + + ] + }, + { + "assignedUserMode": "ANY", + "eventStatus": "OVERDUE", + "eventCreatedPeriod": { + "periodFrom": -20, + "periodTo": 2 + }, + "assignedUsers": [ + ] + } + ], + "userAccesses": [ + + ] + } + ] +} \ No newline at end of file diff --git a/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceMetadataHelperShould.kt b/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceMetadataHelperShould.kt index 761656bb9d..56f3c64dfb 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceMetadataHelperShould.kt +++ b/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsServiceMetadataHelperShould.kt @@ -46,6 +46,8 @@ import org.hisp.dhis.android.core.organisationunit.OrganisationUnitLevel import org.hisp.dhis.android.core.period.internal.ParentPeriodGenerator import org.hisp.dhis.android.core.period.internal.PeriodHelper import org.hisp.dhis.android.core.program.ProgramIndicatorCollectionRepository +import org.hisp.dhis.android.core.program.internal.ProgramStoreInterface +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute import org.junit.Test import org.junit.runner.RunWith import org.junit.runners.JUnit4 @@ -62,6 +64,8 @@ class AnalyticsServiceMetadataHelperShould { private val organisationUnitStore: IdentifiableObjectStore = mock() private val organisationUnitGroupStore: IdentifiableObjectStore = mock() private val organisationUnitLevelStore: IdentifiableObjectStore = mock() + private val programStore: ProgramStoreInterface = mock() + private val trackedEntityAttribute: IdentifiableObjectStore = mock() private val programIndicatorRepository: ProgramIndicatorCollectionRepository = mock() private val analyticsOrganisationUnitHelper: AnalyticsOrganisationUnitHelper = mock() private val parentPeriodGenerator: ParentPeriodGenerator = mock() @@ -77,6 +81,8 @@ class AnalyticsServiceMetadataHelperShould { organisationUnitStore, organisationUnitGroupStore, organisationUnitLevelStore, + programStore, + trackedEntityAttribute, programIndicatorRepository, analyticsOrganisationUnitHelper, parentPeriodGenerator, diff --git a/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsVisualizationsServiceDimensionHelperShould.kt b/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsVisualizationsServiceDimensionHelperShould.kt index 951d1c8ce8..c867e01ceb 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsVisualizationsServiceDimensionHelperShould.kt +++ b/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/AnalyticsVisualizationsServiceDimensionHelperShould.kt @@ -39,10 +39,7 @@ import org.hisp.dhis.android.core.common.ObjectWithUid import org.hisp.dhis.android.core.common.RelativeOrganisationUnit import org.hisp.dhis.android.core.common.RelativePeriod import org.hisp.dhis.android.core.organisationunit.OrganisationUnitLevel -import org.hisp.dhis.android.core.visualization.CategoryDimension -import org.hisp.dhis.android.core.visualization.DataDimensionItem -import org.hisp.dhis.android.core.visualization.DataDimensionItemType -import org.hisp.dhis.android.core.visualization.Visualization +import org.hisp.dhis.android.core.visualization.* import org.junit.Assert.fail import org.junit.Test import org.junit.runner.RunWith @@ -154,6 +151,62 @@ class AnalyticsVisualizationsServiceDimensionHelperShould { } } + @Test + fun `Should parse event dataElements dimension items`() { + val dataDimensionItems = listOf( + DataDimensionItem.builder() + .programDataElement( + DataDimensionItemProgramDataElement.builder() + .uid("$uid1.$uid2") + .build() + ) + .dataDimensionItemType(DataDimensionItemType.PROGRAM_DATA_ELEMENT) + .build() + ) + + whenever(visualization.dataDimensionItems()) doReturn dataDimensionItems + + val dimensionItems = helper.getDimensionItems(visualization, listOf("dx")) + + assertThat(dimensionItems).hasSize(1) + when (val item = dimensionItems.first()) { + is DimensionItem.DataItem.EventDataItem.DataElement -> { + assertThat(item.program).isEqualTo(uid1) + assertThat(item.dataElement).isEqualTo(uid2) + } + else -> + fail("Unexpected dimension item type") + } + } + + @Test + fun `Should parse event attribute dimension items`() { + val dataDimensionItems = listOf( + DataDimensionItem.builder() + .programAttribute( + DataDimensionItemProgramAttribute.builder() + .uid("$uid1.$uid2") + .build() + ) + .dataDimensionItemType(DataDimensionItemType.PROGRAM_ATTRIBUTE) + .build() + ) + + whenever(visualization.dataDimensionItems()) doReturn dataDimensionItems + + val dimensionItems = helper.getDimensionItems(visualization, listOf("dx")) + + assertThat(dimensionItems).hasSize(1) + when (val item = dimensionItems.first()) { + is DimensionItem.DataItem.EventDataItem.Attribute -> { + assertThat(item.program).isEqualTo(uid1) + assertThat(item.attribute).isEqualTo(uid2) + } + else -> + fail("Unexpected dimension item type") + } + } + @Test fun `Should parse organisation unit uids and levels`() { val orgunitItems = listOf( diff --git a/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsDimensionHelperShould.kt b/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsDimensionHelperShould.kt new file mode 100644 index 0000000000..ebac01aba6 --- /dev/null +++ b/core/src/test/java/org/hisp/dhis/android/core/analytics/aggregated/internal/evaluator/AnalyticsDimensionHelperShould.kt @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.analytics.aggregated.internal.evaluator + +import com.google.common.truth.Truth.assertThat +import org.hisp.dhis.android.core.analytics.AnalyticsException +import org.hisp.dhis.android.core.analytics.aggregated.DimensionItem +import org.hisp.dhis.android.core.analytics.aggregated.internal.AnalyticsServiceEvaluationItem +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class AnalyticsDimensionHelperShould { + + @Test + fun `Should return single dimension item`() { + val item = AnalyticsServiceEvaluationItem( + dimensionItems = listOf( + DimensionItem.DataItem.DataElementItem("dataElement1"), + DimensionItem.PeriodItem.Absolute("periodId") + ), + filters = listOf( + DimensionItem.OrganisationUnitItem.Absolute("orgunit") + ) + ) + + val dataItem = AnalyticsDimensionHelper.getSingleItemByDimension(item) + assertThat(dataItem.size).isEqualTo(1) + assertThat(dataItem.first()).isInstanceOf(DimensionItem.DataItem::class.java) + + val periodItem = AnalyticsDimensionHelper.getSingleItemByDimension(item) + assertThat(periodItem.size).isEqualTo(1) + assertThat(periodItem.first()).isInstanceOf(DimensionItem.PeriodItem::class.java) + + val ouItem = AnalyticsDimensionHelper.getSingleItemByDimension(item) + assertThat(ouItem.size).isEqualTo(1) + assertThat(ouItem.first()).isInstanceOf(DimensionItem.OrganisationUnitItem::class.java) + } + + @Test(expected = AnalyticsException.InvalidArguments::class) + fun `Should return error when multiple dimension items`() { + val item = AnalyticsServiceEvaluationItem( + dimensionItems = listOf( + DimensionItem.DataItem.DataElementItem("dataElement1"), + DimensionItem.DataItem.DataElementItem("dataElement2") + ), + filters = listOf() + ) + + AnalyticsDimensionHelper.getSingleItemByDimension(item) + } + + @Test + fun `Should return last item when multiple items has filter`() { + val item = AnalyticsServiceEvaluationItem( + dimensionItems = listOf(), + filters = listOf( + DimensionItem.DataItem.DataElementItem("dataElement1"), + DimensionItem.DataItem.DataElementItem("dataElement2") + ) + ) + + val dataItem = AnalyticsDimensionHelper.getSingleItemByDimension(item) + assertThat(dataItem.size).isEqualTo(2) + assertThat(dataItem[0]).isInstanceOf(DimensionItem.DataItem::class.java) + assertThat(dataItem[1]).isInstanceOf(DimensionItem.DataItem::class.java) + } +} diff --git a/core/src/test/java/org/hisp/dhis/android/core/common/BaseObjectShould.java b/core/src/test/java/org/hisp/dhis/android/core/common/BaseObjectShould.java index de38ddf0f2..802674d114 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/common/BaseObjectShould.java +++ b/core/src/test/java/org/hisp/dhis/android/core/common/BaseObjectShould.java @@ -34,6 +34,8 @@ import java.io.IOException; import java.io.InputStream; +import java.text.ParseException; +import java.util.Date; public abstract class BaseObjectShould { @@ -56,4 +58,13 @@ protected O deserialize(String jsonString, Class oClass) throws IOExcepti protected String serialize(O object) throws IOException { return objectMapper.writeValueAsString(object); } + + protected static Date getDate(String dateStr) { + try { + return BaseIdentifiableObject.DATE_FORMAT.parse(dateStr); + } catch (ParseException e) { + e.printStackTrace(); + return null; + } + } } \ No newline at end of file diff --git a/core/src/test/java/org/hisp/dhis/android/core/enrollment/internal/EnrollmentHandlerShould.kt b/core/src/test/java/org/hisp/dhis/android/core/enrollment/internal/EnrollmentHandlerShould.kt index 69acfa8620..3930b73e59 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/enrollment/internal/EnrollmentHandlerShould.kt +++ b/core/src/test/java/org/hisp/dhis/android/core/enrollment/internal/EnrollmentHandlerShould.kt @@ -112,6 +112,7 @@ class EnrollmentHandlerShould { // verify that enrollment store is only invoked with delete verify(enrollmentStore, times(1)).deleteIfExists(any()) verify(enrollmentStore, never()).updateOrInsert(any()) + verify(relationshipHandler, times(1)).deleteLinkedRelationships(any()) // event handler should not be invoked verify(eventHandler, never()).handleMany(any(), any(), any()) @@ -130,6 +131,7 @@ class EnrollmentHandlerShould { // verify that enrollment store is only invoked with update verify(enrollmentStore, times(1)).updateOrInsert(any()) verify(enrollmentStore, never()).deleteIfExists(any()) + verify(relationshipHandler, never()).deleteLinkedRelationships(any()) // event handler should be invoked once verify(eventHandler, times(1)).handleMany(any(), any(), any()) diff --git a/core/src/test/java/org/hisp/dhis/android/core/event/internal/EventHandlerShould.kt b/core/src/test/java/org/hisp/dhis/android/core/event/internal/EventHandlerShould.kt index 4e989d5cb9..9b842866f0 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/event/internal/EventHandlerShould.kt +++ b/core/src/test/java/org/hisp/dhis/android/core/event/internal/EventHandlerShould.kt @@ -109,6 +109,7 @@ class EventHandlerShould { // verify that delete is invoked once verify(eventStore, times(1)).deleteIfExists(event.uid()) + verify(relationshipHandler, times(1)).deleteLinkedRelationships(any()) // verify that update and insert is never invoked verify(eventStore, never()).update(any()) @@ -135,6 +136,7 @@ class EventHandlerShould { // verify that delete is never invoked verify(eventStore, never()).deleteIfExists(any()) + verify(relationshipHandler, never()).deleteLinkedRelationships(any()) } @Test diff --git a/core/src/test/java/org/hisp/dhis/android/core/period/internal/PeriodGeneratorShould.kt b/core/src/test/java/org/hisp/dhis/android/core/period/internal/PeriodGeneratorShould.kt new file mode 100644 index 0000000000..9fe068edff --- /dev/null +++ b/core/src/test/java/org/hisp/dhis/android/core/period/internal/PeriodGeneratorShould.kt @@ -0,0 +1,94 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.period.internal + +import com.google.common.truth.Truth.assertThat +import io.reactivex.Single +import io.reactivex.schedulers.Schedulers +import java.util.* +import org.hisp.dhis.android.core.arch.helpers.DateUtils +import org.junit.Test +import org.junit.runner.RunWith +import org.junit.runners.JUnit4 + +@RunWith(JUnit4::class) +class PeriodGeneratorShould { + + private val calendar = Calendar.getInstance() + + private val dailyGenerator: PeriodGenerator = DailyPeriodGenerator(calendar) + private val weeklyGenerator: PeriodGenerator = WeeklyPeriodGeneratorFactory.weekly(calendar) + private val monthlyGenerator: PeriodGenerator = MonthlyPeriodGenerator(calendar) + + @Test + fun generate_single_period_simultaneously() { + val refDate = DateUtils.SIMPLE_DATE_FORMAT.parse("2019-12-30") + + val periods = (-500..500).map { + Single.fromCallable { + dailyGenerator.generatePeriod(refDate, it) + weeklyGenerator.generatePeriod(refDate, it) + monthlyGenerator.generatePeriod(refDate, it) + }.subscribeOn(Schedulers.io()) + } + + Single.merge(periods).blockingSubscribe() + + assertThat(periods.size).isEqualTo(1001) + } + + @Test + fun generate_multiple_periods_simultaneously() { + val periods = (0..100).map { + Single.fromCallable { + dailyGenerator.generatePeriods(it - 100, it) + weeklyGenerator.generatePeriods(it - 100, it) + monthlyGenerator.generatePeriods(it - 100, it) + }.subscribeOn(Schedulers.io()) + } + + Single.merge(periods).blockingSubscribe() + + assertThat(periods.size).isEqualTo(101) + } + + @Test + fun generate_periods_in_year_simultaneously() { + val periods = (-5..5).map { + Single.fromCallable { + dailyGenerator.generatePeriodsInYear(it) + weeklyGenerator.generatePeriodsInYear(it) + monthlyGenerator.generatePeriodsInYear(it) + }.subscribeOn(Schedulers.io()) + } + + Single.merge(periods).blockingSubscribe() + + assertThat(periods.size).isEqualTo(11) + } +} diff --git a/core/src/test/java/org/hisp/dhis/android/core/relationship/RelationshipServiceShould.kt b/core/src/test/java/org/hisp/dhis/android/core/relationship/RelationshipServiceShould.kt new file mode 100644 index 0000000000..f4d4b940b1 --- /dev/null +++ b/core/src/test/java/org/hisp/dhis/android/core/relationship/RelationshipServiceShould.kt @@ -0,0 +1,202 @@ +package org.hisp.dhis.android.core.relationship + +import com.nhaarman.mockitokotlin2.any +import com.nhaarman.mockitokotlin2.doReturnConsecutively +import com.nhaarman.mockitokotlin2.mock +import com.nhaarman.mockitokotlin2.times +import com.nhaarman.mockitokotlin2.verify +import com.nhaarman.mockitokotlin2.whenever +import org.hisp.dhis.android.core.common.Access +import org.hisp.dhis.android.core.common.DataAccess +import org.hisp.dhis.android.core.common.ObjectWithUid +import org.hisp.dhis.android.core.program.Program +import org.hisp.dhis.android.core.program.ProgramCollectionRepository +import org.hisp.dhis.android.core.program.ProgramStage +import org.hisp.dhis.android.core.program.ProgramStageCollectionRepository +import org.hisp.dhis.android.core.trackedentity.TrackedEntityType +import org.hisp.dhis.android.core.trackedentity.TrackedEntityTypeCollectionRepository +import org.junit.Assert.assertTrue +import org.junit.Before +import org.junit.Test +import org.mockito.Mockito + +class RelationshipServiceShould { + + private val programRepository: ProgramCollectionRepository = mock(defaultAnswer = Mockito.RETURNS_DEEP_STUBS) + private val programStageRepository: ProgramStageCollectionRepository = + mock(defaultAnswer = Mockito.RETURNS_DEEP_STUBS) + private val trackedEntityTypeRepository: TrackedEntityTypeCollectionRepository = + mock(defaultAnswer = Mockito.RETURNS_DEEP_STUBS) + private lateinit var relationshipService: RelationshipService + + @Before + fun setUp() { + relationshipService = RelationshipServiceImpl( + programRepository, + programStageRepository, + trackedEntityTypeRepository + ) + } + + @Test + fun `HasAccessPermission should return true if bidirectional and from and to access is true`() { + val bidirectionalRelationship = relationshipType( + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + true + ) + + mockTeTypeAccessResponse(fromAccess = true, toAccess = true) + assertTrue(relationshipService.hasAccessPermission(bidirectionalRelationship)) + } + + @Test + fun `HasAccessPermission should return false if bidirectional and from or to access is false`() { + val bidirectionalRelationship = relationshipType( + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + true + ) + + mockTeTypeAccessResponse(fromAccess = false, toAccess = true) + assertTrue(!relationshipService.hasAccessPermission(bidirectionalRelationship)) + + mockTeTypeAccessResponse(fromAccess = true, toAccess = false) + assertTrue(!relationshipService.hasAccessPermission(bidirectionalRelationship)) + } + + @Test + fun `HasAccessPermission should call correct repository`() { + val teTypeRelationship = relationshipType( + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + true + ) + + val programRelationship = relationshipType( + RelationshipEntityType.PROGRAM_INSTANCE, + RelationshipEntityType.PROGRAM_INSTANCE, + true + ) + + val programStageRelationship = relationshipType( + RelationshipEntityType.PROGRAM_STAGE_INSTANCE, + RelationshipEntityType.PROGRAM_STAGE_INSTANCE, + true + ) + + mockTeTypeAccessResponse(fromAccess = true, toAccess = true) + relationshipService.hasAccessPermission(teTypeRelationship) + verify(trackedEntityTypeRepository, times(2)).uid(any()) + + mockProgramAccessResponse(fromAccess = true, toAccess = true) + relationshipService.hasAccessPermission(programRelationship) + verify(programRepository, times(2)).uid(any()) + + mockProgramStageAccessResponse(fromAccess = true, toAccess = true) + relationshipService.hasAccessPermission(programStageRelationship) + verify(programStageRepository, times(2)).uid(any()) + } + + @Test + fun `HasAccessPermission should return true if from access is true`() { + val unidirectionalRelationship = relationshipType( + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + false + ) + mockTeTypeAccessResponse(fromAccess = true, toAccess = false) + + assertTrue(relationshipService.hasAccessPermission(unidirectionalRelationship)) + } + + @Test + fun `HasAccessPermission should false if from access is false`() { + val unidirectionalRelationship = relationshipType( + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + RelationshipEntityType.TRACKED_ENTITY_INSTANCE, + false + ) + mockTeTypeAccessResponse(fromAccess = false, toAccess = false) + + assertTrue(!relationshipService.hasAccessPermission(unidirectionalRelationship)) + } + + private fun mockTeTypeAccessResponse(fromAccess: Boolean, toAccess: Boolean) { + whenever( + trackedEntityTypeRepository.uid(any()).blockingGet() + ) doReturnConsecutively listOf( + TrackedEntityType.builder().uid("from").access(accessData(fromAccess)).build(), + TrackedEntityType.builder().uid("to").access(accessData(toAccess)).build() + ) + } + + private fun mockProgramAccessResponse(fromAccess: Boolean, toAccess: Boolean) { + whenever( + programRepository.uid(any()).blockingGet() + ) doReturnConsecutively listOf( + Program.builder().uid("from").access(accessData(fromAccess)).build(), + Program.builder().uid("to").access(accessData(toAccess)).build() + ) + } + + private fun mockProgramStageAccessResponse(fromAccess: Boolean, toAccess: Boolean) { + whenever( + programStageRepository.uid(any()).blockingGet() + ) doReturnConsecutively listOf( + ProgramStage.builder().uid("from").access(accessData(fromAccess)).build(), + ProgramStage.builder().uid("to").access(accessData(toAccess)).build() + ) + } + + private fun relationshipType( + fromType: RelationshipEntityType, + toType: RelationshipEntityType, + bidirectional: Boolean + ) = RelationshipType.builder() + .uid("relationshipType") + .fromToName("from") + .toFromName("to") + .fromConstraint( + relationshipConstraint( + RelationshipConstraintType.FROM, + fromType + ) + ) + .toConstraint( + relationshipConstraint( + RelationshipConstraintType.TO, + toType + ) + ) + .bidirectional(bidirectional) + .build() + + private fun relationshipConstraint( + relationshipConstraintType: RelationshipConstraintType, + relationshipEntityType: RelationshipEntityType + ) = RelationshipConstraint.builder() + .relationshipType(ObjectWithUid.create("${relationshipConstraintType.name}_relationshipType")) + .constraintType(relationshipConstraintType) + .relationshipEntity(relationshipEntityType) + .apply { + when (relationshipEntityType) { + RelationshipEntityType.PROGRAM_INSTANCE -> { + program(ObjectWithUid.create("${relationshipConstraintType.name}_program")) + } + RelationshipEntityType.PROGRAM_STAGE_INSTANCE -> { + programStage(ObjectWithUid.create("${relationshipConstraintType.name}_programStage")) + } + RelationshipEntityType.TRACKED_ENTITY_INSTANCE -> { + trackedEntityType(ObjectWithUid.create("${relationshipConstraintType.name}_trackedEntityType")) + } + } + } + .build() + + private fun accessData(hasAccess: Boolean) = Access.builder() + .read(true) + .write(true) + .data(DataAccess.create(true, hasAccess)) + .build() +} diff --git a/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SMSVersionShould.kt b/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SMSVersionShould.kt new file mode 100644 index 0000000000..31c089abb6 --- /dev/null +++ b/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SMSVersionShould.kt @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.systeminfo + +import com.google.common.truth.Truth.assertThat +import org.hisp.dhis.android.core.systeminfo.SMSVersion.Companion.getValue +import org.junit.Test + +class SMSVersionShould { + + @Test + fun return_sms_version_if_patch_version_exists() { + val smsVersion = getValue("2.33.2") + assertThat(smsVersion).isEqualTo(SMSVersion.V1) + } + + @Test + fun return_latest_sms_version_if_patch_does_not_exist() { + val smsVersion = getValue("2.33.100") + assertThat(smsVersion).isEqualTo(SMSVersion.V2) + } + + @Test + fun return_null_if_patch_version_has_no_support() { + val smsVersion = getValue("2.32.1") + assertThat(smsVersion).isNull() + } + + @Test + fun return_null_if_patch_does_not_exist() { + val smsVersion = getValue("2.32.100") + assertThat(smsVersion).isNull() + } + + @Test + fun return_non_null_for_any_version_greater_than_2_32() { + DHISVersion.values() + .filter { it > DHISVersion.V2_32 } + .forEach { + assertThat(getValue(it.prefix + ".0")).isNotNull() + assertThat(getValue(it.prefix + ".9")).isNotNull() + } + } +} diff --git a/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SystemInfoShould.kt b/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SystemInfoShould.kt index ab184814c6..e70b5d1b81 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SystemInfoShould.kt +++ b/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SystemInfoShould.kt @@ -41,7 +41,7 @@ class SystemInfoShould : BaseObjectShould("systeminfo/system_info.json"), Object assertThat(systemInfo.serverDate()).isEqualTo(DateUtils.DATE_FORMAT.parse("2017-11-29T11:27:46.935")) assertThat(systemInfo.dateFormat()).isEqualTo("yyyy-mm-dd") - assertThat(systemInfo.version()).isEqualTo("2.37") + assertThat(systemInfo.version()).isEqualTo("2.38") assertThat(systemInfo.contextPath()).isEqualTo("https://play.dhis2.org/android-current") assertThat(systemInfo.systemName()).isEqualTo("DHIS 2 Demo - Sierra Leone") } diff --git a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeShould.java b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeShould.java index 3418e47d40..0dfb42cfcd 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeShould.java +++ b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityAttributeShould.java @@ -28,6 +28,7 @@ package org.hisp.dhis.android.core.trackedentity; +import org.hisp.dhis.android.core.common.AggregationType; import org.hisp.dhis.android.core.common.BaseIdentifiableObject; import org.hisp.dhis.android.core.common.BaseObjectShould; import org.hisp.dhis.android.core.common.ObjectShould; @@ -66,6 +67,7 @@ public void map_from_json_string() throws IOException, ParseException { assertThat(trackedEntityAttribute.displayInListNoProgram()).isFalse(); assertThat(trackedEntityAttribute.displayOnVisitSchedule()).isFalse(); assertThat(trackedEntityAttribute.generated()).isFalse(); + assertThat(trackedEntityAttribute.aggregationType()).isEqualTo(AggregationType.DEFAULT); assertThat(trackedEntityAttribute.inherit()).isFalse(); assertThat(trackedEntityAttribute.fieldMask()).isEqualTo("XXXXX"); assertThat(trackedEntityAttribute.optionSet().uid()).isEqualTo("xjA5E9MimMU"); diff --git a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterAPI37Should.kt b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterAPI37Should.kt new file mode 100644 index 0000000000..d0de297551 --- /dev/null +++ b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterAPI37Should.kt @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ +package org.hisp.dhis.android.core.trackedentity + +import java.io.IOException +import java.text.ParseException +import org.hisp.dhis.android.core.common.ObjectShould +import org.junit.Test + +class TrackedEntityInstanceFilterAPI37Should : + TrackedEntityInstanceFilterCommonShould("trackedentity/tracked_entity_instance_filter_v_37.json"), + ObjectShould { + + @Test + @Throws(IOException::class, ParseException::class) + override fun map_from_json_string() { + val trackedEntityInstanceFilterAPI37 = objectMapper.readValue( + jsonStream, + TrackedEntityInstanceFilterAPI37::class.java + ) + + teiFilterCommonAsserts(trackedEntityInstanceFilterAPI37.toTrackedEntityInstanceFilter()) + } +} diff --git a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterCommonShould.java b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterCommonShould.java new file mode 100644 index 0000000000..3a637b40d5 --- /dev/null +++ b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterCommonShould.java @@ -0,0 +1,70 @@ +/* + * Copyright (c) 2004-2022, University of Oslo + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * Neither the name of the HISP project nor the names of its contributors may + * be used to endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS + * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +package org.hisp.dhis.android.core.trackedentity; + +import static com.google.common.truth.Truth.assertThat; + +import org.hisp.dhis.android.core.common.AssignedUserMode; +import org.hisp.dhis.android.core.common.BaseObjectShould; +import org.hisp.dhis.android.core.common.ObjectShould; +import org.hisp.dhis.android.core.enrollment.EnrollmentStatus; +import org.hisp.dhis.android.core.event.EventStatus; + +public abstract class TrackedEntityInstanceFilterCommonShould extends BaseObjectShould implements ObjectShould { + + public TrackedEntityInstanceFilterCommonShould(String jsonPath) { + super(jsonPath); + } + + protected void teiFilterCommonAsserts(TrackedEntityInstanceFilter trackedEntityInstanceFilter) { + + assertThat(trackedEntityInstanceFilter.lastUpdated()).isEqualTo(getDate("2019-09-27T00:19:06.590")); + assertThat(trackedEntityInstanceFilter.created()).isEqualTo(getDate("2019-09-27T00:19:06.590")); + assertThat(trackedEntityInstanceFilter.uid()).isEqualTo("klhzVgls081"); + assertThat(trackedEntityInstanceFilter.code()).isEqualTo("assigned_none"); + assertThat(trackedEntityInstanceFilter.name()).isEqualTo("Ongoing foci responses"); + assertThat(trackedEntityInstanceFilter.displayName()).isEqualTo("Ongoing foci responses"); + assertThat(trackedEntityInstanceFilter.description()) + .isEqualTo("Foci response assigned to someone, and the enrollment is still active"); + assertThat(trackedEntityInstanceFilter.followUp()).isFalse(); + assertThat(trackedEntityInstanceFilter.enrollmentStatus()).isEqualTo(EnrollmentStatus.ACTIVE); + assertThat(trackedEntityInstanceFilter.sortOrder()).isEqualTo(2); + assertThat(trackedEntityInstanceFilter.program().uid()).isEqualTo("M3xtLkYBlKI"); + assertThat(trackedEntityInstanceFilter.enrollmentCreatedPeriod().periodFrom()).isEqualTo(-5); + assertThat(trackedEntityInstanceFilter.enrollmentCreatedPeriod().periodTo()).isEqualTo(5); + + TrackedEntityInstanceEventFilter eventFilter = trackedEntityInstanceFilter.eventFilters().get(0); + assertThat(eventFilter.programStage()).isEqualTo("uvMKOn1oWvd"); + assertThat(eventFilter.assignedUserMode()).isEqualTo(AssignedUserMode.ANY); + assertThat(eventFilter.eventStatus()).isEqualTo(EventStatus.OVERDUE); + + assertThat(eventFilter.eventCreatedPeriod().periodFrom()).isEqualTo(-11); + assertThat(eventFilter.eventCreatedPeriod().periodTo()).isEqualTo(11); + } +} \ No newline at end of file diff --git a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterShould.java b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterShould.java index 5ec84ef617..21a8e3b283 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterShould.java +++ b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/TrackedEntityInstanceFilterShould.java @@ -28,20 +28,27 @@ package org.hisp.dhis.android.core.trackedentity; +import static com.google.common.truth.Truth.assertThat; + +import com.google.common.collect.Lists; + import org.hisp.dhis.android.core.common.AssignedUserMode; -import org.hisp.dhis.android.core.common.BaseIdentifiableObject; -import org.hisp.dhis.android.core.common.BaseObjectShould; +import org.hisp.dhis.android.core.common.DateFilterPeriod; +import org.hisp.dhis.android.core.common.DatePeriodType; +import org.hisp.dhis.android.core.common.FilterPeriod; import org.hisp.dhis.android.core.common.ObjectShould; +import org.hisp.dhis.android.core.common.ObjectWithUid; +import org.hisp.dhis.android.core.common.RelativePeriod; import org.hisp.dhis.android.core.enrollment.EnrollmentStatus; import org.hisp.dhis.android.core.event.EventStatus; +import org.hisp.dhis.android.core.organisationunit.OrganisationUnitMode; import org.junit.Test; +import org.mockito.internal.util.collections.Sets; import java.io.IOException; import java.text.ParseException; -import static com.google.common.truth.Truth.assertThat; - -public class TrackedEntityInstanceFilterShould extends BaseObjectShould implements ObjectShould { +public class TrackedEntityInstanceFilterShould extends TrackedEntityInstanceFilterCommonShould implements ObjectShould { public TrackedEntityInstanceFilterShould() { super("trackedentity/tracked_entity_instance_filter.json"); @@ -53,29 +60,89 @@ public void map_from_json_string() throws IOException, ParseException { TrackedEntityInstanceFilter trackedEntityInstanceFilter = objectMapper.readValue(jsonStream, TrackedEntityInstanceFilter.class); - assertThat(trackedEntityInstanceFilter.lastUpdated()).isEqualTo( - BaseIdentifiableObject.DATE_FORMAT.parse("2019-09-27T00:19:06.590")); - assertThat(trackedEntityInstanceFilter.created()).isEqualTo( - BaseIdentifiableObject.DATE_FORMAT.parse("2019-09-27T00:19:06.590")); - assertThat(trackedEntityInstanceFilter.uid()).isEqualTo("klhzVgls081"); - assertThat(trackedEntityInstanceFilter.code()).isEqualTo("assigned_none"); - assertThat(trackedEntityInstanceFilter.name()).isEqualTo("Ongoing foci responses"); - assertThat(trackedEntityInstanceFilter.displayName()).isEqualTo("Ongoing foci responses"); - assertThat(trackedEntityInstanceFilter.description()) - .isEqualTo("Foci response assigned to someone, and the enrollment is still active"); - assertThat(trackedEntityInstanceFilter.followUp()).isFalse(); - assertThat(trackedEntityInstanceFilter.enrollmentStatus()).isEqualTo(EnrollmentStatus.ACTIVE); - assertThat(trackedEntityInstanceFilter.sortOrder()).isEqualTo(2); - assertThat(trackedEntityInstanceFilter.program().uid()).isEqualTo("M3xtLkYBlKI"); - assertThat(trackedEntityInstanceFilter.enrollmentCreatedPeriod().periodFrom()).isEqualTo(-15); - assertThat(trackedEntityInstanceFilter.enrollmentCreatedPeriod().periodTo()).isEqualTo(15); - - TrackedEntityInstanceEventFilter eventFilter = trackedEntityInstanceFilter.eventFilters().get(0); - assertThat(eventFilter.programStage()).isEqualTo("uvMKOn1oWvd"); - assertThat(eventFilter.assignedUserMode()).isEqualTo(AssignedUserMode.ANY); - assertThat(eventFilter.eventStatus()).isEqualTo(EventStatus.OVERDUE); + teiFilterCommonAsserts(trackedEntityInstanceFilter); + assertThat(trackedEntityInstanceFilter).isEqualTo(teiFilterSample()); + } - assertThat(eventFilter.eventCreatedPeriod().periodFrom()).isEqualTo(-11); - assertThat(eventFilter.eventCreatedPeriod().periodTo()).isEqualTo(11); + private static TrackedEntityInstanceFilter teiFilterSample() { + return TrackedEntityInstanceFilter.builder() + .uid("klhzVgls081") + .code("assigned_none") + .name("Ongoing foci responses") + .displayName("Ongoing foci responses") + .created(getDate("2019-09-27T00:19:06.590")) + .lastUpdated(getDate("2019-09-27T00:19:06.590")) + .description("Foci response assigned to someone, and the enrollment is still active") + .sortOrder(2) + .program(ObjectWithUid.create("M3xtLkYBlKI")) + .eventFilters(Lists.newArrayList(TrackedEntityInstanceEventFilter.builder() + .trackedEntityInstanceFilter("klhzVgls081") + .programStage("uvMKOn1oWvd") + .eventStatus(EventStatus.OVERDUE) + .assignedUserMode(AssignedUserMode.ANY) + .eventCreatedPeriod(FilterPeriod.builder() + .periodFrom(-11) + .periodTo(11) + .build()) + .build())) + .entityQueryCriteria(EntityQueryCriteria.builder() + .followUp(Boolean.FALSE) + .enrollmentStatus(EnrollmentStatus.ACTIVE) + .eventStatus(EventStatus.COMPLETED) + .programStage("uvMKOn1oWvd") + .enrollmentCreatedDate(DateFilterPeriod.builder() + .period(RelativePeriod.TODAY) + .startDate(getDate("2014-05-01T00:00:00.000")) + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .endDate(getDate("2019-03-20T00:00:00.000")) + .build()) + .enrollmentIncidentDate(DateFilterPeriod.builder() + .period(RelativePeriod.TODAY) + .startDate(getDate("2014-05-01T00:00:00.000")) + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .endDate(getDate("2019-03-20T00:00:00.000")) + .build()) + .ouMode(OrganisationUnitMode.SELECTED) + .trackedEntityType("trackedEntityTypeUid") + .assignedUserMode(AssignedUserMode.PROVIDED) + .trackedEntityInstances(Lists.newArrayList("a3kGcGDCuk7", "a3kGcGDCuk8")) + .displayColumnOrder(Lists.newArrayList("eventDate", "status")) + .order("dueDate:asc,createdDate:desc") + .organisationUnit("orgUnitUid") + .eventDate(DateFilterPeriod.builder() + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .build()) + .lastUpdatedDate(DateFilterPeriod.builder() + .startBuffer(-5) + .endBuffer(5) + .type(DatePeriodType.RELATIVE) + .build()) + .attributeValueFilters(Lists.newArrayList(AttributeValueFilter.builder() + .ew("aa") + .sw("ac") + .like("abc") + .lt("20") + .le("20") + .attribute("w75KJ2mc4zz") + .gt("10") + .ge("10") + .dateFilter(DateFilterPeriod.builder() + .period(RelativePeriod.LAST_WEEK) + .endBuffer(5) + .startBuffer(-5) + .type(DatePeriodType.RELATIVE) + .startDate(getDate("2014-05-01T00:00:00.000")) + .endDate(getDate("2019-03-20T00:00:00.000")) + .build()) + .in(Sets.newSet("Norway", "India")) + .build())) + .build()) + .build(); } } \ No newline at end of file diff --git a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeHandlerShould.java b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeHandlerShould.java index caa36d3452..4ab67db6af 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeHandlerShould.java +++ b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityAttributeHandlerShould.java @@ -28,11 +28,17 @@ package org.hisp.dhis.android.core.trackedentity.internal; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore; import org.hisp.dhis.android.core.arch.handlers.internal.IdentifiableHandlerImpl; +import org.hisp.dhis.android.core.arch.handlers.internal.OrderedLinkHandler; import org.hisp.dhis.android.core.common.Access; import org.hisp.dhis.android.core.common.ObjectStyle; +import org.hisp.dhis.android.core.common.ObjectWithUid; import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttribute; +import org.hisp.dhis.android.core.trackedentity.TrackedEntityAttributeLegendSetLink; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -43,15 +49,15 @@ import java.util.ArrayList; import java.util.List; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(JUnit4.class) public class TrackedEntityAttributeHandlerShould { @Mock private IdentifiableObjectStore trackedEntityAttributeStore; + @Mock + private OrderedLinkHandler trackedEntityAttributeLegendSetLinkHandler; + @Mock private ObjectStyle objectStyle; @@ -67,7 +73,10 @@ public class TrackedEntityAttributeHandlerShould { @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); - trackedEntityAttributeHandler = new TrackedEntityAttributeHandler(trackedEntityAttributeStore); + trackedEntityAttributeHandler = new TrackedEntityAttributeHandler( + trackedEntityAttributeStore, + trackedEntityAttributeLegendSetLinkHandler + ); trackedEntityAttribute = TrackedEntityAttribute.builder() .uid("test_tracked_entity_attribute_uid") @@ -87,7 +96,7 @@ public void setUp() throws Exception { @Test public void extend_identifiable_handler_impl() { IdentifiableHandlerImpl genericHandler = - new TrackedEntityAttributeHandler(trackedEntityAttributeStore); + new TrackedEntityAttributeHandler(trackedEntityAttributeStore, trackedEntityAttributeLegendSetLinkHandler); } @Test diff --git a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterHandlerShould.java b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterHandlerShould.java index a2b0c18ed2..199a3d2b35 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterHandlerShould.java +++ b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceFilterHandlerShould.java @@ -28,6 +28,11 @@ package org.hisp.dhis.android.core.trackedentity.internal; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + import com.google.common.collect.Lists; import org.hisp.dhis.android.core.arch.db.stores.internal.IdentifiableObjectStore; @@ -36,6 +41,8 @@ import org.hisp.dhis.android.core.arch.handlers.internal.IdentifiableHandlerImpl; import org.hisp.dhis.android.core.common.ObjectStyle; import org.hisp.dhis.android.core.common.ObjectWithUid; +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter; +import org.hisp.dhis.android.core.trackedentity.EntityQueryCriteria; import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceEventFilter; import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter; import org.junit.Before; @@ -48,11 +55,6 @@ import java.util.ArrayList; import java.util.List; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.eq; -import static org.mockito.Mockito.verify; -import static org.mockito.Mockito.when; - @RunWith(JUnit4.class) public class TrackedEntityInstanceFilterHandlerShould { @@ -65,6 +67,9 @@ public class TrackedEntityInstanceFilterHandlerShould { @Mock private HandlerWithTransformer trackedEntityInstanceEventFilterHandler; + @Mock + private HandlerWithTransformer attributeValueFilterHandler; + @Mock private TrackedEntityInstanceEventFilter eventFilter; @@ -78,7 +83,8 @@ public void setUp() throws Exception { MockitoAnnotations.initMocks(this); trackedEntityInstanceFilterHandler = new TrackedEntityInstanceFilterHandler( trackedEntityInstanceFilterStore, - trackedEntityInstanceEventFilterHandler); + trackedEntityInstanceEventFilterHandler, + attributeValueFilterHandler); eventFilters = Lists.newArrayList(eventFilter); @@ -89,6 +95,7 @@ public void setUp() throws Exception { .name("name") .displayName("display_name") .eventFilters(eventFilters) + .entityQueryCriteria(EntityQueryCriteria.builder().build()) .build(); when(trackedEntityInstanceFilterStore.updateOrInsert(any())).thenReturn(HandleAction.Insert); @@ -101,7 +108,7 @@ public void setUp() throws Exception { public void extend_identifiable_handler_impl() { IdentifiableHandlerImpl genericHandler = new TrackedEntityInstanceFilterHandler(trackedEntityInstanceFilterStore, - trackedEntityInstanceEventFilterHandler); + trackedEntityInstanceEventFilterHandler, attributeValueFilterHandler); } @Test diff --git a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceHandlerShould.kt b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceHandlerShould.kt index 03ce7cc631..75e4b96e4d 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceHandlerShould.kt +++ b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/internal/TrackedEntityInstanceHandlerShould.kt @@ -136,6 +136,7 @@ class TrackedEntityInstanceHandlerShould { verify(trackedEntityInstanceStore, times(1)).deleteIfExists(any()) verify(trackedEntityInstanceStore, never()).updateOrInsert(any()) verify(trackedEntityAttributeValueHandler, never()).handleMany(any(), any()) + verify(relationshipHandler, times(1)).deleteLinkedRelationships(any()) verifyNoMoreInteractions(trackedEntityAttributeValueStore) // verify that enrollment handler is never called @@ -157,6 +158,7 @@ class TrackedEntityInstanceHandlerShould { // verify that tracked entity instance store is only called with update verify(trackedEntityInstanceStore, times(1)).updateOrInsert(any()) verify(trackedEntityInstanceStore, never()).deleteIfExists(any()) + verify(relationshipHandler, never()).deleteLinkedRelationships(any()) verify(trackedEntityAttributeValueHandler, times(1)).handleMany(any(), any()) verify(trackedEntityAttributeValueStore, times(1)) .deleteByInstanceAndNotInAccessibleAttributes(any(), any(), any(), any()) diff --git a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/search/TrackedEntityInstanceQueryRepositoryScopeHelperShould.kt b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/search/TrackedEntityInstanceQueryRepositoryScopeHelperShould.kt index 71573c2c0c..14970ecfa1 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/trackedentity/search/TrackedEntityInstanceQueryRepositoryScopeHelperShould.kt +++ b/core/src/test/java/org/hisp/dhis/android/core/trackedentity/search/TrackedEntityInstanceQueryRepositoryScopeHelperShould.kt @@ -29,10 +29,12 @@ package org.hisp.dhis.android.core.trackedentity.search import com.google.common.truth.Truth.assertThat import org.hisp.dhis.android.core.common.AssignedUserMode +import org.hisp.dhis.android.core.common.DateFilterPeriod import org.hisp.dhis.android.core.common.FilterPeriod import org.hisp.dhis.android.core.common.ObjectWithUid import org.hisp.dhis.android.core.enrollment.EnrollmentStatus import org.hisp.dhis.android.core.event.EventStatus +import org.hisp.dhis.android.core.trackedentity.EntityQueryCriteria import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceEventFilter import org.hisp.dhis.android.core.trackedentity.TrackedEntityInstanceFilter import org.junit.Assert.fail @@ -57,9 +59,18 @@ class TrackedEntityInstanceQueryRepositoryScopeHelperShould { val filter = TrackedEntityInstanceFilter.builder() .uid(filterUid) .program(ObjectWithUid.create(programId)) - .enrollmentStatus(enrollmentStatus) - .followUp(followUp) - .enrollmentCreatedPeriod(FilterPeriod.create(-2, 5)) + .entityQueryCriteria( + EntityQueryCriteria.builder() + .enrollmentStatus(enrollmentStatus) + .followUp(followUp) + .enrollmentCreatedDate( + DateFilterPeriod.builder() + .startBuffer(-2) + .endBuffer(5) + .build() + ) + .build() + ) .build() val updatedScope = TrackedEntityInstanceQueryRepositoryScopeHelper.addTrackedEntityInstanceFilter(scope, filter) @@ -88,6 +99,7 @@ class TrackedEntityInstanceQueryRepositoryScopeHelperShould { .eventCreatedPeriod(FilterPeriod.create(-5, 2)).build() ) ) + .entityQueryCriteria(EntityQueryCriteria.builder().build()) .build() val updatedScope = TrackedEntityInstanceQueryRepositoryScopeHelper.addTrackedEntityInstanceFilter(scope, filter) @@ -128,6 +140,7 @@ class TrackedEntityInstanceQueryRepositoryScopeHelperShould { TrackedEntityInstanceEventFilter.builder().assignedUserMode(AssignedUserMode.ANY).build() ) ) + .entityQueryCriteria(EntityQueryCriteria.builder().build()) .build() val updatedScope = TrackedEntityInstanceQueryRepositoryScopeHelper.addTrackedEntityInstanceFilter(scope, filter) diff --git a/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SMSVersionShould.java b/core/src/test/java/org/hisp/dhis/android/testapp/trackedentity/AttributeValueFilterPublicAccessShould.java similarity index 64% rename from core/src/test/java/org/hisp/dhis/android/core/systeminfo/SMSVersionShould.java rename to core/src/test/java/org/hisp/dhis/android/testapp/trackedentity/AttributeValueFilterPublicAccessShould.java index c83218e17a..4084fe8583 100644 --- a/core/src/test/java/org/hisp/dhis/android/core/systeminfo/SMSVersionShould.java +++ b/core/src/test/java/org/hisp/dhis/android/testapp/trackedentity/AttributeValueFilterPublicAccessShould.java @@ -26,35 +26,34 @@ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -package org.hisp.dhis.android.core.systeminfo; +package org.hisp.dhis.android.testapp.trackedentity; -import org.junit.Test; +import org.hisp.dhis.android.core.trackedentity.AttributeValueFilter; +import org.hisp.dhis.android.testapp.arch.BasePublicAccessShould; +import org.mockito.Mock; -import static com.google.common.truth.Truth.assertThat; +public class AttributeValueFilterPublicAccessShould extends BasePublicAccessShould { -public class SMSVersionShould { + @Mock + private AttributeValueFilter object; - @Test - public void return_sms_version_if_patch_version_exists() { - SMSVersion smsVersion = SMSVersion.getValue("2.33.2"); - assertThat(smsVersion).isEqualTo(SMSVersion.V1); + @Override + public AttributeValueFilter object() { + return object; } - @Test - public void return_latest_sms_version_if_patch_does_not_exist() { - SMSVersion smsVersion = SMSVersion.getValue("2.33.100"); - assertThat(smsVersion).isEqualTo(SMSVersion.V2); + @Override + public void has_public_create_method() { + AttributeValueFilter.create(null); } - @Test - public void return_null_if_patch_version_has_no_support() { - SMSVersion smsVersion = SMSVersion.getValue("2.32.1"); - assertThat(smsVersion).isNull(); + @Override + public void has_public_builder_method() { + AttributeValueFilter.builder(); } - @Test - public void return_null_if_patch_does_not_exist() { - SMSVersion smsVersion = SMSVersion.getValue("2.32.100"); - assertThat(smsVersion).isNull(); + @Override + public void has_public_to_builder_method() { + object().toBuilder(); } } \ No newline at end of file diff --git a/docs/content/developer/analytics.md b/docs/content/developer/analytics.md index 1addea664c..d8ae5b1f62 100644 --- a/docs/content/developer/analytics.md +++ b/docs/content/developer/analytics.md @@ -297,7 +297,7 @@ Properties included in the `GridDimensionalResponse` object: | **Data:** | Indicators | Yes* | | | DataElements | Yes | | | DataElements details | Yes | -| | Event data items | No | +| | Event data items | Yes | | | Program indicators | Yes** | | | DataSets: Reporting rate | No | | | DataSets: Reporting rate on time | No | diff --git a/docs/content/developer/getting-started.md b/docs/content/developer/getting-started.md index cfb2b1e0fb..175dc39cc4 100644 --- a/docs/content/developer/getting-started.md +++ b/docs/content/developer/getting-started.md @@ -6,7 +6,7 @@ Include dependency in build.gradle. ```gradle dependencies { - implementation "org.hisp.dhis:android-core:1.6.1" + implementation "org.hisp.dhis:android-core:1.6.2" ... } ``` diff --git a/docs/dhis2_android_sdk_developer_guide_INDEX.md b/docs/dhis2_android_sdk_developer_guide_INDEX.md index 7380bde2e3..a3494a0a49 100644 --- a/docs/dhis2_android_sdk_developer_guide_INDEX.md +++ b/docs/dhis2_android_sdk_developer_guide_INDEX.md @@ -7,7 +7,7 @@ month: June keywords: [DHIS2, Android] commit: version: master -applicable_txt: 'Applicable to version 1.6.1' +applicable_txt: 'Applicable to version 1.6.2' ---