Pure transformations

FeatureQL includes a rich set of functions for transforming data — arithmetic, string manipulation, date math, conditionals, and more. This page shows a representative example for each data type to give you a feel for the syntax. It is not exhaustive: the complete list of all functions is in the syntax reference .

Numerics

Arithmetic operators (+, -, *, /) work as expected. / always returns DOUBLE. // divides, then truncates toward zero at the dividend's scale — not Python floor, not round-to-even. 7 // 2 is 3; -7 // 2 is -3; 1.5 // 0.4 is 3.7 (DECIMAL(2,1)). Compile-time 1 // 0 is UE/ARGUMENT-MUST-BE-NON-ZERO. For a floating quotient use /. FeatureQL also includes rounding and mathematical functions like ABS(), SQRT(), EXP(), and MOD().

FeatureQL
DEFINE
    price := 49.99e0,
    tax_rate := 0.21e0
RETURN
    price,
    tax := ROUND(price * tax_rate, 2),
    total := ROUND(price * (1e0 + tax_rate), 2),
    half := price / 2e0,
    rounded := CEIL(total)
;
Result
PRICE DOUBLETAX DOUBLETOTAL DOUBLEHALF DOUBLEROUNDED BIGINT
49.9910.560.4924.99561

Strings

String concatenation uses || or CONCAT(). FeatureQL provides the usual toolkit for splitting, extracting, replacing, and formatting strings.

FeatureQL
DEFINE
    first_name := 'Alice',
    last_name := 'Johnson',
    email := 'alice.johnson@example.com'
RETURN
    full_name := first_name || ' ' || last_name,
    domain := SPLIT_PART(email, '@', 2),
    initials := SUBSTR(first_name, 1, 1) || SUBSTR(last_name, 1, 1),
    slug := LOWER(REPLACE(full_name, ' ', '-'))
;
Result
FULL_NAME VARCHARDOMAIN VARCHARINITIALS VARCHARSLUG VARCHAR
Alice Johnsonexample.comAJalice-johnson

Conditionals

IF() handles simple branching, CASE WHEN handles multi-branch logic, and COALESCE() picks the first non-null value. All three return typed values — no implicit coercion.

FeatureQL
DEFINE
    score := 73
RETURN
    score,
    grade := CASE
        WHEN score >= 90 THEN 'A'
        WHEN score >= 80 THEN 'B'
        WHEN score >= 70 THEN 'C'
        WHEN score >= 60 THEN 'D'
        ELSE 'F'
    END,
    is_passing := score >= 60,
    label := IF(is_passing, 'Pass', 'Fail')
;
Result
SCORE BIGINTGRADE VARCHARIS_PASSING BOOLEANLABEL VARCHAR
73CtruePass

Dates and timestamps

Date functions follow a consistent pattern: DATE_ADD(timestamp, count, unit) to shift (DATE_ADD(d, 7, 'day')), DATE_SUBTRACT(end, start, unit) to measure elapsed complete units, and DATE_DIFF(end, start, unit) to count boundary crossings. DATE_FORMAT() renders a timestamp. DATE_PART(d, 'year') pulls out a component; EXTRACT_FROM_DATE() is the permissive alias. The old DATE_ADD(d, 'day', 7) order is refused with a hint. Timestamps support up to microsecond precision.

FeatureQL
DEFINE
    signup := TIMESTAMP '2025-11-03 14:30:00',
    now := TIMESTAMP '2026-02-17 10:00:00'
RETURN
    signup,
    days_since := DATE_SUBTRACT(now, signup, 'day'),
    month := DATE_FORMAT(signup, '%B %Y'),
    is_recent := DATE_SUBTRACT(now, signup, 'day') <= 90
;
Result
SIGNUP TIMESTAMP(3)DAYS_SINCE BIGINTMONTH VARCHARIS_RECENT BOOLEAN
2025-11-03T14:30:00105November 2025false

JSON

FeatureQL can parse, extract from, and format JSON values. Use JSON_EXTRACT_SCALAR() to pull a single value as a string, or JSON_EXTRACT() to get a nested JSON fragment.

FeatureQL
DEFINE
    event := JSON '{"type": "purchase", "user_id": "u_42", "payload": {"amount": 29.99, "currency": "EUR"}}'
RETURN
    event,
    event_type := JSON_EXTRACT_SCALAR(event, '$.type'),
    user_id := JSON_EXTRACT_SCALAR(event, '$.user_id'),
    amount := JSON_EXTRACT_SCALAR(event, '$.payload.amount')
;
Result
EVENT JSONEVENT_TYPE VARCHARUSER_ID VARCHARAMOUNT VARCHAR
{"type": "purchase", "user_id": "u_42", "payload": {"amount": 29.99, "currency": "EUR"}}purchaseu_4229.99

Arrays

Arrays support set operations (ARRAY_UNION(), ARRAY_INTERSECT(), ARRAY_EXCEPT()), membership checks (CONTAINS()), sorting, and aggregation (ARRAY_SUM(), ARRAY_COUNT()). For vector operations, see COSINE_SIMILARITY(), DOT_PRODUCT(), and EUCLIDEAN_DISTANCE().

FeatureQL
DEFINE
    tags := ARRAY('premium', 'vip', 'early-adopter'),
    other_tags := ARRAY('vip', 'enterprise', 'beta')
RETURN
    tags,
    tag_count := ARRAY_COUNT(tags),
    has_vip := CONTAINS(tags, 'vip'),
    sorted := ARRAY_SORT(tags),
    common := ARRAY_INTERSECT(tags, other_tags)
;
Result
TAGS ARRAY<VARCHAR>TAG_COUNT BIGINTHAS_VIP BOOLEANSORTED ARRAY<VARCHAR>COMMON ARRAY<VARCHAR>
[premium, vip, early-adopter]3true[early-adopter, premium, vip][vip]

Rows

A ROW is a named struct. You create one with ROW(...), name fields with AS, and extract fields with []. Extracting multiple fields returns a new row with just those fields.

FeatureQL
DEFINE
    address := ROW(
        '123 Main St' AS street,
        'Paris' AS city,
        '75001' AS postal_code
    )
RETURN
    address,
    city := address[city],
    summary := address[city, postal_code]
;
Result
ADDRESS ROW<street VARCHAR, city VARCHAR, postal_code VARCHAR>CITY VARCHARSUMMARY ROW<city VARCHAR, postal_code VARCHAR>
{street: 123 Main St, city: Paris, postal_code: 75001}Paris{city: Paris, postal_code: 75001}

Array of rows

Arrays of rows are FeatureQL's primary structure for one-to-many relationships — they replace SQL JOINs with nested data. See Array of rows for a full treatment.