Skip to main content

Global functions

Rell has a diverse collection of built-in functions that you can use to perform common tasks and write efficient Rell code.

Essential calculations

abs(value: integer): integer

Gets the absolute value of an integer.

Parameters:

  • value: integer - The integer for which to calculate the absolute value.

Returns:

  • The absolute value of the input value as an integer.

abs(value: big_integer): big_integer

Gets the absolute value of a big integer.

Parameters:

  • value: big_integer - The big integer for which to calculate the absolute value.

Returns:

  • The absolute value of the input value as a big integer.

abs(value: decimal): decimal

Gets the absolute value of a decimal.

Parameters:

  • value: decimal - The decimal for which to calculate the absolute value.

Returns:

  • The absolute value of the input value as a decimal.

function max(value1: integer, value2: integer): integer

Identifies the larger of two integer values.

Parameters:

  • value1: integer - The first integer to compare.
  • value2: integer - The second integer to compare.

Returns:

  • The larger of the two input integers.

function max(value1: big_integer, value2: big_integer): big_integer

Determines the larger of two big integer values.

Parameters:

  • value1: big_integer - The first big integer to compare.
  • value2: big_integer - The second big integer to compare.

Returns:

  • The larger of the two input big integers.

function max(value1: decimal, value2: decimal): decimal

Determines the larger of two decimal values.

Parameters:

  • value1: decimal - The first decimal to compare.
  • value2: decimal - The second decimal to compare.

Returns:

  • The larger of the two input decimals.

function min(value1: integer, value2: integer): integer

Determine the smaller of two integer values.

Parameters:

  • value1: integer - The first integer to compare.
  • value2: integer - The second integer to compare.

Returns:

  • The smaller of the two input integers.

function min(value1: big_integer, value2: big_integer): big_integer

Identify the smaller of two big integer values.

Parameters:

  • value1: big_integer - The first big integer to compare.
  • value2: big_integer - The second big integer to compare.

Returns:

  • The smaller of the two input big integers.

function min(value1: decimal, value2: decimal): decimal

Pinpoint the smaller of two decimal values.

Parameters:

  • value1: decimal - The first decimal to compare.
  • value2: decimal - The second decimal to compare.

Returns:

  • The smaller of the two input decimals.

Collection checks

empty(value: T?): boolean

Determines if a value is null or an empty collection.

Parameters:

  • value: T? - The value to check for emptiness, which can be any nullable type.

Returns:

  • True if the value is null or an empty collection, False otherwise.

empty(list: list<T>): boolean

Specifically checks if a list is empty.

Parameters:

  • list: list<T> - The list to check for emptiness.

Returns:

  • True if the list contains no elements, False otherwise.

empty(set: set<T>): boolean

Verifies if a set is empty.

Parameters:

  • set: set<T> - The set to check for emptiness.

Returns:

  • True if the set contains no elements, False otherwise.

empty(map: map<K, V>): boolean

Checks if a map is empty.

Parameters:

  • map: map<K, V> - The map to check for emptiness.

Returns:

  • True if the map contains no key-value pairs, False otherwise.

Nested at-expressions with empty()

The empty() function supports nested at-expressions, allowing them to access entities from an outer at-expression. This enhancement enables more complex and efficient database queries.

Example:

user @* {
empty(company @* { .city == user.city })
}

Translated SQL query:

SELECT U."name"
FROM "c0.user" U
WHERE NOT EXISTS(
SELECT C."rowid"
FROM "c0.company" C
WHERE C."city" = U."city"
)

Usage in update and delete statements:

delete user @* { empty( company @* { .city == user.city } ) } ;

Notes on cardinality:

  • Use @* in nested at-expressions to ensure the entire query is executed as a single SQL query.
  • Using operators @+, @?, or @ will result in independent SQL queries, potentially reducing performance due to loading the entire result set into memory.

Simplified attribute matching:

  • In the where part of a nested at-expression, you can use outer_entity.attribute directly.

Example:

user @* {
empty(company @* { user.city })
}

exists(value: T?): boolean

Confirms the presence of a value.

Parameters:

  • value: T? - The value to check for existence, which can be any nullable type.

Returns:

  • True if the value is not null and contains elements (for collections), False otherwise.

exists(list: list<T>): boolean

Specifically verifies if a list contains elements.

Parameters:

  • list: list<T> - The list to check for the existence of elements.

Returns:

  • True if the list has at least one element, False if it's empty.

exists(set: set<T>): boolean

Determines if a set contains elements.

Parameters:

  • set: set<T> - The set to check for the existence of elements.

Returns:

  • True if the set has at least one element, False if it's empty.

exists(map: map<K, V>): boolean

Checks if a map contains key-value pairs.

Parameters:

  • map: map<K, V> - The map to check for the existence of key-value pairs.

Returns:

  • True if the map has at least one key-value pair, False if it's empty.

Nested at-expressions with exists()

The exists() function supports nested at-expressions, allowing them to access entities from an outer at-expression. This enhancement enables more complex and efficient database queries.

Example:

user @* {
exists(company @* { .city == user.city })
}

Translated SQL query:

SELECT U."name"
FROM "c0.user" U
WHERE EXISTS(
SELECT C."rowid"
FROM "c0.company" C
WHERE C."city" = U."city"
)

Usage in update and delete statements:

delete user @* { not exists( company @* { .city == user.city } ) } ;

Notes on cardinality:

  • Use @* in nested at-expressions to ensure the entire query is executed as a single SQL query.
  • Using operators @+, @?, or @ will result in independent SQL queries, potentially reducing performance due to loading the entire result set into memory.

Simplified attribute matching:

  • In the where part of a nested at-expression, you can use outer_entity.attribute directly.

Example:

user @* {
empty(company @* { .city == user.city })
}

Output and logging

function print(...)

Prints a message to STDOUT.

Example:

  • print() - prints an empty line.
  • print('Hello', 123) - prints "Hello 123".

Parameters:

  • ...: Accepts any number of arguments to be printed, including strings, numbers, variables, and expressions.

Returns:

  • None (no explicit return value).

function log(...)

Generates a detailed record of program execution for debugging and analysis purposes.

Parameters:

  • ...: Accepts any number of arguments to be logged, similar to print.

Returns:

  • None (no explicit return value).

Cryptographic hashes

function keccak256(byte_array: byte_array): byte_array

Produces a 32-byte Keccak256 hash from a given byte array.

Parameters:

  • byte_array: byte_array - The byte array to be hashed.

Returns:

  • A 32-byte byte array representing the Keccak256 hash of the input byte_array.

function sha256(byte_array: byte_array): byte_array

Generates a 32-byte SHA-256 hash from a provided byte array.

Parameters:

  • byte_array: byte_array - The byte array to be hashed.

Returns:

  • A 32-byte byte array representing the SHA-256 hash of the input byte_array.

Signature verification

function verify_signature(message: byte_array, pubkey: pubkey, signature: byte_array): boolean

Verifies the authenticity of a given signature, ensuring data integrity and non-repudiation.

Parameters:

  • message: byte_array - The original message that was signed.
  • pubkey: pubkey - The public key allegedly used for signing.
  • signature: byte_array - The signature to be verified.

Returns:

  • True if the signature is valid for the given message and public key, False otherwise.

Ethereum public key recovery

function eth_ecrecover(r: byte_array, s: byte_array, rec_id: integer, hash: byte_array): byte_array

Derives the Ethereum public key from a signature and hash, enabling identity recovery in blockchain transactions.

Parameters:

  • r: byte_array - The R component of the elliptic curve signature.
  • s: byte_array - The S component of the elliptic curve signature.
  • rec_id: integer - The recovery ID, indicating which signature variant was used.
  • hash: byte_array - The hash of the message that was signed.

Returns:

  • The 64-byte Ethereum public key recovered from the provided signature and hash components.

Error handling with try_call

function try_call()

Catches exceptions within a function call, providing graceful error handling and fallback mechanisms.

Variants:

  1. try_call(f: ()->T): T?
    • Calls the function f.
    • Returns the result of f on success or null if an exception occurs.
  2. try_call(f: ()->unit): boolean
    • Calls the function f that doesn't return a value.
    • Returns true on success or false if an exception occurs.
  3. try_call(f: ()->T, fallback: T): T
    • Calls the function f.
    • Returns the result of f on success or the specified fallback value if an exception occurs.
note

The try_call method restores the state of a program in the event of a failure. This means that even if the program writes data to the database, all changes will be reverted in case of an error.

Examples:

  • val int_or_null = try_call(integer.from_hex(s, *)); - converts the hexadecimal string s to an integer and assigns it to int_or_null, or assigns None if the conversion fails.
  • val int_or_default = try_call(integer.from_hex(s, *), -1); - converts the hexadecimal string s to an integer and assigns it to int_or_default, or assigns -1 if the conversion fails.
  • val l = try_call(list<integer>.from_gtv(my_gtv, *)); - converts the GTV my_gtv to a list of integers and assigns it to l or assigns None if the conversion fails.

Text pattern matching with text.like

text.like(pattern: text): boolean

The text.like() function provides a simple way to perform pattern matching, similar to the SQL LIKE clause. It operates consistently in both interpreted expressions and at-expressions.

Parameters:

  • pattern: text - The pattern to match against the text, incorporating wildcards for flexibility.

Returns:

  • True if the text matches the pattern, False otherwise.

Special Characters:

  • _: Matches any single character, similar to the SQL LIKE clause.
  • %: Matches any string of zero or more characters, enabling broader matching capabilities.

Examples:

  • Basic pattern matching: print(name.like(% von %)) - returns all names that have a von inside.

  • Pattern matching in collections: user @* { .name.like('% von %') } - returns all users whose names contain the substring " von ".

  • Escaping special characters: To match the special characters _ or %, you need to escape them with a backslash (\). Note that in string literals, you must use a double backslash (\\) to produce a single backslash at runtime.

    title.like('string\\_with\\_underscores') - this matches the string string_with_underscores where _ is treated as a literal underscore rather than a wildcard.