TGL: Functions

TGL: Functions

Built-in functions are the only callable functions in TGL. They do not mutate your input or output. Most return null for a wrong type or a missing value, while predicates such as isEmpty and isValidDate return a boolean and typeOf always returns a type name. now() is intentionally time-dependent, so it returns a different value as time advances.

There are five categories: math, string, array, type, and date.

Math

FunctionReturns
add(a, b, ...)sum of all arguments (variadic)
subtract(a, b)a minus b
multiply(a, b, ...)product of all arguments (variadic)
divide(a, b)a divided by b (returns null if b is 0)
mod(a, b)a modulo b (returns null if b is 0)
abs(n)absolute value
round(n, decimals?)rounds to N decimals (default 0)
floor(n)rounds down
ceil(n)rounds up
min(a, b, ...)smallest argument (variadic)
max(a, b, ...)largest argument (variadic)
$out.tax = round(multiply($row.subtotal, 0.0825), 2)
$out.bucket = floor(divide($row.age, 10))
$out.peak = max($row.q1, $row.q2, $row.q3, $row.q4)

Null handling in math

add and subtract treat null as 0 so accumulator patterns work:

$out.sum = 0
#each $row.values as $v
  $out.sum = add($out.sum, $v)   // null v contributes 0, doesn't break the chain
/each

multiply, divide, mod short-circuit on null. If any argument is null, the result is null. This catches “missing field” cases loudly instead of silently making everything zero.

String

FunctionReturns
lowerCase(s)lowercased string
upperCase(s)uppercased string
trim(s)whitespace stripped from both ends
trimStart(s)leading whitespace stripped
trimEnd(s)trailing whitespace stripped
concat(...)joins arguments into one string (variadic)
length(s_or_array)character or element count
contains(s, search)true if s contains search
startsWith(s, prefix)true if s starts with prefix
endsWith(s, suffix)true if s ends with suffix
substring(s, start, end?)slice (negative indices count from end)
split(s, delimiter, limit?)array of pieces
replace(s, search, replacement)replaces first occurrence
replaceAll(s, search, replacement)replaces every occurrence
$out.email = lowerCase(trim($row.email))
$out.full_name = concat($row.first, " ", $row.last)
$out.domain = split($row.email, "@")[1]
$out.is_gmail = endsWith($row.email, "@gmail.com")

concat is variadic and converts numbers/booleans to their string form: concat("Hello, ", $row.name, "! You have ", $row.count, " messages") works directly. If any argument is null, the whole result is null. Handle missing values with ?? first.

length is grapheme-aware on strings: length("👋") is 1, not 2. It also works on arrays.

Array

FunctionReturns
includes(array, value)true if array contains value
push(array, value)new array with value appended
prepend(array, value)new array with value prepended
merge(arr1, arr2, ...)concatenates arrays
flat(array, depth?)flattens nested arrays (default depth 1)
unique(array)removes duplicate primitives
join(array, separator)joins into a string

Arrays in TGL are immutable from the script’s perspective. push doesn’t mutate the source, it returns a new array. That means the accumulator pattern looks like:

$out.tags = null
#each $row.raw_tags as $t
  $out.tags = push($out.tags, lowerCase($t))
/each

push(null, x) returns [x], so the loop builds up an array starting from null without needing a separate initialization.

There are no array literals ([1, 2, 3]). Build arrays via push/prepend or read them off $row.

Type

FunctionReturns
int(value)parsed integer (truncates), null if not parseable
float(value)parsed float, null if not parseable
string(value)string form of a primitive, null for objects/arrays
bool(value)true / false / null (only for explicit boolean-like values)
typeOf(value)“string” / “number” / “boolean” / “null” / “array” / “object”
isEmpty(value)true if value is null, undefined, "", whitespace-only, [], or {}

The most common use is numeric coercion for CSV-ingested data, where everything arrives as a string:

$out.total = add(int($row["Quantity"]), int($row["Bonus"]))
$out.price = float($row["Price"])

add(string, number) returns null because add is strict about types. int($row["Quantity"]) parses "42" into 42, then add works.

bool is strict: it accepts true/false, 1/0, and "true"/"false" (case-insensitive). It does NOT treat truthiness loosely: bool(2) is null, bool("yes") is null, bool("") is null. Use !!$row.value if you want truthiness; use bool when the source is a real boolean encoded in another type.

isEmpty is the platform’s shared definition of “missing”; useful for branching on optional fields. Unlike ??, which only catches null and undefined, isEmpty also treats empty strings, whitespace-only strings, empty arrays, and empty objects as missing. Real values like 0, false, and "0" are NOT empty:

// normalize missing-shaped values to null in view output
#if isEmpty($row.secondary_type)
  $out.secondary_type = null
#else
  $out.secondary_type = $row.secondary_type
/if

Date

Date functions emit milliseconds since epoch as plain integers. They accept several input forms, including ISO strings, Unix seconds or milliseconds, and timestamp objects with seconds and nanoseconds.

FunctionReturns
now()current UTC time in ms
date(input)parses any common date format into ms
isValidDate(input)true if input parses
addTime(ms, amount, unit)shifted timestamp
startOf(ms, unit)start of day/hour/etc.
endOf(ms, unit)end of day/hour/etc.
year(ms) / month(ms) / day(ms)components (UTC)
weekday(ms) / weekdayName(ms)1=Mon..7=Sun, name string
hour(ms) / minute(ms) / second(ms) / millisecond(ms)components
formatDate(ms, format)formatted string (Luxon tokens)
toISO(ms)ISO 8601 string
toDateString(ms)YYYY-MM-DD
toTimeString(ms)HH:mm:ss
toMillis(input) / toSeconds(input)parsed date as ms / whole Unix seconds
dateDiff(a, b, unit)difference in unit (days, hours, etc.)
isWeekend(ms) / isWeekday(ms)true/false
isBefore(a, b) / isAfter(a, b)comparison

Units accepted by addTime / startOf / endOf / dateDiff: year, month, week, day, hour, minute, second, millisecond (with or without a trailing s).

// Bucket by week
$out.week_start = startOf(date($row.created_at), "week")

// Days since signup
$out.tenure_days = dateDiff(now(), date($row.signup_at), "days")

// Pretty-print
$out.label = formatDate(date($row.created_at), "yyyy-MM-dd HH:mm")

If the input doesn’t parse, date() returns null. Date functions that produce a value or formatted string return null for invalid input; date predicates such as isValidDate, isWeekend, and isBefore return false.

Numeric date input below 10 billion is interpreted as Unix seconds; larger numeric input is interpreted as milliseconds. Both toMillis and toSeconds apply that parsing rule before converting to their requested unit.

What’s next

  • Recipes: common patterns combining these functions.
  • Operators: comparison, logical, nullish coalescing.