dynamo-repo
is a TypeScript library designed to create type-safe, consistent and easier-to-use DynamoDB repositories. It simplifies the interaction with DynamoDB by providing a repository pattern with type safety and handling of reserved words, among other features.
Type Safety: Ensures that all your DynamoDB operations are type-safe.
Consistency: By overriding upsertItemFn()
, your entity will be automatically validated and updated (index keys etc.) for every insertion or update.
Reserved Words Handling: Automatically handles DynamoDB reserved words.
Ease of Use: Simplifies common DynamoDB operations with a repository pattern.
npm install dynamo-repo
All you need to do is to create a type to represent your table and a repo to handle it.
export class UserRepo extends Repo<TableType, "partitionKey", "optionalSortingKey"> {
constructor(ddbDocClient: DynamoDBDocument) {
super(ddbDocClient, "tableName", ["att1", "att2", "att3", ...], "partitionKey", "optionalSortingKey");
...
The first step is to create a type or interface representing your table entity. Make sure you extend the DBItemBase
type.
export interface User extends DBItemBase {
id: string;
country: string;
email: string;
firstName: string;
surname: string;
birthYear: number;
birthMonth: number;
/**
* Reserved words in DynamoDB will be automatically handled
*/
role: string;
/**
* Used as DynamoDB index property, it will always be properly set and updated
*/
birthYearMonth: number;
}
Create a repository class for your entity by extending the Repo
class. This repository class will define the structure and operations for your DynamoDB table.
Overriding upsertItemFn()
is optional.
export class UserRepo extends Repo<User, "id"> {
constructor(ddbDocClient: DynamoDBDocument) {
super(
ddbDocClient,
"user",
[
"id",
"firstName",
"surname",
"email",
"birthYear",
"birthMonth",
"country",
"role",
"birthYearMonth"
],
"id"
);
}
override upsertItemFn = (item: Partial<User>) => {
if (item.birthYear === undefined || item.birthMonth === undefined) {
throw new Error(`User with id ${item.id} doesn't have all required fields`);
}
item.birthYearMonth = item.birthYear * 100 + item.birthMonth;
return item;
};
}
const ddbDocClient = /* initiate your ddbDocClient instance with your credentials */
const userRepo = new UserRepo(ddbDocClient);
Add an item to the repository.
const user = {
id: "123",
country: "Australia",
email: "[email protected]",
firstName: "John",
surname: "Doe",
birthYear: 1990,
birthMonth: 3,
role: "user"
} as User;
await userRepo.addItem(user);
Find an item by its key.
const user = await userRepo.findItem({ id: "123" });
Update an item simply passing the item object.
await userRepo.updateItem(
{ id: "123" },
{
...user,
firstName: "Mike",
role: "admin"
}
);
Update an item using an expression.
await userRepo.updateExpressionItem(
{ id: "123" },
"firstName = :firstName, role = :role",
{
firstName: "Mike",
role: "admin"
},
user
);
Search for items using the keys or a secondary index.
const users = await userRepo.searchItems(
"country = :country AND birthYearMonth = :birthYearMonth",
{
country: "Australia",
birthYearMonth: 199003
},
"country-birth-index"
);
Both findItem()
and searchItems()
allow defining projectionExpression
so it can return partial entities
You can also delete an item, get all items at once or get items in batches with deleteItem()
, getAllItems()
and batchGetItems()
The library automatically handles DynamoDB reserved words, ensuring your operations are safe and compliant; no need to ever concatenate "#", no need to avoid or modify them.
Example test cases demonstrate the usage of the library.
In order to run the test cases locally you will need a local dynamodb instance running. It's simple and everything you need is described here: https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.DownloadingAndRunning.html
This project is licensed under the ISC License.