Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Queries and Counting

query

fact Foo[deviceID id]=>{count int}

let x = query Foo[deviceID: me]

Perform a query against the fact database, returning an optional struct containing all fields of the first matching fact. The value side of the fact must be omitted. The type of the struct returned is the auto-generated struct for the fact.

In the above example, x is an optional struct Foo with two fields, for deviceID and count. If no facts are found, it returns None. query is commonly used with unwrap or check_unwrap to terminate execution immediately if the fact does not exist, or to access field values in the returned struct if it does.

Bind Marker

In Fact queries and statements with indefinite values, the bind marker ? can be substituted to mark that a key field can be any value. This allows more general matching to be achieved. For performance reasons, the concrete fields must be strictly on the left. So binds should only appear on the rightmost fields of the key. For example,

let x = query Thing[a: 1, b: ?]     // OK
let x = query Thing[a: ?, b: ?]     // OK
let x = query Thing[a: ?, b: 2]     // Not OK

A query will return one fact at most, and if more than one fact matches, the one with the lowest sorted key will be returned (see Queries and Iteration).

at_least N, at_most N, exactly N

check at_most 1 Foo[deviceID: ?]
let sufficient_admins = at_least 2 TeamAdmin[teamID: t, deviceID: ?]
let is_highlander = exactly 1 Immortals[name: ?]

at_least, at_most, and exactly are counting query functions which return a boolean value depending on whether the fact expression satisfies the condition. at_least requires at least the stated number, at_most requires at most the stated number, and exactly requires exactly the stated number of facts to exist.

The same fact key binding rules as query apply - unbound key fields must be on the right.

exists

check !exists FooCounter[deviceID: this.deviceId]

exists is syntactic sugar for at_least 1.

count_up_to

let admin_count = count_up_to 5 TeamAdmin[teamID: t, deviceID: ?]

count_up_to counts the number of facts up to an upper bound, and returns either the number of facts found or that upper limit.