View all results

Script structure

An FQL script is a sequence of statements that runs from top to bottom and produces a final value.

Statements provide the outer structure of a script: they introduce bindings, iterate collections, and decide what value is returned. Inside those statements, expressions do most of the work. They produce the values that get assigned, returned, filtered, queried, or composed.

Scripts

A script is a top-level sequence of statements. Statements are evaluated in order, and each statement can reference names declared by earlier ones. A name cannot be used before it is declared.

Most scripts follow a simple pattern: declare or receive input, transform data, return a result.

example.fql Ferret v2
query.fql
FQL
LET user = { name: "Ada", roles: ["admin", "editor"] } LET isAdmin = CONTAINS(user.roles, "admin") RETURN { name: user.name, isAdmin: isAdmin }

Statements

A statement describes a step in the script. Some statements create bindings; others produce results or control iteration.

LET creates an immutable binding:

example.fql Ferret v2
query.fql
FQL
LET name = "Ada" RETURN name

VAR creates a mutable binding: one whose value can be reassigned later in the same scope:

example.fql Ferret v2
query.fql
FQL
VAR total = 0 FOR price IN [10, 20, 30] total = total + price RETURN total

Only VAR bindings can be reassigned. LET bindings cannot be changed after they are created, and no binding can be declared twice in the same scope. Prefer LET unless mutation is actually needed.

More advanced scripts may also use FOR, FILTER, COLLECT, MATCH, WAITFOR, DISPATCH, DO WHILE, or function declarations. Those constructs are covered in their own pages.

Expressions

Most of the useful work in FQL happens inside expressions. An expression is any piece of syntax that produces a value: a literal, a function call, an arithmetic combination, a field access, a query, or a nested FOR. Expressions can be assigned to bindings, passed as arguments, or returned directly.

Simple literals and arithmetic:

example.fql Ferret v2
query.fql
FQL
RETURN (1 + 2) * 3

Function calls:

example.fql Ferret v2
query.fql
FQL
RETURN UPPER("hello")

Object and array construction:

example.fql Ferret v2
query.fql
FQL
RETURN { name: "Ada", active: true, score: 42, tags: ["admin", "editor"], missingValue: NONE }

Expressions can also be composed. The output of one becomes the input of another:

example.fql Ferret v2
query.fql
FQL
LET user = { name: "Ada", roles: ["admin", "editor"] } RETURN { name: user.name, roleCount: LENGTH(user.roles) }

FQL is dynamically typed. Values carry their type at runtime, and operations expect compatible types: arithmetic works on numbers, field access works on objects, collection operations expect arrays or other iterable values.

Statements describe the flow of the script. Expressions produce the values that move through that flow.

Returning a result

Every FQL script must end in a terminal statement.

A terminal statement produces the script result. FQL currently has two terminal forms:

  • RETURN, which returns a single value
  • a top-level FOR statement, which iterates over a collection and returns the produced collection

The returned value can be any FQL value: NONE, a boolean, number, string, array, object, binary value, or host value.

example.fql Ferret v2
query.fql
FQL
RETURN "Hello, world!"
example.fql Ferret v2
query.fql
FQL
FOR i IN 1..10 RETURN i * i

The loop body is the same in both cases. The difference is what happens to the produced collection: a top-level FOR makes it the script result; a parenthesized FOR stores it for further use.

Scopes and blocks

Some statements introduce a nested scope. Names declared inside that scope are not visible outside it.

FOR is the most common block-producing statement:

example.fql Ferret v2
query.fql
FQL
LET values = (FOR i IN 1..5 LET square = i * i RETURN square ) RETURN values

square exists only inside the FOR block. Referencing it outside the block is an error.

Other statements have block-like shapes as well. A MATCH expression describes branching logic:

example.fql Ferret v2
query.fql
FQL
RETURN MATCH @status ( "active" => "Account is active", "paused" => "Account is paused", _ => "Unknown status" )

A WAITFOR block describes event-oriented runtime logic:

example.fql
read-only
WAITFOR EVENT network.response_received WHEN event.status == 200 RETURN event.url

A function declaration creates a reusable local function:

example.fql Ferret v2
query.fql
FQL
FUNC fullName(user) => user.firstName + " " + user.lastName RETURN fullName({ firstName: "Ada", lastName: "Lovelace" })

Each of these has its own detailed rules and is covered in its dedicated documentation — MATCH and WAITFOR in Control Flow, and function declarations in Functions. This section shows the structural shape only.

Comments

FQL supports single-line comments that begin with // and extend to the end of the line:

example.fql Ferret v2
query.fql
FQL
// This is a comment RETURN "Hello, world!" // This is another comment

Multi-line comments are enclosed in /* and */:

example.fql Ferret v2
query.fql
FQL
/* This is a multi-line comment. It can span multiple lines. */ RETURN "Hello, world!"

FQL is whitespace-insensitive. Spaces, tabs, and newlines separate tokens but do not affect semantics. Whitespace inside strings is preserved.

Names and keywords

Names identify variables, object fields, functions, and other script-level symbols. A name must start with a letter or underscore, followed by any combination of letters, digits, and underscores:

example.fql
read-only
LET _name = "Ada" LET name2 = "Grace" LET Name = "Turing"

Keywords are reserved words with special meaning in FQL. They are case-sensitive and conventionally written in uppercase. The full set of reserved keywords is:

example.fql
read-only
USE AS MATCH WHEN FUNC FOR RETURN QUERY USING WAITFOR DISPATCH OPTIONS TIMEOUT EVERY BACKOFF JITTER EXISTS COUNT ONE DISTINCT FILTER SORT LIMIT LET VAR COLLECT ASC DESC AT LEAST INTO KEEP WITH ALL ANY AGGREGATE EVENT LIKE NOT IN DO WHILE AND OR ON ERROR FAIL RETRY DELAY DELETE VALUE

When an object field shares its name with a keyword, quote the field name:

example.fql Ferret v2
query.fql
FQL
RETURN { "return": "This field is named 'return', which is a keyword, so it is quoted." }