Skip to main content

Wolf DSL Expressions

Expressions are the heart of data manipulation in Wolf DSL. They enable dynamic data processing, conditional logic, and complex transformations within Mapping nodes, Flow transitions, and Value nodes.

What are Expressions?

Expressions are declarative statements for data transformation, conditional logic, calculations, and data access.

Expression Categories

Arithmetic Expressions

Mathematical operations and calculations:

result = price * quantity + tax
total = subtotal - discountAmount
average = sum / count

Boolean Expressions

Logical operations and boolean algebra:

isValid = hasEmail && hasPassword && isActive
canProceed = isAuthorized || isAdmin
isDisabled = !isEnabled

Conditional Expressions

Comparisons, ternary operations, and membership tests:

// Comparisons
isAdult = age >= 18
isPremium = accountType == "premium"

// Ternary
status = if isActive then "enabled" else "disabled"
price = if isPremium then regularPrice * 0.8 else regularPrice

// Membership
isValidStatus = status in ["active", "pending", "trial"]

Expression Usage Contexts

In Mapping Transformations

Schema OrderProcessing {
number quantity
number unitPrice
number taxRate
number total
string status
}

Mapping calculateOrder input OrderData output OrderProcessing {
// Arithmetic expressions
OrderProcessing.total = (OrderData.quantity * OrderData.unitPrice) * (1 + OrderData.taxRate)

// Conditional expressions
OrderProcessing.status = if OrderProcessing.total > 100
then "priority"
else "standard"
}

In Flow Transitions

Flow orderProcessingFlow {
Start validateOrder {
transition {
// Boolean expressions control flow
order.isValid && order.total > 0 ? processPayment : handleError

// Complex conditions
(customer.isPremium || order.total > 500) && inventory.available ?
expediteOrder :
standardProcessing
}
}

processPayment {}
expediteOrder {}
standardProcessing {}
handleError {}
}

In Value Definitions

Schema DynamicConfig {
string environment
number maxRetries
boolean debugMode
string apiUrl
}

value appConfig -> DynamicConfig {
environment: ${if isDevelopment then "dev" else "prod"}
maxRetries: ${if environment == "prod" then 5 else 1}
debugMode: ${environment != "prod" && enableDebugging}
apiUrl: ${baseUrl + "/" + version + "/api"}
}

With Function Calls

Schema UserProcessing {
string firstName
string lastName
string email
string fullName
boolean hasValidEmail
number accountAge
}

Mapping processUser input UserData output UserProcessing {
// Combining functions with expressions
UserProcessing.fullName = upperCase(UserData.firstName) + " " + upperCase(UserData.lastName)

// Boolean expressions with functions
UserProcessing.hasValidEmail = contains(UserData.email, "@") && length(UserData.email) > 5

// Arithmetic with functions
UserProcessing.accountAge = dayDifference(
UserData.registrationDate,
currentDate("yyyy-MM-dd"),
"yyyy-MM-dd"
) / 365
}

Expression Types and Literals

Primitive Values

// String literals
greeting = "Hello, World!"
path = "/api/v1/users"
template = "User {name} has {count} items"

// String expressions
fullPath = basePath + "/" + resourcePath
message = "Welcome " + userName + "!"

Variable References

Direct Field Access

Schema UserProfile {
string name
number age
address {
string street
string city
string zipCode
}
}

Mapping accessFields input UserProfile output DisplayInfo {
// Direct field access
DisplayInfo.userName = UserProfile.name
DisplayInfo.userAge = UserProfile.age

// Nested field access
DisplayInfo.userCity = UserProfile.address.city
DisplayInfo.fullAddress = UserProfile.address.street + ", " + UserProfile.address.city
}

Array Access

Schema DataProcessor {
number[] values
item[] items
}

Mapping processArrays input DataProcessor output Results {
// Array element access
Results.firstValue = DataProcessor.values[0]
Results.lastValue = DataProcessor.values[-1] // Last element
Results.thirdItem = DataProcessor.items[2]

// Array expressions
Results.hasValues = length(DataProcessor.values) > 0
Results.totalItems = length(DataProcessor.items)
}

Scoped References

Schema ContextualData {
string globalValue
items [
string name
number value
]
}

Mapping useScopes input ContextualData as global output ProcessedData {
// Global scope reference
ProcessedData.header = global.globalValue

// Local scope in mapping
ProcessedData.filteredItems = filter(
global.items,
// Within filter, 'item' is local scope, use :: for global
item -> item.value > 100 && contains(item.name, ::global.globalValue)
)
}

Expression Evaluation Rules

1. Operator Precedence

// Mathematical precedence (like standard algebra)
result = 2 + 3 * 4 // = 14 (not 20)
result = (2 + 3) * 4 // = 20 (explicit grouping)
result = 10 / 2 * 3 // = 15 (left-to-right for same precedence)

// Boolean precedence
result = true || false && false // = true (AND before OR)
result = (true || false) && false // = false (explicit grouping)

2. Type Coercion

// Automatic string conversion
message = "Count: " + 42 // = "Count: 42"
path = "/users/" + userId // = "/users/123"

// Numeric operations
total = "10" + 5 // = 15 (string to number)
result = "3.14" * 2 // = 6.28

3. Null Handling

// Safe null operations
result = null + 5 // = 5
text = null + "default" // = "default"
flag = null && true // = false
flag = null || true // = true

// Explicit null checks
value = if data != null then data.field else "fallback"

Advanced Expression Patterns

Complex Conditional Logic

Schema BusinessRules {
number orderTotal
string customerTier
boolean isHoliday
number discountRate
string shippingSpeed
}

Mapping applyBusinessRules input OrderData output BusinessRules {
// Complex discount calculation
BusinessRules.discountRate = if OrderData.customerTier == "platinum"
then if OrderData.orderTotal > 1000 then 0.15 else 0.10
else if OrderData.customerTier == "gold"
then if OrderData.orderTotal > 500 then 0.08 else 0.05
else if OrderData.orderTotal > 200 then 0.03 else 0.0

// Multi-condition shipping logic
BusinessRules.shippingSpeed = if OrderData.isHoliday && OrderData.orderTotal > 100
then "express"
else if OrderData.customerTier in ["platinum", "gold"] && OrderData.orderTotal > 50
then "priority"
else "standard"
}

Function Chaining with Expressions

Schema DataPipeline {
string[] rawData
string[] processedData
string summary
}

Mapping processDataPipeline input DataPipeline output DataPipeline {
// Complex chaining with expressions
DataPipeline.processedData = map(
filter(
DataPipeline.rawData,
item -> length(item) > 3 && contains(item, "@")
),
item -> upperCase(replace(item, "@", " at "))
)

// Summary with complex expression
DataPipeline.summary = "Processed " +
length(DataPipeline.processedData) +
" out of " +
length(DataPipeline.rawData) +
" items (" +
(length(DataPipeline.processedData) * 100 / length(DataPipeline.rawData)) +
"% success rate)"
}

Dynamic Value Construction

Schema DynamicApiCall {
string baseUrl
string version
string resource
string queryParams
string fullUrl
}

Mapping buildApiUrl input RequestContext output DynamicApiCall {
DynamicApiCall.fullUrl = DynamicApiCall.baseUrl +
"/" + DynamicApiCall.version +
"/" + DynamicApiCall.resource +
if length(DynamicApiCall.queryParams) > 0
then "?" + DynamicApiCall.queryParams
else ""
}

Best Practices

1. Use Parentheses for Clarity

//  Good: Clear precedence
result = (price * quantity) + (tax * rate)
condition = (isValid && hasPermission) || isAdmin

// Confusing: Relies on implicit precedence
result = price * quantity + tax * rate
condition = isValid && hasPermission || isAdmin

2. Break Complex Expressions

//  Good: Break into logical steps
baseAmount = price * quantity
taxAmount = baseAmount * taxRate
total = baseAmount + taxAmount

// Hard to read: Everything in one expression
total = (price * quantity) + ((price * quantity) * taxRate)

3. Use Meaningful Variable Names

//  Good: Descriptive names
isEligibleForDiscount = customerTier in ["gold", "platinum"] && orderTotal > 100
finalPrice = if isEligibleForDiscount then basePrice * 0.9 else basePrice

// Unclear: Generic names
flag = tier in ["gold", "platinum"] && total > 100
price = if flag then bp * 0.9 else bp

4. Handle Edge Cases

//  Good: Safe operations
averageScore = if length(scores) > 0
then sum(scores, score -> score) / length(scores)
else 0

percentage = if total > 0 then (completed / total) * 100 else 0

// Risky: No edge case handling
averageScore = sum(scores, score -> score) / length(scores) // Division by zero!
  • Arithmetic Expressions - Mathematical operations and calculations
  • Arithmetic Expressions - Mathematical operations and calculations
  • Boolean Expressions - Logical operations and boolean algebra (covered above)
  • Conditional Expressions - Comparisons, ternary, and membership (covered above)
  • Functions Reference - Using functions in expressions
  • Mapping Node - Transforming data with expressions
  • Flow Node - Controlling flow with conditional expressions