252 lines
7.5 KiB
Markdown
252 lines
7.5 KiB
Markdown
|
|
# Query Expression
|
||
|
|
|
||
|
|
Query expressions are used to select rows of a table. When executed as a query (i.e. by pressing <kbd>?</kbd>),
|
||
|
|
they will be translated into query or table scans that will run over the DynamoDB table in AWS.
|
||
|
|
They work similar to the "where" clause in PartiQL except that they only require Query and Scan permission
|
||
|
|
on the AWS table and do not require "select" clauses.
|
||
|
|
Such expressions can also be used in other areas of Dynamo-Browse, such as populating the value of new columns.
|
||
|
|
|
||
|
|
## Names And Values
|
||
|
|
|
||
|
|
A query expressions support the following literals:
|
||
|
|
|
||
|
|
- Strings: `"Hello"`
|
||
|
|
- Integers: `123`
|
||
|
|
- Boolean: `true` or `false`
|
||
|
|
|
||
|
|
Field names are represented as regular identifiers, such as `pk` or `address`.
|
||
|
|
|
||
|
|
## Equality
|
||
|
|
|
||
|
|
To select rows with a field that equals a given value, use the `=` operator:
|
||
|
|
|
||
|
|
```
|
||
|
|
pk = "something"
|
||
|
|
```
|
||
|
|
|
||
|
|
Either operand will can be an identifier, placeholder, or value that resolves to any type.
|
||
|
|
The result will be true if both the LHS and RHS equal the same type and value. If the types differ or
|
||
|
|
the values differ, the result will be false. The field types can be different, but will always produce false.
|
||
|
|
|
||
|
|
The compliment is the `!=` operator:
|
||
|
|
|
||
|
|
```
|
||
|
|
pk != "not this"
|
||
|
|
```
|
||
|
|
|
||
|
|
## Numerical Comparison
|
||
|
|
|
||
|
|
The operands `<`, `<=`, `>`, `>=` can be used to compare numerical fields and values:
|
||
|
|
|
||
|
|
```
|
||
|
|
three < 5 // true
|
||
|
|
three <= 3 // true
|
||
|
|
three > 12 // false
|
||
|
|
three >= 1 // true
|
||
|
|
```
|
||
|
|
|
||
|
|
To verify that a number exists within a range, use the `between` operand:
|
||
|
|
|
||
|
|
```
|
||
|
|
three between 1 and 5 // true
|
||
|
|
```
|
||
|
|
|
||
|
|
## Prefix Operator
|
||
|
|
|
||
|
|
To select rows with a field that starts with a given substring, use the `^=` operator:
|
||
|
|
|
||
|
|
```
|
||
|
|
pk ^= "some"
|
||
|
|
```
|
||
|
|
|
||
|
|
This is equivalent to using the [begins_with](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Expressions.OperatorsAndFunctions.html) function in AWS query expressions.
|
||
|
|
|
||
|
|
## Logical Operators
|
||
|
|
|
||
|
|
The logical operators `and`, `or` and `not` can be used to express conjunctions, disjunctions and logical negation
|
||
|
|
between multiple expressions:
|
||
|
|
|
||
|
|
```
|
||
|
|
pk = "this" and sk = "that"
|
||
|
|
pk != "that" and count > 123
|
||
|
|
not count = 21
|
||
|
|
```
|
||
|
|
|
||
|
|
The order of precedence of these operators, from lowest to highest, is `or`, `and`, then `not`. This differs
|
||
|
|
from AWS, in which all operators have the same precedence. For example, the query:
|
||
|
|
|
||
|
|
```
|
||
|
|
pk="this" or pk="that" and sk="foo"
|
||
|
|
```
|
||
|
|
|
||
|
|
is equivalent to:
|
||
|
|
|
||
|
|
```
|
||
|
|
pk="this" or (pk="that" and sk="foo")
|
||
|
|
```
|
||
|
|
|
||
|
|
The order can be overridden using brackets:
|
||
|
|
|
||
|
|
```
|
||
|
|
(pk="this" or pk="that") and sk="foo"
|
||
|
|
```
|
||
|
|
{{< hint info >}}
|
||
|
|
If a query expression is of the form `pk = <val>` or `pk = <val> and sk <op> <val>`,
|
||
|
|
where:
|
||
|
|
|
||
|
|
- _pk_ and _sk_ are the partition and sort keys of the base table or a GSI,
|
||
|
|
- _val_ resolves to a constant value, and,
|
||
|
|
- _op_ is either `=`, `^=`, `<`, `<=`, `>`, `>=`, or `between`
|
||
|
|
|
||
|
|
the expression will be executed as a Query call. Unlike expressions on the AWS Query API method itself,
|
||
|
|
the order of the `pk` and `sk` subexpressions can be swapped.
|
||
|
|
|
||
|
|
Other expressions are supported but they will be executed as a table Scan.
|
||
|
|
{{< /hint >}}
|
||
|
|
|
||
|
|
## The `in` Operator
|
||
|
|
|
||
|
|
The `in` operator can be used to determine if a value exists in a collection:
|
||
|
|
|
||
|
|
```
|
||
|
|
three in (1, 2, 3, 4, 5)
|
||
|
|
|
||
|
|
name in ("Tom", "Dick", "Harry")
|
||
|
|
```
|
||
|
|
|
||
|
|
The result will be a boolean, which will be true if the value of the LHS equals any of the items within the RHS.
|
||
|
|
|
||
|
|
The collection can be one or more fixed set of values within parenthesis separated by commas. A single
|
||
|
|
value present within parenthesis is equivalent to the equality test:
|
||
|
|
|
||
|
|
```
|
||
|
|
three in (3) // equivalent to: three = 3
|
||
|
|
```
|
||
|
|
|
||
|
|
The right hand side can also be a subexpression without parenthesis that will resolve to either a string,
|
||
|
|
list or map. The operand will behave differently based on the RHS type:
|
||
|
|
|
||
|
|
- If the RHS is a string, the result will be true if the LHS is a substring of the RHS (equivalent to the `contains` AWS conditional expressions function)
|
||
|
|
- If the RHS is a list, the result will be true if the LHS equals any of the items of the list
|
||
|
|
- If the RHS is a map, the result will be true if the LHS appears as a key of the map
|
||
|
|
|
||
|
|
The compliment operand is `not in`:
|
||
|
|
|
||
|
|
```
|
||
|
|
three not in (6, 7, 8, 9)
|
||
|
|
```
|
||
|
|
|
||
|
|
## The `is` Operator
|
||
|
|
|
||
|
|
The `is` operator can be used to assert the value type. The RHS operand is a string which is to represent an AWS
|
||
|
|
DynamoDB item attribute type, for example `S` for strings, `N` for numbers, etc.
|
||
|
|
|
||
|
|
```
|
||
|
|
"hello" is "S" // true
|
||
|
|
123 is "N" // true
|
||
|
|
"hello" is "N" // false
|
||
|
|
```
|
||
|
|
|
||
|
|
This is equivalent to the `attribute_type` AWS conditional expressions function.
|
||
|
|
|
||
|
|
The special value `any` can be used to check that a field is set, regardless of type:
|
||
|
|
|
||
|
|
```
|
||
|
|
pk is "any" // true
|
||
|
|
```
|
||
|
|
|
||
|
|
This is equivalent to the `attribute_exists` AWS conditional expressions function.
|
||
|
|
|
||
|
|
The compliment operand is `not is`. Using it with the "any" special value (`not is "any"`) is equivalent to the
|
||
|
|
`attribute_not_exists` AWS conditional expressions function.
|
||
|
|
|
||
|
|
## The `using` Options
|
||
|
|
|
||
|
|
A query that is to be executed on the actual table in AWS will go though a short planning phase to determine
|
||
|
|
whether it's possible to invoke the expression as a `Query` call. If the attributes map to partition and sort keys
|
||
|
|
of either the main table, or exactly one GSI associated with the table, the expression will be executed as a Query
|
||
|
|
over the table or the GSI found with those attributes.
|
||
|
|
|
||
|
|
In cases where multiple GSI candidates exist on the base table, the query will fail with the following error:
|
||
|
|
|
||
|
|
```
|
||
|
|
multiple plans with index found. Specify index or scan with 'using' clause
|
||
|
|
```
|
||
|
|
|
||
|
|
In these cases, the index will need to be specified with the `using` keyword with the `index` option:
|
||
|
|
|
||
|
|
```
|
||
|
|
address="something" using index("specific-gsi-name")
|
||
|
|
```
|
||
|
|
|
||
|
|
The `using` keyword can also be used to force the expression to run as a table scan,
|
||
|
|
even if the query can be invoked using a Query call over the base table or GSI:
|
||
|
|
|
||
|
|
```
|
||
|
|
address="something" using scan
|
||
|
|
```
|
||
|
|
|
||
|
|
## Builtin Functions
|
||
|
|
|
||
|
|
Query expressions support a number of builtin functions.
|
||
|
|
|
||
|
|
### The `marked` function
|
||
|
|
|
||
|
|
```
|
||
|
|
marked(fieldname)
|
||
|
|
```
|
||
|
|
|
||
|
|
The `marked` function will return a list of field values of all marked rows of the current result set. The
|
||
|
|
items will appear in the list as they appear in the result set. The _fieldname_ currently only supports top-level fields.
|
||
|
|
If no fields are marked, the empty list is returned.
|
||
|
|
|
||
|
|
```
|
||
|
|
marked("city")
|
||
|
|
```
|
||
|
|
|
||
|
|
### The `range` function
|
||
|
|
|
||
|
|
```
|
||
|
|
range(from, to)
|
||
|
|
```
|
||
|
|
|
||
|
|
The `range` function will return a list of integers between _from_ and _to_ inclusive. Non integers will be truncated
|
||
|
|
to integers, and the step is always be 1.
|
||
|
|
|
||
|
|
```
|
||
|
|
range(2, 5) // [2, 3, 4, 5]
|
||
|
|
three in range(2, 5) // true
|
||
|
|
```
|
||
|
|
|
||
|
|
### The `size` function
|
||
|
|
|
||
|
|
```
|
||
|
|
size(v)
|
||
|
|
```
|
||
|
|
|
||
|
|
The `size` function will return the number of items of a list or map, or the length of a string.
|
||
|
|
|
||
|
|
{{< hint info >}}
|
||
|
|
The `size` function is equivalent to the `size` AWS conditional expressions function, and as such is the
|
||
|
|
only function that is included as is in the generated Query or Scan expression. All other functions are evaluated
|
||
|
|
prior to making the Query or Scan AWS call.
|
||
|
|
{{</hint>}}
|
||
|
|
|
||
|
|
|
||
|
|
## Placeholders
|
||
|
|
|
||
|
|
In some circumstances, such as the [session.query](/docs/reference/script-api/#session-query) method, it's possible to use a placeholder as a field or value. To expand a placeholder to an identifier, use the `:` prefix. To expanded the placeholder as a value, use the `$` prefix. For example, the expression `:key = $value` in the following script:
|
||
|
|
|
||
|
|
```
|
||
|
|
out := session.query(":key = $value", {
|
||
|
|
table: "some-table",
|
||
|
|
args: {
|
||
|
|
key: "pk",
|
||
|
|
value: "value"
|
||
|
|
}
|
||
|
|
}
|
||
|
|
```
|
||
|
|
|
||
|
|
Is equivalent to the query `pk = "hello"`, as the placeholder `:key` is expanded to an identifier and `$value` is expanded
|
||
|
|
to a value, in this case a string.
|