Test Rule Engine Documentation
Test Rule Engine: Concept and API Contract
Concept
The CLQMS Rule Engine executes business rules when specific events occur.
Each rule follows this lifecycle:
- Author DSL in
ConditionExpr. - Compile DSL using
POST /api/rule/compile. - Save compiled JSON in
ConditionExprCompiled. - Link the rule to tests via
testrule.TestSiteID. - On trigger (
test_created,result_updated), executethenorelseactions.
Rules without compiled JSON or without test links are not executed.
Event Triggers
| Event Code | Status | Trigger Point |
|---|---|---|
test_created |
Active | Runs after a new test row is saved |
result_updated |
Active | Runs when a result is saved or edited |
Other event codes may exist in data, but these are the active runtime triggers.
Rule Shape
Rule = Event + Condition + Actions
DSL format:
if(condition; then-action; else-action)
Multi-action branches use : and execute left to right:
if(sex('M'); result_set(0.5):test_insert('HBA1C'); nothing)
Catalog (Simplified)
Conditions
| Function / Pattern | Meaning | Example |
|---|---|---|
| `sex('M' | 'F')` | Match patient sex |
| `priority('R' | 'S' | 'U')` |
age comparisons |
Numeric age checks | age >= 18 && age <= 65 |
requested('CODE') |
Checks if test code exists in order | requested('GLU') |
Logical Operators
| Operator | Meaning | Example |
|---|---|---|
&& |
AND | sex('M') && age > 40 |
|| |
OR | sex('M') || age > 65 |
! |
NOT | !(sex('M')) |
() |
Grouping | (sex('M') && age > 40) || priority('S') |
Actions
| Action | Meaning | Example |
|---|---|---|
result_set(value) |
Set current-context result (deprecated style) | result_set(0.5) |
result_set('CODE', value) |
Set result for a specific test code | result_set('tesA', 0.5) |
test_insert('CODE') |
Insert test if missing | test_insert('HBA1C') |
test_delete('CODE') |
Remove test from order | test_delete('INS') |
comment_insert('text') |
Insert order comment | comment_insert('Review required') |
nothing |
No operation | nothing |
set_priority() is removed; use comment_insert() when you need to record priority notes.
Example API Contract
1) Compile DSL
POST /api/rule/compile
Content-Type: application/json
Purpose: Validate DSL and return compiled JSON for ConditionExprCompiled.
Request example:
{
"expr": "if(sex('M'); result_set(0.5); result_set(0.6))"
}
Success response example:
{
"status": "success",
"data": {
"raw": "if(sex('M'); result_set(0.5); result_set(0.6))",
"compiled": {
"conditionExpr": "sex('M')",
"then": [{ "type": "result_set", "args": [0.5] }],
"else": [{ "type": "result_set", "args": [0.6] }]
},
"conditionExprCompiled": "{...json string...}"
}
}
Error response example:
{
"status": "error",
"message": "Invalid expression near ';'",
"data": null
}
2) Validate Expression Against Context
POST /api/rule/validate
Content-Type: application/json
Purpose: Evaluate an expression with context only (no compile, no persistence).
Request example:
{
"expr": "order[\"Age\"] > 18",
"context": {
"order": {
"Age": 25
}
}
}
Success response example:
{
"status": "success",
"data": {
"result": true
}
}
3) Create Rule
POST /api/rule
Content-Type: application/json
Purpose: Save rule metadata, DSL, compiled payload, and linked tests.
Request example:
{
"RuleCode": "RULE_001",
"RuleName": "Sex-based result",
"EventCode": "test_created",
"ConditionExpr": "if(sex('M'); result_set(0.5); result_set(0.6))",
"ConditionExprCompiled": "<compiled JSON here>",
"TestSiteIDs": [1, 2]
}
Success response example:
{
"status": "success",
"message": "Rule created",
"data": {
"RuleCode": "RULE_001"
}
}
Minimal End-to-End Flow
- Compile DSL with
/api/rule/compile. - Store returned
conditionExprCompiledinruledef.ConditionExprCompiled. - Create rule and link
TestSiteIDsvia/api/rule. - Trigger event (
test_createdorresult_updated) and verify actions ran.
Runtime Requirements (Quick Check)
ConditionExprCompiledmust be present.- Rule must be linked to the target
TestSiteID. - Trigger event must match
EventCode. - Context must include required identifiers for write actions.