CEL Expressions
expr
expressions use the Common Expression Language (CEL)
The CEL playground lets you quickly test CEL expressions
---
apiVersion: canaries.flanksource.com/v1
kind: Canary
metadata:
name: currency-converter-display-cel
spec:
http:
- name: USD
url: https://api.frankfurter.app/latest?from=USD&to=GBP,EUR,ILS,ZAR
display:
expr: "'$1 = €' + string(json.rates.EUR) + ', £' + string(json.rates.GBP) + ', ₪' + string(json.rates.ILS)"
Values in CEL represent any of the following:
Type | Description |
---|---|
int | 64-bit signed integers |
uint | 64-bit unsigned integers |
double | 64-bit IEEE floating-point numbers |
bool | Booleans (true or false ) |
string | Strings of Unicode code points |
bytes | Byte sequences |
list | Lists of values |
map | Associative arrays with int , uint , bool , or string keys |
null_type | The value null |
message names | Protocol buffer messages |
type | Values representing the types in the first column |
Handling null types and missing keys
When dealing with CEL objects, we might get errors where a key does not exist or if you're chaining keys, then one of the keys in the middle will be missing
// Assume we have an obj with value: {'a': {'b': 'c'}}
o.a.b => c
// But this will yield an error
o.a.d // Error, attribute 'd' does not exist
// To handle these, we can use the `or` or `orValue` directives
o.a.?d.orValue('fallback value') => 'fallback value'
// And if d exists, its value is returned
You can read more about or and orValue below
aws
aws.arnToMap
Takes in an AWS arn and parses it and returns a map.
aws.arnToMap("arn:aws:sns:eu-west-1:123:MMS-Topic") //
// map[string]string{
// "service": string,
// "region": string,
// "account": string,
// "resource": string,
// }
aws.fromAWSMap
aws.fromAWSMap
takes a list of map[string]string
and merges them into a single map. The input map is expected to have the field "Name".
aws.fromAWSMap(x).hello" == "world" // `true`
// Where
// x = [
// { Name: 'hello', Value: 'world' },
// { Name: 'John', Value: 'Doe' },
// ];
base64
base64.encode
base64.encode
encodes the given byte slice to a Base64 encoded string.
base64.decode("aGVsbG8=") // return b'hello'
base64.decode
base64.decode
decodes the given base64 encoded string back to its original form.
base64.decode("aGVsbG8=") // return b'hello'
collections
.keys
The keys
method on a map returns a list of keys.
Syntax:
e.keys()
// Where:
// `e` is a map .
Examples:
{"first": "John", "last": "Doe"}.keys() // ["first", "last"]
.merge
The merge
method on a map takes a second map to merge.
Syntax:
e.merge(x)
// Where:
// `e` is the map you want to merge to.
// `x` is the second map to merge from.
Examples:
{"first": "John"}.merge({"last": "Doe"}) // {"first": "John", "last": "Doe"}
.omit
The omit
method on a map takes a list of keys to remove.
Syntax:
e.omit(x)
// Where:
// `e` is a list .
// `x` is a list of keys to omit.
Examples:
{"first": "John", "last": "Doe"}.omit(["first"]) // {"last": "Doe"}
.sort
The sort
method on a list returns a sorted list.
Syntax:
e.sort()
// Where:
// `e` is a list .
Examples:
[3, 2, 1].sort() // [1, 2, 3]
['c', 'b', 'a'].sort() // ['a', 'b', 'c']
.uniq
The uniq
method on a list returns a list of unique items.
Syntax:
e.uniq()
// Where:
// `e` is a list .
Examples:
[1,2,3,3,3,].uniq().sum() // 10
["a", "b", "b"].uniq().join() // "ab"
.values
The values
method on a map returns a list of items.
Syntax:
e.values()
// Where:
// `e` is a map .
Examples:
{'a': 1, 'b': 2}.values().sum() // 3
all
The all
macro tests whether a predicate holds for all elements of a list e
or keys of a map e
. It returns a boolean value based on the evaluation.
If any predicate evaluates to false, the macro evaluates to false, ignoring any errors from other predicates
Syntax:
e.all(x, p)
// Where:
// `e` is the list or a map.
// `x` represents each element of the list.
// `p` is the condition applied to each entry.
Examples:
// Checking if all elements of a list are greater than 0:
[1, 2, 3].all(e, e > 0) // true
// Ensure that the all the map keys begin with the letter "a"
{"a": "apple", "b": "banana", "c": "coconut"}.all(k, k.startsWith("a")) // false
exists
The exists
macro checks if there is at least one element in a list that satisfies a given condition. It returns a boolean value based on the evaluation.
Syntax:
e.exists(x, p)
// Where:
// `e` is the list you're checking.
// `x` represents each element of the list.
// `p` is the condition applied to each entry.
Example:
// Checking if any element of a list is equal to 2:
[1, 2, 3].exists(e, e == 2) // true
exists_one
The exists_one
macro checks if there is exactly one element in a list that satisfies a given condition. It returns a boolean value based on the evaluation.
Syntax:
e.exists_one(x, p)
// Where:
// `e` is the list you're checking.
// `x` represents each element of the list.
// `p` is the condition applied to each entry.
Example:
[1, 2, 3].exists_one(e, e > 1) // false
[1, 2, 3].exists_one(e, e == 2) // true
filter
The filter
macro creates a new list containing only the elements or entries of an existing list that satisfy the given condition.
Syntax:
e.filter(x, p)
Where:
e
is the list you are filtering.x
represents each element of the list.p
is the predicate expression applied to each entry.
Examples:
// Filtering a list to include only numbers greater than 2:
[1, 2, 3, 4].filter(e, e > 2) // [3, 4]
fold
The fold
macro combines all elements of a collection, such as a list or a map, using a binary function. It's a powerful tool for aggregating or reducing data.
Syntax:
//For lists:
list.fold(e, acc, <binary_function>)
//For maps:
map.fold(k, v, acc, <binary_function>)
Where:
list
is the list you're folding.map
is the map you're folding.e
represents each element of the list.k
represents each key of the map.v
represents each value of the map.acc
is the accumulator, which holds the intermediate results.<binary_function>
is the function applied to each entry and the accumulator.
Examples:
[1, 2, 3].fold(e, acc, acc + e) // 6
// Concatenating all values of a map:
{"a": "apple", "b": "banana"}.fold(k, v, acc, acc + v) // "applebanana"
has
The has
macro tests whether a field is available. It's particularly useful for protobuf messages where fields can be absent rather than set to a default value. It's especially useful for distinguishing between a field being set to its default value and a field being unset. For instance, in a protobuf message, an unset integer field is indistinguishable from that field set to 0 without the has
macro.
Syntax
has(x.y): boolean
// Where
// `x` is a message or a map and
// `y` (string) is the field you're checking for.
Example:
If you have a message person
with a potential field name
, you can check for its presence with:
has(person.name) // true if 'name' is present, false otherwise
in
The membership test operator checks whether an element is a member of a collection, such as a list or a map. It's worth noting that the in
operator doesn't check for value membership in maps, only key membership.
Syntax:
"apple" in ["apple", "banana"] // => true
3 in [1, 2, 4] // => false
map
The map
macro creates a new list by transforming a list e
by taking each element x
to the function given by the expression t
, which can use the variable x
.
Syntax:
e.map(x, t)
// Where:
// `e` is the list you are transforming.
// `x` represents each element of the list.
// `t` is the transformation function applied to each entry.
e.map(x, p, t)
// Where:
// `e` is the list you're transforming.
// `p` filter before the value is transformed
// `x` represents each element of the list.
// `t` is the transformation function applied to each entry.
Examples:
// Transforming each element of a list by multiplying it by 2:
[1, 2, 3].map(e, e * 2) // [2, 4, 6]
[(1, 2, 3)].map(x, x > 1, x + 1) // [3, 4]
or
If the value on the left-hand side is none-type, the optional value on the right hand side is returned. If the value on the left-hand set is valued, then it is returned. This operation is short-circuiting and evaluates as many links in the or
chain as are needed to return a non-empty optional value.
obj.?field.or(m[?key]) // if obj.field is none, m.key is returned
l[?index].or(obj.?field.subfield).or(obj.?other) // first non-none of l[index], obj.field.subfield, obj.other is returned
orValue
When creating map or list, if a field may be optionally set based on its presence, then placing a ?
before the field name or key ensures the type on the right-hand side must be optional(T) where T is the type of the field or key-value.
// The following returns a map with the key expression set only if the subfield is present, otherwise a default value is returned
{'a': 'x', 'b': 'y', 'c': 'z'}.?c.orValue('empty') // Returns z since `c` exists
{'a': 'x', 'b': 'y'}.?c.orValue('empty') // Returns 'empty' since `c` doesn't exist
// We can use the same for list types
[1, 2, 3][?2].orValue(5) // Return 3 since 2nd index has a value
[1, 2][?2].orValue(5) // Return 5 since 2nd index doesn't exist
size
size
determines the number of elements in a collection or the number of Unicode characters in a string.
Syntax
(string) -> int string length
(bytes) -> int bytes length
(list(A)) -> int list size
(map(A, B)) -> int map size
"apple".size() // 5
b"abc".size() // 3
["apple", "banana", "cherry"].size() // 3
{"a": 1, "b": 2}.size(); // 2
slice
Returns a new sub-list using the indices provided.
[1, 2, 3, 4].slice(1, 3) // return [2, 3]
[(1, 2, 3, 4)].slice(2, 4) // return [3 ,4]
sets
sets.contains
Returns whether the first list argument contains all elements in the second list argument. The list may contain elements of any type and standard CEL equality is used to determine whether a value exists in both lists. If the second list is empty, the result will always return true.
sets.contains(list(T), list(T)) -> bool
Examples:
sets.contains([], []) // true
sets.contains([], [1]) // false
sets.contains([1, 2, 3, 4], [2, 3]) // true
sets.contains([1, 2.0, 3u], [1.0, 2u, 3]) // true
sets.equivalent
Returns whether the first and second list are set equivalent. Lists are set equivalent if for every item in the first list, there is an element in the second which is equal. The lists may not be of the same size as they do not guarantee the elements within them are unique, so size doesn't factor into the computation.
sets.equivalent(list(T), list(T)) -> bool
Examples:
sets.equivalent([], []) // true
sets.equivalent([1], [1, 1]) // true
sets.equivalent([1], [1u, 1.0]) // true
sets.equivalent([1, 2, 3], [3u, 2.0, 1]) // true
sets.intersects
Returns whether the first list has at least one element whose value is equal to an element in the second list. If either list is empty, the result is false.
sets.intersects([1], []) // false
sets.intersects([1], [1, 2]) // true
sets.intersects(
[[1], [2, 3]],
[
[1, 2],
[2, 3.0]
]
) // true
csv
CSV
CSV
converts a CSV formatted array into a two-dimensional array, where each element is a row string.
CSV(["Alice,30", "Bob,31"])[0][0] // "Alice"
crypto
crypto.SHA1|256|384|512
The crypto.SHA*
functions are used to compute the SHA hash of the input data.
crypto.SHA1("hello") // "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c"
crypto.SHA256("hello") // "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824"
dates
timestamp
timestamp
represent a point in time. It's typically used in conjunction with other functions to extract or manipulate time-related data.
// Creating a timestamp for January 1st, 2023:
timestamp("2023-01-01T00:00:00Z")
// Creating another timestamp:
timestamp("2023-07-04T12:00:00Z")
.getDate
getDate
extract the date part from a timestamp. It returns a string representation of the date.
// Extracting the date from a timestamp:
"2023-01-01T12:34:56Z".getDate() // "2023-01-01"
// Getting the date from another timestamp:
"2023-07-04T00:00:00Z".getDate() // "2023-07-04"
.get[DatePart]
Function | Description | Example |
---|---|---|
{date>.getDayOfMonth() | A integer value representing the day of the month, with the first day being 1. | 1 - 31 |
<date>.getDayOfWeek() | eturns an integer value representing the day of the week, where Sunday is 0 and Saturday is 6. | 0 - 6 |
<date>.getDayOfYear() | an integer value representing the day of the year, with January 1st being day 1. | 1 - 366 |
<date>.getDayOfMonth() | the full year (4 digits for 4-digit years) of the specified timestamp. | |
<date>.getHours() | the full year (4 digits for 4-digit years) of the specified timestamp. | 0- 23 |
<date>.getMilliseconds() | 0 -999 | |
<date>.getMinutes() | ||
<date>.getMonth() | 0 -11 | |
<date>.getSeconds() | 0 - 59 | 0 - 59 |
<date>.getHours() |
duration
duration
parses a string into a new duration.
The format is an integer followed by a unit: s
for seconds, m
for minutes, h
for hours, and d
for days.
// Creating a duration of 5 hours:
duration("5h") // Represents a duration of 5 hours
duration("30m") // Represents a duration of 30 minutes
Durations can also be crated using arithmetic:
Field | Description |
---|---|
time.Unix(epoch) | converts a UNIX time (seconds since the UNIX epoch) into a time.Time object |
time.Nanosecond | converts to a time.Duration |
time.Microsecond | |
time.Millisecond | |
time.Second | |
time.Minute | |
time.Hour |
time.ZoneName
time.ZoneName
returns the name of the local system's time zone. It doesn't require any parameters and is useful for retrieving the time zone information.
// Retrieving the local time zone name:
time.ZoneName() // Might evaluate to "PST" if the local time zone is Pacific Standard Time
time.ZoneOffset
time.ZoneOffset
returns the offset of the local system's time zone in minutes. It helps in understanding the time difference between the local time zone and UTC.
// Getting the time zone offset:
time.ZoneOffset() // Could evaluate to -480 for PST
time.Parse
time.Parse
parse a given string into a time object based on a specified layout. It's handy for converting string representations of time into actual time objects.
Syntax:
time.Parse(layout, value)
layout
is the time layout string.value
is the string representation of the time to be parsed.
// Parsing a time string with a specific format:
time.Parse("2006-01-02", "2023-09-26") // a time object representing September 26, 2023
// Another example with a different format:
time.Parse("02-01-2006", "26-09-2023") // the same time object as above
// Parsing a time with hour and minute information:
time.Parse("15:04 02-01-2006", "14:30 26-09-2023") // Includes time of day information
time.ParseLocal
time.ParseLocal
parses a given string into a time object according to a specified layout and the local time zone. It's useful for working with local times.
time.ParseLocal(layout, value)
layout
is the time layout string.value
is the string representation of the time to be parsed.
Examples:
// Parsing a local time string:
time.ParseLocal("2006-01-02 15:04", "2023-09-26 14:30") // a local time object for 14:30 on September 26, 2023
// Another example:
time.ParseLocal("02-01-2006", "26-09-2023") // a local time object for September 26, 2023
// Parsing with a different time format:
time.ParseLocal("15:04 02-01-2006", "14:30 26-09-2023") // Includes time of day information in local time zone
time.ParseInLocation
time.ParseInLocation
parses a string into a time object according to a specified layout and time zone. It provides more control over the time zone compared to time.ParseLocal
.
Syntax:
time.ParseInLocation(layout, location, value)
layout
is the time layout string.location
is the string name of the time zone.value
is the string representation of the time to be parsed.
Examples:
// Parsing a time string for a specific time zone:
time.ParseInLocation("2006-01-02", "America/New_York", "2023-09-26") // a time object for EST/EDT
// Another example for a different time zone:
time.ParseInLocation("02-01-2006", "Europe/London", "26-09-2023") // a time object for GMT/BST
// Parsing with hour and minute for a specific zone:
time.ParseInLocation("15:04 02-01-2006", "Asia/Tokyo", "14:30 26-09-2023") // a time object for JST
time.Now
time.Now
returns the current time. It's a straightforward way to retrieve the current date and time according to the system's local time zone.
// Getting the current time:
time.Now() // the current date and time
time.ParseDuration
time.ParseDuration
parses a string into a duration. It supports various units like "s" for seconds, "m" for minutes, "h" for hours, etc.
// Parsing a duration string:
time.ParseDuration("1h30m") // a duration of 1 hour and 30 minutes
// Another example with a different format:
time.ParseDuration("15m30s") // a duration of 15 minutes and 30 seconds
// Parsing a negative duration:
time.ParseDuration("-2h45m") // a duration of -2 hours and -45 minutes
time.Since
time.Since
calculates the duration that has elapsed since a given time. It is commonly used to measure the time difference between a specified time and the current moment.
// Calculating the time elapsed since a specific past time:
time.Since(time.Parse("2006-01-02", "2023-09-26")) // the duration since September 26, 2023
// Another example with a different past time:
time.Since(time.Parse("15:04 02-01-2006", "14:30 26-09-2023")) // the duration since 14:30 on September 26, 2023
// Using `time.Now` for a real-time duration:
time.Since(time.Now()) // Always evaluates to a very small duration, as it's the time since "now"
time.Until
time.Until
calculates the duration remaining until a specified future time. It helps in determining the time left for an event or deadline.
// Calculating the time remaining until a specific future time:
time.Until(time.Parse("2006-01-02", "2023-10-01")) // the duration until October 1, 2023
// Another example with a different future time:
time.Until(time.Parse("15:04 02-01-2006", "16:00 30-09-2023")) // the duration until 16:00 on September 30, 2023
// Using `time.Now` for a real-time duration:
time.Until(time.Now()) // Always evaluates to zero, as it's the time until "now"
encode
urlencode
urlencode
encodes the given string into a URL-encoded string.
urlencode("hello world ?") // hello+world+%3F
urldecode
urldecode
decodes a URL-encoded string.
urldecode("hello+world+%3F") // 'hello world ?'
filepath
filepath.Base
filepath.Base
returns the last element of path.
Trailing path separators are removed before extracting the last element.
If the path is empty, Base returns .
.
If the path consists entirely of separators, Base returns a single separator.
filepath.Base("/home/flanksource/projects/gencel") // gencel
filepath.Clean
filepath.Clean
returns the shortest path name equivalent to path by purely lexical processing.
It applies the following rules iteratively until no further processing can be done:
filepath.Clean("/foo/bar/../baz") // Evaluates /foo/baz
filepath.Dir
filepath.Dir
returns all but the last element of path, typically the path's directory.
After dropping the final element, Dir calls Clean on the path and trailing
slashes are removed.
If the path is empty, Dir returns .
.
If the path consists entirely of separators, Dir returns a single separator.
The returned path does not end in a separator unless it is the root directory.
filepath.Dir("/home/flanksource/projects/gencel") // /home/flanksource/projects
filepath.Ext
filepath.Ext
returns the file name extension used by path.
The extension is the suffix beginning at the final dot in the final element of path; it is empty if there is no dot.
filepath.Ext("/opt/image.jpg") // .jpg
filepath.IsAbs
filepath.IsAbs
reports whether the path is absolute.
filepath.Base("/home/flanksource/projects/gencel") // true
filepath.Base("projects/gencel") // false
filepath.Join
filepath.Join
joins any number of path elements into a single path,
separating them with an OS specific Separator. Empty elements
are ignored. The result is Cleaned. However, if the argument
list is empty or all its elements are empty, Join returns
an empty string.
On Windows, the result is only a UNC path if the first
non-empty element is a UNC path.
filepath.Join(["/home/flanksource", "projects", "gencel"]; // /home/flanksource/projects/gencel
filepath.Match
filepath.Match
reports whether name matches the shell file name pattern.
filepath.Match("*.txt", "foo.json") // false
filepath.Match("*.txt", "foo.txt") // true
filepath.Rel
filepath.Rel
returns a relative path that is lexically equivalent to targpath when
joined to basepath with an intervening separator. That is,
Join(basepath, Rel(basepath, targpath)) is equivalent to targpath itself.
On success, the returned path will always be relative to basepath,
even if basepath and targpath share no elements.
An error is returned if targpath can't be made relative to basepath or if
knowing the current working directory would be necessary to compute it.
Rel calls Clean on the result.
filepath.Rel("/foo/bar", "/foo/bar/baz") // baz
filepath.Split
filepath.Split
splits path immediately following the final Separator,
separating it into a directory and file name component.
If there is no Separator in path, Split returns an empty dir
and file set to path.
The returned values have the property that path = dir+file.
filepath.Split("/foo/bar/baz") // [/foo/bar/ baz]
JSON
.JSON
JSON
parses a string into an object
'{"name": "Alice", "age": 30}'.JSON()
.JSONArray
JSONArray
parses a string into an array
'[{"name": "Alice"}, {"name": "Bob"}]'.JSONArray()
.toJSON
toJSON
converts an object into a JSON formatted string.
[{ name: "John" }].toJSON() // [{"name":"John"}]
{'name': 'John'}.toJSON() // {"name":"John"}
1.toJSON() // 1
.toJSONPretty
toJSONPretty
converts any data type into a JSON formatted string with proper indentation.
{'name': 'aditya'}.toJSONPretty('\t')
//
// {
// "name": "aditya"
// }
// Using tab for indentation:
["Alice", 30].toJSONPretty("\t")
// An empty map with four spaces indent:
{}.toJSONPretty(" ", );
jq
jq
applies a jq expression to filter or transform data.
// Filtering data with a jq expression:
jq(".name", { name: "John", age: 30 }) // "John"
// Transforming data with a jq expression:
jq("{name, age}", { name: "John", age: 30, city: "NY" }) // {"name": "John", "age": 30}
// Using a complex jq expression:
jq(".[] | select(.age > 25)", [
{ name: "John", age: 30 },
{ name: "Jane", age: 25 }
]) // [{"name": "John", "age": 30}]
kubernetes
k8s.cpuAsMillicores
k8s.cpuAsMillicores
returns the millicores of a Kubernetes resource.
k8s.cpuAsMillicores("10m") // 10
k8s.cpuAsMillicores("0.5") // 500
k8s.cpuAsMillicores("1.234") // 1234
k8s.getHealth
k8s.getHealth
retrieves the health status of a Kubernetes resource as a map. The map contains key-value pairs providing detailed information about the resource's health.
Examples:
// Retrieving the health information of a pod:
k8s.getHealth(pod) // a map with keys and values indicating the pod's health
// Getting the health information of a service:
k8s.getHealth(service) // a map with keys and values indicating the service's health
// Checking the health information of a deployment:
k8s.getHealth(deployment) // a map with keys and values indicating the deployment's health
k8s.getStatus
k8s.getStatus
retrieves the status of a Kubernetes resource as a string. It provides detailed information about the current state of the resource.
// Retrieving the status of a pod:
k8s.getStatus(pod) // "Running" if the pod is running
// Getting the status of a service:
k8s.getStatus(service) // "Active" if the service is active
// Checking the status of a deployment:
k8s.getStatus(deployment) // "Deployed" if the deployment is successful
k8s.getResourcesLimit
k8s.getResourcesLimit
retrieves the resource (cpu/memory) limit of a Kubernetes resource.
Syntax:
k8s.getResourcesLimit(pod, resource)
Where:
pod
is the pod objectresource
is either 'cpu' or 'memory'
// Retrieving the status of a pod:
k8s.getResourcesLimit(pod, "cpu") // 2
k8s.getResourcesLimit(pod, "memory") // 200
k8s.getResourcesRequests
k8s.getResourcesRequests
retrieves the status of a Kubernetes resource as a string. It provides detailed information about the current state of the resource.
Syntax:
k8s.getResourcesRequests(pod, resource)
Where:
pod
is the pod objectresource
is either 'cpu' or 'memory'
// Retrieving the status of a pod:
k8s.getResourcesRequests(pod, "cpu") // 2
k8s.getResourcesRequests(pod, "memory") // 200
k8s.isHealthy
k8s.isHealthy
determine if a Kubernetes resource is healthy. It returns a boolean value indicating the health status of the resource.
// Checking if a pod is healthy:
k8s.isHealthy(pod) // true if the pod is healthy
// Verifying the health of a service:
k8s.isHealthy(service) // false if the service is not healthy
// Assessing the health of a deployment:
k8s.isHealthy(deployment) // true if the deployment is healthy
k8s.labels
k8s.labels
takes in a kubernetes object & returns a map of all the labels.
-
The namespace is also returned as a label for namespaced objects.
-
Any labels ending with
-hash
are removed from the map.
// Checking if a pod is healthy:
k8s.labels(pod) // {"namespace": "kube-system", "app": "kube-dns"}
k8s.memoryAsBytes
k8s.memoryAsBytes
converts the memory string to bytes.
k8s.memoryAsBytes("10Ki") // 10240
k8s.memoryAsBytes("1.234gi") // 1324997410
k8s.nodeProperties
k8s.nodeProperties
is a helper function that takes in a kubernetes Node object and returns a map of the following node's properties
- ephemeral-storage (in bytes)
- cpu
- memory
- zone (extracted from topology.kubernetes.io/zone)
// Checking if a pod is healthy:
k8s.nodeProperties(pod) // {"cpu": 2, "memory": 200, ephemeral-storage": 100000, zone": "us-east-1a"}
k8s.podProperties
k8s.podProperties
is a helper function that takes in a kubernetes pod object and returns a map of the following pod's properties
- image
- cpu
- memory
- node
- created-at
- namespace
// Checking if a pod is healthy:
k8s.podProperties(pod) // {"image": "postgres:14", "node": "saka", ...}
math
math.Add
math.Add
takes a list of number and returns their sum
math.Add([1, 2, 3, 4, 5]) // 15
math.Sub
math.Sub
takes two numbers and returns their difference
math.Sub(5, 4) // 1
math.Mul
math.Mul
takes a list of numbers and returns their product
math.Mul([1, 2, 3, 4, 5]) // 120
math.Div
math.Div
takes two numbers and returns their quotient
math.Div(4, 2) // 2
math.Rem
math.Rem
takes two numbers and returns their remainder
math.Rem(4, 3) // 1
math.Pow
math.Pow
takes two numbers and returns their power
math.Pow(4, 2) // 16
math.Seq
math.Seq
generates a sequence of numbers from the start value to the end value, incrementing by the step value.
Syntax:
math.Seq([start, end, ?step])
start
is the starting value of the sequence.end
is the ending value of the sequence.step
is the increment value of the sequence. (optional. Defaults to 1)
math.Seq([1, 5]) // [1, 2, 3, 4, 5]
math.Seq([1, 6, 2]) // [1, 3, 5]
math.Abs
math.Abs
takes a number and returns its absolute value
math.Abs(-1) // 1
math.greatest
math.greatest
takes a list of numbers and returns the greatest value
math.greatest([1, 2, 3, 4, 5]) // 5
math.least
math.least
takes a list of numbers and returns the least value
math.least([1, 2, 3, 4, 5]) // 1
math.Ceil
math.Ceil
returns the smallest integer greater than or equal to the provided float.
math.Ceil(2.3) // 3
math.Floor
math.Floor
returns the largest integer less than or equal to the provided float.
math.Floor(2.3) // 2
math.Round
math.Round
returns the nearest integer to the provided float.
math.Round(2.3) // 2
random
random.ASCII
random.ASCII
generates random ASCII strings of a specified length.
random.ASCII(5)
random.Alpha
random.Alpha
generates random alphabetic strings of a specified length.
random.Alpha(5)
random.AlphaNum
random.AlphaNum
generates random alphanumeric strings of a specified length.
random.AlphaNum(5)
random.String
random.String
generates random strings of a specified length and character set.
random.String(5)
// generate 5 chars between a and d
random.String(5, ["a", "d"])
random.Item
random.Item
generates a random item from a list.
random.Item(["a", "b", "c"])
random.Number
random.Number
generates a random integer within a specified range.
Syntax:
random.Number(min, max)
min
is the minimum value of the range (inclusive).max
is the maximum value of the range (inclusive).
Examples:
random.Number(1, 10)
random.Float
random.Float
generates a random float within a specified range.
Syntax:
random.Float(min, max)
min
is the minimum value of the range (inclusive).max
is the maximum value of the range (inclusive).
Examples:
random.Float(1, 10)
regexp
regexp.Find
regexp.Find
find the first occurrence of a pattern within a string. It returns the matched substring or an error if the pattern is invalid.
// Finding a pattern within a string:
regexp.Find("llo", "hello") // "llo"
// Searching for digits within a string:
regexp.Find("\\d+", "abc123def") // "123"
// Pattern not found in the string:
regexp.Find("xyz", "hello") // ""
regexp.FindAll
regexp.FindAll
retrieves all occurrences of a pattern within a string, up to a specified count. It returns a list of matched substrings or an error if the pattern is invalid.
regexp.FindAll(pattern, count, input)
pattern
is the regular expression pattern to find.count
is the maximum number of occurrences to return.input
is the string to search within.
Examples:
// Finding all occurrences of a pattern:
regexp.FindAll("a.", -1, "banana") // ["ba", "na", "na"]
// Limiting the number of matches:
regexp.FindAll("\\d", 2, "12345") // ["1", "2"]
// Pattern not found:
regexp.FindAll("z", -1, "hello") // []
regexp.Match
regexp.Match
checks if a string matches a given regular expression pattern. It returns a boolean value indicating the match status.
// Checking if a string matches a pattern:
regexp.Match("^h.llo", "hello") // true
// Pattern does not match the string:
regexp.Match("^b", "apple") // false
// Matching digits in a string:
regexp.Match("\\d+", "abc123") // true
regexp.QuoteMeta
regexp.QuoteMeta
quotes all regular expression metacharacters inside a string. It returns the quoted string.
// Quoting metacharacters in a string:
regexp.QuoteMeta("a.b") // "a\\.b"
// String without metacharacters:
regexp.QuoteMeta("abc") // "abc"
// Quoting a complex pattern:
regexp.QuoteMeta("[a-z].*") // "\\[a\\-z\\]\\.\\*"
regexp.Replace
regexp.Replace
replaces occurrences of a pattern within a string with a specified replacement string. It returns the modified string.
Syntax:
regexp.Replace(pattern, replacement, input)
pattern
is the regular expression pattern to replace.replacement
is the string to replace the pattern with.input
is the original string.
// Replacing a pattern in a string:
regexp.Replace("a.", "x", "banana") // "bxnxna"
// Pattern not found:
regexp.Replace("z", "x", "apple") // "apple"
// Replacing digits:
regexp.Replace("\\d+", "num", "abc123") // "abcnum"
regexp.ReplaceLiteral
regexp.ReplaceLiteral
replaces occurrences of a pattern within a string with a specified replacement string, without interpreting the pattern as a regular expression. It returns the modified string or an error if the pattern is invalid.
Syntax:
regexp.ReplaceLiteral(pattern, replacement, input)
Where:
pattern
is the substring to replace.replacement
is the string to replace the pattern with.input
is the original string.
Examples:
// Replacing a substring:
regexp.ReplaceLiteral("apple", "orange", "apple pie") // "orange pie"
// Substring not found:
regexp.ReplaceLiteral("z", "x", "apple") // "apple"
// Replacing a pattern without regex interpretation:
regexp.ReplaceLiteral("a.", "x", "a.b c.d") // "x.b c.d"
regexp.Split
regexp.Split
splits a string into a slice of substrings separated by a pattern. It returns the slice of strings or an error if the pattern is invalid.
regexp.Split(pattern, count, input)
pattern
is the regular expression pattern that separates the substrings.count
is the maximum number of splits. Use -1 for no limit.input
is the string to split.
regexp.Split("a.", -1, "banana") // ["", "n", "n"]
// Limiting the number of splits:
regexp.Split("\\s", 2, "apple pie is delicious") // ["apple", "pie is delicious"]
// Pattern not found:
regexp.Split("z", -1, "hello") // ["hello"]
strings
.abbrev
abbrev
on a string abbreviates the string using ellipses. This will turn the string "Now is the time for all good men" into "...s the time for..."
This function works like Abbreviate(string, int)
, but allows you to specify a "left edge" offset. The left edge is not
necessarily going to be the leftmost character in the result, or the first character following the ellipses, but it will appear
somewhere in the result.
In no case will it return a string of length greater than maxWidth.
"string".abbrev(offset, maxWidth)
- str - the string to check
- offset - left edge of source string
- maxWidth - maximum length of result string, must be at least 4
Examples:
"Now is the time for all good men".abbrev(5, 20) // "...s the time for..."
"KubernetesPod".abbrev(1, 5) // "Ku..."
"KubernetesPod".abbrev(6) // "Kub..."
.camelCase
camelCase
converts a given string into camelCase format.
// Converting a string to camelCase:
"hello world".camelCase() // "HelloWorld"
// Converting a snake_case string:
"hello_world".camelCase() // "HelloWorld"
// Converting a string with spaces and special characters:
"hello beautiful world!".camelCase() // "HelloBeautifulWorld"
.charAt
Returns the character at the given position. If the position is negative, or greater than the length of the string, the function will produce an error:
"hello".charAt(4) // return 'o'
"hello".charAt(5) // return ''
"hello".charAt(-1) // error
.contains
contains
check if a string contains a given substring.
"apple".contains("app") // true
.endsWith
endsWith
determine if a string ends with a specified substring.
"hello".endsWith("lo") // true
.format
format
Returns a new string with substitutions being performed, printf-style.
The valid formatting clauses are:
%s
substitutes a string. This can also be used onbools
,lists
,maps
,bytes
,Duration
,Timestamp
,int
,double
the dot/period decimal separator will always be used when printing a list or map that contains a double, and that null can be passed (which results in the string "null") in addition to types.%d
substitutes an integer.%f
substitutes a double with fixed-point precision. The default precision is 6, but this can be adjusted. The stringsInfinity
,-Infinity
, andNaN
are also valid input for this clause.%e
substitutes a double in scientific notation. The default precision is 6, but this can be adjusted.%b
substitutes an integer with its equivalent binary string. Can also be used on bools.%x
substitutes an integer with its equivalent in hexadecimal, or if given a string or bytes, will output each character's equivalent in hexadecimal.%X
same as above, but with A-F capitalized.%o
substitutes an integer with its equivalent in octal.
"this is a string: %s\nand an integer: %d".format(["str", 42]) thsis is a string: str\nand an integer: 42
.indent
indent
indents each line of a string by the specified width and prefix
"hello world".indent(4, "-") // ----hello world
.indexOf
Returns the integer index of the first occurrence of the search string. If the search string is not found the function returns -1.
The function also accepts an optional position from which to begin the substring search. If the substring is the empty string, the index where the search starts is returned (zero or custom).
<string>.indexOf(<string>) -> <int>
<string>.indexOf(<string>, <int>) -> <int>
Examples:
"hello mellow".indexOf("") // returns 0
"hello mellow".indexOf("ello") // returns 1
"hello mellow".indexOf("jello") // returns -1
"hello mellow".indexOf("", 2) // returns 2
"hello mellow".indexOf("ello", 20) // error
.join
Returns a new string where the elements of string list are concatenated.
The function also accepts an optional separator which is placed between elements in the resulting string.
["hello", "mellow"].join() // returns 'hellomellow'
["hello", "mellow"].join(" ") // returns 'hello mellow'
[].join() // returns ''
[].join("/") // returns ''
.kebabCase
kebabCase
converts a given string into kebab-case format.
// Converting a string to kebab-case:
"Hello World".kebabCase() // "hello-world"
// Converting a CamelCase string:
"HelloWorld".kebabCase() // "hello-world"
// Converting a string with spaces and special characters:
"Hello Beautiful World!".kebabCase() // "hello-beautiful-world"
.lastIndexOf
Returns the integer index of the last occurrence of the search string. If the search string is not found the function returns -1.
The function also accepts an optional position which represents the last index to be considered as the beginning of the substring match. If the substring is the empty string, the index where the search starts is returned (string length or custom).
"hello mellow".lastIndexOf("") // returns 12
"hello mellow".lastIndexOf("ello") // returns 7
"hello mellow".lastIndexOf("jello") // returns -1
"hello mellow".lastIndexOf("ello", 6) // returns 1
"hello mellow".lastIndexOf("ello", -1) // error
.lowerAscii
Returns a new string where all ASCII characters are lower-cased.
This function does not perform Unicode case-mapping for characters outside the ASCII range.
"TacoCat".lowerAscii() // returns 'tacocat'
"TacoCÆt Xii".lowerAscii() // returns 'tacocÆt xii'
.matches
matches
determine if a string matches a given regular expression pattern. It returns a boolean value indicating whether the string conforms to the pattern.
// Checking if a string matches a simple pattern:
"apple".matches("^a.*e$") // true
// Validating an email format:
"example@email.com".matches("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$") // true
// Checking for a pattern of digits:
"12345".matches("^\\d+$") // true
.quote
Takes the given string and makes it safe to print (without any formatting due to escape sequences). If any invalid UTF-8 characters are encountered, they are replaced with \uFFFD.
strings.quote('single-quote with "double quote"') // returns '"single-quote with \"double quote\""'
strings.quote("two escape sequences a\n") // returns '"two escape sequences \\a\\n"'
.repeat
repeat
on a string repeats the string for a given number of times.
"apple".repeat(3) // "appleappleapple"
.replace
Returns a new string based on the target, which replaces the occurrences of a search string with a replacement string if present. The function accepts an optional limit on the number of substring replacements to be made.
When the replacement limit is 0, the result is the original string. When the limit is a negative number, the function behaves the same as replace all.
<string>.replace(<string>, <string>) -> <string>
<string>.replace(<string>, <string>, <int>) -> <string>
Examples:
"hello hello".replace("he", "we") // returns 'wello wello'
"hello hello".replace("he", "we", -1) // returns 'wello wello'
"hello hello".replace("he", "we", 1) // returns 'wello hello'
"hello hello".replace("he", "we", 0) // returns 'hello hello'
.replaceAll
replaceAll
replaces all occurrences of a substring within a string with another substring.
"I have an apple".replaceAll("apple", "orange") // "I have an orange"
.reverse
Returns a new string whose characters are the same as the target string, only formatted in reverse order. This function relies on converting strings to rune arrays in order to reverse.
"gums".reverse() // returns 'smug'
"John Smith".reverse() // returns 'htimS nhoJ'
.runeCount
runeCount
counts the number of runes in a given string.
"Hello World".runeCount() // 11
"Hello$World".runeCount() // 11
.shellQuote
shellQuote
quotes a string such that it can be safely used as a token in a shell command.
"Hello World".shellQuote() // "'Hello World'"
// Shell quoting a string with special characters:
"Hello$World".shellQuote() // "'Hello$World'"
// Shell quoting a string with spaces and special characters:
"Hello World$123".shellQuote() // "'Hello World$123'"
.size
size
determine the number of elements in a collection or the number of Unicode characters in a string.
// Getting the size of a list:
["apple", "banana", "cherry"].size() // 3
// Determining the number of characters in a string:
"hello".size() // 5
.slug
slug
converts a given string into a URL-friendly slug format.
Syntax:
'string'.slug()
Where:
string
is the input string to be converted.
Examples:
// Converting a string to a slug:
"Hello World!".slug() // "hello-world"
// Converting a string with special characters:
"Hello, World!".slug() // "hello-world"
// Converting a multi-word string:
"Hello Beautiful World".slug() // "hello-beautiful-world"
.snakeCase
snakeCase
converts a given string into snake_case format.
// Converting a string to snake_case:
"Hello World".snakeCase() // "hello_world"
// Converting a CamelCase string:
"HelloWorld".snakeCase() // "hello_world"
// Converting a string with spaces and special characters:
"Hello Beautiful World!".snakeCase() // "hello_beautiful_world"
.sort
sort
on a string sorts the string alphabetically.
"hello".sort() // ehllo
.split
Returns a list of strings split from the input by the given separator. The function accepts an optional argument specifying a limit on the number of substrings produced by the split.
When the split limit is 0, the result is an empty list. When the limit is 1, the result is the target string to split. When the limit is a negative number, the function behaves the same as split all.
Examples:
"hello hello hello".split(" ") // returns ['hello', 'hello', 'hello']
"hello hello hello".split(" ", 0) // returns []
"hello hello hello".split(" ", 1) // returns ['hello hello hello']
"hello hello hello".split(" ", 2) // returns ['hello', 'hello hello']
"hello hello hello".split(" ", -1) // returns ['hello', 'hello', 'hello']
.squote
squote
adds single quotes around a given string.
// Single quoting a simple string:
"Hello World".squote() // "'Hello World'"
// Single quoting a string with a number:
"12345".squote() // "'12345'"
// Single quoting an already single quoted string:
"'Hello World'".squote() // "'''Hello World'''"
.startsWith
startsWith
determine if a string starts with a specified substring.
// Checking if a string starts with a certain substring:
"hello".startsWith("he") // true
.substring
Returns the substring given a numeric range corresponding to character positions. Optionally may omit the trailing range for a substring from a given character position until the end of a string.
Character offsets are 0-based with an inclusive start range and exclusive end range. It is an error to specify an end range that is lower than the start range, or for either the start or end index to be negative or exceed the string length.
"tacocat".substring(4) // returns 'cat'
"tacocat".substring(0, 4) // returns 'taco'
"tacocat".substring(-1) // error
"tacocat".substring(2, 1) // error
.title
title
converts the first character of each word in a string to uppercase.
// Converting a string:
"hello world".title() // "Hello World"
// Working with mixed case:
"mIxEd CaSe".title() // "MIxED CASe"
.trim
Returns a new string which removes the leading and trailing space. The trim function uses the Unicode definition of space. which does not include the zero-width spaces.
" \ttrim\n ".trim() // 'trim'
.trimPrefix
trimPrefix
removes a given prefix from a string if the string starts with that prefix.
// Removing a prefix from a string:
"Mr. Smith".trimPrefix("Mr.") // "Smith"
// Another example:
"Astronaut".trimPrefix("Astro") // "naut"
// If the prefix is not present:
"Mr. Smith".trimPrefix("Dr.") // "Mr. Smith"
.trimSuffix
trimSuffix
removes a given suffix from a string if the string ends with that suffix.
// Removing a suffix from a string:
"image.jpg".trimSuffix(".jpg") // "image"
// If the suffix is not present:
"image.jpg".trimSuffix(".png") // "image.jpg"
.upperAscii
Returns a new string where all ASCII characters are upper-cased.
This function does not perform Unicode case-mapping for characters outside the ASCII range.
"TacoCat".upperAscii() // returns 'TACOCAT'
"TacoCÆt Xii".upperAscii() // returns 'TACOCÆT XII'
.wordWrap
wordWrap
on a string inserts line-breaks into the string, before it reaches the given max width
Syntax:
'string'.wordWrap(maxWidth) 'string'.wordWrap(maxWidth, lineBreakSequence)
Where:
maxWidth
is the desired maximum line length in characterslineBreakSequence
is the Line-break sequence to insert (defaults to "\n")
Examples:
"testing this line from here".wordWrap(10) // testing\nthis line\nfrom here
"Hello Beautiful World".wordWrap(16, "===") // Hello Beautiful===World
HumanDuration
HumanDuration
converts a duration into a human-readable format.
// Converting a duration into a human-readable format:
HumanDuration(3600) // "1 hour"
// Converting another duration:
HumanDuration(600) // "10 minutes"
// Converting a longer duration:
HumanDuration(86400) // "1 day"
HumanSize
HumanSize
converts a size in bytes into a human-readable format.
// Converting a size into a human-readable format:
HumanSize(1024) // "1 KiB"
// Converting another size:
HumanSize(1048576) // "1 MiB"
// Converting a larger size:
HumanSize(1073741824) // "1 GiB"
Semver
Semver
parses a version string and returns a map containing the major, minor, patch, prerelease, metadata, and original version.
// Parsing a semantic version:
Semver("1.2.3-alpha+meta") // a map with major: "1", minor: "2", patch: "3", prerelease: "alpha", metadata: "meta", original: "1.2.3-alpha+meta"
Semver("2.3.4-beta+meta2") // a map with major: "2", minor: "3", patch: "4", prerelease: "beta", metadata: "meta2", original: "2.3.4-beta+meta2"
// Parsing a simple semantic version:
Semver("3.4.5") // a map with major: "3", minor: "4", patch: "5", prerelease: "", metadata: "", original: "3.4.5"
SemverCompare
SemverCompare
compares two semantic version strings.
// Comparing two semantic versions:
SemverCompare("1.2.3", "1.2.4") // false
// Comparing two identical versions:
SemverCompare("2.3.4", "2.3.4") // true
// Comparing with a prerelease version:
SemverCompare("3.4.5", "3.4.5-alpha") // false
YAML
YAML
YAML
converts a YAML formatted string into a map. It provides an easy way to handle YAML data.
// Converting a simple YAML string to a map:
YAML("name: Alice\nage: 30") // a map with keys "name" and "age"
// Handling a YAML sequence:
YAML("numbers:\n- 1\n- 2\n- 3") // a map with a key "numbers" containing an array
// Nested YAML data conversion:
YAML("person:\n name: Bob\n age: 35") // a nested map
toYAML
toYAML
converts an object into a YAML formatted string.
toYAML({ name: "John" })
toYAML(["John", "Alice"])
YAMLArray
YAMLArray
converts a YAML formatted string representing a sequence into an array.
// Converting a YAML sequence to an array:
YAMLArray("- 1\n- 2\n- 3") // an array [1, 2, 3]
// Handling complex objects in a YAML sequence:
YAMLArray("- name: Alice\n- name: Bob") // an array of maps
// An empty YAML sequence:
YAMLArray("") // an empty array
TOML
TOML
TOML
converts a TOML formatted string into a map, making it easy to work with TOML data.
// Converting a TOML string to a map:
TOML('name = "Alice"\nage = 30') // a map with keys "name" and "age"
// Handling an array in TOML:
TOML("numbers = [1, 2, 3]") // a map with a key "numbers" containing an array
// Nested TOML data conversion:
TOML('[person]\nname = "Bob"\nage = 35') // a nested map
toTOML
toTOML
converts a map or an array into a TOML formatted string.
Syntax:
toTOML(data)
Where:
data
is the map or array to be converted.
Examples:
// Converting a map to a TOML string:
toTOML({ name: "Alice", age: 30 }) // "name = \"Alice\"\nage = 30"
// Handling an array (TOML arrays must be of the same type):
toTOML({ people: ["Alice", "Bob"] }) // "people = [\"Alice\", \"Bob\"]"
// An empty map:
toTOML({}) // an empty string
uuid
uuid.Nil
uuid.Nil
returns the nil UUID.
uuid.V1() != uuid.Nil()
uuid.V1
uuid.V1
returns a version 1 UUID.
uuid.V1() != uuid.Nil()
uuid.V4
uuid.V4
returns a version 4 UUID.
uuid.V4() != uuid.Nil()
uuid.IsValid
uuid.IsValid
checks if a string is a valid UUID.
uuid.IsValid("2a42e576-c308-4db9-8525-0513af307586")
uuid.Parse
uuid.Parse
parses a string into a UUID.
uuid.Parse("2a42e576-c308-4db9-8525-0513af307586")