Steel language reference
Table scripts use a fail-closed allowlist. The server macro-expands the program with Steel’s own parser and rejects every form or identifier that is not explicitly accepted.
Syntax and result
Section titled “Syntax and result”A script must be a non-empty S-expression beginning with (. Steel validates balanced syntax. Literals, comments, quoting, if, begin, and, or, let, lambdas, and immutable vectors are supported when their contents also pass the allowlist.
The last expression supplies the target value. A target must ultimately receive a string, number, integer, boolean, or correctly typed money result.
Database-aware functions
Section titled “Database-aware functions”| Function | Purpose |
|---|---|
steel_get_column name column |
Read one current-row or linked-row column |
steel_related_aggregate operation table column anchor |
Aggregate a related collection |
steel_related_count_rows table anchor |
Count related rows |
steel_related_exists table anchor |
Test for related rows |
has-var? name |
Test whether a key exists in the active row snapshot |
quantity-add link column amount |
Record a positive quantity-ledger contribution |
quantity-subtract link column amount |
Record a negative quantity-ledger contribution |
All database names and operations must be string literals. These functions read request context prepared outside the VM; they do not issue unrestricted queries themselves.
Quantity contributions are explained in Quantity ledger.
Decimal operations
Section titled “Decimal operations”Source math forms are transformed to exact-decimal operations before the script is stored:
+ - * / ^ ** pow sqrt> < = >= <= min max abs roundln log log10 exp sin cos tanDirect decimal functions are also available:
to-decimaldecimal-add decimal-sub decimal-mul decimal-divdecimal-abs decimal-round decimal-min decimal-maxdecimal-eq decimal-gt decimal-gte decimal-lt decimal-ltedecimal-zero decimal-one decimal-pi decimal-edecimal-exp decimal-ln decimal-log10 decimal-pow decimal-sqrtdecimal-sin decimal-cos decimal-tandecimal-compound decimal-percentage decimal-formatset-precision clear-precision get-precisionPer-script precision changes are cleared after execution and cannot leak into another request.
Columns with these kinds cannot participate in math:
BIGINT TEXT BOOLEANPHONE and phone component typesIBAN and IBAN component typesCREDIT_CARDDATE TIME INSTANT USER_DATETIME RAW_DATETIMEDURATION PERIOD TIMESTAMPTZ TIMESTAMPMoney operations
Section titled “Money operations”Money is a currency-aware runtime value. Use explicit functions:
money? money-newmoney-add money-sub money-mul money-divmoney-abs money-amountmoney-eq money-gt money-gte money-lt money-lteRules:
money-newrequires an uppercase ISO currency and a decimal amount;- addition, subtraction, and comparison require matching currencies;
- multiplication and division take a non-money decimal scalar;
money-amountexplicitly extracts an amount for decimal operations;- every money-returning branch must return the same currency;
- a MONEY target must receive its configured currency;
- a non-money target cannot receive a money value.
(money-add (money-new "EUR" "10.00") (money-new "EUR" "2.50"))See How money works for storage and rounding rules.
Pure helpers
Section titled “Pure helpers”Numbers and predicates
quotient remainder modulo exptexact->inexact inexact->exact floor ceiling truncatenumber? complex? real? rational? int? integer? exact-integer?float? nan? positive? negative? zero? even? odd?exact? inexact? finite? infinite?boolean? not eq? eqv? equal?Strings and characters
string? string string-append to-stringstring-length utf8-length substring string-refstring=? string-ci=? string<? string-ci<?string<=? string-ci<=? string>? string-ci>?string>=? string-ci>=?string->list string->vector string->bytes string->number string->intnumber->string int->string string->symbol symbol->stringstring-upcase string-downcase string-foldcasestarts-with? ends-with? string-contains? string-replace string-pushmake-string split-whitespace split-once split-many string-jointrim trim-start trim-end trim-start-matches trim-end-matcheschar-upcase char-downcase char-foldcase char-digit? char-whitespace?char->number char->integer integer->char char=? char-ci=?Lists, immutable vectors, and hashes
list list? pair? null? car cdr cons length list-refappend reverse member memq list-contains second thirdtake list-tail list-drop try-list-ref list-chunks list->stringlist->vector empty?
immutable-vector make-immutable-vector vector-ref vector-lengthimmutable-vector->list immutable-vector->string immutable-vector-copyimmutable-vector-append immutable-vector-push immutable-vector-restimmutable-vector-take immutable-vector-drop
hash hash-ref hash-try-get hash-length hash-contains? hash-empty?hash-insert hash-remove hash-clear hash-unionThe hash functions above return new values; mutation is not enabled.
Higher-order helpers
map filter foldl fold reduce apply for-each rangefirst rest last list-sortFunctions passed to a higher-order helper must themselves be allowed.
Target-column rules
Section titled “Target-column rules”Common supported targets include TEXT, BOOLEAN, INT, DECIMAL, and MONEY.
A script cannot target:
- system columns:
id,deleted,created_at, orrow_revision; - a quantity-ledger-backed column;
- an accounting-transfer source column;
- BIGINT;
- phone, IBAN, or credit-card types;
- DATE, TIME, INSTANT, datetime, duration, period, timestamp, or timestamptz types.
BIGINT is also prohibited as a referenced input. Other non-math types may be read for supported value operations but cannot be passed through decimal arithmetic.
Rejected behavior
Section titled “Rejected behavior”The following forms illustrate behavior that is not permitted:
steel_query_sqldefine define-syntax define-valuesset! set-car! set-cdr! set-box! box-set!vector-set! mutable-vector-set! string-set! bytes-set!hash-set! hash-remove!eval load require returnUnknown functions are rejected as well. Scripts cannot import code, evaluate generated code, change global bindings, mutate collections, access undeclared database data, or retain state between requests.