DEFINE FUNCTION
statementThe DEFINE FUNCTION
statement allows you to define custom functions that can be reused throughout a database. When using the DEFINE FUNCTION
statement, you can define a function that takes one or more arguments and returns a value. You can then call this function in other SurrealQL statements.
Functions can be used to encapsulate logic that you want to reuse in multiple queries. They can also be used to simplify complex queries by breaking them down into smaller, more manageable pieces. The are particularly useful when you have a complex query that you need to run multiple times with different arguments.
DEFINE FUNCTION
statement.DEFINE FUNCTION
statement.
SurrealQL SyntaxDEFINE FUNCTION [ OVERWRITE | IF NOT EXISTS ] fn::@name( [ @argument: @type ... ] ) { [ @query ... ] [ RETURN @returned ] } [ COMMENT @string ] [ PERMISSIONS [ NONE | FULL | WHERE @condition]]
Below shows how you can define a custom function using the DEFINE FUNCTION
statement, and how to call it.
-- It is necessary to prefix the name of your function with "fn::" -- This indicates that it's a custom function DEFINE FUNCTION fn::greet($name: string) { RETURN "Hello, " + $name + "!"; } -- Returns: "Hello, Tobie!" RETURN fn::greet("Tobie");
To showcase a slightly more complex custom function, this will check if a relation between two nodes exists:
-- Define a function that checks if a relation exists between two nodes DEFINE FUNCTION fn::relation_exists( $in: record, $tb: string, $out: record ) { -- Check if a relation exists between the two nodes. LET $results = SELECT VALUE id FROM type::table($tb) WHERE in = $in AND out = $out; -- Return true if a relation exists, false otherwise RETURN array::len($results) > 0; };
If one or more ending arguments have the option<T>
type, they can be omitted when you run the invoke the function.
DEFINE FUNCTION fn::last_option($required: number, $optional: option<number>) { RETURN { required_present: type::is::number($required), optional_present: type::is::number($optional), } }; RETURN fn::last_option(1, 2); { required_present: true, optional_present: true, }; RETURN fn::last_option(1); { required_present: true, optional_present: false, };
You can set the permissions for a custom function using the PERMISSIONS
clause. The PERMISSIONS
clause is mostly used to restrict who can access a function and what data they can access. It can be set to NONE
, FULL
, or WHERE @condition
.
FULL
: When Full permissions are granted record users have access to the function. This is the default permission when not specified.NONE
: When this permission is granted, record users have no access to the defined function.WHERE @condition
: Permissions are granted to the function based on the specified condition.NoteThe examples below use the
Surreal Deal Store
dataset.
FULL
permissionThe FULL
permission grants all users access to the function. The following example defines a function that fetches all products from the product
table and grants the function full permissions to access the data to all users.
NONE
permissionThe NONE
permission denies all record users access to the function. The following example defines a function that fetches all products from the product
table
-- Define a function that fetches all expiration years from the payment_details table and denies access to all none-admin users DEFINE FUNCTION fn::fetchAllPaymentDetails() { RETURN (SELECT stored_cards.expiry_year FROM payment_details LIMIT 5); } PERMISSIONS NONE; RETURN fn::fetchAllPaymentDetails();
WHERE
clauseThe WHERE
clause allows you to specify a condition that determines the permissions granted to the function. The condition must evaluate to a boolean value. If the condition evaluates to true
, the function is granted permissions. If the condition evaluates to false
, the function is not granted permissions.
-- Define a function that fetches all products with the condition that only admin users can access it DEFINE FUNCTION fn::fetchAllProducts() { RETURN (SELECT * FROM product LIMIT 10); } PERMISSIONS WHERE $auth.admin = true;
IF NOT EXISTS
clauseAvailable since: v1.3.0
The IF NOT EXISTS
clause can be used to define a function only if it does not already exist. You should use the IF NOT EXISTS
clause when defining a function in SurrealDB if you want to ensure that the function is only created if it does not already exist. If the function already exists, the DEFINE FUNCTION
statement will return an error.
It’s particularly useful when you want to safely attempt to define a function without manually checking its existence first.
On the other hand, you should not use the IF NOT EXISTS
clause when you want to ensure that the function definition is updated regardless of whether it already exists. In such cases, you might prefer using the OVERWRITE
clause, which allows you to define a function and overwrite an existing one if it already exists, ensuring that the latest version of the function definition is always in use
-- Create a FUNCTION if it does not already exist DEFINE FUNCTION IF NOT EXISTS fn::example() {};
OVERWRITE
clauseAvailable since: v2.0.0
The OVERWRITE
clause can be used to define a function and overwrite an existing one if it already exists. You should use the OVERWRITE
clause when you want to modify an existing user definition. If the user already exists, the DEFINE FUNCTION
statement will overwrite the existing definition with the new one.
-- Create an FUNCTION and overwrite if it already exists DEFINE FUNCTION OVERWRITE fn::example {};