Just as a sentence in English comprises words, phrases, and clauses, a CQL expression is composed of different parts that come together to form a complete expression.
In this section, we discuss the structure of expressions, explain key concepts such as precedence, and provide examples to demonstrate how these elements work together.
CQL expressions follow a well-defined structure for writing valid queries. Similar to how individual words convey little meaning on their own, you must combine the various parts of an expression coherently to form a valid expression.
An expression can be as simple as a single value, like a literal or a variable, or even a combination of multiple sub-expressions.
Let's examine the following expression to see how it is structured:
user's score is greater than 90
This expression is composed of the following parts:
- user is a variable that refers to the current user.
- score is an attribute of the user variable.
- user's score is a property access expression that returns the user's score.
- is greater than is a test that checks whether the left-hand side is greater than the right-hand side.
- 90 is a literal value representing the score threshold.
As you can see, each element has a specific meaning and purpose within the expression. When combined, they form a complete expression that can be evaluated to produce a result.
Below is a brief description of the main parts that make up an expression:
|Literals||Values directly written into the expression, such as true, "Croct" or [1, 2, 3].|
|Variables||Names that refer to values defined in the context, such as user or cart.|
|Accessors||Expressions that extract values from data structures, such as user's score or collection.|
|Macros||Natural language functions that take one or more parameters and return a value, such as sum of [1, 2, 3].|
|Modifiers||Natural language functions that convert one value to another, such as "Croct" in upper case.|
|Tests||Natural language conditions that test if value satisfies a predicate, such as user's age is greater than 18.|
|Quantifiers||Natural language conditions that test if a collection satisfies a predicate, such as no items in cart satisfies item's name matches "smartphone".|
|Operations||Operations on one or more values, such as 1 plus 2 or 1 + 2.|
These are some of the most basic expressions you will frequently use when writing CQL queries.
You can use parentheses to group sub-expressions together and change the order in which they are evaluated:
(1 + 2) * 3 // 9
In some cases, you need parentheses to disambiguate expressions. For example, when using quantifiers as part of a logical expression, you must use parentheses to explicitly define the scope of the quantifier predicate:
(no item in cart satisfies item's name matches "smartphone") and user is returning
Without parentheses, the above expression would be evaluated as follows:
no item in cart satisfies (item's name matches "smartphone" and user is returning)
As a result, the expression becomes illogical. It evaluates whether the user is a returning customer for each item added to the cart, despite these conditions being unrelated.
Variables are names that refer to values you define or values provided by the context. To use a variable, you simply type its name, such as user, cart or now.
Depending on the context in which your query is evaluated, you may have access to different variables and information. See the context reference for a complete list of variables available in each context.
If you remember your math classes, you might recall that some operations take precedence over others. For example, multiplication comes before addition in arithmetic expressions.
To determine the order of operations, we follow the rules of precedence and associativity. These concepts are explained in more detail below.
In CQL, as in mathematics, precedence dictates the order in which sub-expressions are evaluated. High-precedence operations, such as parentheses or multiplication, are performed before lower-precedence operations, like addition or logical operators.
For example, consider the following expression:
3 + 4 * 5
According to the precedence rules, the multiplication operation has higher precedence than the addition operation. Thus, the above expression is equivalent to 3 + (4 * 5), which equals 23.
Now, take a look at the following expression:
user's score is greater than 90 and user's plan is "premium"
In this case, since the logical operator and has lower precedence than the test operations, the above expression is evaluated as follows:
(user's score is greater than 90) and (user's plan is "premium")
To group sub-expressions together and override the default precedence, you can use parentheses. For example, the following expression evaluates the addition operation first:
(3 + 4) * 5
The table below shows the precedence of the different expressions in CQL, from highest to lowest:
|1||Parenthesized expressions||(1 + 2) * 3|
|2||Unary operators||not - %|
|3||Property access||user.score user['score']|
|5||Possessive expressions||property score of user|
|6||Ownership expressions||user's score|
|7||Duration expressions||1 day 2 weeks, 3 minutes|
|8||Macros||sum of average of|
|9||Modifiers||in upper case rounded|
|10||Exponentiation||** to power of|
|11||Multiplicative expressions||* times / mod|
|12||Additive expressions||+ plus - minus|
|15||Fallback||?? or else, otherwise|
|16||Order comparison||< > <= >=|
|17||Equality comparison||== !=|
|18||Test predicates||is matches contains|
|19||Functions||(x y) => x + y|
|20||Quantifiers||no every some at least at most|
|22||Logical conjunction||&& and|
|23||Logical disjunction|||| or|
Associativity is the tiebreaker determining the order in which expressions with the same precedence are evaluated.
Expressions can be left-associative, meaning they are evaluated from left to right, or right-associative, meaning they are evaluated from right to left. Non-associative expressions are those that cannot be chained together.
For example, consider the following expression:
1 + 2 - 3
Since the addition and subtraction operations have the same precedence, the associativity determines the order of evaluation. As both operations are left-associative, the above expression is equivalent to (1 + 2) - 3, which equals 0.
Now look at this other example:
3 ** 2 ** 1
The exponentiation operation, on the other hand, is right-associative. That is, the above expression is semantically equivalent to 3 ** (2 ** 1), which results in 9.
The following table shows the associativity of expressions in CQL:
|Conditionals||Right||a ? true : c ? false : true|
|Unary operators||Right||not not true|
|Fallback||Left||a ?? b ?? c|
|Concatenation||Left||a & b & c|
|Equality comparison||Left||true == true == true|
|Exponentiation||Right||2 ** 3 ** 4|
|Multiplicative expressions||Left||2 * 3 / 4 mod 5|
|Additive expressions||Left||2 + 3 - 4 + 5|
|Logical conjunction||Left||true and true and true|
|Logical disjunction||Left||true or true or true|