Skip to content

Commit 63ae0b4

Browse files
author
Elad Ben-Israel
authored
feat(dynamodb): partitionKey and sortKey are now immutable (#1744)
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.
1 parent a84157d commit 63ae0b4

File tree

7 files changed

+178
-230
lines changed

7 files changed

+178
-230
lines changed

packages/@aws-cdk/aws-dynamodb/README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,14 @@ const table = new dynamodb.Table(this, 'Table', {
1212

1313
### Keys
1414

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

1818
### Billing Mode
1919

2020
DynamoDB supports two billing modes:
2121
* PROVISIONED - the default mode where the table and global secondary indexes have configured read and write capacity.
22-
* 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.
22+
* 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.
2323

2424
```ts
2525
import dynamodb = require('@aws-cdk/aws-dynamodb');
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
11
export * from './dynamodb.generated';
22
export * from './table';
3-
export * from './scalable-attribute-api';
3+
export * from './scalable-attribute-api';

packages/@aws-cdk/aws-dynamodb/lib/table.ts

Lines changed: 19 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,18 @@ export interface Attribute {
4444
}
4545

4646
export interface TableProps {
47+
/**
48+
* Partition key attribute definition.
49+
*/
50+
partitionKey: Attribute;
51+
52+
/**
53+
* Table sort key attribute definition.
54+
*
55+
* @default no sort key
56+
*/
57+
sortKey?: Attribute;
58+
4759
/**
4860
* The read capacity for the table. Careful if you add Global Secondary Indexes, as
4961
* those will share the table's provisioned throughput.
@@ -99,18 +111,6 @@ export interface TableProps {
99111
* @default undefined, TTL is disabled
100112
*/
101113
ttlAttributeName?: string;
102-
103-
/**
104-
* Partition key attribute definition. This is eventually required, but you
105-
* can also use `addPartitionKey` to specify the partition key at a later stage.
106-
*/
107-
partitionKey?: Attribute;
108-
109-
/**
110-
* Table sort key attribute definition. You can also use `addSortKey` to set
111-
* this up later.
112-
*/
113-
sortKey?: Attribute;
114114
}
115115

116116
export interface SecondaryIndexProps {
@@ -200,15 +200,15 @@ export class Table extends Construct {
200200
private readonly secondaryIndexNames: string[] = [];
201201
private readonly nonKeyAttributes: string[] = [];
202202

203-
private tablePartitionKey?: Attribute;
204-
private tableSortKey?: Attribute;
203+
private readonly tablePartitionKey: Attribute;
204+
private readonly tableSortKey?: Attribute;
205205

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

211-
constructor(scope: Construct, id: string, props: TableProps = {}) {
211+
constructor(scope: Construct, id: string, props: TableProps) {
212212
super(scope, id);
213213

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

240240
this.scalingRole = this.makeScalingRole();
241241

242-
if (props.partitionKey) {
243-
this.addPartitionKey(props.partitionKey);
244-
}
242+
this.addKey(props.partitionKey, HASH_KEY_TYPE);
243+
this.tablePartitionKey = props.partitionKey;
245244

246245
if (props.sortKey) {
247-
this.addSortKey(props.sortKey);
246+
this.addKey(props.sortKey, RANGE_KEY_TYPE);
247+
this.tableSortKey = props.sortKey;
248248
}
249249
}
250250

251-
/**
252-
* Add a partition key of table.
253-
*
254-
* @param attribute the partition key attribute of table
255-
* @returns a reference to this object so that method calls can be chained together
256-
*/
257-
public addPartitionKey(attribute: Attribute): this {
258-
this.addKey(attribute, HASH_KEY_TYPE);
259-
this.tablePartitionKey = attribute;
260-
return this;
261-
}
262-
263-
/**
264-
* Add a sort key of table.
265-
*
266-
* @param attribute the sort key of table
267-
* @returns a reference to this object so that method calls can be chained together
268-
*/
269-
public addSortKey(attribute: Attribute): this {
270-
this.addKey(attribute, RANGE_KEY_TYPE);
271-
this.tableSortKey = attribute;
272-
return this;
273-
}
274-
275251
/**
276252
* Add a global secondary index of table.
277253
*
@@ -315,10 +291,6 @@ export class Table extends Construct {
315291
throw new RangeError('a maximum number of local secondary index per table is 5');
316292
}
317293

318-
if (!this.tablePartitionKey) {
319-
throw new Error('a partition key of the table must be specified first through addPartitionKey()');
320-
}
321-
322294
this.validateIndexName(props.indexName);
323295

324296
// build key schema and projection for index

packages/@aws-cdk/aws-dynamodb/test/integ.autoscaling.lit.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import dynamodb = require('../lib');
55
const app = new cdk.App();
66
const stack = new cdk.Stack(app, 'aws-cdk-dynamodb');
77

8-
const table = new dynamodb.Table(stack, 'Table', {});
9-
table.addPartitionKey({ name: 'hashKey', type: dynamodb.AttributeType.String });
8+
const table = new dynamodb.Table(stack, 'Table', {
9+
partitionKey: { name: 'hashKey', type: dynamodb.AttributeType.String }
10+
});
1011

1112
/// !show
1213
const readScaling = table.autoScaleReadCapacity({ minCapacity: 1, maxCapacity: 50 });

packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ondemand.ts

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,21 +41,23 @@ const app = new App();
4141
const stack = new Stack(app, STACK_NAME);
4242

4343
// Provisioned tables
44-
const table = new Table(stack, TABLE, {billingMode: BillingMode.PayPerRequest});
45-
table.addPartitionKey(TABLE_PARTITION_KEY);
44+
new Table(stack, TABLE, {
45+
billingMode: BillingMode.PayPerRequest,
46+
partitionKey: TABLE_PARTITION_KEY
47+
});
4648

4749
const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_AND_LOCAL_SECONDARY_INDEX, {
4850
pitrEnabled: true,
4951
sseEnabled: true,
5052
streamSpecification: StreamViewType.KeysOnly,
5153
billingMode: BillingMode.PayPerRequest,
52-
ttlAttributeName: 'timeToLive'
54+
ttlAttributeName: 'timeToLive',
55+
partitionKey: TABLE_PARTITION_KEY,
56+
sortKey: TABLE_SORT_KEY
5357
});
5458

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

57-
tableWithGlobalAndLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
58-
tableWithGlobalAndLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
5961
tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({
6062
indexName: GSI_TEST_CASE_1,
6163
partitionKey: GSI_PARTITION_KEY,
@@ -104,16 +106,21 @@ tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({
104106
nonKeyAttributes: LSI_NON_KEY
105107
});
106108

107-
const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, {billingMode: BillingMode.PayPerRequest});
108-
tableWithGlobalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
109+
const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, {
110+
billingMode: BillingMode.PayPerRequest,
111+
partitionKey: TABLE_PARTITION_KEY,
112+
});
109113
tableWithGlobalSecondaryIndex.addGlobalSecondaryIndex({
110114
indexName: GSI_TEST_CASE_1,
111115
partitionKey: GSI_PARTITION_KEY
112116
});
113117

114-
const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, {billingMode: BillingMode.PayPerRequest});
115-
tableWithLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
116-
tableWithLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
118+
const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, {
119+
billingMode: BillingMode.PayPerRequest,
120+
partitionKey: TABLE_PARTITION_KEY,
121+
sortKey: TABLE_SORT_KEY,
122+
});
123+
117124
tableWithLocalSecondaryIndex.addLocalSecondaryIndex({
118125
indexName: LSI_TEST_CASE_1,
119126
sortKey: LSI_SORT_KEY

packages/@aws-cdk/aws-dynamodb/test/integ.dynamodb.ts

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,20 @@ const app = new App();
4141

4242
const stack = new Stack(app, STACK_NAME);
4343

44-
const table = new Table(stack, TABLE, {});
45-
table.addPartitionKey(TABLE_PARTITION_KEY);
44+
const table = new Table(stack, TABLE, {
45+
partitionKey: TABLE_PARTITION_KEY
46+
});
4647

4748
const tableWithGlobalAndLocalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_AND_LOCAL_SECONDARY_INDEX, {
4849
pitrEnabled: true,
4950
sseEnabled: true,
5051
streamSpecification: StreamViewType.KeysOnly,
51-
ttlAttributeName: 'timeToLive'
52+
ttlAttributeName: 'timeToLive',
53+
partitionKey: TABLE_PARTITION_KEY,
54+
sortKey: TABLE_SORT_KEY
5255
});
5356

5457
tableWithGlobalAndLocalSecondaryIndex.node.apply(new Tag('Environment', 'Production'));
55-
tableWithGlobalAndLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
56-
tableWithGlobalAndLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
5758
tableWithGlobalAndLocalSecondaryIndex.addGlobalSecondaryIndex({
5859
indexName: GSI_TEST_CASE_1,
5960
partitionKey: GSI_PARTITION_KEY,
@@ -104,16 +105,19 @@ tableWithGlobalAndLocalSecondaryIndex.addLocalSecondaryIndex({
104105
nonKeyAttributes: LSI_NON_KEY
105106
});
106107

107-
const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, {});
108-
tableWithGlobalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
108+
const tableWithGlobalSecondaryIndex = new Table(stack, TABLE_WITH_GLOBAL_SECONDARY_INDEX, {
109+
partitionKey: TABLE_PARTITION_KEY
110+
});
109111
tableWithGlobalSecondaryIndex.addGlobalSecondaryIndex({
110112
indexName: GSI_TEST_CASE_1,
111113
partitionKey: GSI_PARTITION_KEY
112114
});
113115

114-
const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, {});
115-
tableWithLocalSecondaryIndex.addPartitionKey(TABLE_PARTITION_KEY);
116-
tableWithLocalSecondaryIndex.addSortKey(TABLE_SORT_KEY);
116+
const tableWithLocalSecondaryIndex = new Table(stack, TABLE_WITH_LOCAL_SECONDARY_INDEX, {
117+
partitionKey: TABLE_PARTITION_KEY,
118+
sortKey: TABLE_SORT_KEY
119+
});
120+
117121
tableWithLocalSecondaryIndex.addLocalSecondaryIndex({
118122
indexName: LSI_TEST_CASE_1,
119123
sortKey: LSI_SORT_KEY

0 commit comments

Comments
 (0)