Lesson 10.2: Function chaining
Simple function chaining
Much like views in a relational database, which can be generated from other views, functions in TypeDB can leverage answers generated by other functions.
fun verified-reviews($book: book) -> { review }:
match
$review isa review;
rating ($review, $book);
order-line ($order, $book);
$_ isa action-execution ($user, $review), has timestamp $review-time;
$_ isa action-execution ($user, $order), has timestamp $order-time;
$review-time > $order-time;
return { $review };
fun unverified-reviews($book: book) -> { review }:
match
$review isa review;
rating ($review, $book);
not {
let $verified-review in verified-reviews($book);
$review is $verified-review;
};
return { $review };
The unverified-reviews function can re-use the work of the first function, modularizing logic effectively and promoting re-use.
Recursive function chaining
Functions can recurse as well! A recursive function is one which invokes itself.
fun transitive_places_unoptimized($place: place) -> { place }:
match
{
locating (located: $place, location: $transitive);
} or {
locating (located: $place, location: $next);
let $transitive in transitive_places_unoptimized($next);
};
return { $transitive };
Note that this function is written in the unoptimized recursive form. Read the Optimizing queries page to understand how to write this more efficiently.
match
$user isa user, has id "u0003";
(located: $user, location: $place) isa locating;
fetch {
"direct-place": $place.name,
"transitive-places": [
match let $transitive in transitive_places_unoptimized($place);
fetch { "place": $transitive.name };
],
};
{
"direct-place": "Newark",
"transitive-places": [
{
"place": "United States"
},
{
"place": "New Jersey"
}
]
}
Recursive functions have "self-terminating" behaviours that are guaranteed to reach a fixed point and finish their computation, under the condition that the function isn’t continuously generating new values (or in the future - lists).
In other words, when using functions to simply modularize queries and invoke recursion without computing new data, functions will always terminate - even in the case of data cycles. Beware that passing an incrementing or decrementing integer argument does invalidate this guarantee - which might be what you want!