Skip to main content

Schema

A Schema is a list of attributes that describe the items of an Entity:

import { schema } from 'dynamodb-toolbox/schema'
import { string } from 'dynamodb-toolbox/attributes/string'
import { number } from 'dynamodb-toolbox/attributes/number'

const pokemonSchema = schema({
pokemonId: string().key(),
level: number().default(1),
pokeType: string()
.enum('fire', 'water', 'grass')
.optional()
})

const PokemonEntity = new Entity({
...,
schema: pokemonSchema
})

Schemas always start with a root object, listing attributes by their names.

Attribute Types

Schema attributes can be imported by their dedicated exports, or through the attribute or attr shorthands. For instance, those declarations output the same attribute:

// 👇 More tree-shakable
import { string } from 'dynamodb-toolbox/attributes/string'

const nameAttr = string()

// 👇 Less tree-shakable, but single import
import {
attribute,
attr
} from 'dynamodb-toolbox/attributes'

const nameAttr = attribute.string()
const nameAttr = attr.string()

Available attribute types are:

  • any - Contains any value
  • null - Contains null
  • boolean - Contains booleans
  • number: Contains numbers
  • string: Contains strings
  • binary: Contains binaries
  • set: Contains sets of either number, string, or binary elements
  • list: Contains lists of elements of any type
  • map: Contains maps, i.e. a finite list of key-value pairs, values being child attributes of any type
  • record: Contains a different kind of maps - Records differ from maps as they have a non-explicit (potentially infinite) range of keys, but with a single value type
  • anyOf: Contains a finite union of possible attributes
info

DynamoDB-Toolbox attribute types closely mirror the capabilities of DynamoDB. See the DynamoDB documentation for more details.

Note that some attribute types can be defined with other attributes. For instance, here's a list of string:

const nameAttr = string()
const namesAttr = list(nameAttr)
info

Schemas are a standalone feature of DynamoDB-Toolbox (you can use them separately to parse and format data for instance) and might even be moved into a separate library one day.

Fine-Tuning Attributes

You can update attribute properties by using dedicated methods or by providing option objects.

The former provides a slick devX with autocomplete and shorthands, while the latter theoretically requires less compute time and memory usage (although it should be negligible):

// Using methods
const pokemonName = string().required('always')
// Using options
const pokemonName = string({ required: 'always' })
info

Attribute methods do not mute the origin attribute, but return a new attribute (hence the impact in memory usage).

The output of an attribute method is also an attribute, so you can chain methods:

const pokeTypeAttr = string()
.required('always')
.enum('fire', 'water', 'grass')
.savedAs('t')

See each attribute type documentation (for instance the string page) to learn about available options.

Finally, note that once schema is applied, attributes cannot be modified anymore (check the Warm vs Frozen section for more details):

const pokemonSchema = schema({
name: string().required('always'),
...
})

pokemonSchema.attributes.name.required
// => 'always'

pokemonSchema.attributes.name.required('atLeastOnce')
// => ❌ `required` is not a function