Skip to main content

Helper Functions

DDO: Helper Functions

DDO provides a rich set of template helpers that can be used within template expressions to perform calculations, transformations, and data manipulation. Template helpers are functions that start with @ and can be used in various expression contexts.

Template Expression Syntax

DDO supports multiple ways to use template expressions:

# String interpolation (result is always a string)
{
"message": "Hello {{ user.name }}, you have {{ @length(notifications) }} notifications"
}

# Native type preservation with ?{{ }}
{
"count": "?{{ @length(notifications) }}", # Returns number, not string
"isActive": "?{{ user.status == 'active' }}", # Returns boolean, not string
"userData": "?{{ user }}" # Returns object, not string
}

# Shorthand syntax with & prefix
{
"&count": "@length(notifications)", # Equivalent to ?{{ @length(notifications) }}
"&isActive": "user.status == 'active'", # Equivalent to ?{{ user.status == 'active' }}
"&fullName": "user.firstName + ' ' + user.lastName"
}

# Mixed expressions
{
"summary": "User {{ user.name }} has {{ @length(user.orders) }} orders",
"&totalValue": "@sum(@map(user.orders, 'total'))",
"isVip": "?{{ @length(user.orders) >= 10 }}"
}

Working with Nested Data

Template helpers can access and manipulate nested data structures:

# Access nested properties
{
"&userAge": "user.profile.age",
"&firstOrderTotal": "user.orders[0].total",
"&adminEmails": "@map(@filter(users, 'role == \"admin\"'), 'email')"
}

# Complex nested operations
{
"departmentStats": {
"&totalEmployees": "@length(departments[0].employees)",
"&avgSalary": "@avg(@map(departments[0].employees, 'salary'))",
"&seniorCount": "@length(@filter(departments[0].employees, 'level == \"senior\"'))"
}
}

# JMESPath with templates
{
"&activeUserEmails": "@map(@search(users, '[?status==`active`]'), 'email')",
"&recentOrders": "@search(orders, '[?created_at>=`2024-01-01`]')"
}

Date and Time Helpers

@now()

@now(shift)

Get the current UTC datetime.

{
"createdAt": "{{ @now() }}", # String: "2024-01-15T10:30:00Z"
"&timestamp": "@now()", # DateTime object
"scheduledFor": "{{ @now('+2days') }}" # Shifted datetime
}

@format_date(date, format)

Format a date using a specified format string.

{
"displayDate": "{{ @format_date(user.createdAt, 'YYYY-MM-DD') }}",
"shortDate": "{{ @format_date(@now(), 'MMM DD') }}",
"timestamp": "{{ @format_date(order.date, 'YYYY-MM-DD HH:mm:ss') }}"
}

# Format codes: YYYY (year), MM (month), DD (day), HH (hour), mm (minute), ss (second)

@timestamp()

Get the current Unix timestamp.

{
"created": "{{ @timestamp() }}", # String: "1705320600"
"&createdTs": "@timestamp()", # Number: 1705320600
"expiresAt": "?{{ @timestamp() + 3600 }}" # Number: timestamp + 1 hour
}

@time_ago(date)

Get human-readable relative time.

{
"lastSeen": "{{ @time_ago(user.lastLogin) }}", # "2 hours ago"
"orderAge": "{{ @time_ago(order.createdAt) }}", # "3 days ago"
"accountAge": "{{ @time_ago(user.registeredAt) }}" # "2 months ago"
}

@duration(seconds)

Format a duration in seconds to human-readable form.

{
"sessionLength": "{{ @duration(user.sessionTime) }}", # "2 hours 30 minutes"
"videoLength": "{{ @duration(video.durationSeconds) }}", # "1 hour 15 minutes"
"&totalTime": "@duration(@sum(@map(sessions, 'duration')))" # Duration object
}

ID Generation Helpers

@uuid()

Generate a UUID without dashes.

{
"sessionId": "{{ @uuid() }}", # String: "a1b2c3d4e5f6..."
"&userId": "@uuid()", # String: "a1b2c3d4e5f6..."
"trackingCode": "TRK-{{ @uuid() }}" # String: "TRK-a1b2c3d4e5f6..."
}

@uuid4()

Generate a standard UUID4 with dashes.

{
"orderId": "{{ @uuid4() }}", # String: "a1b2c3d4-e5f6-4789-..."
"&documentId": "@uuid4()", # String: "a1b2c3d4-e5f6-4789-..."
}

@shortid()

Generate a short, URL-safe ID (8 characters).

{
"code": "{{ @shortid() }}", # String: "a1B2c3D4"
"&referralCode": "@shortid()", # String: "a1B2c3D4"
"inviteLink": "https://app.com/invite/{{ @shortid() }}"
}

@md5(value)

Generate MD5 hash of a value.

{
"emailHash": "{{ @md5(user.email) }}", # For Gravatar URLs
"&passwordHash": "@md5(user.password)", # Hash for storage
"cacheKey": "user_{{ @md5(user.id) }}" # Cache key generation
}

String Manipulation Helpers

@uppercase(text)

@lowercase(text)

Convert text case.

{
"displayName": "{{ @uppercase(user.firstName) }}",
"email": "{{ @lowercase(user.email) }}",
"&code": "@uppercase(product.sku)",
"urlSlug": "{{ @lowercase(@replace(title, ' ', '-')) }}"
}

@titlecase(text)

@capitalize(text)

Format text for display.

{
"title": "{{ @titlecase(article.title) }}", # "Hello World"
"name": "{{ @capitalize(user.firstName) }}", # "John"
"&displayTitle": "@titlecase(product.name)"
}

@trim(text)

Remove whitespace from text.

{
"cleanEmail": "{{ @trim(user.email) }}",
"&username": "@trim(@lowercase(user.inputName))",
"description": "{{ @trim(product.description) }}"
}

@length(value)

Get the length of strings, arrays, or objects.

{
"nameLength": "{{ @length(user.name) }}", # String length
"&itemCount": "@length(cart.items)", # Array length
"fieldCount": "?{{ @length(user.profile) }}", # Object property count
"hasItems": "?{{ @length(cart.items) > 0 }}" # Boolean result
}

@slice(text, start, end)

Extract substring using slice notation.

{
"initials": "{{ @slice(user.firstName, 0, 1) }}{{ @slice(user.lastName, 0, 1) }}",
"preview": "{{ @slice(article.content, 0, 100) }}...",
"&productCode": "@slice(product.sku, 0, 6)"
}

@replace(text, old, new)

Replace text within strings.

{
"phoneDisplay": "{{ @replace(user.phone, '+1', '') }}",
"urlSlug": "{{ @replace(@lowercase(title), ' ', '-') }}",
"&cleanDescription": "@replace(product.description, '\\n', ' ')"
}

@split(text, separator)

Split string into array.

{
"tags": "?{{ @split(product.tagString, ',') }}", # Returns array
"&skills": "@split(user.skillsText, ';')", # Array of skills
"nameParts": "?{{ @split(user.fullName, ' ') }}" # ["John", "Doe"]
}

@slugify(text)

Convert text to URL-friendly slug.

{
"articleSlug": "{{ @slugify(article.title) }}", # "hello-world-article"
"&productUrl": "@slugify(product.name)", # "awesome-product"
"categoryPath": "/{{ @slugify(category.name) }}/{{ @slugify(product.name) }}"
}

Mathematical Helpers

Basic Math Operations

Perform mathematical calculations.

{
"total": "?{{ @add(order.subtotal, order.tax) }}",
"discount": "?{{ @mul(order.subtotal, 0.1) }}", # 10% discount
"&finalPrice": "@sub(product.price, product.discount)",
"average": "?{{ @div(@sum(scores), @length(scores)) }}"
}

@round(number)

@floor(number)

@ceil(number)

Round numbers to integers.

{
"rating": "?{{ @round(product.averageRating) }}", # 4
"pages": "?{{ @ceil(@div(content.length, 500)) }}", # Round up
"&priceRange": "@floor(product.price / 100) * 100" # Price to nearest 100
}

@random(min, max)

Generate random numbers.

{
"orderNumber": "ORD-{{ @random(10000, 99999) }}",
"&priority": "@random(1, 10)", # Random priority
"couponCode": "SAVE{{ @random(10, 99) }}"
}

Collection Helpers

@sum(array)

@avg(array)

Calculate sum and average of arrays.

{
"totalAmount": "?{{ @sum(@map(orders, 'total')) }}",
"&averageScore": "@avg(@map(reviews, 'rating'))",
"cartTotal": "?{{ @sum(@map(cart.items, 'price')) }}"
}

@min(array)

@max(array)

Find minimum and maximum values.

{
"lowestPrice": "?{{ @min(@map(products, 'price')) }}",
"&highestRating": "@max(@map(reviews, 'rating'))",
"oldestUser": "?{{ @min(@map(users, 'createdAt')) }}"
}

@filter(array, expression)

Filter arrays based on conditions.

{
"&activeUsers": "@filter(users, 'status == \"active\"')",
"highRatedProducts": "?{{ @filter(products, 'rating >= 4') }}",
"&recentOrders": "@filter(orders, 'createdAt >= \"2024-01-01\"')"
}

@map(array, expression)

Transform array elements.

{
"&userEmails": "@map(users, 'email')",
"productNames": "?{{ @map(products, 'name') }}",
"&orderTotals": "@map(orders, 'total')",
"fullNames": "?{{ @map(users, 'firstName + \" \" + lastName') }}"
}

@sort_by(array, key, reverse)

Sort arrays by a property.

{
"&sortedUsers": "@sort_by(users, 'createdAt', true)", # Newest first
"topProducts": "?{{ @sort_by(products, 'rating', true) }}",
"&orderedItems": "@sort_by(cart.items, 'price', false)" # Cheapest first
}

@group_by(array, key)

Group array elements by a property.

{
"&usersByRole": "@group_by(users, 'role')",
"ordersByStatus": "?{{ @group_by(orders, 'status') }}",
"&productsByCategory": "@group_by(products, 'category')"
}

@unique(array, key)

Get unique values from an array.

{
"&uniqueCategories": "@unique(@map(products, 'category'))",
"userRoles": "?{{ @unique(@map(users, 'role')) }}",
"&activeCities": "@unique(@map(@filter(users, 'active'), 'city'))"
}

Conditional Helpers

@if_else(condition, trueValue, falseValue)

Conditional logic within templates.

{
"status": "{{ @if_else(user.isActive, 'Online', 'Offline') }}",
"&canEdit": "@if_else(user.role == 'admin', true, false)",
"displayPrice": "{{ @if_else(product.onSale, product.salePrice, product.price) }}"
}

@switch(value, cases, default)

Multi-condition switching.

{
"statusColor": "{{ @switch(order.status, {'pending': 'yellow', 'shipped': 'blue', 'delivered': 'green'}, 'gray') }}",
"&priority": "@switch(user.role, {'admin': 10, 'moderator': 5, 'user': 1}, 0)",
"icon": "{{ @switch(file.type, {'pdf': 'file-pdf', 'image': 'image', 'video': 'play'}, 'file') }}"
}

@coalesce(value1, value2, ...)

Return the first non-null/non-empty value.

{
"displayName": "{{ @coalesce(user.nickname, user.firstName, 'Anonymous') }}",
"&userImage": "@coalesce(user.avatar, user.profilePicture, '/default-avatar.png')",
"contactEmail": "{{ @coalesce(user.workEmail, user.personalEmail, 'no-email@example.com') }}"
}

Validation Helpers

@is_empty(value)

@is_null(value)

Check for empty or null values.

{
"&hasDescription": "?@is_empty(product.description)",
"showProfile": "?{{ !@is_null(user.profile) }}",
"&requiresInput": "@is_empty(form.requiredField)"
}

@is_email(value)

@is_url(value)

Validate data formats.

{
"&validEmail": "@is_email(user.email)",
"hasWebsite": "?{{ @is_url(company.website) }}",
"&contactValid": "@is_email(contact.email)"
}

Advanced Template Examples

Complex User Profile

{
"&userProfile": {
"id": "@uuid4()",
"fullName": "user.firstName + ' ' + user.lastName",
"displayName": "@coalesce(user.nickname, user.firstName)",
"email": "@lowercase(@trim(user.email))",
"isActive": "user.status == 'active'",
"memberSince": "@format_date(user.createdAt, 'YYYY-MM-DD')",
"stats": {
"orderCount": "@length(user.orders)",
"totalSpent": "@sum(@map(user.orders, 'total'))",
"averageOrder": "@div(@sum(@map(user.orders, 'total')), @length(user.orders))",
"isVip": "@length(user.orders) >= 10"
}
}
}

Dynamic Product Catalog

{
"&catalog": {
"totalProducts": "@length(products)",
"categories": "@unique(@map(products, 'category'))",
"priceRange": {
"min": "@min(@map(products, 'price'))",
"max": "@max(@map(products, 'price'))",
"average": "@avg(@map(products, 'price'))"
},
"featuredProducts": "@filter(products, 'featured == true')",
"topRated": "@sort_by(@filter(products, 'rating >= 4.5'), 'rating', true)"
}
}

Order Summary with Calculations

{
"orderSummary": {
"orderId": "ORD-{{ @shortid() }}",
"itemCount": "?{{ @length(cart.items) }}",
"subtotal": "?{{ @sum(@map(cart.items, 'price * quantity')) }}",
"&tax": "@mul(@sum(@map(cart.items, 'price * quantity')), 0.08)",
"shipping": "?{{ @if_else(@sum(@map(cart.items, 'price * quantity')) > 100, 0, 9.99) }}",
"&total": "@add(@add(@sum(@map(cart.items, 'price * quantity')), @mul(@sum(@map(cart.items, 'price * quantity')), 0.08)), @if_else(@sum(@map(cart.items, 'price * quantity')) > 100, 0, 9.99))",
"estimatedDelivery": "{{ @format_date(@now('+3days'), 'YYYY-MM-DD') }}"
}
}

Template helpers provide powerful data transformation capabilities that make DDO suitable for complex data processing scenarios while maintaining readability and ease of use.