From be6074eb1cb278001510acaecb180540ecd3ae80 Mon Sep 17 00:00:00 2001 From: Enrico Date: Wed, 8 Apr 2026 11:40:58 +0200 Subject: [PATCH] feat: Add collectInOrgUnitGroups to Expression [DHIS2-21245] --- api/expression-parser.api | 1 + build.gradle.kts | 2 +- .../org/hisp/dhis/lib/expression/Expression.kt | 6 ++++++ .../org/hisp/dhis/lib/expression/eval/Api.kt | 14 ++++++++++++++ .../dhis/lib/expression/function/HasValueTest.kt | 13 +++++++++++++ .../ExpressionJs.kt | 4 ++++ 6 files changed, 39 insertions(+), 1 deletion(-) diff --git a/api/expression-parser.api b/api/expression-parser.api index 79aa793..bccf6dd 100644 --- a/api/expression-parser.api +++ b/api/expression-parser.api @@ -3,6 +3,7 @@ public final class org/hisp/dhis/lib/expression/Expression { public synthetic fun (Ljava/lang/String;Lorg/hisp/dhis/lib/expression/ExpressionMode;ZILkotlin/jvm/internal/DefaultConstructorMarker;)V public final fun collectDataItemForRegenerate ()Ljava/util/Set; public final fun collectDataItems ()Ljava/util/Set; + public final fun collectInOrgUnitGroups ()Ljava/util/Set; public final fun collectProgramRuleVariableNames ()Ljava/util/Set; public final fun collectProgramVariables ()Ljava/util/Set; public final fun collectProgramVariablesNames ()Ljava/util/Set; diff --git a/build.gradle.kts b/build.gradle.kts index 82945a6..2723048 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -9,7 +9,7 @@ repositories { mavenCentral() } -version = "1.4.0-SNAPSHOT" +version = "1.4.1-SNAPSHOT" group = "org.hisp.dhis.lib.expression" if (project.hasProperty("removeSnapshotSuffix")) { diff --git a/src/commonMain/kotlin/org/hisp/dhis/lib/expression/Expression.kt b/src/commonMain/kotlin/org/hisp/dhis/lib/expression/Expression.kt index 5a5e6c2..fb20ba2 100644 --- a/src/commonMain/kotlin/org/hisp/dhis/lib/expression/Expression.kt +++ b/src/commonMain/kotlin/org/hisp/dhis/lib/expression/Expression.kt @@ -1,8 +1,10 @@ package org.hisp.dhis.lib.expression +import org.hisp.dhis.lib.expression.ast.NamedFunction import org.hisp.dhis.lib.expression.ast.Node import org.hisp.dhis.lib.expression.ast.VariableType import org.hisp.dhis.lib.expression.eval.Api.collectDataItems +import org.hisp.dhis.lib.expression.eval.Api.collectFunctionStringArguments import org.hisp.dhis.lib.expression.eval.Api.collectUIDs import org.hisp.dhis.lib.expression.eval.Api.collectVariableNames import org.hisp.dhis.lib.expression.eval.Api.collectVariables @@ -43,6 +45,10 @@ class Expression( return collectVariableNames(root, VariableType.PROGRAM) } + fun collectInOrgUnitGroups(): Set { + return collectFunctionStringArguments(root, NamedFunction.d2_inOrgUnitGroup) + } + /** * For testing only. * diff --git a/src/commonMain/kotlin/org/hisp/dhis/lib/expression/eval/Api.kt b/src/commonMain/kotlin/org/hisp/dhis/lib/expression/eval/Api.kt index 153b586..713158c 100644 --- a/src/commonMain/kotlin/org/hisp/dhis/lib/expression/eval/Api.kt +++ b/src/commonMain/kotlin/org/hisp/dhis/lib/expression/eval/Api.kt @@ -1,5 +1,6 @@ package org.hisp.dhis.lib.expression.eval +import org.hisp.dhis.lib.expression.ast.NamedFunction import org.hisp.dhis.lib.expression.ast.Node import org.hisp.dhis.lib.expression.ast.NodeType import org.hisp.dhis.lib.expression.ast.Nodes.VariableNode @@ -110,4 +111,17 @@ Support functions to collect identifiers to supply values to main functions } ) { node: Node<*> -> node.getType() === NodeType.DATA_ITEM } } + + internal fun collectFunctionStringArguments(root: Node<*>, function: NamedFunction, argIndex: Int = 0): Set { + return root.aggregate( + LinkedHashSet(), + { node: Node<*> -> + val argNode = node.childOrNull(argIndex) + if (node.getValue() === function && argNode != null && argNode.getType() === NodeType.ARGUMENT && argNode.size() > 0) + argNode.child(0).getRawValue() + else null + }, + { set: MutableSet, e: String? -> set.add(e!!) } + ) { node: Node<*> -> node.getType() === NodeType.FUNCTION } + } } diff --git a/src/commonTest/kotlin/org/hisp/dhis/lib/expression/function/HasValueTest.kt b/src/commonTest/kotlin/org/hisp/dhis/lib/expression/function/HasValueTest.kt index 02bbb36..32b1c91 100644 --- a/src/commonTest/kotlin/org/hisp/dhis/lib/expression/function/HasValueTest.kt +++ b/src/commonTest/kotlin/org/hisp/dhis/lib/expression/function/HasValueTest.kt @@ -81,6 +81,14 @@ internal class HasValueTest : AbstractVariableBasedTest() { assertProgramVariableNames(setOf("var"), "d2:hasValue(V{var})") } + @Test + fun collectOrgUnitGroup() { + assertOrgUnitGroups(setOf("groupA"), "d2:inOrgUnitGroup(\"groupA\")") + assertOrgUnitGroups(setOf("CXw2yu5fodb"), "d2:inOrgUnitGroup(\"CXw2yu5fodb\")") + assertOrgUnitGroups(setOf("CXw2yu5fodb","gzcv65VyaGq"), "d2:inOrgUnitGroup(\"CXw2yu5fodb\") && d2:inOrgUnitGroup(\"gzcv65VyaGq\")") + assertOrgUnitGroups(setOf(), "d2:hasValue(A{var})") + } + private fun assertHasValue(expression: String, values: Map, expected: Boolean) { assertEquals(expected, evaluate(expression, values)) } @@ -95,4 +103,9 @@ internal class HasValueTest : AbstractVariableBasedTest() { assertEquals(expected, expr.collectProgramVariablesNames()); } + private fun assertOrgUnitGroups(expected: Set, expression: String) { + val expr = Expression(expression, ExpressionMode.RULE_ENGINE_CONDITION) + assertEquals(expected, expr.collectInOrgUnitGroups()); + } + } diff --git a/src/jsMain/kotlin/org.hisp.dhis.lib.expression.js/ExpressionJs.kt b/src/jsMain/kotlin/org.hisp.dhis.lib.expression.js/ExpressionJs.kt index ca036fa..a00d362 100644 --- a/src/jsMain/kotlin/org.hisp.dhis.lib.expression.js/ExpressionJs.kt +++ b/src/jsMain/kotlin/org.hisp.dhis.lib.expression.js/ExpressionJs.kt @@ -36,6 +36,10 @@ class ExpressionJs(expression: String, mode: ExpressionMode) { return expr.collectUIDs().toTypedArray() } + fun collectInOrgUnitGroups(): Array { + return expr.collectInOrgUnitGroups().toTypedArray() + } + fun describe(displayNames: JsMap): String { return expr.describe(toMap(displayNames, { it }, { it })) }