Entity
Entities represent a category of items in your Table.
An entity must belong to a Table, but a Table can contain items from several entities. DynamoDB-Toolbox is designed with Single Tables in mind, but works just as well with multiple tables and still makes your life much easier (e.g. for batch operations or transactions):
import { Entity } from 'dynamodb-toolbox/entity';
import { schema } from 'dynamodb-toolbox/schema';
const PokemonEntity = new Entity({
name: 'POKEMON',
table: PokeTable,
schema: schema(...)
});
Constructor
The Entity constructor takes a single parameter of type object and accepts the following properties:
name
(required)
A string that uniquely identifies your entity:
const PokemonEntity = new Entity({
name: 'POKEMON',
...
})
DynamoDB-Toolbox automatically tags your items with their respective entity names (see Internal Attributes).
☝️ The consequence is that name cannot be updated once your Entity has its first items* (at least not without a data migration first), so choose wisely!
schema
(required)
The schema of the Entity. See the Schema Section for more details on how to define schemas.
table
(required)
The Table of the Entity.
DynamoDB-Toolbox must check that an entity schema matches its Table primary key somehow. In simple cases, both schemas can simply fit:
- Direct match
- Renaming
- Prefixing
- Linked
const PokeTable = new Table({
partitionKey: { name: 'pk', type: 'string' },
sortKey: { name: 'sk', type: 'number' },
...
})
const PokemonEntity = new Entity({
table: PokeTable,
schema: schema({
pk: string().key(),
sk: number().key(),
...
}),
})
const PokeTable = new Table({
partitionKey: { name: 'pk', type: 'string' },
sortKey: { name: 'sk', type: 'number' },
...
})
const PokemonEntity = new Entity({
table: PokeTable,
schema: schema({
// 👇 renaming works
pokemonId: string().savedAs('pk').key(),
level: number().savedAs('sk').key(),
...
}),
})
import { prefix } from 'dynamodb-toolbox/transformers/prefix'
const PokeTable = new Table({
partitionKey: { name: 'pk', type: 'string' },
sortKey: { name: 'sk', type: 'number' },
...
})
const PokemonEntity = new Entity({
table: PokeTable,
schema: schema({
// 👇 saved as `POKEMON#${pokemonId}`
pokemonId: string()
.transform(prefix('POKEMON'))
.savedAs('pk')
.key(),
level: number().savedAs('sk').key(),
...
})
})
👉 See the transformers section for more details on transformers.
const PokeTable = new Table({
partitionKey: { name: 'pk', type: 'string' },
...
})
const PokemonEntity = new Entity({
table: PokeTable,
schema: schema({
// 👇 linked attributes should also be tagged as `.key()`
pokemonId: string().key(),
trainerId: string().key(),
...
}).and(prevSchema => ({
pk: string()
.key()
.link<typeof prevSchema>(
({ trainerId, pokemonId }) =>
`${trainerId}#${pokemonId}`
)
}))
})
computeKey
(potentially required, depending on schema)
...but using schemas that don't fit is OK.
In this case, the Entity constructor requires a computeKey function to derive the primary key from the Entity key attributes.
This can be useful for more complex cases like mapping several attributes to the same key:
- Renaming
- Composing
const PokemonEntity = new Entity({
table: PokeTable,
schema: schema({
// 👇 linked attributes should also be tagged as `.key()`
pokemonId: string().key(),
level: number().key(),
...
}),
// 🙌 Types are correctly inferred!
computeKey: ({ pokemonId, level }) => ({
pk: pokemonId,
sk: level
})
})
const PokemonEntity = new Entity({
table: PokeTable,
schema: schema({
// 👇 linked attributes should also be tagged as `.key()`
specifiers: list(string()).key(),
sk: number().key(),
...
}),
computeKey: ({ specifiers, sk }) => ({
pk: specifiers.join('#'),
sk
})
})
entityAttributeName
A string to customize the name of the internal entity attribute (see Internal Attributes).
timestamps
A boolean or object to customize the internal created and modified attributes (see Internal Attributes).