YusufSyam 1 lună în urmă
comite
8b72d067f0

+ 105 - 0
README.md

@@ -0,0 +1,105 @@
+# ACE_LIB.getConfig - More Examples
+
+Repository ini berisi contoh-contoh penggunaan fungsi `ACE_LIB.getConfig()` untuk parsing YAML nested dengan berbagai skenario.
+
+## 📋 Overview
+
+Fungsi `getConfig()` adalah YAML parser yang dapat membaca file konfigurasi dengan struktur nested (object dan array) dan mengembalikan JSON yang dapat langsung diakses di ESQL.
+
+## 🧪 Test Scenarios
+
+Repository ini menyediakan **5 skenario testing** yang mencakup berbagai use case:
+
+| Config | Scenario | Description |
+|--------|----------|-------------|
+| [CONFIG1.yaml](configs/CONFIG1.yaml) | **Standard Nested YAML** | Multiple root keys dengan nested objects dan arrays |
+| [CONFIG2.yaml](configs/CONFIG2.yaml) | **Flat YAML** | Structure flat tanpa root key, diakses dengan wildcard `'*'` |
+| [CONFIG3.yaml](configs/CONFIG3.yaml) | **Corner Case: Empty Values** | Testing empty values, mixed arrays, dan special characters |
+| [CONFIG4.yaml](configs/CONFIG4.yaml) | **Corner Case: Deep Nesting** | Deep nesting (5+ levels) dan complex nested structures |
+| [CONFIG5.yaml](configs/CONFIG5.yaml) | **Simple Key-Value** | Practical real-world config dengan arrays dan nested objects |
+
+## 📂 Repository Structure
+
+```
+ACE_LIB.getConfig-moreExample/
+├── README.md                           # File ini
+├── configs/                            # 5 File YAML untuk testing
+│   ├── CONFIG1.yaml
+│   ├── CONFIG2.yaml
+│   ├── CONFIG3.yaml
+│   ├── CONFIG4.yaml
+│   └── CONFIG5.yaml
+├── parseResults/                       # Hasil JSON dari parsing
+│   ├── hasilParseConfig1.json
+│   ├── hasilParseConfig2.json
+│   ├── hasilParseConfig3.json
+│   ├── hasilParseConfig4.json
+│   └── hasilParseConfig5.json
+└── docs/                               # Detailed documentation
+    ├── config1-scenario.md
+    ├── config2-scenario.md
+    ├── config3-scenario.md
+    ├── config4-scenario.md
+    └── config5-scenario.md
+```
+
+## 📖 Detailed Documentation
+
+Untuk penjelasan lengkap setiap skenario, lihat dokumentasi berikut:
+
+- [Config 1: Standard Nested YAML](docs/config1-scenario.md)
+- [Config 2: Flat YAML with Wildcard](docs/config2-scenario.md)
+- [Config 3: Empty Values & Mixed Content](docs/config3-scenario.md)
+- [Config 4: Deep Nesting & Complex Structures](docs/config4-scenario.md)
+- [Config 5: Simple & Practical Config](docs/config5-scenario.md)
+
+## 🚀 Quick Start
+
+### Cara Menggunakan Test Files
+
+```esql
+-- Example: Load CONFIG1 dengan key 'fundtastic'
+DECLARE config REFERENCE TO Environment.Variables;
+DECLARE success BOOLEAN;
+
+CALL ACE_LIB.getConfig(
+    'TEST_CONFIG1',           -- Cache ID
+    'fundtastic',             -- Key yang akan diambil
+    '/path/to/CONFIG1.yaml',  -- Path ke file
+    '600',                    -- Cache expiry (seconds)
+    config                    -- OUT: Reference hasil parse
+) INTO success;
+
+IF success THEN
+    -- Akses data
+    DECLARE apiSecret CHARACTER config.ApiSecret;
+    DECLARE endpoint CHARACTER config.endpoint;
+END IF;
+```
+
+## ✅ Test Coverage
+
+| Feature | Config 1 | Config 2 | Config 3 | Config 4 | Config 5 |
+|---------|----------|----------|----------|----------|----------|
+| Nested Objects | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Arrays of Strings | ✅ | ✅ | - | ✅ | ✅ |
+| Arrays of Objects | ✅ | ✅ | ✅ | ✅ | ✅ |
+| Multiple Root Keys | ✅ | - | - | - | ✅ |
+| Flat YAML (wildcard) | - | ✅ | - | - | - |
+| Empty Values | - | - | ✅ | - | - |
+| Mixed Arrays | - | - | ✅ | - | - |
+| Deep Nesting (5+ levels) | - | - | - | ✅ | - |
+| Special Characters | - | - | ✅ | - | - |
+
+## 📝 Notes
+
+- Semua config menggunakan **indentasi 2 spasi** per level
+- Parser support struktur nested unlimited depth (limited by memory)
+- Semua values di-parse sebagai **string** (tidak ada type conversion)
+- Empty values (`key:`) di-parse menjadi empty string `""`
+
+---
+
+**Version:** 1.0.0  
+**Last Updated:** October 2026  
+**Maintainer:** IBM ACE Middleware Team

+ 31 - 0
configs/CONFIG1.yaml

@@ -0,0 +1,31 @@
+# CONFIG 1: Standard Nested YAML dengan Multiple Keys
+# Test: Nested objects, arrays dengan properties, multiple root keys
+
+fundtastic:
+  ApiSecret: secret_fundtastic_123
+  TrxAuthMethod: basic
+  TrxSignKey: X-Signature
+  TrxSignAlgorithm: HMACSHA256(hex)/ApiSecret
+  endpoint: https://api.fundtastic.com/v1
+  timeout: 30000
+  headers:
+    - name: Content-Type
+      type: LITERAL
+      value: application/json
+    - name: X-Timestamp
+      type: DEFAULT
+    - name: X-Signature
+      type: PATH
+      value: Environment.Variables.Signature
+
+itm:
+  ApiSecret: secret_itm_456
+  TrxAuthMethod: bearer
+  TrxSignKey: Authorization
+  endpoint: https://api.itm.com/payment
+  headers:
+    - name: Authorization
+      type: LITERAL
+      value: Bearer token123
+    - name: Content-Type
+      value: application/json

+ 25 - 0
configs/CONFIG2.yaml

@@ -0,0 +1,25 @@
+# CONFIG 2: Flat YAML tanpa Root Key
+# Test: Direct key-value pairs, arrays di root level, untuk diakses dengan key '*'
+
+ApiSecret: flat_secret_789
+TrxAuthMethod: oauth2
+TrxSignKey: X-Auth-Token
+endpoint: https://api.example.com
+retryAttempts: 3
+connectionTimeout: 5000
+headers:
+  - name: X-Api-Key
+    type: LITERAL
+    value: api_key_xyz
+  - name: User-Agent
+    value: ACE-Middleware/1.0
+allowedMethods:
+  - GET
+  - POST
+  - PUT
+  - DELETE
+responseFields:
+  - id
+  - status
+  - timestamp
+  - data

+ 29 - 0
configs/CONFIG3.yaml

@@ -0,0 +1,29 @@
+# CONFIG 3: CORNER CASE - Empty Values dan Mixed Content
+# Test: Empty strings, nilai kosong, nested empty objects, mixed array types
+
+payment:
+  provider: stripe
+  ApiSecret: 
+  EmptyObject:
+  NestedEmpty:
+    level1:
+    level2:
+      level3: 
+  MixedArray:
+    - simpleString1
+    - name: objectInArray
+      value: 123
+    - simpleString2
+    - key: anotherObject
+      type: TEST
+      subconfig:
+  StatusCodes:
+    - 200
+    - 201
+    - 204
+  SpecialChars: "value:with:colons"
+  MultilineValue: TrxUrlMethod || ':' || relurl || ':' || minifiedMsg
+  NullishValues:
+    empty: 
+    zero: 0
+    false: false

+ 43 - 0
configs/CONFIG4.yaml

@@ -0,0 +1,43 @@
+# CONFIG 4: CORNER CASE - Deep Nesting dan Complex Structures
+# Test: 5+ level deep nesting, arrays dalam arrays (list item dengan nested properties kompleks)
+
+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

+ 27 - 0
configs/CONFIG5.yaml

@@ -0,0 +1,27 @@
+# CONFIG 5: Simple Key-Value dengan Array Sederhana
+# Test: Basic scenario, simple arrays, no deep nesting
+
+database:
+  host: localhost
+  port: 5432
+  name: middleware_db
+  username: ace_user
+  password: secure_pass_123
+  connectionPool:
+    minSize: 5
+    maxSize: 20
+    timeout: 30
+  allowedIPs:
+    - 192.168.1.100
+    - 192.168.1.101
+    - 10.0.0.50
+
+cache:
+  enabled: true
+  ttl: 3600
+  provider: redis
+  nodes:
+    - host: redis1.example.com
+      port: 6379
+    - host: redis2.example.com
+      port: 6379

+ 143 - 0
docs/config1-scenario.md

@@ -0,0 +1,143 @@
+# Config 1: Standard Nested YAML
+
+## Scenario
+Testing standard nested YAML structure dengan **multiple root keys** dan **arrays of objects** dengan properties kompleks.
+
+## Use Case
+Configuration file untuk multiple billers dengan struktur yang sama, di mana setiap biller punya API credentials dan HTTP headers configuration.
+
+---
+
+## Input: CONFIG1.yaml
+
+```yaml
+fundtastic:
+  ApiSecret: secret_fundtastic_123
+  TrxAuthMethod: basic
+  TrxSignKey: X-Signature
+  TrxSignAlgorithm: HMACSHA256(hex)/ApiSecret
+  endpoint: https://api.fundtastic.com/v1
+  timeout: 30000
+  headers:
+    - name: Content-Type
+      type: LITERAL
+      value: application/json
+    - name: X-Timestamp
+      type: DEFAULT
+    - name: X-Signature
+      type: PATH
+      value: Environment.Variables.Signature
+
+itm:
+  ApiSecret: secret_itm_456
+  TrxAuthMethod: bearer
+  TrxSignKey: Authorization
+  endpoint: https://api.itm.com/payment
+  headers:
+    - name: Authorization
+      type: LITERAL
+      value: Bearer token123
+    - name: Content-Type
+      value: application/json
+```
+
+---
+
+## Output: hasilParseConfig1.json
+
+```json
+{
+  "fundtastic": {
+    "ApiSecret": "secret_fundtastic_123",
+    "TrxAuthMethod": "basic",
+    "TrxSignKey": "X-Signature",
+    "TrxSignAlgorithm": "HMACSHA256(hex)/ApiSecret",
+    "endpoint": "https://api.fundtastic.com/v1",
+    "timeout": "30000",
+    "headers": [
+      {
+        "name": "Content-Type",
+        "type": "LITERAL",
+        "value": "application/json"
+      },
+      {
+        "name": "X-Timestamp",
+        "type": "DEFAULT"
+      },
+      {
+        "name": "X-Signature",
+        "type": "PATH",
+        "value": "Environment.Variables.Signature"
+      }
+    ]
+  },
+  "itm": {
+    "ApiSecret": "secret_itm_456",
+    "TrxAuthMethod": "bearer",
+    "TrxSignKey": "Authorization",
+    "endpoint": "https://api.itm.com/payment",
+    "headers": [
+      {
+        "name": "Authorization",
+        "type": "LITERAL",
+        "value": "Bearer token123"
+      },
+      {
+        "name": "Content-Type",
+        "value": "application/json"
+      }
+    ]
+  }
+}
+```
+
+---
+
+## ESQL Usage
+
+```esql
+-- Ambil config untuk biller 'fundtastic'
+DECLARE billerConfig REFERENCE TO Environment.Variables;
+DECLARE success BOOLEAN;
+
+CALL ACE_LIB.getConfig(
+    'BILLER_CONFIG_fundtastic',
+    'fundtastic',
+    '/path/to/CONFIG1.yaml',
+    '600',
+    billerConfig
+) INTO success;
+
+IF success THEN
+    -- Akses scalar values
+    DECLARE apiSecret CHARACTER billerConfig.ApiSecret;
+    DECLARE endpoint CHARACTER billerConfig.endpoint;
+    DECLARE timeout CHARACTER billerConfig.timeout;
+    
+    -- Loop headers array
+    DECLARE headerRef REFERENCE TO billerConfig.headers[1];
+    WHILE LASTMOVE(headerRef) DO
+        DECLARE headerName CHARACTER headerRef.name;
+        DECLARE headerType CHARACTER headerRef.type;
+        DECLARE headerValue CHARACTER COALESCE(headerRef.value, '');
+        
+        -- Process header...
+        
+        MOVE headerRef NEXTSIBLING;
+    END WHILE;
+END IF;
+```
+
+---
+
+## Key Features Tested
+
+✅ Multiple root keys (`fundtastic`, `itm`)  
+✅ Nested scalar values  
+✅ Arrays of objects with multiple properties  
+✅ Optional properties in array items (some headers have `value`, some don't)  
+✅ Dynamic key selection (dapat pilih `fundtastic` atau `itm`)
+
+---
+
+[⬅️ Back to README](../README.md)

+ 127 - 0
docs/config2-scenario.md

@@ -0,0 +1,127 @@
+# Config 2: Flat YAML with Wildcard
+
+## Scenario
+Testing **flat YAML structure** (tanpa root key) yang diakses menggunakan **wildcard key `'*'`**. Config ini berisi direct key-value pairs di root level dengan arrays.
+
+## Use Case
+Simple configuration file yang tidak memerlukan grouping, langsung berisi settings yang dibutuhkan.
+
+---
+
+## Input: CONFIG2.yaml
+
+```yaml
+ApiSecret: flat_secret_789
+TrxAuthMethod: oauth2
+TrxSignKey: X-Auth-Token
+endpoint: https://api.example.com
+retryAttempts: 3
+connectionTimeout: 5000
+headers:
+  - name: X-Api-Key
+    type: LITERAL
+    value: api_key_xyz
+  - name: User-Agent
+    value: ACE-Middleware/1.0
+allowedMethods:
+  - GET
+  - POST
+  - PUT
+  - DELETE
+responseFields:
+  - id
+  - status
+  - timestamp
+  - data
+```
+
+---
+
+## Output: hasilParseConfig2.json
+
+```json
+{
+  "ApiSecret": "flat_secret_789",
+  "TrxAuthMethod": "oauth2",
+  "TrxSignKey": "X-Auth-Token",
+  "endpoint": "https://api.example.com",
+  "retryAttempts": "3",
+  "connectionTimeout": "5000",
+  "headers": [
+    {
+      "name": "X-Api-Key",
+      "type": "LITERAL",
+      "value": "api_key_xyz"
+    },
+    {
+      "name": "User-Agent",
+      "value": "ACE-Middleware/1.0"
+    }
+  ],
+  "allowedMethods": ["GET", "POST", "PUT", "DELETE"],
+  "responseFields": ["id", "status", "timestamp", "data"]
+}
+```
+
+---
+
+## ESQL Usage
+
+```esql
+-- PENTING: Gunakan wildcard '*' untuk flat YAML
+DECLARE config REFERENCE TO Environment.Variables;
+DECLARE success BOOLEAN;
+
+CALL ACE_LIB.getConfig(
+    'FLAT_CONFIG',
+    '*',                      -- Wildcard key untuk ambil semua
+    '/path/to/CONFIG2.yaml',
+    '600',
+    config
+) INTO success;
+
+IF success THEN
+    -- Akses scalar values
+    DECLARE apiSecret CHARACTER config.ApiSecret;
+    DECLARE endpoint CHARACTER config.endpoint;
+    DECLARE retries CHARACTER config.retryAttempts;
+    
+    -- Loop simple string arrays
+    DECLARE methodRef REFERENCE TO config.allowedMethods[1];
+    WHILE LASTMOVE(methodRef) DO
+        DECLARE method CHARACTER methodRef;
+        -- Process method: "GET", "POST", etc.
+        MOVE methodRef NEXTSIBLING;
+    END WHILE;
+    
+    -- Loop array of objects
+    DECLARE headerRef REFERENCE TO config.headers[1];
+    WHILE LASTMOVE(headerRef) DO
+        DECLARE headerName CHARACTER headerRef.name;
+        DECLARE headerValue CHARACTER COALESCE(headerRef.value, '');
+        MOVE headerRef NEXTSIBLING;
+    END WHILE;
+END IF;
+```
+
+---
+
+## Key Features Tested
+
+✅ Flat YAML structure (no root key)  
+✅ Wildcard `'*'` key untuk akses full config  
+✅ Arrays of simple strings (`allowedMethods`, `responseFields`)  
+✅ Mixed content: objects and arrays at root level  
+✅ Direct key-value pairs di root level
+
+---
+
+## Important Notes
+
+- **Key `'*'` adalah special key** untuk flat YAML
+- Semua content di root level langsung accessible
+- Ideal untuk config sederhana yang tidak perlu grouping
+
+---
+
+[⬅️ Back to README](../README.md)

+ 150 - 0
docs/config3-scenario.md

@@ -0,0 +1,150 @@
+# Config 3: Empty Values & Mixed Content
+
+## Scenario
+**Corner case testing** untuk validasi parser behavior dengan **empty values**, **mixed arrays** (kombinasi string dan object), dan **special characters**.
+
+## Use Case
+Testing edge cases yang mungkin ditemukan di production: config dengan optional values, mixed content types, dan special characters dalam values.
+
+---
+
+## Input: CONFIG3.yaml
+
+```yaml
+payment:
+  provider: stripe
+  ApiSecret: 
+  EmptyObject:
+  NestedEmpty:
+    level1:
+    level2:
+      level3: 
+  MixedArray:
+    - simpleString1
+    - name: objectInArray
+      value: 123
+    - simpleString2
+    - key: anotherObject
+      type: TEST
+      subconfig:
+  StatusCodes:
+    - 200
+    - 201
+    - 204
+  SpecialChars: "value:with:colons"
+  MultilineValue: TrxUrlMethod || ':' || relurl || ':' || minifiedMsg
+  NullishValues:
+    empty: 
+    zero: 0
+    false: false
+```
+
+---
+
+## Output: hasilParseConfig3.json
+
+```json
+{
+  "payment": {
+    "provider": "stripe",
+    "ApiSecret": "",
+    "EmptyObject": "",
+    "NestedEmpty": {
+      "level1": "",
+      "level2": {
+        "level3": ""
+      }
+    },
+    "MixedArray": [
+      "simpleString1",
+      {
+        "name": "objectInArray",
+        "value": "123",
+        "subconfig": ""
+      },
+      "simpleString2",
+      {
+        "key": "anotherObject",
+        "type": "TEST"
+      }
+    ],
+    "StatusCodes": ["200", "201", "204"],
+    "SpecialChars": "value:with:colons",
+    "MultilineValue": "TrxUrlMethod || ':' || relurl || ':' || minifiedMsg",
+    "NullishValues": {
+      "empty": "",
+      "zero": "0",
+      "false": "false"
+    }
+  }
+}
+```
+
+---
+
+## ESQL Usage
+
+```esql
+DECLARE config REFERENCE TO Environment.Variables;
+DECLARE success BOOLEAN;
+
+CALL ACE_LIB.getConfig(
+    'EDGE_CASE_CONFIG',
+    'payment',
+    '/path/to/CONFIG3.yaml',
+    '600',
+    config
+) INTO success;
+
+IF success THEN
+    -- Empty values menjadi empty string
+    DECLARE apiSecret CHARACTER config.ApiSecret;  -- ""
+    
+    -- Nested empty values
+    DECLARE level3 CHARACTER config.NestedEmpty.level2.level3;  -- ""
+    
+    -- Mixed array: bisa string atau object
+    DECLARE itemRef REFERENCE TO config.MixedArray[1];
+    WHILE LASTMOVE(itemRef) DO
+        -- Check if it's object or string
+        IF itemRef.name IS NOT NULL THEN
+            -- It's an object
+            DECLARE itemName CHARACTER itemRef.name;
+        ELSE
+            -- It's a simple string
+            DECLARE itemValue CHARACTER itemRef;
+        END IF;
+        MOVE itemRef NEXTSIBLING;
+    END WHILE;
+    
+    -- Special characters preserved
+    DECLARE specialVal CHARACTER config.SpecialChars;
+    -- Value: "value:with:colons"
+END IF;
+```
+
+---
+
+## Key Features Tested
+
+✅ Empty string values (`ApiSecret:`)  
+✅ Nested empty objects  
+✅ Mixed arrays (strings and objects together)  
+✅ Special characters in values (`:` tidak break parser)  
+✅ Numeric values as strings (`"0"`, `"200"`)  
+✅ Boolean-like values as strings (`"false"`)  
+✅ Complex expression strings
+
+---
+
+## Important Notes
+
+- Empty values (`key:`) → empty string `""`
+- All numeric values → parsed as string (`"0"`, `"123"`)
+- Boolean values → parsed as string (`"false"`, `"true"`)
+- Special chars in value → preserved as-is
+- Mixed arrays → valid dan bisa di-handle
+
+---
+
+[⬅️ Back to README](../README.md)

+ 196 - 0
docs/config4-scenario.md

@@ -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)

+ 166 - 0
docs/config5-scenario.md

@@ -0,0 +1,166 @@
+# Config 5: Simple & Practical Config
+
+## Scenario
+**Real-world practical scenario** dengan configuration yang umum digunakan: database connection, cache settings, dengan **simple nested objects** dan **arrays of objects**.
+
+## Use Case
+Standard application configuration untuk database connection pooling dan cache cluster configuration.
+
+---
+
+## Input: CONFIG5.yaml
+
+```yaml
+database:
+  host: localhost
+  port: 5432
+  name: middleware_db
+  username: ace_user
+  password: secure_pass_123
+  connectionPool:
+    minSize: 5
+    maxSize: 20
+    timeout: 30
+  allowedIPs:
+    - 192.168.1.100
+    - 192.168.1.101
+    - 10.0.0.50
+
+cache:
+  enabled: true
+  ttl: 3600
+  provider: redis
+  nodes:
+    - host: redis1.example.com
+      port: 6379
+    - host: redis2.example.com
+      port: 6379
+```
+
+---
+
+## Output: hasilParseConfig5.json
+
+```json
+{
+  "database": {
+    "host": "localhost",
+    "port": "5432",
+    "name": "middleware_db",
+    "username": "ace_user",
+    "password": "secure_pass_123",
+    "connectionPool": {
+      "minSize": "5",
+      "maxSize": "20",
+      "timeout": "30"
+    },
+    "allowedIPs": ["192.168.1.100", "192.168.1.101", "10.0.0.50"]
+  },
+  "cache": {
+    "enabled": "true",
+    "ttl": "3600",
+    "provider": "redis",
+    "nodes": [
+      {
+        "host": "redis1.example.com",
+        "port": "6379"
+      },
+      {
+        "host": "redis2.example.com",
+        "port": "6379"
+      }
+    ]
+  }
+}
+```
+
+---
+
+## ESQL Usage
+
+### Get Database Config
+```esql
+DECLARE dbConfig REFERENCE TO Environment.Variables;
+DECLARE success BOOLEAN;
+
+CALL ACE_LIB.getConfig(
+    'APP_DB_CONFIG',
+    'database',
+    '/path/to/CONFIG5.yaml',
+    '600',
+    dbConfig
+) INTO success;
+
+IF success THEN
+    -- Connection details
+    DECLARE dbHost CHARACTER dbConfig.host;
+    DECLARE dbPort CHARACTER dbConfig.port;
+    DECLARE dbName CHARACTER dbConfig.name;
+    
+    -- Connection pool settings
+    DECLARE minPool CHARACTER dbConfig.connectionPool.minSize;
+    DECLARE maxPool CHARACTER dbConfig.connectionPool.maxSize;
+    
+    -- Allowed IPs
+    DECLARE ipRef REFERENCE TO dbConfig.allowedIPs[1];
+    WHILE LASTMOVE(ipRef) DO
+        DECLARE allowedIP CHARACTER ipRef;
+        -- "192.168.1.100", "192.168.1.101", "10.0.0.50"
+        MOVE ipRef NEXTSIBLING;
+    END WHILE;
+END IF;
+```
+
+### Get Cache Config
+```esql
+DECLARE cacheConfig REFERENCE TO Environment.Variables;
+DECLARE success BOOLEAN;
+
+CALL ACE_LIB.getConfig(
+    'APP_CACHE_CONFIG',
+    'cache',
+    '/path/to/CONFIG5.yaml',
+    '600',
+    cacheConfig
+) INTO success;
+
+IF success THEN
+    -- Cache settings
+    DECLARE cacheEnabled CHARACTER cacheConfig.enabled;
+    DECLARE cacheTTL CHARACTER cacheConfig.ttl;
+    DECLARE cacheProvider CHARACTER cacheConfig.provider;
+    
+    -- Redis nodes
+    DECLARE nodeRef REFERENCE TO cacheConfig.nodes[1];
+    WHILE LASTMOVE(nodeRef) DO
+        DECLARE nodeHost CHARACTER nodeRef.host;
+        DECLARE nodePort CHARACTER nodeRef.port;
+        -- Connect to redis node...
+        MOVE nodeRef NEXTSIBLING;
+    END WHILE;
+END IF;
+```
+
+---
+
+## Key Features Tested
+
+✅ Multiple root keys (`database`, `cache`)  
+✅ Simple nested objects (1-level deep)  
+✅ Arrays of simple strings (`allowedIPs`)  
+✅ Arrays of objects (`nodes`)  
+✅ Practical real-world config structure  
+✅ Multiple configs dari same file
+
+---
+
+## Important Notes
+
+- Config ini representasi typical application configuration
+- Dapat load multiple keys dari same file dengan cache ID berbeda
+- Structure simple tapi complete untuk production use
+- Numeric dan boolean values jadi string (`"5432"`, `"true"`)
+
+---
+
+[⬅️ Back to README](../README.md)

+ 43 - 0
parseResults/hasilParseConfig1.json

@@ -0,0 +1,43 @@
+{
+    "itm": {
+        "headers": [
+            {
+                "name": "Authorization",
+                "type": "LITERAL",
+                "value": "Bearer token123"
+            },
+            {
+                "name": "Content-Type",
+                "value": "application/json"
+            }
+        ],
+        "endpoint": "https://abb.com/payment",
+        "TrxAuthMethod": "bearer",
+        "ApiSecret": "secret_itm_456",
+        "TrxSignKey": "Authorization"
+    },
+    "config1": {
+        "headers": [
+            {
+                "name": "Content-Type",
+                "type": "LITERAL",
+                "value": "application/json"
+            },
+            {
+                "name": "X-Timestamp",
+                "type": "DEFAULT"
+            },
+            {
+                "name": "X-Signature",
+                "type": "PATH",
+                "value": "Environment.Variables.Signature"
+            }
+        ],
+        "endpoint": "https://xxx.com/v1",
+        "TrxAuthMethod": "basic",
+        "ApiSecret": "secret_fundtastic_123",
+        "TrxSignKey": "X-Signature",
+        "TrxSignAlgorithm": "HMACSHA256(hex)/ApiSecret",
+        "timeout": "30000"
+    }
+}

+ 31 - 0
parseResults/hasilParseConfig2.json

@@ -0,0 +1,31 @@
+{
+    "headers": [
+        {
+            "name": "X-Api-Key",
+            "type": "LITERAL",
+            "value": "api_key_xyz"
+        },
+        {
+            "name": "User-Agent",
+            "value": "ACE-Middleware/1.0"
+        }
+    ],
+    "endpoint": "https://api.example.com",
+    "TrxAuthMethod": "oauth2",
+    "ApiSecret": "flat_secret_789",
+    "TrxSignKey": "X-Auth-Token",
+    "allowedMethods": [
+        "GET",
+        "POST",
+        "PUT",
+        "DELETE"
+    ],
+    "connectionTimeout": "5000",
+    "responseFields": [
+        "id",
+        "status",
+        "timestamp",
+        "data"
+    ],
+    "retryAttempts": "3"
+}

+ 38 - 0
parseResults/hasilParseConfig3.json

@@ -0,0 +1,38 @@
+{
+    "config3": {
+        "MultilineValue": "TrxUrlMethod || ':' || relurl || ':' || minifiedMsg",
+        "NestedEmpty": {
+            "level1": "",
+            "level2": {
+                "level3": ""
+            }
+        },
+        "provider": "stripe",
+        "EmptyObject": "",
+        "MixedArray": [
+            "simpleString1",
+            {
+                "name": "objectInArray",
+                "value": "123"
+            },
+            "simpleString2",
+            {
+                "subconfig": "",
+                "type": "TEST",
+                "key": "anotherObject"
+            }
+        ],
+        "NullishValues": {
+            "zero": "0",
+            "false": "false",
+            "empty": ""
+        },
+        "ApiSecret": "",
+        "StatusCodes": [
+            "200",
+            "201",
+            "204"
+        ],
+        "SpecialChars": "value:with:colons"
+    }
+}

+ 63 - 0
parseResults/hasilParseConfig4.json

@@ -0,0 +1,63 @@
+{
+    "config4": {
+        "metadata": {
+            "author": "ACE Team",
+            "version": "2.1.0",
+            "tags": [
+                "production",
+                "critical",
+                "payment"
+            ]
+        },
+        "level1": {
+            "level2": {
+                "level3": {
+                    "level4": {
+                        "level5": {
+                            "deepArray": [
+                                "item1",
+                                "item2"
+                            ],
+                            "finalValue": "reached_bottom"
+                        }
+                    }
+                }
+            }
+        },
+        "complexMapping": {
+            "rules": [
+                {
+                    "condition": "status == SUCCESS",
+                    "mapping": {
+                        "sourceField": "response.data.id",
+                        "targetField": "output.transactionId",
+                        "transformation": "UPPERCASE"
+                    },
+                    "action": "PROCEED",
+                    "fallback": ""
+                },
+                {
+                    "condition": "status == FAILED",
+                    "mapping": {
+                        "sourceField": "response.error.code",
+                        "targetField": "output.errorCode"
+                    },
+                    "retryConfig": {
+                        "maxAttempts": "3",
+                        "backoffMs": "1000"
+                    },
+                    "action": "RETRY"
+                },
+                {
+                    "notification": [
+                        "email",
+                        "sms",
+                        "webhook"
+                    ],
+                    "condition": "status == TIMEOUT",
+                    "action": "CANCEL"
+                }
+            ]
+        }
+    }
+}

+ 34 - 0
parseResults/hasilParseConfig5.json

@@ -0,0 +1,34 @@
+{
+    "database": {
+        "password": "secure_pass_123",
+        "port": "5432",
+        "allowedIPs": [
+            "192.168.1.100",
+            "192.168.1.101",
+            "10.0.0.50"
+        ],
+        "host": "localhost",
+        "name": "middleware_db",
+        "connectionPool": {
+            "minSize": "5",
+            "maxSize": "20",
+            "timeout": "30"
+        },
+        "username": "user"
+    },
+    "cache": {
+        "nodes": [
+            {
+                "port": "6379",
+                "host": "redis1.example.com"
+            },
+            {
+                "port": "6379",
+                "host": "redis2.example.com"
+            }
+        ],
+        "provider": "redis",
+        "ttl": "3600",
+        "enabled": "true"
+    }
+}