Skip to content

Commit ec72cd7

Browse files
committed
Do not create a type index if we only have one model type in the table.
1 parent 420aec4 commit ec72cd7

File tree

3 files changed

+35
-19
lines changed

3 files changed

+35
-19
lines changed

lib/table.js

Lines changed: 31 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,7 @@ class Table {
105105
AttributeDefinitions: uniqueRequiredAttributes,
106106
KeySchema: tableKeySchema,
107107
BillingMode: 'PAY_PER_REQUEST',
108-
GlobalSecondaryIndexes: requiredIndexes.map(x => x.index),
108+
...(requiredIndexes.length && {GlobalSecondaryIndexes: requiredIndexes.map(x => x.index)})
109109
}));
110110
} catch (err) {
111111
// ResourceInUseException is only thrown if the table already exists
@@ -272,8 +272,11 @@ class Table {
272272
}
273273

274274
#requiredIndexes() {
275-
const requiredIndexes = [
276-
{
275+
const requiredIndexes = [];
276+
// Only require the type index if we have multiple schemas in this
277+
// table, to support single-model tables mode efficiently:
278+
if (this.#models.size > 1) {
279+
requiredIndexes.push({
277280
index: {
278281
// The built-in type index,
279282
IndexName: 'type',
@@ -289,8 +292,8 @@ class Table {
289292
],
290293
hashKey: this.#typeFieldName,
291294
sortKey: this.#idFieldName
292-
}
293-
];
295+
});
296+
}
294297
for (const schema of this.#models.keys()) {
295298
requiredIndexes.push(...schema[kSchemaIndices]);
296299
}
@@ -301,6 +304,15 @@ class Table {
301304
const uniqueRequiredAttributes = [];
302305
const attributeTypes = new Map();
303306
const indexNames = new Map();
307+
308+
// The table hash key is always the ID field, and while it is not an
309+
// index field, it is a required attribute type that we need to check
310+
// compatibility with:
311+
allRequiredIndexes = [{
312+
requiredAttributes: [
313+
{ AttributeName: this.#idFieldName, AttributeType: 'S' },
314+
]
315+
}].concat(allRequiredIndexes);
304316
for (const {index, requiredAttributes} of allRequiredIndexes) {
305317
for (const {AttributeName, AttributeType} of requiredAttributes) {
306318
// store all the types we encounter for each attribute name for comparison:
@@ -326,21 +338,23 @@ class Table {
326338
throw new Error(`Schema(s) "${offendingSchemas.join(', ')}" define incompatible types (${offendingDefinitions.join(',')}) for ".${AttributeName}" in index(es) "${offendingIndexes.join(', ')}".`);
327339
}
328340
}
329-
if(!indexNames.has(index.IndexName)) {
330-
indexNames.set(index.IndexName, index);
331-
} else if(!indexDescriptionsEqual(index, indexNames.get(index.IndexName))) {
332-
let offendingSchemas = [];
333-
let offendingDefinitions = [];
334-
for (const schema of this.#models.keys()) {
335-
for (const schemaIndex of schema[kSchemaIndices]) {
336-
if (schemaIndex.index.IndexName === index.IndexName) {
337-
offendingSchemas.push(schema.name);
338-
offendingDefinitions.push(schemaIndex.index);
339-
break;
341+
if (index) {
342+
if(!indexNames.has(index.IndexName)) {
343+
indexNames.set(index.IndexName, index);
344+
} else if(!indexDescriptionsEqual(index, indexNames.get(index.IndexName))) {
345+
let offendingSchemas = [];
346+
let offendingDefinitions = [];
347+
for (const schema of this.#models.keys()) {
348+
for (const schemaIndex of schema[kSchemaIndices]) {
349+
if (schemaIndex.index.IndexName === index.IndexName) {
350+
offendingSchemas.push(schema.name);
351+
offendingDefinitions.push(schemaIndex.index);
352+
break;
353+
}
340354
}
341355
}
356+
throw new Error(`Schema(s) "${offendingSchemas.join(', ')}" define incompatible versions of index "${index.IndexName}".`);
342357
}
343-
throw new Error(`Schema(s) "${offendingSchemas.join(', ')}" define incompatible versions of index "${index.IndexName}".`);
344358
}
345359
}
346360
return {uniqueRequiredAttributes};

readme.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -777,7 +777,7 @@ const result = await Comment.queryOne({
777777
**Querying for a two properties** named `field1`, and `field2`, equal to
778778
values `"v1"` and `2`. This requires an index that either:
779779
* has `field1` as its hash key, and `field2` as its sort key, or:
780-
* has `field2` as its hash key, and `field2` as its sort key.
780+
* has `field2` as its hash key, and `field1` as its sort key.
781781
782782
Note that this query may return multiple results, since neither hash key nor
783783
sort key values in global secondary indexes are necessarily unique.
@@ -1016,7 +1016,8 @@ console.log(await Comment.queryMany({ section: 'thread-123' }))
10161016
10171017
### Caveats for Indexes
10181018
A dynamoDB table supports up to 20 global secondary indexes in the default
1019-
quota. DynamoDM creates one built-in index on the id field.
1019+
quota. DynamoDM creates one built-in index on the type field, if a table
1020+
contains multiple types of models.
10201021
10211022
All documents in the same table share the same indexes, and all documents that
10221023
include a field that is used as the hash key of an index will be included in

test/multi.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ tap.test('crud with schema from separate module', async t => {
3636
additionalProperties: false
3737
});
3838
const Thing = table.model(ThingSchema);
39+
table.model(DynamoDM2.Schema('other'));
3940

4041
await table.ready();
4142

0 commit comments

Comments
 (0)