|
@@ -0,0 +1,196 @@
|
|
|
|
|
+# Config 4: Deep Nesting & Complex Structures
|
|
|
|
|
+
|
|
|
|
|
+## Scenario
|
|
|
|
|
+**Corner case testing** untuk validasi parser dengan **deep nesting** (5+ levels) dan **complex nested structures** seperti nested arrays dan objects dalam berbagai kombinasi.
|
|
|
|
|
+
|
|
|
|
|
+## Use Case
|
|
|
|
|
+Configuration dengan hierarchical structure yang kompleks, seperti routing rules dengan nested conditions dan transformations.
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Input: CONFIG4.yaml
|
|
|
|
|
+
|
|
|
|
|
+```yaml
|
|
|
|
|
+deepNested:
|
|
|
|
|
+ level1:
|
|
|
|
|
+ level2:
|
|
|
|
|
+ level3:
|
|
|
|
|
+ level4:
|
|
|
|
|
+ level5:
|
|
|
|
|
+ finalValue: reached_bottom
|
|
|
|
|
+ deepArray:
|
|
|
|
|
+ - item1
|
|
|
|
|
+ - item2
|
|
|
|
|
+ complexMapping:
|
|
|
|
|
+ rules:
|
|
|
|
|
+ - condition: status == SUCCESS
|
|
|
|
|
+ action: PROCEED
|
|
|
|
|
+ mapping:
|
|
|
|
|
+ sourceField: response.data.id
|
|
|
|
|
+ targetField: output.transactionId
|
|
|
|
|
+ transformation: UPPERCASE
|
|
|
|
|
+ fallback:
|
|
|
|
|
+ - condition: status == FAILED
|
|
|
|
|
+ action: RETRY
|
|
|
|
|
+ mapping:
|
|
|
|
|
+ sourceField: response.error.code
|
|
|
|
|
+ targetField: output.errorCode
|
|
|
|
|
+ retryConfig:
|
|
|
|
|
+ maxAttempts: 3
|
|
|
|
|
+ backoffMs: 1000
|
|
|
|
|
+ - condition: status == TIMEOUT
|
|
|
|
|
+ action: CANCEL
|
|
|
|
|
+ notification:
|
|
|
|
|
+ - email
|
|
|
|
|
+ - sms
|
|
|
|
|
+ - webhook
|
|
|
|
|
+ metadata:
|
|
|
|
|
+ version: 2.1.0
|
|
|
|
|
+ author: ACE Team
|
|
|
|
|
+ tags:
|
|
|
|
|
+ - production
|
|
|
|
|
+ - critical
|
|
|
|
|
+ - payment
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Output: hasilParseConfig4.json
|
|
|
|
|
+
|
|
|
|
|
+```json
|
|
|
|
|
+{
|
|
|
|
|
+ "deepNested": {
|
|
|
|
|
+ "level1": {
|
|
|
|
|
+ "level2": {
|
|
|
|
|
+ "level3": {
|
|
|
|
|
+ "level4": {
|
|
|
|
|
+ "level5": {
|
|
|
|
|
+ "finalValue": "reached_bottom",
|
|
|
|
|
+ "deepArray": ["item1", "item2"]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ "complexMapping": {
|
|
|
|
|
+ "rules": [
|
|
|
|
|
+ {
|
|
|
|
|
+ "condition": "status == SUCCESS",
|
|
|
|
|
+ "action": "PROCEED",
|
|
|
|
|
+ "mapping": {
|
|
|
|
|
+ "sourceField": "response.data.id",
|
|
|
|
|
+ "targetField": "output.transactionId",
|
|
|
|
|
+ "transformation": "UPPERCASE"
|
|
|
|
|
+ },
|
|
|
|
|
+ "fallback": ""
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "condition": "status == FAILED",
|
|
|
|
|
+ "action": "RETRY",
|
|
|
|
|
+ "mapping": {
|
|
|
|
|
+ "sourceField": "response.error.code",
|
|
|
|
|
+ "targetField": "output.errorCode"
|
|
|
|
|
+ },
|
|
|
|
|
+ "retryConfig": {
|
|
|
|
|
+ "maxAttempts": "3",
|
|
|
|
|
+ "backoffMs": "1000"
|
|
|
|
|
+ }
|
|
|
|
|
+ },
|
|
|
|
|
+ {
|
|
|
|
|
+ "condition": "status == TIMEOUT",
|
|
|
|
|
+ "action": "CANCEL",
|
|
|
|
|
+ "notification": ["email", "sms", "webhook"]
|
|
|
|
|
+ }
|
|
|
|
|
+ ]
|
|
|
|
|
+ },
|
|
|
|
|
+ "metadata": {
|
|
|
|
|
+ "version": "2.1.0",
|
|
|
|
|
+ "author": "ACE Team",
|
|
|
|
|
+ "tags": ["production", "critical", "payment"]
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## ESQL Usage
|
|
|
|
|
+
|
|
|
|
|
+```esql
|
|
|
|
|
+DECLARE config REFERENCE TO Environment.Variables;
|
|
|
|
|
+DECLARE success BOOLEAN;
|
|
|
|
|
+
|
|
|
|
|
+CALL ACE_LIB.getConfig(
|
|
|
|
|
+ 'COMPLEX_CONFIG',
|
|
|
|
|
+ 'deepNested',
|
|
|
|
|
+ '/path/to/CONFIG4.yaml',
|
|
|
|
|
+ '600',
|
|
|
|
|
+ config
|
|
|
|
|
+) INTO success;
|
|
|
|
|
+
|
|
|
|
|
+IF success THEN
|
|
|
|
|
+ -- Access deep nested value (5 levels)
|
|
|
|
|
+ DECLARE deepValue CHARACTER
|
|
|
|
|
+ config.level1.level2.level3.level4.level5.finalValue;
|
|
|
|
|
+ -- Result: "reached_bottom"
|
|
|
|
|
+
|
|
|
|
|
+ -- Access array in deep nested object
|
|
|
|
|
+ DECLARE deepArrayItem CHARACTER
|
|
|
|
|
+ config.level1.level2.level3.level4.level5.deepArray[1];
|
|
|
|
|
+ -- Result: "item1"
|
|
|
|
|
+
|
|
|
|
|
+ -- Process complex rules array
|
|
|
|
|
+ DECLARE ruleRef REFERENCE TO config.complexMapping.rules[1];
|
|
|
|
|
+ WHILE LASTMOVE(ruleRef) DO
|
|
|
|
|
+ DECLARE condition CHARACTER ruleRef.condition;
|
|
|
|
|
+ DECLARE action CHARACTER ruleRef.action;
|
|
|
|
|
+
|
|
|
|
|
+ -- Check for nested mapping object
|
|
|
|
|
+ IF ruleRef.mapping IS NOT NULL THEN
|
|
|
|
|
+ DECLARE sourceField CHARACTER ruleRef.mapping.sourceField;
|
|
|
|
|
+ DECLARE targetField CHARACTER ruleRef.mapping.targetField;
|
|
|
|
|
+ END IF;
|
|
|
|
|
+
|
|
|
|
|
+ -- Check for nested retryConfig object
|
|
|
|
|
+ IF ruleRef.retryConfig IS NOT NULL THEN
|
|
|
|
|
+ DECLARE maxRetries CHARACTER ruleRef.retryConfig.maxAttempts;
|
|
|
|
|
+ END IF;
|
|
|
|
|
+
|
|
|
|
|
+ -- Check for nested notification array
|
|
|
|
|
+ DECLARE notifRef REFERENCE TO ruleRef.notification[1];
|
|
|
|
|
+ IF LASTMOVE(notifRef) THEN
|
|
|
|
|
+ WHILE LASTMOVE(notifRef) DO
|
|
|
|
|
+ DECLARE channel CHARACTER notifRef;
|
|
|
|
|
+ -- "email", "sms", "webhook"
|
|
|
|
|
+ MOVE notifRef NEXTSIBLING;
|
|
|
|
|
+ END WHILE;
|
|
|
|
|
+ END IF;
|
|
|
|
|
+
|
|
|
|
|
+ MOVE ruleRef NEXTSIBLING;
|
|
|
|
|
+ END WHILE;
|
|
|
|
|
+END IF;
|
|
|
|
|
+```
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Key Features Tested
|
|
|
|
|
+
|
|
|
|
|
+✅ Deep nesting hingga 5+ levels
|
|
|
|
|
+✅ Arrays dalam deep nested objects
|
|
|
|
|
+✅ Array of complex objects
|
|
|
|
|
+✅ Nested objects dalam array items (`mapping`, `retryConfig`)
|
|
|
|
|
+✅ Nested arrays dalam array items (`notification`)
|
|
|
|
|
+✅ Multiple nested structures dalam satu config
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+## Important Notes
|
|
|
|
|
+
|
|
|
|
|
+- Parser support nesting unlimited depth (limited by memory)
|
|
|
|
|
+- Nested objects/arrays dalam list items harus properly indented
|
|
|
|
|
+- Properties dalam nested object tetap accessible dengan dot notation
|
|
|
|
|
+- Complex navigation path tetap valid di ESQL
|
|
|
|
|
+
|
|
|
|
|
+---
|
|
|
|
|
+
|
|
|
|
|
+[⬅️ Back to README](../README.md)
|