Parser
Given an input of any type and a mode, validates that it respects the schema and applies transformations:
import { Parser } from 'dynamodb-toolbox/schema/actions/parse'
const validPokemon = pokemonSchema
.build(Parser)
.parse(pokemon)
The default mode is put
, but you can switch it to update
or key
if needed:
const validKey = pokemonSchema.build(Parser).parse(
key,
// Additional options
{ mode: 'key' }
)
In DynamoDB-Toolbox, parsing is done in 4 steps:
Note that:
- Additional fields are omitted, but inputs are not mutated
- The mode
defaults
andlinks
are applied by default - Transformations (i.e.
savedAs
andtransforms
) are applied by default
Here are step-by-step parsing examples:
☝️ Schema
const now = () => new Date().toISOString()
const pokemonSchema = schema({
// key attributes
pokemonClass: string()
.key()
.transform(prefix('POKEMON'))
.savedAs('partitionKey'),
pokemonId: string().key().savedAs('sortKey'),
// timestamps
created: string().default(now),
updated: string()
.required('always')
.putDefault(now)
.updateDefault(now),
// other attributes
name: string().optional(),
level: number().default(1)
}).and(prevSchema => ({
levelPlusOne: number().link<typeof prevSchema>(
({ level }) => level + 1
)
}))
🔎 'put'
mode
- Input
- Defaulted
- Linked
- Parsed
- Transformed
{
"pokemonClass": "pikachu",
"pokemonId": "123",
"name": "Pikachu"
}
{
"pokemonClass": "pikachu",
"pokemonId": "123",
+ "created": "2022-01-01T00:00:00.000Z",
+ "modified": "2022-01-01T00:00:00.000Z",
"name": "Pikachu",
+ "level": 1,
}
{
"pokemonClass": "pikachu",
"pokemonId": "123",
"created": "2022-01-01T00:00:00.000Z",
"modified": "2022-01-01T00:00:00.000Z",
"name": "Pikachu",
"level": 1,
+ "levelPlusOne": 2,
}
{
"pokemonClass": "pikachu",
"pokemonId": "123",
"created": "2022-01-01T00:00:00.000Z",
"modified": "2022-01-01T00:00:00.000Z",
"name": "Pikachu",
"level": 1,
"levelPlusOne": 2,
}
+ Item is valid ✅
{
- "pokemonClass": "pikachu",
+ "partitionKey": "POKEMON#pikachu",
- "pokemonId": "123",
+ "sortKey": "123",
"created": "2022-01-01T00:00:00.000Z",
"modified": "2022-01-01T00:00:00.000Z",
"name": "Pikachu",
"level": 1,
"levelPlusOne": 2,
}
🔎 'key'
mode
- Input
- Defaulted
- Linked
- Parsed
- Transformed
{
"pokemonClass": "pikachu",
"pokemonId": "123",
}
+ (Only key attributes are required)
{
"pokemonClass": "pikachu",
"pokemonId": "123",
}
+ No default to apply ✅
{
"pokemonClass": "pikachu",
"pokemonId": "123",
}
+ No link to apply ✅
{
"pokemonClass": "pikachu",
"pokemonId": "123",
}
+ Item is valid ✅
{
- "pokemonClass": "pikachu",
+ "partitionKey": "POKEMON#pikachu",
- "pokemonId": "123",
+ "sortKey": "123",
}
🔎 'update'
mode
- Input
- Defaulted
- Linked
- Parsed
- Transformed
{
"pokemonClass": "bulbasaur",
"pokemonId": "123",
"name": "PlantyDino",
}
{
"pokemonClass": "bulbasaur",
"pokemonId": "123",
+ "modified": "2022-01-01T00:00:00.000Z",
"name": "PlantyDino",
}
{
"pokemonClass": "bulbasaur",
"pokemonId": "123",
"modified": "2022-01-01T00:00:00.000Z",
"name": "PlantyDino",
}
+ No updateLink to apply ✅
{
"pokemonClass": "bulbasaur",
"pokemonId": "123",
"modified": "2022-01-01T00:00:00.000Z",
"name": "PlantyDino",
}
+ Item is valid ✅
{
- "pokemonClass": "bulbasaur",
+ "partitionKey": "POKEMON#bulbasaur",
- "pokemonId": "123",
+ "sortKey": "123",
"modified": "2022-01-01T00:00:00.000Z",
"name": "PlantyDino",
}
Methods
parse(...)
(input: unknown, options?: ParseValueOptions) => ParsingResults<SCHEMA>
Parses an input of any type:
const parsedValue = pokemonSchema.build(Parser).parse(input)
You can provide options as a second argument. Available options:
Option | Type | Default | Description |
---|---|---|---|
fill | boolean | true | Whether to complete the input (with defaults and links ) prior to validation or not. |
transform | boolean | true | Whether to transform the input (with savedAs and transform ) after validation or not. |
mode | put , key or update | put | The mode of the parsing: Impacts which default and link should be used, as well as requiredness during validation. |
parseExtension | (internal) | - | Dependency injection required to parse extended syntax ($get , $add etc.) when using the update mode (check example below). |
- Put
- Key
- Update
- Update (extended)
const pokemon = {
pokemonId: 'pikachu1',
name: 'Pikachu',
types: ['Electric'],
...
}
const validPokemon = pokemonSchema.build(Parser).parse(pokemon)
const validKey = pokemonSchema
.build(Parser)
.parse({ pokemonId: 'pikachu1' }, { mode: 'key' })
const validUpdate = pokemonSchema
.build(Parser)
.parse(
{ pokemonId: 'bulbasaur1', customName: 'PlantyDino' },
{ mode: 'update' }
)
import {
$add,
parseUpdateExtension
} from 'dynamodb-toolbox/entity/actions/update'
const validUpdate = pokemonSchema.build(Parser).parse(
// 👇 `$add` is an extension, so `parseExtension` is needed
{ pokemonId: 'pikachu1', customName: $add(1) },
{ mode: 'update', parseExtension: parseUpdateExtension }
)
You can use the TransformedValue
generic type (or ValidValue
if transform
is set to false
) to explicitly type an object as a parsing output object:
import type { TransformedValue } from 'dynamodb-toolbox/schema'
const parsedKey: TransformedValue<
typeof pokemonSchema,
// 👇 Optional options
{ mode: 'key' }
// ❌ Throws a type error
> = { invalid: 'input' }
reparse(...)
(input: InputValue<SCHEMA>, options?: ParseValueOptions) => ParsingResults<SCHEMA>
Similar to .parse
, but with the input correctly typed (taking the mode into account) instead of unknown
:
pokemonSchema
.build(Parser)
// ❌ Throws a type error
.reparse({ invalid: 'input' })
You can use the InputValue
generic type (or ValidValue
if fill
is set to false
) to explicitly type an object as a parsing input object:
import type { InputValue } from 'dynamodb-toolbox/schema'
const keyInput: InputValue<
typeof pokemonSchema,
// 👇 Optional options
{ mode: 'key' }
// ❌ Throws a type error
> = { invalid: 'input' }
start(...)
(input: unknown, options?: ParseValueOptions) => Generator<ParsingResults<SCHEMA>>
Similar to .parse
, but returns the underlying Generator to inspect the intermediate results of the parsing steps:
- Complete
- Transformed only
- Filled only
const parsingGenerator = pokemonSchema
.build(Parser)
.start(pokemon)
const defaultedPokemon = parsingGenerator.next().value
const linkedPokemon = parsingGenerator.next().value
const parsedPokemon = parsingGenerator.next().value
const transformedPokemon = parsingGenerator.next().value
const parsingGenerator = pokemonSchema
.build(Parser)
.start(pokemon, { fill: false })
// 👇 No `fill` step
const parsedPokemon = parsingGenerator.next().value
const transformedPokemon = parsingGenerator.next().value
const parsingGenerator = pokemonSchema
.build(Parser)
.start(pokemon, { transform: false })
const defaultedPokemon = parsingGenerator.next().value
const linkedPokemon = parsingGenerator.next().value
const parsedPokemon = parsingGenerator.next().value
// 👆 No `transform` step
validate(...)
(input: unknown, options?: ValidationOptions) => boolean
Runs only the parsing step of the parsing workflow on the provided input. Returns true
if the input is valid, catches any parsing error and returns false
otherwise:
const isValid = pokemonSchema.build(Parser).validate(input)
Note that .validate(...)
acts as a type guard:
if (pokemonSchema.build(Parser).validate(input)) {
// 🙌 Typed as `Pokemon`!
const { level, name } = input
...
}
Available options:
Option | Type | Default | Description |
---|---|---|---|
mode | put , key or update | put | The mode of the parsing: Impacts requiredness during validation. |
parseExtension | (internal) | - | Dependency injection required to parse extended syntax ($get , $add etc.) when using the update mode (check example below). |
- Put
- Key
- Update
- Update (extended)
const pokemon = {
pokemonId: 'pikachu1',
name: 'Pikachu',
types: ['Electric'],
...
}
const isValid = pokemonSchema.build(Parser).validate(pokemon)
const isValid = pokemonSchema
.build(Parser)
.validate({ pokemonId: 'pikachu1' }, { mode: 'key' })
const isValid = pokemonSchema
.build(Parser)
.validate(
{ pokemonId: 'bulbasaur1', customName: 'PlantyDino' },
{ mode: 'update' }
)
import {
$add,
parseUpdateExtension
} from 'dynamodb-toolbox/entity/actions/update'
const isValid = pokemonSchema.build(Parser).validate(
// 👇 `$add` is an extension, so `parseExtension` is needed
{ pokemonId: 'pikachu1', customName: $add(1) },
{ mode: 'update', parseExtension: parseUpdateExtension }
)