Built-in Functions Reference

Complete reference for built-in functions available in TinySystems expressions.

Source of truth: ajson/math.go (expression engine, github.com/tiny-systems/ajson v0.1.6) and pkg/evaluator/functions.go (SDK additions).

Function names are case-insensitive (RFC3339(...) and rfc3339(...) are the same function). There is no int() and no len() — use length() or size() for lengths. JavaScript-style property access like $.items.length is not supported; use length($.items).

Time Functions

now()

Returns the current Unix timestamp in seconds.

Returns: number (seconds since Unix epoch)

{{now()}}
// 1705312200

RFC3339()

Formats a Unix timestamp (seconds) as an RFC3339 string. With a non-numeric argument it formats the current time.

{{RFC3339(now())}}
// "2024-01-15T10:30:00Z"

{{RFC3339($.createdAtSeconds)}}
// "2024-01-10T14:22:35Z"

Time and duration arithmetic with + and -

The SDK overrides + and - for strings so RFC3339 times and Go duration strings combine:

{{RFC3339(now()) + "1h"}}      // one hour from now (RFC3339 string)
{{"2h" - "30m"}}               // "5400s" (durations combine to seconds)
{{RFC3339(now()) - "24h"}}     // yesterday

Type Conversion

string()

Converts a value to string.

InputOutput
42"42"
3.14"3.14"
true / false"true" / "false"
objectits JSON representation
stringunchanged
null, array"unknown"
{{string($.count)}}
// 42 -> "42"

{{'ID-' + string($.id)}}
// "ID-123"

There is no int(), float() or number() function. To force numeric context, use arithmetic on already-numeric data, or round()/floor()/trunc() for rounding.


Length and Size

length()

Array length or string byte length; 1 for other values, 0 when the argument is missing (e.g. a path that resolved to nothing).

{{length($.items)}}   // [1,2,3] -> 3
{{length($.name)}}    // "Alice" -> 5
{{length($.text) > 0}}

size()

Container size: array element count, object key count, string byte length.

{{size($.items)}}
{{size($.userMap)}}

String Functions

Single-argument (error if the argument is not a string):

FunctionDescriptionExample
upper(s)Uppercase{{upper($.name)}}"ALICE"
lower(s)Lowercase{{lower($.email)}}
trim(s)Strip surrounding whitespace{{trim($.input)}}
reverse(s)Reverse characters (rune-aware){{reverse('abc')}}"cba"

Multi-argument:

FunctionSignatureDescription
splitsplit(string, separator) → arraySplit a string
joinjoin(array, separator) → stringJoin an array of strings
containscontains(string, substring) → boolSubstring test
hasprefixhasprefix(string, prefix) → boolPrefix test
hassuffixhassuffix(string, suffix) → boolSuffix test
replacereplace(string, old, new) → stringReplace all occurrences
substrsubstr(string, start[, length]) → stringSubstring; negative start counts from the end
indexindex(string, substring) → numberFirst occurrence index, -1 if absent
{{join(split($.csv, ','), ';')}}
{{contains($.email, '@example.com')}}
{{substr($.id, 0, 8)}}
{{replace($.path, '/', '-')}}

For regex matching use the =~ operator: {{$.email =~ '^[^@]+@[^@]+$'}}.


Base64

FunctionDescription
b64encode(s)Standard base64 with padding
b64encoden(s)Standard base64 without padding
b64decode(s)Decode (accepts padded and unpadded input)

Non-string input returns null.

{{b64encode($.payload)}}
{{b64decode($.encoded)}}

Aggregates

sum()

Sum of a numeric array (errors if any element is non-numeric). A bare number passes through; empty array → 0; non-numeric scalar → null.

{{sum($.prices)}}

avg()

Average of a numeric array. Empty array → 0; bare number passes through.

{{avg($.scores)}}

first() / last()

First/last element of an array; null for empty arrays or non-arrays.

{{first($.items)}}
{{last($.items)}}

Logic

not()

Boolean negation with truthiness coercion (there is no unary ! operator).

{{not($.disabled)}}
{{not($.a > $.b)}}

Truthiness: false, 0, "", null, empty array, empty object → false; everything else → true.


Node Navigation

FunctionDescription
parent(n)Parent node of a path result (null at root)
root(n)Root of the document the node belongs to
key(n)Object key under which the node is stored (null if parent is not an object)
{{key($.items.first)}}
{{parent($.deeply.nested.value)}}

Random

FunctionDescription
rand(n)Random float in [0, n)
randint(n)Random integer in [0, n)
{{randint(100)}}
{{rand(1)}}

Math Functions

All operate on numbers and error on non-numeric input.

FunctionDescription
abs(n)Absolute value
ceil(n)Round up
floor(n)Round down
round(n)Round half away from zero
roundtoeven(n)Round half to even
trunc(n)Truncate toward zero
sqrt(n), cbrt(n)Square/cube root
exp(n), exp2(n), expm1(n)Exponentials
log(n), log2(n), log10(n), log1p(n), logb(n)Logarithms
pow10(n)10ⁿ (integer n)
factorial(n)n! (non-negative integer)
sin, cos, tan, asin, acos, atanTrigonometry
sinh, cosh, tanh, asinh, acosh, atanhHyperbolic
gamma, erf, erfc, erfinv, erfcinv, j0, j1, y0, y1Special functions

For exponentiation with an arbitrary base use the ** operator: {{2 ** 10}}1024.

{{round($.price * 100) / 100}}   // round to 2 decimal places
{{abs($.a - $.b)}}

Constants

ConstantValue
e2.71828…
pi3.14159…
phi1.61803…
sqrt2, sqrte, sqrtpi, sqrtphiSquare roots of 2, e, π, φ
ln2, ln10, log2e, log10eLog constants
true, false, nullLiterals
{{2 * pi * $.radius}}

Function Quick Reference

FunctionReturnsDescription
now()numberCurrent Unix timestamp (seconds)
RFC3339(ts)stringFormat seconds timestamp as RFC3339
string(v)stringConvert to string (null/array → "unknown")
length(v)numberArray/string length
size(v)numberContainer size
upper/lower/trim/reverse(s)stringString transforms
split(s, sep)arraySplit string
join(a, sep)stringJoin array
contains/hasprefix/hassuffix(s, x)boolString tests
replace(s, old, new)stringReplace all
substr(s, start[, len])stringSubstring
index(s, sub)numberFind substring
b64encode/b64encoden/b64decode(s)stringBase64
sum(a) / avg(a)numberAggregates
first(a) / last(a)anyArray ends
not(v)boolNegation (no ! operator)
parent/root/key(n)nodeNavigation
rand(n) / randint(n)numberRandom
factorial(n), pow10(n)numberMath
abs, ceil, floor, round, trunc, sqrt, log*, exp*, trignumberGo math set

Usage Examples

Timestamp Formatting

created: "{{RFC3339(now())}}"
# "2024-01-15T10:30:00Z"

Data Normalization

email: "{{lower(trim($.email))}}"
# " USER@EXAMPLE.COM " -> "user@example.com"

Calculations

discountedPrice: "{{round(($.price * 0.9) * 100) / 100}}"

Conditionals with Functions

hasContent: "{{length($.text) > 0}}"
displayName: "{{length($.nickname) > 0 ? $.nickname : $.fullName}}"

Combined Operations

summary: "{{upper($.name)}} - Items: {{length($.items)}} - Total: ${{round($.total)}}"
# "ALICE - Items: 5 - Total: $150"

Error Handling

  • A whole-string expression ("{{expr}}") that fails evaluates to null; the error is reported to the flow's expression error log.
  • A failed expression inside an interpolated string is left unevaluated (the literal {{expr}} stays visible) so you can see what failed.
  • Passing the wrong type to a function is an error (e.g. upper(5)), not a coercion.
  • || does not provide default values — it always returns a boolean. Use the ternary instead:
# Correct default value
name: "{{length($.name) > 0 ? $.name : 'unknown'}}"

# Wrong — always true/false, never the string
name: "{{$.name || 'unknown'}}"