clqms-be/docs/test-calc-engine.md

338 lines
7.3 KiB
Markdown
Raw Normal View History

# Calculator Service Operators Reference
## Overview
The `CalculatorService` (`app/Services/CalculatorService.php`) evaluates formulas with Symfony's `ExpressionLanguage`. This document lists the operators, functions, and constants that are available in the current implementation.
---
## API Endpoints
All endpoints live under `/api` and accept JSON. Responses use the standard `{ status, message, data }` envelope unless stated otherwise.
### Calculate By Test Site
Uses the `testdefcal` definition for a test site. The incoming body supplies the variables required by the formula.
```http
POST /api/calc/testsite/123
Content-Type: application/json
{
"result": 85,
"gender": "female",
"age": 30
}
```
Response:
```json
{
"status": "success",
"data": {
"result": 92.4,
"testSiteID": 123,
"formula": "{result} * {factor} + {age}",
"variables": {
"result": 85,
"gender": "female",
"age": 30
}
}
}
```
### Calculate By Code Or Name
Evaluates a configured calculation by `TestSiteCode` or `TestSiteName`. Returns a compact map with a single key/value or `{}` on failure.
```http
POST /api/calc/testcode/GLU
Content-Type: application/json
{
"result": 110,
"factor": 1.1
}
```
Response:
```json
{
"GLU": 121
}
```
---
## Supported Operators
### Arithmetic Operators
| Operator | Description | Example | Result |
|----------|-------------|---------|--------|
| `+` | Addition | `5 + 3` | `8` |
| `-` | Subtraction | `10 - 4` | `6` |
| `*` | Multiplication | `6 * 7` | `42` |
| `/` | Division | `20 / 4` | `5` |
| `%` | Modulo | `20 % 6` | `2` |
| `**` | Exponentiation (power) | `2 ** 3` | `8` |
### Comparison Operators
| Operator | Description | Example |
|----------|-------------|---------|
| `==` | Equal | `{result} == 10` |
| `!=` | Not equal | `{result} != 10` |
| `<` | Less than | `{result} < 10` |
| `<=` | Less than or equal | `{result} <= 10` |
| `>` | Greater than | `{result} > 10` |
| `>=` | Greater than or equal | `{result} >= 10` |
### Logical Operators
| Operator | Description | Example |
|----------|-------------|---------|
| `and` / `&&` | Logical AND | `{result} > 0 and {factor} > 0` |
| `or` / `||` | Logical OR | `{gender} == 1 or {gender} == 2` |
| `!` / `not` | Logical NOT | `not ({result} > 0)` |
### Conditional Operators
| Operator | Description | Example |
|----------|-------------|---------|
| `?:` | Ternary | `{result} > 10 ? {result} : 10` |
| `??` | Null coalescing | `{result} ?? 0` |
### Parentheses
Use parentheses to control operation precedence:
```
(2 + 3) * 4 // Result: 20
2 + 3 * 4 // Result: 14
```
### Notes
- `^` is bitwise XOR (not exponentiation). Use `**` for powers.
- Variables must be numeric after normalization (gender is mapped to 0/1/2).
---
## Functions
Only the default ExpressionLanguage functions are available:
| Function | Description | Example |
|----------|-------------|---------|
| `min(a, b, ...)` | Minimum value | `min({result}, 10)` |
| `max(a, b, ...)` | Maximum value | `max({result}, 10)` |
| `constant(name)` | PHP constant by name | `constant("PHP_INT_MAX")` |
| `enum(name)` | PHP enum case by name | `enum("App\\Enum\\Status::Active")` |
---
## Constants
ExpressionLanguage recognizes boolean and null literals:
| Constant | Value | Description |
|----------|-------|-------------|
| `true` | `true` | Boolean true |
| `false` | `false` | Boolean false |
| `null` | `null` | Null value |
---
## Variables in CalculatorService
When using `calculateFromDefinition()`, the following variables are automatically available:
| Variable | Description | Type |
|----------|-------------|------|
| `{result}` | The test result value | Float |
| `{factor}` | Calculation factor (default: 1) | Float |
| `{gender}` | Gender value (0=Unknown, 1=Female, 2=Male) | Integer |
| `{age}` | Patient age | Float |
| `{ref_low}` | Reference range low value | Float |
| `{ref_high}` | Reference range high value | Float |
### Gender Mapping
The `gender` variable accepts the following values:
| Value | Description |
|-------|-------------|
| `0` | Unknown |
| `1` | Female |
| `2` | Male |
Or use string values: `'unknown'`, `'female'`, `'male'`
---
## Implicit Multiplication
Implicit multiplication is not supported. Always use `*` between values:
| Expression | Use Instead |
|------------|-------------|
| `2x` | `2 * x` |
| `{result}{factor}` | `{result} * {factor}` |
---
## Usage Examples
### Basic Calculation
```php
use App\Services\CalculatorService;
$calculator = new CalculatorService();
// Simple arithmetic
$result = $calculator->calculate("5 + 3 * 2");
// Result: 11
// Using min/max
$result = $calculator->calculate("max({result}, 10)", ['result' => 7]);
// Result: 10
```
### With Variables
```php
$formula = "{result} * {factor} + 10";
$variables = [
'result' => 5.2,
'factor' => 2
];
$result = $calculator->calculate($formula, $variables);
// Result: 20.4
```
### BMI Calculation
```php
$formula = "{weight} / ({height} ** 2)";
$variables = [
'weight' => 70, // kg
'height' => 1.75 // meters
];
$result = $calculator->calculate($formula, $variables);
// Result: 22.86
```
### Gender-Based Calculation
```php
// Apply different multipliers based on gender
$formula = "{result} * (1 + 0.1 * {gender})";
$variables = [
'result' => 100,
'gender' => 1 // Female = 1
];
$result = $calculator->calculate($formula, $variables);
// Result: 110
```
### Complex Formula
```php
// Pythagorean theorem
$formula = "(({a} ** 2 + {b} ** 2) ** 0.5)";
$variables = [
'a' => 3,
'b' => 4
];
$result = $calculator->calculate($formula, $variables);
// Result: 5
```
### Using calculateFromDefinition
```php
$calcDef = [
'FormulaCode' => '{result} * {factor} + {gender}',
'Factor' => 2
];
$testValues = [
'result' => 10,
'gender' => 1 // Female
];
$result = $calculator->calculateFromDefinition($calcDef, $testValues);
// Result: 21 (10 * 2 + 1)
```
---
## Formula Validation
Validate formulas before storing them:
```php
$validation = $calculator->validate("{result} / {factor}");
// Returns: ['valid' => true, 'error' => null]
$validation = $calculator->validate("{result} /");
// Returns: ['valid' => false, 'error' => 'Error message']
```
### Extract Variables
Get a list of variables used in a formula:
```php
$variables = $calculator->extractVariables("{result} * {factor} + {age}");
// Returns: ['result', 'factor', 'age']
```
---
## Error Handling
The service throws exceptions for invalid formulas or missing variables:
```php
try {
$result = $calculator->calculate("{result} / 0");
} catch (\Exception $e) {
// Handle division by zero or other errors
log_message('error', $e->getMessage());
}
```
Common errors:
- **Invalid formula syntax**: Malformed expressions
- **Missing variable**: Variable placeholder not provided in data array
- **Non-numeric value**: Variables must be numeric
- **Division by zero**: Mathematical error
---
## Best Practices
1. **Always validate formulas** before storing in database
2. **Use placeholder syntax** `{variable_name}` for clarity
3. **Handle exceptions** in production code
4. **Test edge cases** like zero values and boundary conditions
5. **Document formulas** with comments in your code
---
## References
- [Symfony ExpressionLanguage](https://symfony.com/doc/current/components/expression_language.html)
- `app/Services/CalculatorService.php`