Skip to main content

ConditionParser

Builds a Condition Expression that can be used to condition write operations, or filter the results of a Query or a Scan:

import { ConditionParser } from 'dynamodb-toolbox/entity/actions/parseCondition'

// 👇 To be used in DynamoDB commands
const {
ConditionExpression,
ExpressionAttributeNames,
ExpressionAttributeValues
} = PokemonEntity.build(ConditionParser)
.parse({
// Pokemons with levels ≥ 50
attr: 'level',
gte: 50
})
.toCommandOptions()

Methods

parse(...)

(condition: Condition<ENTITY>) => ConditionParser

Parses a condition. Throws an invalidCondition error if the condition is invalid:

PokemonEntity.build(ConditionParser).parse({
attr: 'level',
gte: 50
})

Note that the parse method should only be used once per instance (for now). See Building Conditions for more details on how to write conditions.

toCommandOptions()

() => CommandOptions

Collapses the ConditionParser state to a set of options that can be used in a DynamoDB command:

const {
ConditionExpression,
ExpressionAttributeNames,
ExpressionAttributeValues
} = PokemonEntity.build(ConditionParser)
.parse({ attr: 'level', gte: 50 })
.toCommandOptions()

setId(...)

(id: string) => ConditionParser

Adds a prefix to expression attribute keys. Useful to avoid conflicts when using several expressions in a single command:

PokemonEntity.build(ConditionParser)
.parse({ attr: 'level', gte: 50 })
.toCommandOptions()
// => {
// ConditionExpression: '#c_1 >= :c_1',
// ExpressionAttributeNames: { '#c_1': 'sk' },
// ExpressionAttributeValues: { ':c_1': 50 }
// }

PokemonEntity.build(ConditionParser)
.setId('0')
.parse({ attr: 'level', gte: 50 })
.toCommandOptions()
// => {
// ConditionExpression: '#c0_1 >= :c0_1',
// ExpressionAttributeNames: { '#c0_1': 'sk' },
// ExpressionAttributeValues: { ':c0_1': 50 }
// }

Building Conditions

The condition syntax from DynamoDB-Toolbox follows the DynamoDB specifications, while making it type-safe and much simpler:

import type { Condition } from 'dynamodb-toolbox/entity/actions/parseCondition'

const condition: Condition<typeof PokemonEntity> = {
attr: 'level',
gte: 50
}

Each condition contains an attribute path and an operator.

info

You can only specify one operator per condition. To combine multiple conditions, use Logical Combinations.

Paths

attr contains the path of the attribute value to check (potentially deep). You can also specify size instead of attr if you want to check the size of an attribute (in which case the attribute type becomes number):

Examples
const nameCheck: Condition<typeof PokemonEntity> = {
attr: 'name',
eq: 'Pikachu'
}

Value conditions

Value conditions evaluate against the value of an attribute:

KeyValueAttribute TypeDescription
eqscalarscalar*Checks that the attribute is equal to the specified value
nescalarscalarChecks that the attribute is different than the specified value
inscalar[]scalarChecks that the attribute is in a finite range of values (100 values max)
containsscalarstring, sets or listsChecks that the attribute is one of the following:
  • A string that contains a particular substring
  • A set that contains a particular element
  • A list that contains a particular element
existsboolean-Checks that the attribute is present in the item (or not)
typestring-Checks that the attribute is of a particular data type:
  • "NULL" = null
  • "BOOL" = boolean
  • "N" = number
  • "S" = string
  • "B" = binary
  • "NS|SS|BS" = set of number, string or binary
  • "L" = list
  • "M" = map
*Scalar = boolean, number, string or binary
Examples
const nameCheck: Condition<typeof PokemonEntity> = {
attr: 'name',
eq: 'Pikachu'
}

Range conditions

Range conditions evaluate whether an attribute of sortable type (i.e. number, string or binary) is within a certain range.

info

Apart from the eq value condition, only range conditions are accepted in Query ranges.

KeyValueAttribute TypeDescription
gtesortablesortableChecks that the attribute is greater than or equal to the specified value
gtsortable*sortableChecks that the attribute is strictly greater than the specified value
ltesortablesortableChecks that the attribute is lower than or equal to the specified value
ltsortablesortableChecks that the attribute is strictly lower than the specified value
between[sortable, sortable]sortableChecks that the attribute is between two values (inclusive)
beginsWith[string, string]stringChecks that the string attribute specified begins with a particular substring
* Sortable = number, string or binary
Examples
const levelGte50: Condition<typeof PokemonEntity> = {
attr: 'level',
gte: 50
}
caution

Again, only one operator can be applied per condition: Using gte and lte simultaneously does not result in a between.

Combining Conditions

You can combine conditions logically with the or, and and not operators:

NameValueAttribute TypeDescription
orCondition<ENTITY>[]-Checks that one of the child conditions evaluate to true
andCondition<ENTITY>[]-Checks that all of the child conditions evaluate to true
notCondition<ENTITY>-Negates the evaluation of the condition
Examples
const lvlGte50OrElec: Condition<typeof PokemonEntity> = {
or: [
{ attr: 'level', gte: 50 },
{ attr: 'pokeType', eq: 'electric' }
]
}

Comparing Attributes

Instead of directly providing values, you can compare attributes to other attributes by providing objects with an attr key to the operators:

const atMaxLevel: Condition<typeof PokemonEntity> = {
attr: 'level',
eq: { attr: 'maxLevel' }
}
caution

Note that the compared attribute path is type-checked and validated, but whether its type CAN be compared is not for the moment, so be extra-careful:

const invalidCondition: Condition<typeof PokemonEntity> = {
attr: 'level',
// ❌ Reaches DynamoDB and fail
gte: { attr: 'name' }
}