Record
Describes a different kind of map attribute. Records differ from maps
as they can have a non-explicit (and potentially infinite) range of keys, but have a single value type:
import { record } from 'dynamodb-toolbox/schema/record'
const pokeTypeSchema = string().enum('fire', ...)
const weaknessesSchema = record(pokeTypeSchema, number())
type Weaknesses = FormattedValue<typeof weaknessesSchema>
// => Record<PokeType, number>
Record elements can have any type. However, they must respect some constraints:
- They cannot be
optional
or always required - They cannot be
hidden
orkey
(tagging therecord
itself askey
is enough) - They cannot have
default
orlinks
// ❌ Raises a type AND a run-time error
const strRecord = record(string(), string().optional())
const strRecord = record(string(), string().hidden())
const strRecord = record(string(), string().key())
const strRecord = record(string(), string().default('foo'))
Record keys share the same constraints and must be of type string
.
Properties
.required()
string | undefined
Tags schema values as required (within items
or maps
). Possible values are:
'atLeastOnce' (default)
: Required (starting value)'always'
: Always required (including updates)'never'
: Optional
// Equivalent
const weaknessesSchema = record(
string().enum('fire', ...),
number()
)
const weaknessesSchema = record(
string().enum('fire', ...),
number()
).required()
const weaknessesSchema = record(
string().enum('fire', ...),
number(),
// Options can be provided as 3rd argument
{ required: 'atLeastOnce' }
)
// shorthand for `.required('never')`
const weaknessesSchema = record(...).optional()
const weaknessesSchema = record(..., { required: 'never' })
.hidden()
boolean | undefined
Omits schema values during formatting:
const weaknessesSchema = record(
string().enum('fire', ...),
number()
).hidden()
const weaknessesSchema = record(..., { hidden: true })
.key()
boolean | undefined
Tags schema values as a primary key attribute or linked to a primary key attribute:
// Note: The method also sets the `required` property to 'always'
// (it is often the case in practice, you can still use `.optional()` if needed)
const idsSchema = record(string(), string()).key()
const idsSchema = record(..., {
key: true,
required: 'always'
})
.savedAs(...)
string
Renames schema values during the transformation step (within items
or maps
):
const weaknessesSchema = record(
string().enum('fire', ...),
number()
).savedAs('w')
const weaknessesSchema = record(..., { savedAs: 'w' })
.partial()
boolean | undefined
Turns the record into a partial record:
const weaknessesSchema = record(
string().enum('fire', ...),
number()
).partial()
const weaknessesSchema = record(..., { partial: true })
type Weaknesses = FormattedValue<typeof weaknessesSchema>
// => Partial<Record<PokeType, number>>
.default(...)
ValueOrGetter<ATTRIBUTES>
Specifies default values. See Defaults and Links for more details:
- Put/Update
- Key
const now = () => new Date().toISOString()
const timestampsSchema = record(string(), string())
.default(() => ({ created: now() }))
.updateDefault(() => ({ updated: now() }))
// 👇 Similar to
const timestampsSchema = record(...)
.putDefault(() => ({ created: now() }))
.updateDefault(() => ({ updated: now() }))
// 👇 ...or
const timestampsSchema = record(..., {
putDefault: () => ({ created: now() }),
updateDefault: () => ({ updated: now() })
})
const idsSchema = record(string(), string())
.key()
.default({ abc: '123' })
// 👇 Similar to
const idsSchema = record(...)
.key()
.keyDefault({ abc: '123' })
// 👇 ...or
const idsSchema = record(..., {
key: true,
required: 'always',
keyDefault: { abc: '123' }
})
.link<Schema>(...)
Link<SCHEMA, ATTRIBUTES>
Similar to .default(...)
but allows deriving the default value from other attributes. See Defaults and Links for more details:
const pokemonSchema = item({
name: string()
}).and(prevSchema => ({
parsedName: record(string(), string()).link<
typeof prevSchema
>(
// 🙌 Correctly typed!
({ name }) => {
const [firstName, lastName] = name.split(' ')
return { firstName, lastName }
}
)
}))
.validate(...)
Validator<ATTRIBUTES>
Adds custom validation. See Custom Validation for more details:
const nonEmptyRecordSchema = record(
string(),
string()
).validate(input => Object.keys(input).length > 0)
// 👇 Similar to
const nonEmptyRecordSchema = record(
string(),
string()
).putValidate(input => Object.keys(input).length > 0)
// 👇 ...or
const nonEmptyRecordSchema = record(string(), string(), {
putValidator: input => Object.keys(input).length > 0
})