- Fixed MacOS release and moved UCL site into repository Reviewed-on: #3 Co-authored-by: Leon Mika <lmika@lmika.org> Co-committed-by: Leon Mika <lmika@lmika.org>
		
			
				
	
	
		
			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.
 |