GUBUS COMPOSE

COMPOSE creates formatted messages from object data using template patterns and special operations. Modern implementation with direct field mapping, special placeholders, and SchemaContext integration.

💡

Use COMPOSE to create formatted messages with dynamic field values and aggregations. Supports special placeholders like {$counter}, {$summator:field}, and {$context_variable:name} for powerful message construction.

Overview

COMPOSE creates formatted messages from object data. Combines static text (header/footer) with dynamic field values using template patterns and special operations.

When to use:

  • Build notification messages for Telegram/Viber bots
  • Create summary reports with aggregations (counts, sums, enumerations)
  • Format confirmation messages for users
  • Construct email bodies with dynamic content and context variables

Key characteristics:

  • Direct field reference with {field_name} placeholders
  • Special operations with {$operation:field} syntax (counters, enumerators, summators)
  • SchemaContext integration for cross-transform variable access
  • 3 destination types: main_message, obj_field, context_variable
  • Conditional composition based on field values
  • Empty data handling with custom fallback messages

How It Works (Modern Implementation)

[Preprocessing]
  → [Apply special placeholders to header/footer/pattern]
  → [Resolve {$counter}, {$enumerator}, {$summator}, etc.]
  → [Resolve {$context_variable:var_name} from SchemaContext]

[For each object]
  → [Check condition if specified]
  → [Replace {field_name} directly from object properties]
  → [No need for message_construct_fields list]
  → [Concatenate with newlines]

[Finalization]
  → [Prepend header with \n\n]
  → [Append footer with \n]
  → [Write to destination]
💡

Key difference from legacy: Modern approach uses direct field mapping from object properties rather than requiring explicit field lists. Special placeholders are processed before object iteration.


Rule Properties (Modern)

PROPERTYDESCRIPTION
referenceRequired. Example: “orderConfirmation”
message_construct_patternRequired. Template with {field_name} and {$operation:field}. Example: “Order {order_id} total: {total}“
destination_typeRequired. “set_main_message”, “join_main_message_empty_line”, “join_main_message_new_line”, “obj_field”, or “context_variable”
headerStatic text prepended. Supports special placeholders. Example: ”📋 ORDER SUMMARY ({$counter} items)“
footerStatic text appended. Supports special placeholders. Example: “Total: {$summator:price}“
if_empty_messageMessage when no objects match condition
field_name_if_target_in_objRequired if destination_type=“obj_field”. Field name to write to
conditionCondition type. Example: “equals”
condition_fieldField to check for condition
condition_valueValue to match for condition

Key changes from legacy:

  • message_construct_fields is NO LONGER REQUIRED - fields are extracted directly from pattern
  • Special placeholders work in header, footer, AND pattern
  • Must pass SchemaContext (sc) for context variable resolution

Special Placeholders (NEW in Modern)

Special placeholders use the syntax {$operation:field} and are resolved BEFORE object iteration. They provide aggregation and cross-transform capabilities.

PLACEHOLDERDESCRIPTIONEXAMPLE
{$counter}Total count of objects{$counter} → “5” (for 5 objects)
{$enumerator:field}Comma-separated values of field{$enumerator:item_no} → “A1, A2, A3”
{$enumerator_newline:field}Newline-separated values{$enumerator_newline:name} → “Widget\nGadget\nTool”
{$unique_enumerator:field}Unique comma-separated values{$unique_enumerator:category} → “Electronics, Tools”
{$summator:field}Sum of numeric field{$summator:quantity} → “150” (sum of all quantities)
{$context_variable:var_name}Value from SchemaContext{$context_variable:user_id} → retrieves sc.contextVariables[‘user_id’]

Where they work: header, footer, message_construct_pattern

Use cases:

  • Headers showing totals: "Processing {$counter} orders"
  • Footers with sums: "Total amount: ${$summator:price}"
  • Listing all values: "Items: {$enumerator:item_name}"
  • Cross-transform data: "User {$context_variable:username} completed {$counter} tasks"

Destination Types

set_main_message

REPLACES SchemaContext.mainMessage entirely (overwrites existing content).

{
  "destination_type": "set_main_message",
  "message_construct_pattern": "System initialized with {$counter} records"
}

join_main_message_new_line / join_main_message_empty_line

APPENDS to SchemaContext.mainMessage with newline or empty line separator.

{
  "destination_type": "join_main_message_new_line",
  "header": "Orders ({$counter}):",
  "message_construct_pattern": "- {order_id}: {customer_name}"
}

obj_field

Writes message to specified field in each object.

{
  "destination_type": "obj_field",
  "field_name_if_target_in_obj": "notification",
  "message_construct_pattern": "Item {name}: ${price}"
}

Each object gets new field with formatted message.


context_variable

Stores message in SchemaContext variable for use by other transforms.


Common Use Cases (Modern Implementation)

Use Case 1: Order Confirmation with Aggregations

{
  "destination_type": "join_main_message_new_line",
  "header": "✅ ORDER CONFIRMED ({$counter} items)",
  "message_construct_pattern": "- {item_name} x{quantity}",
  "footer": "Total: ${$summator:total_price}\nThank you!"
}

Input:

[
  {item_name: "Widget", quantity: 2, total_price: 50},
  {item_name: "Gadget", quantity: 1, total_price: 100}
]

Output (mainMessage):

✅ ORDER CONFIRMED (2 items)

- Widget x2
- Gadget x1

Total: $150
Thank you!
💡

No message_construct_fields needed! Fields extracted directly from pattern.


Use Case 2: Summary Report with Special Placeholders

{
  "destination_type": "set_main_message",
  "header": "📦 SHIPMENT REPORT",
  "message_construct_pattern": "Tracking: {tracking_no}\nDestination: {city}",
  "footer": "Total packages: {$counter}\nCities: {$unique_enumerator:city}"
}

Input:

[
  {tracking_no: "TRK001", city: "New York"},
  {tracking_no: "TRK002", city: "Los Angeles"},
  {tracking_no: "TRK003", city: "New York"}
]

Output:

📦 SHIPMENT REPORT

Tracking: TRK001
Destination: New York
Tracking: TRK002
Destination: Los Angeles
Tracking: TRK003
Destination: New York

Total packages: 3
Cities: New York, Los Angeles

Use Case 3: Context Variable Integration

{
  "destination_type": "join_main_message_empty_line",
  "header": "Processing for user: {$context_variable:username}",
  "message_construct_pattern": "Task {task_id}: {task_name}",
  "footer": "Completed {$counter} tasks"
}

Prerequisites: SchemaContext must have contextVariables['username'] set by previous transform.

Output: Uses username from context and counts current objects.


Use Case 4: Static Message (No Object Iteration)

{
  "destination_type": "set_main_message",
  "message_construct_pattern": "System initialized. Found {$counter} records from {$context_variable:source_file}"
}

Use case: When destination_type includes “set_main_message”, the pattern can be used without iterating objects. Special placeholders still work.


Use Case 5: Newline-Separated Enumeration

{
  "destination_type": "set_main_message",
  "header": "Pending Items:",
  "message_construct_pattern": "{$enumerator_newline:item_no}"
}

Input: [{item_no: "A1"}, {item_no: "A2"}, {item_no: "A3"}]

Output:

Pending Items:

A1
A2
A3

Use Case 6: Per-Object Field with Aggregations

{
  "destination_type": "obj_field",
  "field_name_if_target_in_obj": "summary",
  "message_construct_pattern": "{name} (${price}) - Part of {$counter} total items"
}

Input: {name: "Laptop", price: 999}

Output: Object gets summary: "Laptop ($999) - Part of 5 total items" (if 5 objects total)


Best Practices (Modern)

Do’s ✅

  • Use special placeholders for aggregations instead of manual counting
  • Reference fields directly in pattern: {field_name}
  • Use {$context_variable:name} for cross-transform data sharing
  • Set if_empty_message when using conditions
  • Use newlines (\n) in pattern for multi-line formatting
  • Pass SchemaContext when using context variables
  • Use {$unique_enumerator:field} to avoid duplicates in lists

Don’ts ❌

  • Don’t use message_construct_fields - it’s deprecated in modern implementation
  • Don’t forget curly braces: {field_name} not field_name
  • Don’t use special placeholder syntax for regular fields: {field} not {$field}
  • Don’t use COMPOSE for data transformation - use TRANSFORM flow
  • Don’t try to iterate objects when using set_main_message with only special placeholders

Troubleshooting (Modern)

Special placeholders not working:

  • Ensure syntax is exact: {$counter} not {counter}
  • For field operations: {$enumerator:field_name} not {$enumerator field_name}
  • Verify SchemaContext passed when using {$context_variable:name}
  • Check field exists in objects for field-based operations

Regular placeholders not replaced:

  • Verify field exists in objects
  • Check spelling in pattern (case-sensitive)
  • Ensure curly braces: {field} not {{field}}
  • Don’t mix with message_construct_fields - remove that property

Empty message:

  • Add if_empty_message for user feedback
  • Check condition logic
  • Verify objects array is not empty
  • For set_main_message without objects, ensure using only special placeholders

Destination not working:

  • For obj_field: must specify field_name_if_target_in_obj
  • For main_message variations: use correct type (set_main_message, join_main_message_new_line, join_main_message_empty_line)
  • Check destination_type spelling (case-sensitive)

Context variables undefined:

  • Ensure SchemaContext parameter passed to function
  • Verify variable set in previous transform
  • Check variable name spelling: {$context_variable:var_name}

Technical Implementation Details

The modern composeReadMessageFromStraightObjsModern function uses:

1. replaceSpecialPlaceholders() - Preprocesses header, footer, and pattern

  • Regex: /\{\$([^{}]+)\}/g matches {$operation:field}
  • Splits on : to get operation and field name
  • Executes operations (counter, enumerator, summator, etc.)
  • Returns early-resolved strings before object iteration

2. DataOperatorUtil.replaceFieldsWithValues() - Direct field mapping

  • Replaced legacy replaceArrayValues() which required field arrays
  • Pattern {field_name} directly replaced with obj[field_name]
  • No need for message_construct_fields property
  • Cleaner, more maintainable code

3. SchemaContext Integration

  • Required parameter for context variable access
  • sc.contextVariables[fieldName] provides cross-transform state
  • Enables complex multi-step workflows with shared data
💡

Key architectural improvement: Separation of concerns - special placeholders resolved once (aggregations), then per-object field replacement happens independently.


Migration from Legacy to Modern

Legacy approach:

{
  "message_construct_pattern": "Order {0} total: {1}",
  "message_construct_fields": "order_id,total"
}

Modern approach:

{
  "message_construct_pattern": "Order {order_id} total: {total}"
}

Steps to migrate:

  1. Remove message_construct_fields property
  2. Replace numeric placeholders {0}, {1} with field names {field_name}
  3. Add special placeholders for aggregations in header/footer
  4. Ensure SchemaContext passed to function
  5. Update destination_type if using “main_message” (change to specific type)

Benefits:

  • More readable patterns (self-documenting)
  • Less configuration (no field lists)
  • Fewer errors (typos caught immediately)
  • More powerful (special placeholders, context variables)

Summary

COMPOSE (Modern) creates formatted messages from object data:

  • Direct field reference with {field_name} syntax
  • Special operations: {$counter}, {$enumerator:field}, {$summator:field}, {$unique_enumerator:field}, {$enumerator_newline:field}
  • SchemaContext integration via {$context_variable:name}
  • Header/footer with full placeholder support
  • Multiple destination types for different use cases
  • Conditional composition
  • Empty data handling

When to use: Bot notifications, email composition, report generation, user messages with aggregations, cross-transform data sharing

When NOT to use: Data transformations (TRANSFORM), calculations (TRANSFORM), filtering (FILTER), complex data restructuring

Modern advantages: Simpler configuration, more readable patterns, powerful aggregations, context sharing, maintainable code


Next Steps

👉 GUBUS SCHEMA → - Learn how schemas orchestrate workflows

👉 GUBUS MULTIPANEL → - Learn about panel-based message construction

👉 ← Back to Getting Started - Return to the main documentation