A TypeScript-friendly wrapper for AWS DynamoDB that simplifies common database operations with type safety and clean abstractions.
- Type-safe operations with TypeScript generics
- Simplified CRUD operations
- Batch operations support
- Query and Scan operations with filters
- Support for tables with composite keys (hash + range)
- Index querying support
- Automatic batch processing for large operations
yarn add @initd.sg/dynamodb-service
Create a service by extending the AbstractService
class:
interface User {
userId: string;
email: string;
name: string;
createdAt: number;
}
class UserService extends AbstractService<User> {
tableName = "Users";
save(user: User) {
await userService._save({
hashKey: "userId",
obj: user,
});
}
get(id: string) {
return this._get({
hashKey: "userId",
hashKeyValue: "123"
})
}
getWithRange(id: string, createAt: number) {
return this._get({
hashKey: "userId",
hashKeyValue: id,
rangeKey: "createdAt",
rangeKeyValue: createdAt,
})
}
query(opt: GetOptions) {
return this._query(opts);
}
queryBetween(opt: GetOptions & { rangeKeyStartValue: number, rangeKeyEndValue: number }) {
return this._queryBetween(opts);
}
batchGet(items: BatchGetOptions) {
return this._batchGet(items);
}
list(opts: ListOptions) {
return this._list(opts);
}
delete(id: string) {
return this._delete({
hashKey: "userId",
hashKeyValue: id
});
}
paginate(opts: PaginateOptions) {
return this._paginate(opts);
}
}
const userService = new UserService();
await userService.save({
userId: "123",
email: "john@example.com",
name: "John Doe",
createdAt: Date.now()
});
// Get by hash key
const user = await userService.get("123");
// Get by hash key and range key
const user = await userService.getWithRange("123", 1234567890);
// Basic query
const users = await userService.query({
hashKey: "userId",
hashKeyValue: "123"
});
// Query with index
const users = await userService.query({
index: "email-index",
hashKey: "email",
hashKeyValue: "john@example.com"
});
// Query with ordering and limit
const users = await userService.query({
hashKey: "userId",
hashKeyValue: "123",
order: "dsc",
limit: 10
});
const users = await userService.queryBetween({
hashKey: "userId",
hashKeyValue: "123",
rangeKey: "createdAt",
rangeKeyStartValue: 1234567890,
rangeKeyEndValue: 1234567899
});
const users = await userService.batchGet({
items: [
{ hashKey: "userId", hashKeyValue: "123" },
{ hashKey: "userId", hashKeyValue: "456" }
]
});
// Get all items
const allUsers = await userService.getAll();
// List with filters
const filteredUsers = await userService.list({
filters: {
status: "active"
},
limit: 10
});
await userService.delete("userId");
// fetch first page
const { items, lastEvaluatedKeys } = await userService.paginate({
limit: 10,
});
// fetch the next page
await userService.paginate({
limit: 10,
lastEvaluatedKeys,
});
You can provide your own DynamoDB client instance:
const customClient = new DynamoDBClient({
region: 'us-east-1',
credentials: {
accessKeyId: 'YOUR_ACCESS_KEY',
secretAccessKey: 'YOUR_SECRET_KEY'
}
});
const userService = new UserService({ dynamoDBClient: customClient });
Base class that provides all DynamoDB operations. Generic type T
represents the shape of your table items.
_save(options: SaveOptions<T>): Promise<T>
_get(options: GetOptions<T>): Promise<T | null>
_query(options: GetOptions<T>): Promise<T[]>
_queryBetween(options: GetOptions<T> & {rangeKeyStartValue, rangeKeyEndValue}): Promise<T[]>
_batchGet(options: BatchGetOptions<T>): Promise<T[]>
_list(options: ListOptions): Promise<T[]>
getAll(): Promise<T[]>
_delete(options: DeleteOptions<H, R>): Promise<void>
_paginate(options: PaginateOptions): Promise<{ items: T[], lastEvaluatedKey: Record<string, any> }>
MIT