Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 55 additions & 31 deletions docs/content/developer/analytics.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,17 @@ This module follows similar concepts to analytics endpoint in the web API. They

For example, a basic query that get the number of "ANC 1st visit" (DataElement "fbfJHSPpUQD") in the last 3 months (RelativePeriod) and filtered by a the orgunit "Ngelehun CHC" (Absolute OrganisationUnit "DiszpKrYNg8") would be like this:

```java
```kotlin
d2.analyticsModule().analytics()
.withDimension(new DimensionItem.DataItem.DataElementItem("fbfJHSPpUQD"))
.withDimension(new DimensionItem.PeriodItem.Relative(RelativePeriod.LAST_3_MONTHS))
.withFilter(new DimensionItem.OrganisationUnitItem.Absolute("DiszpKrYNg8"))
.evaluate();
.withDimension(DimensionItem.DataItem.DataElementItem("fbfJHSPpUQD"))
.withDimension(DimensionItem.PeriodItem.Relative(RelativePeriod.LAST_3_MONTHS))
.withFilter(DimensionItem.OrganisationUnitItem.Absolute("DiszpKrYNg8"))
.suspendEvaluate()
```

The engine will return a `Result` object containing either a `DimensionalResponse` or an `AnalyticsException`. Let's take a look at the structure of the `DimensionalResponse`. We use the Kotlin representation for convenience, but the Java representation would be very similar:
The engine will return a `Result` object containing either a `DimensionalResponse` or an `AnalyticsException`. Let's take a look at the structure of the `DimensionalResponse`:

```kt
```kotlin
DimensionalResponse(
metadata = mapOf(
"fbfJHSPpUQD" to MetadataItem.DataElementItem,
Expand Down Expand Up @@ -76,21 +76,21 @@ Properties included in the `DimensionalResponse` object:

DimensionItems can be used either as dimensions or as filters. And multiple items of the same dimension can be combined in the same query. For example, this query gets "ANC 1st visit" (DataElement "fbfJHSPpUQD") and "ANC 1-3 Dropout Rate" (Indicator "ReUHfIn0pTQ") disaggregated by the category "Location: Fixed/Outreach" (Category "fMZEcRHuamy") using the options "Fixed" (CategoryOption "qkPbeWaFsnU") and "Outreach" (CategoryOption "wbrDrL2aYEc") within the last 3 months (Relative Period) in the UserOrganisationUnit (Relative OrganisationUnit), classifying the values by data item legendSet and overriding the aggregation type:

```java
```kotlin
d2.analyticsModule().analytics()
.withDimension(new DimensionItem.DataItem.DataElementItem("fbfJHSPpUQD"))
.withDimension(new DimensionItem.DataItem.IndicatorItem("ReUHfIn0pTQ"))
.withDimension(new DimensionItem.CategoryItem("fMZEcRHuamy", "qkPbeWaFsnU"))
.withDimension(new DimensionItem.CategoryItem("fMZEcRHuamy", "wbrDrL2aYEc"))
.withDimension(DimensionItem.DataItem.DataElementItem("fbfJHSPpUQD"))
.withDimension(DimensionItem.DataItem.IndicatorItem("ReUHfIn0pTQ"))
.withDimension(DimensionItem.CategoryItem("fMZEcRHuamy", "qkPbeWaFsnU"))
.withDimension(DimensionItem.CategoryItem("fMZEcRHuamy", "wbrDrL2aYEc"))

.withFilter(new DimensionItem.PeriodItem.Relative(RelativePeriod.LAST_3_MONTHS))
.withFilter(new DimensionItem.OrganisationUnitItem.Relative(RelativeOrganisationUnit.USER_ORGUNIT))
.withFilter(DimensionItem.PeriodItem.Relative(RelativePeriod.LAST_3_MONTHS))
.withFilter(DimensionItem.OrganisationUnitItem.Relative(RelativeOrganisationUnit.USER_ORGUNIT))

.withLegendStrategy(AnalyticsLegendStrategy.ByDataItem.INSTANCE)
.withLegendStrategy(AnalyticsLegendStrategy.ByDataItem)

.withAggregationType(AggregationType.LAST)

.evaluate();
.suspendEvaluate()
```

The evaluator imposes some restrictions to the parameters passed as dimensions or filters (they are similar to those imposed by the analtyics web api):
Expand All @@ -103,13 +103,37 @@ Additionally, the query is evaluated against the local metadata and data, which
1. DimensionItems (DataElement, Indicator, OrganisationUnit, ...) must be downloaded in the device. By default, the SDK downloads all the dataSets and programs accessible to the user and the related metadata.
2. Data must be downloaded in the device. The evaluation only takes into account the data stored in the local database.

There are three options to define the legendSet strategy. The class `AnalyticsLegendStrategy` is a sealed class in Kotlin, so the keyword `INSTANCE` must be appended at the end of the object values when coding in Java. Code examples:
#### Program indicator disaggregations { #android_sdk_program_indicator_disaggregations }

```java
A program indicator can declare a category combination and a set of *category mappings*: each mapping assigns, for one category, a filter expression to every category option. When a query includes a program indicator as a data item together with category dimensions, the engine resolves those mappings and applies the corresponding expressions as additional conditions.

The relevant metadata is downloaded with the programs and exposed through:

- `ProgramIndicator.categoryCombo()` and `ProgramIndicator.attributeCombo()`: the category combinations the indicator
is disaggregated by. The new filters `byCategoryCombo()` and `byAttributeCombo()` are available in
`ProgramIndicatorCollectionRepository`.
- `ProgramIndicator.categoryMappingIds()`: the uids of the `CategoryMapping` objects that apply to the indicator.
- `CategoryMapping` (`uid`, `program`, `categoryId`, `mappingName`, `optionMappings`) and `CategoryOptionMapping`
(`categoryMapping`, `optionId`, `filter`).

Querying a disaggregated indicator is no different from any other query: just add the category dimensions.

```kotlin
d2.analyticsModule().analytics()
.withDimension(DimensionItem.DataItem.ProgramIndicatorItem("programIndicatorUid"))
.withDimension(DimensionItem.CategoryItem("categoryUid", "categoryOptionUid1"))
.withDimension(DimensionItem.CategoryItem("categoryUid", "categoryOptionUid2"))
.withFilter(DimensionItem.PeriodItem.Relative(RelativePeriod.LAST_3_MONTHS))
.suspendEvaluate()
```

There are three options to define the legendSet strategy. `AnalyticsLegendStrategy` is a sealed class; from Java, the object values require the `INSTANCE` suffix (`AnalyticsLegendStrategy.ByDataItem.INSTANCE`). Code examples:

```kotlin
d2.analyticsModule().analytics()
.withLegendStrategy(AnalyticsLegendStrategy.ByDataItem.INSTANCE) // Data items use their own LegendSet
.withLegendStrategy(AnalyticsLegendStrategy.None.INSTANCE) // LegendSets are not used
.withLegendStrategy(new AnalyticsLegendStrategy.Fixed("fqs276KXCXi")) // The provided LegendSet will be used for all data items
.withLegendStrategy(AnalyticsLegendStrategy.ByDataItem) // Data items use their own LegendSet
.withLegendStrategy(AnalyticsLegendStrategy.None) // LegendSets are not used
.withLegendStrategy(AnalyticsLegendStrategy.Fixed("fqs276KXCXi")) // The provided LegendSet will be used for all data items
```

### Visualization analytics { #android_sdk_visualization_analytics }
Expand Down Expand Up @@ -138,17 +162,17 @@ The expected representation of the visualization would be something like this:

We can get the result of the visualization by calling the "visualizations" repository within the analtyics module. Optionally, we can override the values for Period and OrganisationUnit. This is useful to expose filters in the UI to allow easy modifications of the results.

```java
```kotlin
d2.analyticsModule().visualizations()
.withVisualization("SwtkWZFhrFQ")
[.withPeriods()]
[.withOrganisationUnits()]
.evaluate();
.suspendEvaluate()
```

The method will return a `Result` with two possible values: a `GridAnalyticsResponse` and an `AnalyticsResponse`. Let's take a look at the structure of the `GridAnalyticsResponse`. We use the Kotlin representation for convenience:

```kt
```kotlin
GridAnalyticsResponse(
metadata = mapOf(
"fbfJHSPpUQD" to MetadataItem.DataElementItem,
Expand Down Expand Up @@ -517,7 +541,7 @@ A common use-case is to generate a list of event or enrollments that meet a cert

For example, a query that contains all the ACTIVE enrollments in the program "fbfJHSPpUQD" whose attribute "p4mRWMtCxtB" has a value between 40 and 50 would look like this. Note that the status is included as a filter, so there is not an explicit column for it.

```kt
```kotlin
d2.analyticsModule().trackerLineList()
.withEnrollmentOutput("fbfJHSPpUQD")
.withFilter(
Expand All @@ -537,12 +561,12 @@ d2.analyticsModule().trackerLineList()
),
),
)
.evaluate()
.suspendEvaluate()
```

The response is a Result object of TrackerLineListResponse, which has the following structure:

```kt
```kotlin
TrackerLineListResponse(
metadata = mapOf(
"p4mRWMtCxtB" to MetadataItem.TrackedEntityAttributeItem
Expand Down Expand Up @@ -575,7 +599,7 @@ Optionally, it is possible to use a TrackerVisualization object (called EventVis

For example, this query uses the configuration in the TrackerVisualization "s85urBIkN0z" and adds or overrides the column ProgramStatusItem filtering by ACTIVE.

```kt
```kotlin
d2.analyticsModule().trackerLineList()
.withTrackerVisualization("s85urBIkN0z")
.withColumn(
Expand All @@ -585,7 +609,7 @@ d2.analyticsModule().trackerLineList()
)
)
)
.evaluate()
.suspendEvaluate()
```

In order to use the TrackerVisualization objects, they must be set in the "Analytics" section of the Android Settings webapp. Currently, it is not possible to download on-demand visualizations from the server, just to downloaded through the Android Settings webapp.
Expand All @@ -598,14 +622,14 @@ A common use-case is to generate an event line list of a repeatable stage in the

For example, let's suppose we have a repeatable stage with two dataElements (height and weight) and one indicator based on those values (BMI, Body Mass Index). We would like to show the evolution of those values across the events

```java
```kotlin
d2.analyticsModule().eventLineList()
.byProgramStage().eq("stage_id")
.byTrackedEntityInstance().eq("tei_id")
.withDataElement("height_id")
.withDataElement("weight_id")
.withProgramIndicator("BMI_id")
.evaluate();
.suspendEvaluate()
```

The result would be a list of events with the evaluated values (dataelement and indicators) as well as some handy `displayName` properties to display the result in a table or chart.
8 changes: 4 additions & 4 deletions docs/content/developer/apk-distribution.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,14 @@ The APK distribution app allows the definition of different versions by user gro

The app can get this version by using the LatestAppVersion repository:

```kt
d2.settingModule().latestAppVersion().get()
```kotlin
d2.settingModule().latestAppVersion().suspendGet()
```

This version is updated with each metadata sync. To check for updates without triggering a full metadata sync, this method can be used:

```kt
d2.settingModule().latestAppVersion().download()
```kotlin
d2.settingModule().latestAppVersion().suspendDownload()
```

Once the download is completed, the version can be read from the database as usual.
Expand Down
1 change: 1 addition & 0 deletions docs/content/developer/compatibility.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ Compatibility table between DHIS2 Android SDK library, DHIS2 core and Android SD

| SDK | DHIS2 core | Android SDK | Rule engine* |
|--------|--------------|-------------|-----------------|
| 1.15.X | 2.30 -> 2.43 | 23 - 37 | 2.0.47 - 2.0.48 |
| 1.14.X | 2.30 -> 2.43 | 23 - 36 | 2.0.47 - 2.0.48 |
| 1.13.X | 2.30 -> 2.42 | 21 - 35 | 2.0.47 - 2.0.48 |
| 1.12.X | 2.30 -> 2.42 | 21 - 35 | 2.0.47 - 2.0.48 |
Expand Down
31 changes: 16 additions & 15 deletions docs/content/developer/data-store.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Data Store { #android_sdk_data_store }

```java
```kotlin
d2.dataStoreModule().dataStore()
```

Expand All @@ -18,45 +18,46 @@ The behavior is similar to the rest of the data:
2. Read or modify the DataStore entries.
3. If there are any modifications in the entries, call the method to upload the entries to the server.

```java
`DataStoreEntry.value()` holds the raw JSON value of the entry, exactly as stored in the server DataStore. Apps are expected to parse it according to the namespace schema.

```kotlin
// Download
d2.dataStoreModule().dataStoreDownloader()
.byNamespace().in("namespace1", "namespace2")
.download();
.byNamespace().`in`("namespace1", "namespace2")
.flowDownload()

// Read example
List<DataStoreEntry> entries = d2.dataStoreModule().dataStore()
val entries = d2.dataStoreModule().dataStore()
.byNamespace().eq("namespace1")
.byKey().in("key1", "key2")
.get()
.byKey().`in`("key1", "key2")
.suspendGet()

// Write example
d2.dataStoreModule().dataStore()
.value("namespace1", "key1")
.set("value");
.suspendSet("value")

// Upload
d2.dataStoreModule().dataStore().upload();
d2.dataStoreModule().dataStore().flowUpload()
```

## Local Data Store { #android_sdk_local_data_store }

```java
```kotlin
d2.dataStoreModule().localDataStore()
```

This repository is ideal for storing any kind of information.

This collection supports key value pairs (`KeyValuePair`) and it can be stored as others values in the SDK.

```java
```kotlin
// Access the object repository
LocalDataStoreObjectRepository objectRepository =
d2.dataStoreModule().localDataStore().value("key");
val objectRepository = d2.dataStoreModule().localDataStore().value("key")

// Set or update a key value pair
objectRepository.set("value");
objectRepository.suspendSet("value")

// Remove key value pair
objectRepository.delete();
objectRepository.suspendDelete()
```
4 changes: 2 additions & 2 deletions docs/content/developer/database.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The database can be exported and imported in a different device.

One of the main use cases of this functionality is debugging: sometimes it is hard to know the reason for a sync problem or a bug, and it is very useful to replicate the issue in an emulator or a different device.

```kt
```kotlin
// Export database
val database = d2.maintenanceModule().databaseImportExport().exportLoggedUserDatabase()

Expand All @@ -39,7 +39,7 @@ val metadata = d2.maintenanceModule().databaseImportExport().importDatabase(data
// The metadata object contains information about the database (serverUrl, username,...)

// Once the database is imported, it is possible to login as usual
d2.userModule().login("username", "password", "serverUrl")
d2.userModule().suspendLogIn("username", "password", "serverUrl")
```

The export process encrypts the database using ZIP encryption, so the database file can't be read unless the right user credentials are provided.
Expand Down
42 changes: 21 additions & 21 deletions docs/content/developer/dhis2-services.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,22 @@ SDK repositories give access to metadata and allow to create and modify data, bu

In order to make this task easier, the SDK includes some services that evaluate pure DHIS2 business logic. They are located in their related module and usually are suffixed by `Service`. Some examples of this:

```java
```kotlin
// Event services
d2.eventModule().eventService()
| .canAddEventToEnrollment("enrollment_uid", "program_stage_uid")
| .getEditableStatus("event_uid")
| .isEditable("event_uid")
| .hasDataWriteAccess("event_uid")
| .suspendCanAddEventToEnrollment("enrollment_uid", "program_stage_uid")
| .suspendGetEditableStatus("event_uid")
| .suspendIsEditable("event_uid")
| .suspendHasDataWriteAccess("event_uid")

// Enrollment services
d2.enrollmentModule().enrollmentService()
| .getEnrollmentAccess("tracked_entity_instance_uid", "program_uid")
| .isOpen("enrollment_uid")
| .suspendGetEnrollmentAccess("tracked_entity_instance_uid", "program_uid")
| .suspendIsOpen("enrollment_uid")

// Tracked entity instance services
d2.trackedEntityModule().trackedEntityInstanceService()
| .inheritAttributes("from_tei_uid", "to_tei_uid", "program_uid")
| .blockingInheritAttributes("from_tei_uid", "to_tei_uid", "program_uid")
```

Check the javadoc documentation in the IDE to know more details about each method.
Expand All @@ -32,23 +32,23 @@ The SDK include a enum helper class called `ValueType`. This class defines all t

To access the type of value you can simply access it through the methods of the valueType.

```java
valueType.isInteger();
valueType.isDecimal();
valueType.isNumeric();
valueType.isBoolean();
valueType.isText();
valueType.isDate();
valueType.isFile();
valueType.isCoordinate();
valueType.isGeo();
valueType.isJson();
```kotlin
valueType.isInteger
valueType.isDecimal
valueType.isNumeric
valueType.isBoolean
valueType.isText
valueType.isDate
valueType.isFile
valueType.isCoordinate
valueType.isGeo
valueType.isJson
```

To validate a value starting from its valueType it can be done in the following way:

```java
valueType.getValidator().validate("value");
```kotlin
valueType.validator.validate("value")
```

This validator will return a `Result` which can be `Success` or `Failure`. In addition each `ValueType` will return different types of errors making it easier to identify what the problem is if the value does not pass validation.
Loading