Introducing DDB-Table
DDB-Table is a library crafted for those looking to work with DynamoDB documents with ease and precision. By combining the strengths of TypeScript and AWS DocumentClient, it elevates the way developers can query and model data within DynamoDB, ensuring that data structure validation happens right in the code, providing a smooth development experience free from runtime errors.
Why DDB-Table?
DDB-Table was designed to address the complexities developers often face when working with untyped JSON data in DynamoDB. By integrating with TypeScript, it offers:
- Strongly Typed Data: From start to finish, your data undergoes TypeScript validation, guaranteeing that every piece of data fits the defined structure.
- Intuitive Query Expressions: Offers automatic escaping for attribute names and values, simplifying the query process.
- Efficient Projections: Ensures that only the fields projectively used are accessed, optimizing the data retrieval process.
- Index Queries and Scans: Full support is provided for working with both global and local indexes, giving developers flexibility and power in their database queries.
- Pure JavaScript Compatibility: Though TypeScript is a feature, DDB-Table seamlessly functions with JavaScript as well, broadening its range of use.
Getting Started
Getting DDB-Table up and running is straightforward. You can easily install it via npm:
npm i ddb-table
Basic Usage Example
Imagine you want to manage a messaging table in DynamoDB. With DDB-Table, you can define a table and manipulate it with strong type checks. Here’s a quick example:
import Table from 'ddb-table';
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { DynamoDBDocument } from '@aws-sdk/lib-dynamodb';
interface MessageSchema {
threadId: string;
timestamp: number;
senderId: string;
message: string;
status: 'sent' | 'received';
tags?: Set<string>;
attachments: {
name: string;
URL: string;
}[];
}
const client = new DynamoDBClient({
// settings...
});
// Define the table structure
const messages = new Table<MessageSchema, 'threadId', 'timestamp'>({
tableName: 'Messages',
primaryKey: 'threadId',
sortKey: 'timestamp',
documentClient: DynamoDBDocument.from(client);
});
// Update a message and handle new attachments seamlessly
const updateRes = await messages
.update('[email protected]', 1588191225322)
.set('message', 'Hello World!')
.add('tags', new Set(['unread', 'important']))
.set('attachments', (exp) =>
exp.listAppend([{ name: 'Test', URL: 'demo.com' }]),
)
.return('ALL_NEW')
.exec();
console.log(updateRes.Attributes);
Working with Indexes
DDB-Table simplifies the process of working with indexes, allowing developers to perform complex queries effectively. Here’s how:
type SenderTimestampIndex = Pick<
MessageSchema,
'threadId' | 'timestamp' | 'senderId'
>;
// Define a secondary index
const outboxIndex = messages.index<
SenderTimestampIndex,
'senderId',
'timestamp'
>('senderId-timestamp-index', 'senderId', 'timestamp');
// Query the index
const it = outboxIndex
.query()
.keyCondition((cond) => cond.eq('senderId', '[email protected]'))
.keyCondition((cond) =>
cond.between('timestamp', Date.now() - 3600e3, Date.now()),
)
.project({ threadId: 1, message: 1 })
.reverseIndex()
.entries();
for await (const item of it) {
console.log(item);
}
Handling Errors
With DDB-Table, error handling is a structured process. Developers can catch and manage exceptions effectively, enhancing application stability:
import { DynamoDBExceptionName } from 'ddb-table';
try {
await table.put(...).exec();
} catch (err) {
if ((err as DynamoDBServiceException)?.name === DynamoDBExceptionName.ConditionalCheckFailedException) {
// handle exception
}
}
Contribution and Support
DDB-Table is open-source and available under the MIT license. If you find this project helpful and wish to support continued development, consider sponsoring it.
This library not only simplifies working with DynamoDB but also leverages the strength of TypeScript for stronger, error-free coding, making it an invaluable tool for developers.