## Rules Syntax

A rule is a string that represents a boolean expression. It should be in the format `<variable> <operator> <value>`. Additionally, rules can be combined in the following format `<rule> <logical expression> <rule>`. Quotes inside the rules need to be escaped appropriately.

The following operators are supported:

### Logical Expressions

| Operator | Meaning | Example |
| --- | --- | --- |
| `!`, `not` | boolean "not" | `not(country = "US")` |
| `or`, `|`, `||` | boolean "or" | `country = "US" or age < 50` |
| `and`, `&`, `&&` | boolean "and" | `age > 20 and age < 50` |

### Relational Expressions

| Operator | Meaning | Example |
| --- | --- | --- |
| `=`, `==`, `is`, `eq` | equal to | `country = "US"` |
| `~=`, `=~` | loose equal to | `age ~= "20"` |
| `<`, `lt` | less than | `age < 50` |
| `>`, `gt` | greater than | `age > 20` |
| `<=` | less than or equal | `age <= 50` |
| `>=` | greater than or equal | `age >= 20` |
| `in` | present in list of items | `country in ["US", "FR"]` |
| `in` | present in range of values | `age in 20 to 50` |

### Quantifiers

| Operator | Meaning | Example |
| --- | --- | --- |
| `oneOf` | group of boolean "or"s | `oneOf(country = "US", age < 50)` |
| `allOf` | group of boolean "and"s | `allOf(age > 20, age < 50)` |
| `exists` | first-order "or" operator | `exists(c:countries, c == "US")` |
| `forAll` | first-order "and" operator | `forAll(p:purchases, p > 50)` |

### String Expressions

| Operator | Meaning | Example |
| --- | --- | --- |
| `contains` | string contains | `user-agent contains "Chrome"` |
| `startsWith` | string startsWith | `user-agent startsWith "Chrome"` |
| `endsWith` | string endsWith | `user-agent endsWith "81"` |
| `matches` | string matches regex | `user-agent matches /^(Chrome|Firefox)$/` |
| `containsWord` | string contains word | `category containsWord "summer"` |

info

The `containsWord` operator ensures to match "whole words" only taking into account word boundaries.

A word boundary is any character that is not `a-z`, `A-Z`, `0-9`, `_` including or excluding `diacritics`.

### Array Expressions

| Operator | Meaning | Example |
| --- | --- | --- |
| `containsAll` | array contains all elements | `ids containsAll [1, 2, 3]` |
| `containsAny` | array contains any element | `ids containsAny [1, 2, 3]` |
| `containsAllWords` | array contains all words | `categories containsAllWords ["Summer", "Sale"]` |
| `containsAnyWord` | array contains any word | `categories containsAnyWord ["Summer", "Sale"]` |

info

The `containsAllWords` and `containsAnyWord` operators ensure to match "whole words" only taking into account word boundaries.

### Geo Expressions

| Operator | Meaning | Example |
| --- | --- | --- |
| `near by` | value near coordinate | `userCoordinates near [41.176296, -8.596050] by 30 km` |

### Date Expressions

| Operator | Meaning | Example |
| --- | --- | --- |
| `after` | timestamp is after x days | `lastPurchase after 7 days ago` |
| `before` | timestamp is before x days | `lastPurchase before 3 days ago` |
| `between` | timestamp is between x and y days | `lastPurchase between 3 and 7 days ago` |

### Built-In Functions

| Function | Meaning | Example |
| --- | --- | --- |
| `isDefined` | returns true if a variable is defined | `isDefined(country)` |
| `normalize` | returns the string in lowercase without combining diacritics | `normalize(category)` |
| `toString` | attempts to convert a value to a string | `toString(status)` |
| `toNumber` | attempts to convert a value to a number | `toNumber(productId)` |
| `toBoolean` | attempts to convert a value to a boolean | `toBoolean(promotion)` |
| `map` | returns a new list with the elements updated based on the expression provided | `map(x:products, x["id"])` |
