Expressions and statements

A query is a series of zero or more statements and expressions separated by newlines or semicolons. Multiple statements and expressions in a block must end with an expression.

Statements and expressions can span multiple lines, and there is no line continuation character.

at

Get the result of an expression at a given time.

Syntax

at (expression1) expression2

Description

The at expression gets the result of expression2 at the expression1 time snapshot of the data. The expression1 operand is a Time or TransactionTime.

The at expression returns null if the requested document doesn’t exist.

This changes the time when byId() is evaluated. Fauna stores document history up to the limit defined by history_days. The default number of days stored is zero so history_days must be increased for at to be meaningful. See Temporality for more information on document retention.

Examples

The following example gets the current document and a snapshot of the document from yesterday.

  1. After running this query yesterday to create a document,

    Books.create({
      id: "9780547928227",
      title: "The Hobbit",
      state: "yesterday state"
    })
    {
      id: "9780547928227",
      coll: Books,
      ts: Time("2023-05-05T23:18:55.830Z"),
      title: "The Hobbit",
      state: "yesterday state"
    }
  2. And running this query today to update the document,

    Books.byId("9780547928227")!.update({
      state: "today state"
    })
    {
      id: "9780547928227",
      coll: Books,
      ts: Time("2023-05-05T23:20:58.420Z"),
      title: "The Hobbit",
      state: "today state"
    }
  3. The following query returns the current data,

    Books.byId("9780547928227")!.state
    "today state"
  4. And the following query returns the data from yesterday,

    let yesterday = Time.now().subtract(1, "day")
    at (yesterday) { Books.byId("9780547928227")!.state }
    "yesterday state"

 

The following examples show that when comparing documents using the == operator, only the document id field is compared, ignoring all other fields.

Compare the state fields of different versions of the same document, which differ because of the state change between yesterday and today:

let yesterday = Time.now().subtract(1, "day")
let book1 = at(yesterday) {
  Books.byId('9780547928227')
}
let book2 = Books.byId('9780547928227')
book1!.state == book2!.state
false

 

Compare versions of the full document. The documents are identical because the document id fields are the same:

let yesterday = Time.now().subtract(1, "day")
let book1 = at(yesterday) {
  Books.byId('9780547928227')
}
let book2 = Books.byId('9780547928227')
book1 == book2
true

if …​ else

Use conditional branching for execution control flow.

Syntax

if (expression1) expression2 [else expression3]

Description

The if and if …​ else expressions conditionally execute a block depending on the Boolean value of expression1. If expression1 evaluates to true, expression2 executes. Otherwise, expression3 executes.

The last expression in the if or else block that satisfies the condition is the value returned for the block.

The result of the if expression is a value that can be assigned to a variable. If the expression evaluates to false and else isn’t included, the expression returns null.

Examples

Change the query result when the if condition evaluates to true:

if (5 > 3) "higher"
"higher"

 

Use an else block if the condition evaluates to false:

if (5 > 6) {
  "higher"
} else {
  "lower"
}
"lower"

 

Assign the result of the if expression to a variable:

let state = if (5 > 6) {
  "higher"
} else {
  "lower"
}

state
"lower"

let

Assign a value to a variable.

Syntax

let name [: type] = value

Description

A let statement declares a variable with a name identifier and assigns a value to the variable. Optionally, you can type the variable as any of the supported types.

The name can be any valid identifier but can’t be a single underscore (_) character.

The variable is scoped to the block in which it is declared. A variable can be referenced in a nested block, but a variable declared in a nested block can’t be referenced outside of the block.

Assigning a value to a variable can be done only using the let statement. You can’t assign a value to name directly:

let x = 100  // valid assignment
x = 1000     // invalid assignment

A variable of the same name can be declared again in the same block and assigned a new value. It is a new variable declaration, and the previously declared variable can no longer be referenced:

let x = 100  // (A) valid assignment
let x = 1000 // (B) valid assignment and (A) can no longer be referenced
x            // returns 1000

Examples

Declare and assign Int, String, and Array values to variables:

let xInt = 5
let yString = "hello"
let zArray = [xInt, yString]
[xInt, yString, zArray]
[
  5,
  "hello",
  [
    5,
    "hello"
  ]
]

 

Variable scoping example where the declared x variable has global scope, while the scope of variables a and b is limited to the block:

let x = {
    // a and b are only accessible in this block
    let a = 1
    let b = 2
    a + b
}
x
3

 

Assign a new value to the variable:

let x = "foo"
let fn = () => x
let x = "bar"
let y = fn()
[x, y]
[
  "bar",
  "foo"
]

 

Use a previous definition of the variable when redefining the variable:

let x = 1
let x = x + 1
x
2

 

Type a variable:

let x: Int = 2
x
2

 

Incorrectly typing a variable results in an error:

let x: Int = "2"
x
invalid_query

error: Type `"2"` isn't a subtype of `Int`
at *query*:1:5
  |
1 | let x: Int = "2"
  |     ^
  |
cause: Type `String` isn't a subtype of `Int`
  |
1 | let x: Int = "2"
  |              ^^^
  |

Is this article helpful? 

Tell Fauna how the article can be improved:
Visit Fauna's forums or email docs@fauna.com

Thank you for your feedback!