Functions

MQL has several built-in functions for capabilities that don't neatly fit into concise syntax. Functions can operate on a variable amount of parameters and always evaluate to a value. The basic syntax for functions is <name>(<arg1>, <arg2>, ... <argN>).

๐Ÿ“˜

Request a function!

Don't see a function you want? Let us know via email or ping us on Slack!

String functions

length

length(input: string) -> integer

Use length to retrieve the number of Unicode code points used to encode a string in UTF-8. Note that this is not equivalent to the number of bytes or glyphs.

length("sublimesecurity.com") -> 19
length("๐Ÿ“ง") -> 1
length("รฉmaรฎl") -> 5

like / ilike

like(input: string, pattern: string, ...) -> bool
ilike(input: string, pattern: string, ...) -> bool

like is used to match a value against a list of predefined wildcard patterns. like performs a case-sensitive match, but ilike is case-insensitive. Use wildcard characters to represent unknown substrings:

  • * is a placeholder for a string of any length, including empty strings
  • ? is a placeholder for a single character within the string

If input is null, then like and ilike will always return null.

Examples

like("[email protected]", "*@sublimesecurity.com") -> true

# use ilike for case-insensitive matches
like("[email protected]", "*@sublimesecurity.com") -> false
ilike("[email protected]", "*@sublimesecurity.com") -> true

# if multiple wildcard patterns are specified, only one needs to match
like("[email protected]", "*@*.org", "*@*.com", "*@*.gov") -> true

# use ? to match exactly 1 unknown character
like("[email protected]", "[email protected]") -> true
like("[email protected]", "[email protected]") -> false

regex_match / iregex_match

regex_match(input: string, pattern: string, ...) -> bool
iregex_match(input: string, pattern: string, ...) -> bool

regex_match is used to match an entire string against a list of regular expressions. If at least one of the regular expressions matches the entire string, then regex_match will return true. regex_match performs a case-sensitive regular expression match, but iregex_match is case-insensitive. Both functions match against the entire string, so add leading and trailing wildcards (.* or .*?) to search for a substring within the entire input string.

If input is null, then regex and iregex will always return null.

Examples

regex_match("[email protected]", ".*[email protected]") -> true

# use iregex for case-insensitive matches
regex_match("[email protected]", "@sublimesecurity.com") -> false
iregex_match("[email protected]", "@sublimesecurity.com") -> true

# if multiple wildcard patterns are specified, only one needs to match
regex_match("[email protected]", "@.*.org$", "@.*.com$", "@.*.gov$") -> true

Note: Both regular expression functions currently use RE2 for the regular expression syntax. RE2 shares many features with PCRE, but is typically more efficient and does not include computationally expensive features of PCRE. For more details, see the official documentation for RE2.

regex_search / iregex_search

regex_search(input: string, pattern: string, ...) -> bool
iregex_search(input: string, pattern: string, ...) -> bool

regex_search is used to check if a string contains a match against a list of regular expressions. Unlike regex_match, the full string does not need to match. regex_search(field, "\bfoo\b") has the same behavior as regex_match(field, ".*\bfoo\b.*").

For case-insensitivity regular expression matching, use iregex_search.

edit_distance / iedit_distance

edit_distance(input1: string, input2: string) -> integer
iedit_distance(input1: string, input2: string) -> integer

edit_distance is used to calculate the Levenshtein edit distance between two strings. The returned value is equal to the minimum number of character operations (deletion, insertion, substitution) required to transform one string into the other. edit_distance finds the case-sensitive distance between the two strings, but iedit_distance is case-insensitive.

edit_distance('Bat', 'bot') -> 2
iedit_distance('Bat', 'bot') -> 1

๐Ÿ“˜

Unicode and strings

Characters in strings are a complicated matter. Within MQL, all strings are always valid unicode and internally encoded as UTF-8. Unicode characters can be inserted into string literals directly or using unicode escape sequences, such as \uXXXX and \UXXXXXXXX.

Functions within MQL typically operate on unicode strings, and a "character" means a single UTF-8 code point, which can span more than one byte and may be an incomplete glyph.

Array functions

Array functions are the only way to loop over arrays in MQL. Array functions loop over an input array with an expression and return another array or some other value.

Within the looping expression, use the prefix . to access the loop item. To access an attribute of the looping item, use .<attribute>. To access fields on the root level of the MDM, drop the prefix. Additionally, a parent loop item can be accessed with an additional ., such as ...

For example, to check if an array of strings contains the string secret:

any(some_array_of_strings, . == "secret")

To check the body.links array that the attribute .mismatched is always false:

all(body.links, .mismatched == false)
{
  "attachments": [
    {
        "file_extension": "xls",
        ...
    },
    {
        "file_extension": "docx",
        ...
    },
    {
        "file_extension": "xls",
        ...
    }
  ],
  ...
}

all

all(input: [T], expression: bool) -> bool
all returns true if all of the values in the original array match an expression, which is provided by the second argument. If the array is empty, then all is vacuously `true.

Example usage

all(attachments, .file_extension == "xls") -> false
all(attachments, .file_extension in ("xls", "docx")) -> true

Tip: Use all if you want to perform an and across the array, and use any to perform an or.

any

any(input: [T], expression: bool) -> bool
any is the counterpart of all. Instead of checking for the expression to evaluate true for all items, any will check if at least one value returns true.

any(attachments, .file_extension == "xls") -> true
any(attachments, .file_extension in ("xls", "docx")) -> true

Tip: Use all if you want to perform an and across the array, and use any to perform an or.

filter

filter(input: [T], expression: bool) -> [T]
filter is used to generate a new filtered array, only returning items that cause the loop expression to evaluate true.

filter(attachments, .file_extension != "xls") -> [{"file_extension": "docx"}]

length

length(input: [T]) -> integer
Use length to retrieve the length of an array. If the input array is null, the function returns null. If the input array is non-null but empty, the function returns 0.

length(attachments) -> 3
length(filter(attachments, .file_extension == "xls")) -> 2

map

any(input: [T], expression: U) -> [U]
map is used to generate a new array, by evaluating an expression for each item in the array.

map(attachments, length(.file_extension)) -> [3, 4, 3]

map is particularly useful when querying an MDM:

map(attachments, .file_name) -> ["unpaid invoice.xlsx", "unpaid invoice.rar"]