DDB-Table was built to provide strongly-typed data structures over DynamoDB tables. Using AWS DocumentClient & TypeScript you can easily fetch and store any JSON document and validate itβs structure statically. Query secondary indexes and run complicated update expressions without any error on runtime.
await table
.update('demo@example.com')
.set('FullName', 'John Doe')
// π¨ TypeScript Error: 'fullName' is not assignable to 'Email' | 'FullName'
.condition((cond) => cond.eq('fullName', 'Johnny Doe'))
.exec();
- Strongly Typed - End-to-end TypeScript validation for your data.
- Easy Query Expressions - Automatically escape name attributes and values.
- Smart Projections - Make sure you only access the fields you project.
- Query & Scan Indexes - Complete support for global or local indexes.
- Pure JavaScript - Also works without TypeScript.
If you like this project, please consider sponsoring us to help us continue to maintain and improve this project.
npm i ddb-table
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...
});
// create the basic table definition
const messages = new Table<MessageSchema, 'threadId', 'timestamp'>({
tableName: 'Messages',
primaryKey: 'threadId',
sortKey: 'timestamp',
documentClient: DynamoDBDocument.from(client);
});
const updateRes = await messages
.update('john@gmail.com', 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);
// create a secondary index definition
type SenderTimestampIndex = Pick<
MessageSchema,
'threadId' | 'timestamp' | 'senderId'
>;
const outboxIndex = messages.index<
SenderTimestampIndex,
'senderId',
'timestamp'
>('senderId-timestamp-index', 'senderId', 'timestamp');
const it = outboxIndex
.query()
.keyCondition((cond) => cond.eq('senderId', 'john@gmail.com'))
.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);
}
import { DynamoDBExceptionName } from 'ddb-table';
try {
await table.put(...).exec();
} catch (err) {
if ((err as DynamoDBServiceException)?.name === DynamoDBExceptionName.ConditionalCheckFailedException) {
// handle exception
}
}