Officially out now: The TypeDB 3.0 Roadmap >>

Defining functions

This page explains how to define functions within TypeDB schemas.

Understanding functions

Functions provide powerful abstractions of query logic, and a cornerstone of the functional database programming model. Functions calls can be nested, recursive, negated, and they natively embed into TypeQL’s declarative patterns.

Functions can be defined in a schema and later used in queries to:

  • Reduce code duplication by encapsulating common logic within functions.

  • Simplify complex TypeQL queries for improved readability and maintenance.

  • Share reusable query logic with other developers.

While this page focuses on defining functions in schemas, it is also possible to create temporary functions for one-time query execution. Refer to the TypeQL documentation for comprehensive information and additional usage examples.

Function definition queries

Similar to type definitions, functions can be stored in a database schema using schema transactions. Three types of schema definition queries are available for working with functions:

  • define <function declaration>. A define query adds a new function to the schema for future use.

  • undefine fun <function name>. An undefine query removes a function from the schema.

  • redefine <function declaration>. A redefine query updates an existing function in the schema.

Arithmetic functions

The simplest functions perform arithmetic operations. For example, the following query defines a function that accepts two integers and returns their sum. The function declaration has several key components:

  • The fun keyword, indicating the start of a function declaration.

  • The function name.

  • A list of arguments, including their variable names and types.

  • The return type: {} denotes a stream function, as it can return multiple results.

  • The function body, which contains a read pipeline and a return statement with valid TypeQL expressions.

Stream arithmetic function definition
define
  fun add_streamed($x: integer, $y: integer) -> { integer }:
    match
      let $z = $x + $y;
    return { $z };

If you are certain that $z will only match a single value (or if only one value is needed), the first or last keywords can be used to ensure the function returns a single result.

Single arithmetic function definition
define
  fun add($x: integer, $y: integer) -> integer:
    match
      let $z = $x + $y;
    return first $z;

Querying for types

Since TypeDB has a strong emphasis on types, functions can also return types. For example, the following function retrieves all phone attributes associated with a specific user:

Stream function definition returning types
define
  fun user_phones($user: user) -> { phone }:
    match
      $user has phone $phone;
    return { $phone };

Functions within functions and tuple outputs

As described in the function syntax basics, return statements can include any valid TypeQL expressions. This allows functions to call other functions. Additionally, multiple expressions can be combined to return a tuple of results instead of a single scalar value.

For example, the following function uses two built-in aggregation function calls to produce a tuple result:

Tuple function definition with inner function calls
define
  fun karma_sum_and_sum_squares() -> double, double:
    match
      $karma isa karma;
      let $karma-squared = $karma * $karma;
    return sum($karma), sum($karma-squared);

The output type here is not a stream because each tuple component is derived from an aggregation, which produces a single result.

Refer to Using functions for more details on calling functions.

Function undefinition

To undefine a function from a schema, you only need its name, which uniquely identifies it. The following query removes a function defined earlier:

undefine
  fun add_streamed;

Function redefinition

To redefine an existing function, use the same define syntax with the redefine keyword. The query below updates a previously defined function to accept a username instead of a specific user:

redefine
  fun user_phones($username-value: string) -> { phone }:
    match
      $user isa user, has username $username, has phone $phone;
      $username == $username-value;
    return { $phone };

You can only redefine existing functions. The function name must remain the same. To change the name, define a new function and undefine the old one.

Using functions

Functions can be called in queries as other statements. As shown in previous examples, to call a function, reference its name and pass the required arguments (if applicable) within parentheses.

For functions returning a single result, use a simple assignment to bind the output variable to the function’s result:

match
  let $answer = add(2016, 9);

The let keyword is required for value assignment in this example.

For functions returning a stream, use let …​ in statements to bind variables:

match
  $user isa user;
  let $phone in user_phones($user);
Practice Task

How would you call this function after redefining it?

Answer
user_phones("Bob")

To handle tuple results, bind the appropriate number of variables to unpack the function’s output:

match
  let $karma, $karma-squared in karma_sum_and_sum_squares();

For further details, refer to the TypeQL documentation.