Object Relational mapper for DynamoDB, inspired by typeorm.
TypeDORM is an ORM built from ground up using typescript and latest javascript features to provide an easy gateway when doing complex highly relational data modeling in dynamoDB. TypeDORM is built with single-table-design first in mind, but should work as smoothly with regular entity table <-> design pattern. TypeDORM would have not existed without TypeORM and dynamodb-toolbox, big shout-out to these projects and their awesome contributors.
TypeDORM borrows decorator based syntax from TypeORM and provides fully type safe ORM to with dynamodb. TypeDORM currently only support Data Mapper.
Package | Latest Stable | Recent Beta |
---|---|---|
@typedorm/common | ||
@typedorm/core | ||
@typedorm/testing |
Branches | Stability |
---|---|
Main | |
Beta |
- DataMapper development pattern
- Full type safety
- Declarative relational schema
- Entity manager
- Transaction manager
- Multiple connections support
- Code follows all possible best practices when modeling for dynamodb
- Additional higher level features like, ability to declare non key attribute as unique(beta)
- Auto Generated values fro attributes
- Auto Update values on update
- Dynamic & Static default values for attributes
- Complex update, key condition and condition expression all made easy to work with (Partial Support)
- Powerful expression builder to auto generate expressions from input
- Typescript and javascript support
And many more to come.
-
Install core and common modules from npm.
npm install @typedorm/core @typedorm/common --save
-
Install aws-sdk for nodejs, TypeDORM uses documentClient to interact with dynamodb.
npm install aws-sdk --save
-
Install
reflect-metadata
shimnpm install reflect-metadata --save
and import it as the first thing in node entry file as
import 'reflect-metadata'
If you are using TypeDORM with typescript, make sure you also have below options enabled in tsconfig.json
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
First thing to do when working with TypeDORM is to setup dynamodb table config. Currently this needs to be manually setup and have also have it configured in deployed table instance(s).
This guide shows how to setup single-table-design
my-table.ts
import {Table} from '@typedorm/common';
// create table
const myGlobalTable = new Table({
name: 'test-table',
partitionKey: 'PK',
sortKey: 'SK',
indexes: {
GSI1: {
type: INDEX_TYPE.GSI,
partitionKey: 'GSI1PK',
sortKey: 'GSI1SK',
},
GSI2: {
type: INDEX_TYPE.GSI,
partitionKey: 'GSI2PK',
sortKey: 'GSI2SK',
},
LSI1: {
type: INDEX_TYPE.LSI,
sortKey: 'LSI1SK',
},
},
});
Note: These indexes must match exactly to what is created in dynamo table instance hosted.
organisation.entity.ts
import {Attribute, Entity, AutoGeneratedAttribute} from '@typedorm/common';
import {AUTO_GENERATE_ATTRIBUTE_STRATEGY} from '@typedorm/common';
@Entity({
name: 'organisation',
primaryKey: {
partitionKey: 'ORG#{{id}}',
sortKey: 'ORG#{{id}}',
},
indexes: {
// specify GSI1 key - "GSI1" named global secondary index needs to exist in above table declaration
GSI1: {
partitionKey: 'ORG#{{id}}#STATUS#{{status}}',
sortKey: 'ORG#{{id}}#ACTIVE#{{active}}',
type: INDEX_TYPE.GSI,
},
// specify LSI1 key
LSI: {
sortKey: 'TICKETS#UPDATED_AT#{{updatedAt}}'
type: INDEX_TYPE.LSI
}
},
})
export class Organisation{
@AutoGeneratedAttribute({
strategy: AUTO_GENERATE_ATTRIBUTE_STRATEGY.UUID4,
})
id: string;
@Attribute()
name: string;
@Attribute()
status: string;
@Attribute()
active: boolean;
@AutoGeneratedAttribute({
strategy: AUTO_GENERATE_ATTRIBUTE_STRATEGY.EPOCH,
autoUpdate: true // this will make this attribute and any indexes referencing it auto update for any write operation
})
updatedAt: number;
}
import {createConnection} from '@typedorm/core';
// initialize with specifying list of entities
createConnection({
table: myGlobalTable,
entities: [Organisation],
});
// or initialize with specifying path match for entities
createConnection({
table: myGlobalTable,
entities: 'path-to-entities/*.entity.ts',
});
import {getEntityManager} from '@typedorm/core';
const org = new Organisation();
org.name = 'My awesome org';
org.status = 'onboarding';
org.active = true;
const entityManger = getEntityManager();
// create item
const response = await entityManger.create(org);
// get item
const org = await entityManger.findOne(Organisation, {
id: response.id,
status: 'onboarding',
active: true,
});
// delete item
await entityManger.delete(Organisation, {
id: response.id,
status: 'onboarding',
active: true,
});
- How it works
- Step by step guide
- Entity inheritance
- Working with multiple connections
- How to recipes
- Debugging
- API
DynamoDB is different, different than most other no-sql databases, and therefore data in dynamodb should be stored the way dynamodb expects to get the most benefits out of it. While doing this development experience suffers and all data can become a huge mess very quickly, this is specially true with single-table-design patten. To resolve this, TypeDORM let's declaratively define schema and later takes control from there to provide best development experience possible.
To find out more about how the data looks like when it is stored in dynamo have a look at this detailed guide.
- To keep things simple TypeDORM, at the moment WILL NOT create/update table configuration and must be done separately.
- There is very minimal support for providing different arguments to queries, and will be resolved soon.
Please submit an issue for any bugs or ideas here, or you can reach out to me on twitter @whimzy_live.