SurrealDB Docs Logo

Enter a search query

Futures

Futures are values which are only computed when the data is selected and returned to the client. Futures can be stored inside records, to enable dynamic values which are always calculated when queried.

Simple futures

Any value or expression can be used inside a future. This value will be dynamically computed on every access to the record.

CREATE person SET accessed_date = <future> { time::now() };

Futures inside schema definitions

A future can be added to a schema definition as well.

DEFINE FIELD accessed_at ON TABLE user VALUE <future> { time::now() }; CREATE user:one; SELECT * FROM ONLY user:one; -- Sleep for one second SLEEP 1s; -- `accessed_at` is a different value now SELECT * FROM ONLY user:one;

This differs from a non-future VALUE clause which is only calculated when it is modified (created or updated), but is not recalculated during a SELECT query which does not modify a record.

DEFINE FIELD updated ON TABLE user VALUE time::now(); CREATE user:one; SELECT * FROM ONLY user:one; -- Sleep for one second SLEEP 1s; -- `updated` is still the same SELECT * FROM ONLY user:one;

Futures depending on statements

If the value of a future is the result of a statement, it must be wrapped in parentheses.

DEFINE FIELD random_movie ON app_screen VALUE <future> { (SELECT * FROM ONLY movie ORDER BY RAND() LIMIT 1) };

Futures depending on other fields

Futures can be used to calculate values which dynamically change based on other fields. This value will be dynamically computed, on every access to the record, and will use the other field when it is accessed.

DEFINE FUNCTION fn::get_age($birthdate: datetime) -> int { duration::years(time::now() - $birthdate) }; CREATE person SET birthday = <datetime> "2007-06-22",
can_drive = <future> { fn::get_age(birthday) >= 18 }
;

Futures can also dynamically access remote records, perform subqueries, or make use of graph traversal.

CREATE person SET name = 'Jason', friends = [person:tobie, person:jaime],
adult_friends = <future> { friends[WHERE age > 18].name }
;

Avoiding infinite recursion

When defining a future on a field, be sure to avoid any statements that would cause infinite recursion. In the following example, the random_friend field is defined by a statement that uses a SELECT statement on all the fields of the same person table, one of which will also use the same future to compute its value.

CREATE |person:10| RETURN NONE; DEFINE FIELD random_friend ON person VALUE <future> { (SELECT * FROM ONLY person ORDER BY RAND() LIMIT 1) }; CREATE person;
Output
'Reached excessive computation depth due to functions, subqueries, or futures'

A SELECT query that does not access the field defined by a future will avoid the infinite recursion.

CREATE |person:10| RETURN NONE; DEFINE FIELD random_friend ON person VALUE <future> { (SELECT VALUE id FROM ONLY person ORDER BY RAND() LIMIT 1) }; CREATE person;
Output
[ { id: person:d7uyc9m5gtg7r4cvvq7d, random_friend: person:fv76w83vbgularvl0dvv } ]

Next steps

You’ve now seen how to create dynamically computed properties on records, using either simple values, and values which depend on local and remote record fields. Take a look at the next chapter to understand how types can be cast and converted to other types.