# Operation Engine ## Purpose `operations.py` defines the generic operation engine used by schema-driven rules, functions, response actions, and some persistence flows. Most operations follow this pattern: ```json { "operation": "operationName", "key": "schema-specific values" } ``` Operation values are usually resolved through `KeyResolver`, so they can reference request fields, environment variables, auth headers, token payloads, request-scoped state, or component functions. ## Execution Context Operations receive: - the operation dictionary from schema - the current request body or prepared GET query-param dictionary Operations may: - return a response payload - set request-scoped state in Flask `g` - execute a database query - upload to S3 - call an external API - generate a JWT - transform request data ## Supported Operations ### `returnResponse` Returns an immediate business response. Common use: - validation beyond JSON Schema - business-rule rejection - flow short-circuit Fields: | Field | Purpose | | --- | --- | | `return_code` | Business return code | | `message` | Client-facing or schema-defined message | | `CF_code` | Internal response selector, usually `CF300` | Example: ```json { "operation": "returnResponse", "return_code": "INVALID_AMOUNT", "message": "Amount is not allowed", "CF_code": "CF300" } ``` ### `setData` Stores a value in request-scoped state. Fields: | Field | Purpose | | --- | --- | | `stateKey` | Flask `g` key to store | | `value` | Value or resolver expression | Special behavior: - If resolved value is `UUID`, a new UUID string is generated. Example: ```json { "operation": "setData", "stateKey": "request_uuid", "value": "UUID" } ``` ### `returnData` Returns a resolved value directly. Fields: | Field | Purpose | | --- | --- | | `resultKey` | Resolver expression | Example: ```json { "operation": "returnData", "resultKey": "$request.application_id" } ``` ### `mapData` Maps a resolved key through an enum dictionary and stores the mapped value. Fields: | Field | Purpose | | --- | --- | | `key` | Resolver expression | | `enum` | Mapping dictionary | | `stateKey` | State key to store result | Example: ```json { "operation": "mapData", "key": "$request.gender", "enum": { "M": "male", "F": "female" }, "stateKey": "gender_text" } ``` ### `length` Stores the length of a resolved value. If the value is a list, list length is used. Otherwise the string length is used. Example: ```json { "operation": "length", "key": "$request.documents", "stateKey": "document_count" } ``` ### `concat` Concatenates resolved values and optionally repeats the final string. Fields: | Field | Purpose | | --- | --- | | `values` | List of values or resolver expressions | | `number` | Optional repetition count | | `stateKey` | Store result in state | | `resultKey` | Return result instead of only storing | Example: ```json { "operation": "concat", "values": ["$request.first_name", " ", "$request.last_name"], "stateKey": "full_name" } ``` ### `query` Executes a database operation through `DatabaseOperations`. Supported query types: - `select` - `insert` - `update` - `raw` Example insert: ```json { "operation": "query", "queryType": "insert", "table": "consumer_application", "values": { "name": "$request.name", "mobile_number": "$request.phone" }, "auto_id": "id" } ``` Example select: ```json { "operation": "query", "queryType": "select", "table": "merchant", "columns": ["id", "merchant_name"], "clause": { "where": ["id"], "queryParams": ["$merchant_id"], "valueOperator": "=" }, "stateKey": "merchant_details" } ``` ### `s3Upload` Uploads base64-decoded content to S3. Fields: | Field | Purpose | | --- | --- | | `contentKey` | Resolver expression for base64 content | | `path` | Resolver expression for S3 key | | `stateKey` | Store upload status | | `resultKey` | Return upload status | Example: ```json { "operation": "s3Upload", "contentKey": "$request.file_content", "path": "$request.file_path", "stateKey": "upload_status" } ``` ### `calculate` Evaluates a simple expression after resolving each space-separated token. Example: ```json { "operation": "calculate", "value": "$request.amount * 10", "stateKey": "calculated_value" } ``` Important: this operation uses Python `eval()`. Avoid untrusted or user-controlled expression strings. ### `conversion` Converts a resolved value to string and stores it. Example: ```json { "operation": "conversion", "value": "$request.amount", "type": "str", "stateKey": "amount_string" } ``` The current implementation always converts to `str`, regardless of `type`. ### `apiCall` Calls an external API using `requests`. Fields: | Field | Purpose | | --- | --- | | `url` | Resolver expression for URL | | `headers` | Header dictionary with resolvable values | | `body` | Request body with resolvable values | | `method` | `get` or any other value for POST | | `stateKey` | Store parsed JSON response | Example: ```json { "operation": "apiCall", "method": "post", "url": "$env.CF_ENDPOINT", "headers": { "Authorization": "$auth.Authorization" }, "body": { "application_id": "$request.application_id" }, "stateKey": "backend_response" } ``` ### `iterate` Transforms a list into a new list using a schema-defined structure. Example: ```json { "operation": "iterate", "storeType": "list", "value": "$request.documents", "struct": { "file_type": "type", "file_name": "name" }, "stateKey": "formatted_documents" } ``` ### `date_calc` Performs date calculations. Current implementation supports age-like subtraction between two dates. Example: ```json { "operation": "date_calc", "type": "subtraction", "values": ["$request.date_of_birth", "today"], "stateKey": "age" } ``` Expected date format is: ```text YYYY-MM-DD ``` ### `generateToken` Generates a JWT using `StaticFunctions.generate_token()`. Fields: | Field | Purpose | | --- | --- | | `payload` | JWT payload with resolvable values | | `algorithm` | JWT algorithm | | `signingKey` | Resolver expression for signing key | | `stateKey` | Store generated token | Payload keys `exp`, `iat`, and `nbf` support relative date values: ```json { "days": 1, "hours": 0, "minutes": 0, "seconds": 0 } ``` Example: ```json { "operation": "generateToken", "stateKey": "access_token", "algorithm": "HS256", "signingKey": "$env.SECRET_KEY", "payload": { "merchant_id": "$merchant_id", "exp": { "hours": 1 } } } ``` ## Conditions Conditions are evaluated by `helper_functions.condition_check()`. Supported condition operators: | Operator | Behavior | | --- | --- | | `equals` | True when first resolved value equals last literal or resolved value | | `notEquals` | True when first and last resolved values differ, or either is `None` | | `isNotNull` | True when first resolved value is truthy | | `greaterThan` | Integer comparison | | `lesserThan` | Integer comparison | | `in` | Checks whether first value exists in last value parsed with `ast.literal_eval()` | Representative condition: ```json ["$request.amount", "greaterThan", "100000"] ``` ## Adding A New Operation When adding a new operation: 1. Add the implementation in `Operations.perform_operation()`. 2. Resolve schema-provided values through `KeyResolver` instead of manually reading raw strings. 3. Define whether the operation returns data, stores state, or returns `1`. 4. Add tests or schema examples for success and failure behavior. 5. Update this file with fields, examples, side effects, and risks.