Skip to content

Commit

Permalink
feat(dynamodb): partitionKey and sortKey are now immutable (#1744)
Browse files Browse the repository at this point in the history
Since partition key is a mandatory parameter for DynamoDB tables, by
our conventions it should be a required property and immutable.

BREAKING CHANGE: `partitionKey` is now a required property when defining a 
`dynamodb.Table`. The `addPartitionKey` and `addSortKey` methods have been removed.
  • Loading branch information
Elad Ben-Israel authored Feb 12, 2019
1 parent a84157d commit 63ae0b4
Show file tree
Hide file tree
Showing 7 changed files with 178 additions and 230 deletions.
6 changes: 3 additions & 3 deletions packages/@aws-cdk/aws-dynamodb/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ const table = new dynamodb.Table(this, 'Table', {

### Keys

You can either specify `partitionKey` and/or `sortKey` when you initialize the
table, or call `addPartitionKey` and `addSortKey` after initialization.
When a table is defined, you must define it's schema using the `partitionKey`
(required) and `sortKey` (optional) properties.

### Billing Mode

DynamoDB supports two billing modes:
* PROVISIONED - the default mode where the table and global secondary indexes have configured read and write capacity.
* PAY_PER_REQUEST - on-demand pricing and scaling. You only pay for what you use and there is no read and write capacity for the table or its gloal secondary indexes.
* PAY_PER_REQUEST - on-demand pricing and scaling. You only pay for what you use and there is no read and write capacity for the table or its global secondary indexes.

```ts
import dynamodb = require('@aws-cdk/aws-dynamodb');
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-dynamodb/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
export * from './dynamodb.generated';
export * from './table';
export * from './scalable-attribute-api';
export * from './scalable-attribute-api';
66 changes: 19 additions & 47 deletions packages/@aws-cdk/aws-dynamodb/lib/table.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,18 @@ export interface Attribute {
}

export interface TableProps {
/**
* Partition key attribute definition.
*/
partitionKey: Attribute;

/**
* Table sort key attribute definition.
*
* @default no sort key
*/
sortKey?: Attribute;

/**
* The read capacity for the table. Careful if you add Global Secondary Indexes, as
* those will share the table's provisioned throughput.
Expand Down Expand Up @@ -99,18 +111,6 @@ export interface TableProps {
* @default undefined, TTL is disabled
*/
ttlAttributeName?: string;

/**
* Partition key attribute definition. This is eventually required, but you
* can also use `addPartitionKey` to specify the partition key at a later stage.
*/
partitionKey?: Attribute;

/**
* Table sort key attribute definition. You can also use `addSortKey` to set
* this up later.
*/
sortKey?: Attribute;
}

export interface SecondaryIndexProps {
Expand Down Expand Up @@ -200,15 +200,15 @@ export class Table extends Construct {
private readonly secondaryIndexNames: string[] = [];
private readonly nonKeyAttributes: string[] = [];

private tablePartitionKey?: Attribute;
private tableSortKey?: Attribute;
private readonly tablePartitionKey: Attribute;
private readonly tableSortKey?: Attribute;

private readonly billingMode: BillingMode;
private readonly tableScaling: ScalableAttributePair = {};
private readonly indexScaling = new Map<string, ScalableAttributePair>();
private readonly scalingRole: iam.IRole;

constructor(scope: Construct, id: string, props: TableProps = {}) {
constructor(scope: Construct, id: string, props: TableProps) {
super(scope, id);

this.billingMode = props.billingMode || BillingMode.Provisioned;
Expand Down Expand Up @@ -239,39 +239,15 @@ export class Table extends Construct {

this.scalingRole = this.makeScalingRole();

if (props.partitionKey) {
this.addPartitionKey(props.partitionKey);
}
this.addKey(props.partitionKey, HASH_KEY_TYPE);
this.tablePartitionKey = props.partitionKey;

if (props.sortKey) {
this.addSortKey(props.sortKey);
this.addKey(props.sortKey, RANGE_KEY_TYPE);
this.tableSortKey = props.sortKey;
}
}

/**
* Add a partition key of table.
*
* @param attribute the partition key attribute of table
* @returns a reference to this object so that method calls can be chained together
*/
public addPartitionKey(attribute: Attribute): this {
this.addKey(attribute, HASH_KEY_TYPE);
this.tablePartitionKey = attribute;
return this;
}

/**
* Add a sort key of table.
*
* @param attribute the sort key of table
* @returns a reference to this object so that method calls can be chained together
*/
public addSortKey(attribute: Attribute): this {
this.addKey(attribute, RANGE_KEY_TYPE);
this.tableSortKey = attribute;
return this;
}

/**
* Add a global secondary index of table.
*
Expand Down Expand Up @@ -315,10 +291,6 @@ export class Table extends Construct {
throw new RangeError('a maximum number of local secondary index per table is 5');
}

if (!this.tablePartitionKey) {
throw new Error('a partition key of the table must be specified first through addPartitionKey()');
}

this.validateIndexName(props.indexName);

// build key schema and projection for index
Expand Down
5 changes: 3 additions & 2 deletions packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@ import dynamodb = require('../lib');
const app = new cdk.App();
const stack = new cdk.Stack(app, 'aws-cdk-dynamodb');

const table = new dynamodb.Table(stack, 'Table', {});
table.addPartitionKey({ name: 'hashKey', type: dynamodb.AttributeType.String });
const table = new dynamodb.Table(stack, 'Table', {
partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.String }
});

/// !show
const readScaling = table.autoScaleReadCapacity({ minCapacity: 1, maxCapacity: 50 });
Expand Down
27 changes: 17 additions & 10 deletions packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,21 +41,23 @@ const app = new App();
const stack = new Stack(app, STACK_NAME);

// Provisioned tables
const table = new Table(stack, TABLE, {billingMode: BillingMode.PayPerRequest});
table.addPartitionKey(TABLE_PARTITION_KEY);
new Table(stack, TABLE, {
billingMode: BillingMode.PayPerRequest,
partitionKey: TABLE_PARTITION_KEY
});

const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_AND_LOCAL_SECONDARY_INDEX, {
pitrEnabled: true,
sseEnabled: true,
streamSpecification: StreamViewType.KeysOnly,
billingMode: BillingMode.PayPerRequest,
ttlAttributeName: 'timeToLive'
ttlAttributeName: 'timeToLive',
partitionKey: TABLE_PARTITION_KEY,
sortKey: TABLE_SORT_KEY
});

tableWithGlobalAndLocalSecondaryIndex.node.apply(new Tag('Environment', 'Production'));

tableWithGlobalAndLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
tableWithGlobalAndLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({
indexName: GSI_TEST_CASE_1,
partitionKey: GSI_PARTITION_KEY,
Expand Down Expand Up @@ -104,16 +106,21 @@ tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({
nonKeyAttributes: LSI_NON_KEY
});

const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, {billingMode: BillingMode.PayPerRequest});
tableWithGlobalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, {
billingMode: BillingMode.PayPerRequest,
partitionKey: TABLE_PARTITION_KEY,
});
tableWithGlobalSecondaryIndex.addGlobalSecondaryIndex({
indexName: GSI_TEST_CASE_1,
partitionKey: GSI_PARTITION_KEY
});

const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, {billingMode: BillingMode.PayPerRequest});
tableWithLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
tableWithLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, {
billingMode: BillingMode.PayPerRequest,
partitionKey: TABLE_PARTITION_KEY,
sortKey: TABLE_SORT_KEY,
});

tableWithLocalSecondaryIndex.addLocalSecondaryIndex({
indexName: LSI_TEST_CASE_1,
sortKey: LSI_SORT_KEY
Expand Down
24 changes: 14 additions & 10 deletions packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,19 +41,20 @@ const app = new App();

const stack = new Stack(app, STACK_NAME);

const table = new Table(stack, TABLE, {});
table.addPartitionKey(TABLE_PARTITION_KEY);
const table = new Table(stack, TABLE, {
partitionKey: TABLE_PARTITION_KEY
});

const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_AND_LOCAL_SECONDARY_INDEX, {
pitrEnabled: true,
sseEnabled: true,
streamSpecification: StreamViewType.KeysOnly,
ttlAttributeName: 'timeToLive'
ttlAttributeName: 'timeToLive',
partitionKey: TABLE_PARTITION_KEY,
sortKey: TABLE_SORT_KEY
});

tableWithGlobalAndLocalSecondaryIndex.node.apply(new Tag('Environment', 'Production'));
tableWithGlobalAndLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
tableWithGlobalAndLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({
indexName: GSI_TEST_CASE_1,
partitionKey: GSI_PARTITION_KEY,
Expand Down Expand Up @@ -104,16 +105,19 @@ tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({
nonKeyAttributes: LSI_NON_KEY
});

const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, {});
tableWithGlobalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, {
partitionKey: TABLE_PARTITION_KEY
});
tableWithGlobalSecondaryIndex.addGlobalSecondaryIndex({
indexName: GSI_TEST_CASE_1,
partitionKey: GSI_PARTITION_KEY
});

const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, {});
tableWithLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
tableWithLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, {
partitionKey: TABLE_PARTITION_KEY,
sortKey: TABLE_SORT_KEY
});

tableWithLocalSecondaryIndex.addLocalSecondaryIndex({
indexName: LSI_TEST_CASE_1,
sortKey: LSI_SORT_KEY
Expand Down
Loading

0 comments on commit 63ae0b4

Please sign in to comment.