dynolink
Version:
A TypeScript ORM for DynamoDB
235 lines (173 loc) โข 5.26 kB
Markdown
# ๐งฌ DynoLink
**DynoLink** is a type-safe, schema-driven DynamoDB ORM for Node.js and TypeScript. It offers a powerful and expressive `QueryBuilder`, lifecycle hooks, and repository patterns to simplify working with AWS DynamoDB.
---
## โจ Features
- ๐ฏ **Type-safe** schema definition using TypeScript decorators
- ๐งฑ **Single-table & multi-table design** support with flexible entity modeling
- ๐ **Full CRUD operations** via a powerful base repository
- ๐ **Query builder** with filter operators, key conditions, and attribute functions
- ๐ **DynamoDB Streams & TTL** integration for real-time and auto-expiring data
- โ๏ธ **Auto table creation** with GSIs, LSIs, TTL, and Streams support
- ๐งฉ **Transformers & default values** for schema fields (e.g., formatting or generated values)
- ๐งช **Pluggable validation, serialization & deserialization** mechanisms
- ๐งน **Optional undefined value filtering** and class-to-map conversion via `marshall()`
---
## ๐ฆ Installation
```bash
npm install dynolink
# or
yarn add dynolink
```
๐ Quick Start
1. Define an Entity
```typescript
import {
Table,
Column,
PartitionKey,
GSI,
LSI, SortKey,
} from '../../core/decorators';
export class User {
id!: string;
name!: string;
email!: string;
status!: string;
createdAt?: string;
// Add any additional fields you want
}
```
2. Create a Repository
```typescript
import { DynamoDBClient } from '@aws-sdk/client-dynamodb';
import { BaseRepository } from 'dynolink';
import { User } from './models/User';
class UserRepository extends BaseRepository<User> {
constructor(client: DynamoDBClient) {
super(User, client);
}
}
```
3. Save and Query Records
```typescript
import {UserRepository} from "./user.repository";
import {User} from "./user.entity";
const client = new DynamoDBClient({});
const repo = new UserRepository(client);
await repo.save(new User({id: '50000123', name: 'user 1', status: 'pending', email: "test@test.com"}));
const result = await repo.findOne({id: '50000123', name: 'user 1' });
```
๐ง Decorators
| Decorator | Description |
| ----------------- | -------------------------------------------------- |
| `` | Maps class to a DynamoDB table |
| `` | Marks a class field as an attribute |
| `` | Declares the field as the partition key |
| `` | Declares the field as the sort key (if applicable) |
| `` | Declares a Global Secondary Index |
| `` | Declares a Local Secondary Index |
Example with TTL and Transformation
```typescript
import {Column} from "./decorators";
createdAt!:string;
ttl?:number; // Used for automatic expiration
```
๐ง Advanced Features
โ
Single Table Design
DynoLink supports single-table designs using entity type discrimination and composite keys.
```typescript
import {Column} from "./decorators";
export class User {
pk!: string;
sk!: string;
name!: string;
email?: string;
status?: string;
}
```
```typescript
import {Column} from "./decorators";
export class Address {
pk!: string;
sk!: string;
street!: string;
zipcode?: string
}
```
โฑ TTL Support
To expire items automatically:
1. Add a TTL attribute:
```typescript
ttl?: number;
```
2. Enable TTL in the table via ensureTable.
๐ DynamoDB Streams
Enable streams via:
```typescript
import {User} from "./user.entity";
await ensureTable(User, client, {
streamEnabled: true,
streamViewType: 'NEW_AND_OLD_IMAGES'
});
```
๐ Table Creation Programmatically
```typescript
import {ensureTable} from 'dynolink';
import {User} from "./user.entity";
await ensureTable(User, client); // Auto-creates table based on metadata
```
You can also pass options for TTL and Streams:
```typescript
import {User} from "./user.entity";
await ensureTable(User, client, {
ttlAttributeName: 'ttl',
streamEnabled: true,
streamViewType: 'NEW_AND_OLD_IMAGES'
});
```
๐งช Testing Example
```typescript
it('should query items using filters', async () => {
const result = await repository.query({
key: {
pk : { eq: '50000123' },
sk: { eq: "User 1" }
},
});
expect(result).toHaveLength(1);
});
```