Skip to content

Commit

Permalink
Merge pull request #54 from jbee/enums-top-level
Browse files Browse the repository at this point in the history
feat! SPI enum types as top level types
  • Loading branch information
jbee authored Apr 11, 2024
2 parents fff002a + c212722 commit f7a7a69
Show file tree
Hide file tree
Showing 65 changed files with 289 additions and 326 deletions.
5 changes: 5 additions & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,11 @@ kotlin {


sourceSets {
all {
languageSettings.apply {
optIn("kotlin.js.ExperimentalJsExport")
}
}
val commonMain by getting {
dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-datetime:0.4.1")
Expand Down
2 changes: 1 addition & 1 deletion buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ repositories {
}

dependencies {
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.0")
implementation("org.jetbrains.kotlin:kotlin-gradle-plugin:1.9.22")
implementation("org.jetbrains.dokka:dokka-gradle-plugin:1.9.0")
implementation("io.github.gradle-nexus:publish-plugin:1.3.0")
implementation("dev.petuska:npm-publish-gradle-plugin:3.4.1")
Expand Down
50 changes: 2 additions & 48 deletions src/commonMain/kotlin/org/hisp/dhis/lib/expression/Expression.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,8 @@ import org.hisp.dhis.lib.expression.eval.Api.evaluate
import org.hisp.dhis.lib.expression.eval.Api.normalise
import org.hisp.dhis.lib.expression.eval.Api.regenerate
import org.hisp.dhis.lib.expression.eval.Api.validate
import org.hisp.dhis.lib.expression.eval.NodeValidator
import org.hisp.dhis.lib.expression.spi.*
import org.hisp.dhis.lib.expression.syntax.ExpressionGrammar
import org.hisp.dhis.lib.expression.syntax.Fragment
import org.hisp.dhis.lib.expression.syntax.Parser
import kotlin.js.ExperimentalJsExport
import kotlin.js.JsExport

/**
* Facade API for working with DHIS2 expressions.
Expand All @@ -26,50 +21,9 @@ import kotlin.js.JsExport
*/
class Expression(
private val expression: String,
private val mode: Mode = Mode.PREDICTOR_GENERATOR_EXPRESSION,
private val mode: ExpressionMode = ExpressionMode.PREDICTOR_GENERATOR_EXPRESSION,
annotate: Boolean = false
) {
enum class Mode(val fragments: List<Fragment>, val validators: List<NodeValidator>, vararg resultTypes: ValueType) {
// analyses data values for validity
VALIDATION_RULE_EXPRESSION(ExpressionGrammar.ValidationRuleExpressionMode, ValueType.NUMBER),
VALIDATION_RULE_RESULT_TEST(ExpressionGrammar.SimpleTestMode, ValueType.BOOLEAN),

// data value generators
PREDICTOR_GENERATOR_EXPRESSION(ExpressionGrammar.PredictorExpressionMode, ValueType.NUMBER, ValueType.STRING),

// do a section in the data needs skipping (ignore)
PREDICTOR_SKIP_TEST(ExpressionGrammar.PredictorSkipTestMode, ValueType.BOOLEAN),

// ad-hoc calculated (no DB)
// query analytics to compute some aggregate value
INDICATOR_EXPRESSION(ExpressionGrammar.IndicatorExpressionMode, ValueType.NUMBER),

// always SQL for entire expression
// query analytics to compute some aggregate value
PROGRAM_INDICATOR_EXPRESSION(ExpressionGrammar.ProgramIndicatorExpressionMode, ValueType.NUMBER),

// never SQL (also we need JS)
// PROGRAM_RULE_EXPRESSION
RULE_ENGINE_CONDITION(ExpressionGrammar.RuleEngineMode, NodeValidator.RuleEngineMode, ValueType.BOOLEAN),
RULE_ENGINE_ACTION(
ExpressionGrammar.RuleEngineMode,
NodeValidator.RuleEngineMode,
ValueType.BOOLEAN,
ValueType.STRING,
ValueType.NUMBER,
ValueType.DATE);

val resultTypes: Set<ValueType>

constructor(fragments: List<Fragment>, vararg resultTypes: ValueType) : this(
fragments,
listOf<NodeValidator>(),
*resultTypes)

init {
this.resultTypes = setOf(*resultTypes)
}
}

private val root: Node<*>

Expand Down Expand Up @@ -114,7 +68,7 @@ class Expression(
* Collects all ID that are UID values.
*
*
* OBS! This does not include [ID]s that are not [ID.Type.isUID].
* OBS! This does not include [ID]s that are not [IDType.isUID].
*
* @return A set of [ID]s used in the expression.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.hisp.dhis.lib.expression

import org.hisp.dhis.lib.expression.eval.NodeValidator
import org.hisp.dhis.lib.expression.spi.ValueType
import org.hisp.dhis.lib.expression.syntax.ExpressionGrammar
import org.hisp.dhis.lib.expression.syntax.Fragment
import kotlin.js.JsExport

@JsExport
enum class ExpressionMode(
internal val fragments: List<Fragment>,
internal val validators: List<NodeValidator>,
vararg resultTypes: ValueType) {
// analyses data values for validity
VALIDATION_RULE_EXPRESSION(ExpressionGrammar.ValidationRuleExpressionMode, ValueType.NUMBER),
VALIDATION_RULE_RESULT_TEST(ExpressionGrammar.SimpleTestMode, ValueType.BOOLEAN),

// data value generators
PREDICTOR_GENERATOR_EXPRESSION(ExpressionGrammar.PredictorExpressionMode, ValueType.NUMBER, ValueType.STRING),

// do a section in the data needs skipping (ignore)
PREDICTOR_SKIP_TEST(ExpressionGrammar.PredictorSkipTestMode, ValueType.BOOLEAN),

// ad-hoc calculated (no DB)
// query analytics to compute some aggregate value
INDICATOR_EXPRESSION(ExpressionGrammar.IndicatorExpressionMode, ValueType.NUMBER),

// always SQL for entire expression
// query analytics to compute some aggregate value
PROGRAM_INDICATOR_EXPRESSION(ExpressionGrammar.ProgramIndicatorExpressionMode, ValueType.NUMBER),

// never SQL (also we need JS)
// PROGRAM_RULE_EXPRESSION
RULE_ENGINE_CONDITION(ExpressionGrammar.RuleEngineMode, NodeValidator.RuleEngineMode, ValueType.BOOLEAN),
RULE_ENGINE_ACTION(
ExpressionGrammar.RuleEngineMode,
NodeValidator.RuleEngineMode,
ValueType.BOOLEAN,
ValueType.STRING,
ValueType.NUMBER,
ValueType.DATE);

internal val resultTypes: Set<ValueType> = setOf(*resultTypes)

constructor(fragments: List<Fragment>, vararg resultTypes: ValueType) : this(
fragments,
listOf<NodeValidator>(),
*resultTypes)
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.hisp.dhis.lib.expression.ast

import org.hisp.dhis.lib.expression.ast.BinaryOperator
import org.hisp.dhis.lib.expression.ast.Node.Factory
import org.hisp.dhis.lib.expression.spi.DataItem
import org.hisp.dhis.lib.expression.spi.ID
import org.hisp.dhis.lib.expression.spi.Variable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package org.hisp.dhis.lib.expression.ast

import kotlinx.datetime.LocalDate
import org.hisp.dhis.lib.expression.ast.NodeAnnotations.Whitespace
import org.hisp.dhis.lib.expression.ast.AggregationType
import org.hisp.dhis.lib.expression.ast.BinaryOperator
import org.hisp.dhis.lib.expression.spi.*

/**
Expand Down
12 changes: 6 additions & 6 deletions src/commonMain/kotlin/org/hisp/dhis/lib/expression/ast/Tag.kt
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
package org.hisp.dhis.lib.expression.ast

import org.hisp.dhis.lib.expression.spi.ID
import org.hisp.dhis.lib.expression.spi.IDType

/**
* Tags allowed to use in data item positions before a UID.
* <pre>
* tag:UID
</pre> *
*/
enum class Tag(val idType: ID.Type) {
enum class Tag(val idType: IDType) {

deGroup(ID.Type.DateElementGroupUID),
coGroup(ID.Type.CategoryOptionGroupUID),
co(ID.Type.CategoryOptionUID),
PS_EVENTDATE(ID.Type.ProgramStageUID)
deGroup(IDType.DateElementGroupUID),
coGroup(IDType.CategoryOptionGroupUID),
co(IDType.CategoryOptionUID),
PS_EVENTDATE(IDType.ProgramStageUID)
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import org.hisp.dhis.lib.expression.ast.NodeType
import org.hisp.dhis.lib.expression.ast.Nodes.VariableNode
import org.hisp.dhis.lib.expression.ast.VariableType
import org.hisp.dhis.lib.expression.spi.*
import kotlin.collections.LinkedHashSet

/**
* This is the exposed API of the evaluation package. It contains all high level functions to turn a [Node]-tree
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
package org.hisp.dhis.lib.expression.math

import kotlin.math.abs

/**
* Uses z-tables as found on https://en.wikipedia.org/wiki/Standard_normal_table
*
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.hisp.dhis.lib.expression.ast
package org.hisp.dhis.lib.expression.spi

import kotlin.js.JsExport

@JsExport
enum class AggregationType {
sum,
avg,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,46 +1,49 @@
package org.hisp.dhis.lib.expression.spi

import kotlin.js.JsExport

/**
* The different types of data value references in the expression grammar.
*
* @author Jan Bernitt
*/
enum class DataItemType(val symbol: String, private val parameterTypes: List<List<ID.Type>>) {
@JsExport
enum class DataItemType(internal val symbol: String, private val parameterTypes: List<List<IDType>>) {

// (data element for aggregate vs. program stage . data element for programs)
DATA_ELEMENT(
"#", listOf(
listOf(ID.Type.DataElementUID),
listOf(ID.Type.ProgramStageUID, ID.Type.DataElementUID),
listOf(ID.Type.DataElementUID, ID.Type.CategoryOptionUID, ID.Type.AttributeOptionComboUID)
listOf(IDType.DataElementUID),
listOf(IDType.ProgramStageUID, IDType.DataElementUID),
listOf(IDType.DataElementUID, IDType.CategoryOptionUID, IDType.AttributeOptionComboUID)
)
),

// (Program Attribute, not currently used for aggregate data)
ATTRIBUTE(
"A", listOf(
listOf(ID.Type.AttributeUID),
listOf(ID.Type.ProgramUID, ID.Type.AttributeUID)
listOf(IDType.AttributeUID),
listOf(IDType.ProgramUID, IDType.AttributeUID)
)
),
CONSTANT("C", ID.Type.ConstantUID),
CONSTANT("C", IDType.ConstantUID),

// (Not to be confused with #, also used in programs)
PROGRAM_DATA_ELEMENT("D", ID.Type.ProgramUID, ID.Type.DataElementUID),
PROGRAM_INDICATOR("I", ID.Type.ProgramIndicatorUID),
PROGRAM_DATA_ELEMENT("D", IDType.ProgramUID, IDType.DataElementUID),
PROGRAM_INDICATOR("I", IDType.ProgramIndicatorUID),

// ('I' was already taken for program indicator)
INDICATOR("N", ID.Type.IndicatorUID),
ORG_UNIT_GROUP("OUG", ID.Type.OrganisationUnitGroupUID),
REPORTING_RATE("R", ID.Type.DataSetUID, ID.Type.ReportingRateType),
PROGRAM_VARIABLE("V", ID.Type.ProgramVariableName);
INDICATOR("N", IDType.IndicatorUID),
ORG_UNIT_GROUP("OUG", IDType.OrganisationUnitGroupUID),
REPORTING_RATE("R", IDType.DataSetUID, IDType.ReportingRateType),
PROGRAM_VARIABLE("V", IDType.ProgramVariableName);

constructor(symbol: String, vararg parameterTypes: ID.Type) : this(
symbol, listOf<List<ID.Type>>(listOf<ID.Type>(*parameterTypes)))
constructor(symbol: String, vararg parameterTypes: IDType) : this(
symbol, listOf<List<IDType>>(listOf<IDType>(*parameterTypes)))

fun getType(numberOfIds: Int, index: Int): ID.Type {
fun getType(numberOfIds: Int, index: Int): IDType {
val params =
parameterTypes.firstOrNull { l: List<ID.Type> -> l.size == numberOfIds } ?: throw IllegalArgumentException(
parameterTypes.firstOrNull { l: List<IDType> -> l.size == numberOfIds } ?: throw IllegalArgumentException(
"Data item $name cannot be used with $numberOfIds ids")
return params[index]
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,10 @@ package org.hisp.dhis.lib.expression.spi
import com.ionspin.kotlin.bignum.decimal.BigDecimal
import kotlinx.datetime.*
import org.hisp.dhis.lib.expression.ast.BinaryOperator.Companion.modulo
import org.hisp.dhis.lib.expression.math.VectorAggregation
import org.hisp.dhis.lib.expression.math.GS1Elements.Companion.fromKey
import org.hisp.dhis.lib.expression.math.NormalDistribution
import org.hisp.dhis.lib.expression.math.VectorAggregation
import org.hisp.dhis.lib.expression.math.ZScore
import kotlin.js.ExperimentalJsExport
import kotlin.js.JsExport
import kotlin.math.ceil
import kotlin.math.floor
import kotlin.math.ln
Expand Down
31 changes: 4 additions & 27 deletions src/commonMain/kotlin/org/hisp/dhis/lib/expression/spi/ID.kt
Original file line number Diff line number Diff line change
@@ -1,42 +1,19 @@
package org.hisp.dhis.lib.expression.spi

import kotlin.js.JsExport

/**
* An identifier of some type as used in [DataItem]s.
*
*
* Mostly these are UIDs but sometimes these are other identifiers.
*
* @author Jan Bernitt
*/
@JsExport
data class ID(
val type: Type,
val type: IDType,
val value: String
) {
enum class Type {
AttributeUID,
AttributeOptionComboUID,
CategoryOptionUID,
CategoryOptionComboUID,
CategoryOptionGroupUID,
DataElementUID,
DateElementGroupUID,
DataSetUID,
ConstantUID,
IndicatorUID,
OrganisationUnitGroupUID,
ProgramUID,
ProgramIndicatorUID,
ProgramVariableName,
ProgramStageUID,

// not a UID but an Identifier
ReportingRateType;

fun isUID(): Boolean {
return this != ProgramVariableName && this != ReportingRateType;
}
}

override fun toString(): String {
return value
}
Expand Down
29 changes: 29 additions & 0 deletions src/commonMain/kotlin/org/hisp/dhis/lib/expression/spi/IDType.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package org.hisp.dhis.lib.expression.spi

import kotlin.js.JsExport

@JsExport
enum class IDType {
AttributeUID,
AttributeOptionComboUID,
CategoryOptionUID,
CategoryOptionComboUID,
CategoryOptionGroupUID,
DataElementUID,
DateElementGroupUID,
DataSetUID,
ConstantUID,
IndicatorUID,
OrganisationUnitGroupUID,
ProgramUID,
ProgramIndicatorUID,
ProgramVariableName,
ProgramStageUID,

// not a UID but an Identifier
ReportingRateType;

fun isUID(): Boolean {
return this != ProgramVariableName && this != ReportingRateType;
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
package org.hisp.dhis.lib.expression.ast
package org.hisp.dhis.lib.expression.spi

import kotlin.js.JsExport

@JsExport
enum class ProgramVariable {
/*
OBS! These are the names as they are expected in the syntax
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package org.hisp.dhis.lib.expression.spi

import kotlinx.datetime.LocalDate
import org.hisp.dhis.lib.expression.ast.AggregationType

data class QueryModifiers (
/**
Expand Down
Loading

0 comments on commit f7a7a69

Please sign in to comment.