Skip to content

Commit

Permalink
aws-cdk-dynamodb: Initial external release
Browse files Browse the repository at this point in the history
Co-authored-by: Romain Marcadier-Muller <rmuller@amazon.com>
Co-authored-by: Breland Miley <brelandm@amazon.com>
Co-authored-by: Mitch Garnaat <garnaat@amazon.com>
Co-authored-by: Shiv Lakshminarayan <shivlaks@amazon.com>
Co-authored-by: Max Hall <hallmaxw@amazon.com>
Co-authored-by: Doug Schwartz <dougsch@amazon.com>
  • Loading branch information
7 people committed May 30, 2018
1 parent 284177d commit 9b34fe8
Show file tree
Hide file tree
Showing 8 changed files with 3,805 additions and 0 deletions.
6 changes: 6 additions & 0 deletions packages/aws-cdk-dynamodb/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
*.js
*.js.map
*.d.ts
node_modules
dist
tsconfig.json
13 changes: 13 additions & 0 deletions packages/aws-cdk-dynamodb/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
## AWS DynamoDB Construct Library
Add a DynamoDB table to you stack like so:
```ts
import { Table } from 'aws-cdk-dynamodb';

const defaultTable = new Table(stack, 'TableName');

const customTable = new Table(stack, 'CustomTable', {
readCapacity: readUnits, // Default is 5
writeCapacity: writeUnits, // Default is 5
tableName: 'MyTableName' // Default is CloudFormation-generated, which is the preferred approach
})
```
118 changes: 118 additions & 0 deletions packages/aws-cdk-dynamodb/lib/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
import { Construct } from 'aws-cdk';
import { dynamodb } from 'aws-cdk-resources';

const HASH_KEY_TYPE = 'HASH';
const RANGE_KEY_TYPE = 'RANGE';

export interface TableProps {
/**
* The read capacity for the table. Careful if you add Global Secondary Indexes, as
* those will share the table's provisioned throughput.
* @default 5
*/
readCapacity?: number;
/**
* The write capacity for the table. Careful if you add Global Secondary Indexes, as
* those will share the table's provisioned throughput.
* @default 5
*/
writeCapacity?: number;

/**
* Enforces a particular physical table name.
* @default <generated>
*/
tableName?: string;
}

/**
* Provides a DynamoDB table.
*/
export class Table extends Construct {
private readonly table: dynamodb.TableResource;

private readonly keySchema = new Array<dynamodb.TableResource.KeySchemaProperty>();
private readonly attributeDefinitions = new Array<dynamodb.TableResource.AttributeDefinitionProperty>();

constructor(parent: Construct, name: string, props: TableProps = {}) {
super(parent, name);

const readCapacityUnits = props.readCapacity || 5;
const writeCapacityUnits = props.writeCapacity || 5;

this.table = new dynamodb.TableResource(this, 'Resource', {
tableName: props.tableName,
keySchema: this.keySchema,
attributeDefinitions: this.attributeDefinitions,
provisionedThroughput: { readCapacityUnits, writeCapacityUnits }
});

if (props.tableName) { this.addMetadata('aws:cdk:hasPhysicalName', props.tableName); }
}

public get tableArn() {
return this.table.tableArn;
}

public get tableName() {
return this.table.ref;
}

public get tableStreamArn() {
return this.table.tableStreamArn;
}

public addPartitionKey(name: string, type: KeyAttributeType): this {
this.addKey(name, type, HASH_KEY_TYPE);
return this;
}

public addSortKey(name: string, type: KeyAttributeType): this {
this.addKey(name, type, RANGE_KEY_TYPE);
return this;
}

public validate(): string[] {
const errors = new Array<string>();
if (!this.findKey(HASH_KEY_TYPE)) {
errors.push('a partition key must be specified');
}
return errors;
}

private findKey(keyType: string) {
return this.keySchema.find(prop => prop.keyType === keyType);
}

private addKey(name: string, type: KeyAttributeType, keyType: string) {
const existingProp = this.findKey(keyType);
if (existingProp) {
throw new Error(`Unable to set ${name} as a ${keyType} key, because ${existingProp.attributeName} is a ${keyType} key`);
}
this.registerAttribute(name, type);
this.keySchema.push({
attributeName: name,
keyType
});
return this;
}

private registerAttribute(name: string, type: KeyAttributeType) {
const existingDef = this.attributeDefinitions.find(def => def.attributeName === name);
if (existingDef && existingDef.attributeType !== type) {
throw new Error(`Unable to specify ${name} as ${type} because it was already defined as ${existingDef.attributeType}`);
}
if (!existingDef) {
this.attributeDefinitions.push({
attributeName: name,
attributeType: type
});
}
}
}

export enum KeyAttributeType {
Binary = 'B',
Number = 'N',
String = 'S',
}
Loading

0 comments on commit 9b34fe8

Please sign in to comment.