From 928349aad6d2775f0b0732d5e3072a4a2bd41e1f Mon Sep 17 00:00:00 2001 From: Leo Singer Date: Mon, 16 Oct 2023 17:25:46 -0400 Subject: [PATCH] Support copying the most recent item to the counter table This is #20 as a one-liner. --- src/index.ts | 4 ++ src/test.ts | 141 +++++++++++++++++++++++++++++++-------------------- 2 files changed, 90 insertions(+), 55 deletions(-) diff --git a/src/index.ts b/src/index.ts index c8edd75..6d69c0e 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,6 +15,9 @@ export interface DynamoDBAutoIncrementProps { /** the name of the attribute in the table in which to store the last value of the counter */ counterTableAttributeName: string + /** whether to copy all of the attributes from the table to the counterTable */ + counterTableCopyItem?: boolean + /** the name of the table in which to store items */ tableName: string @@ -94,6 +97,7 @@ export class DynamoDBAutoIncrement { }, ExpressionAttributeValues, Item: { + ...(this.props.counterTableCopyItem ? item : {}), ...this.props.counterTableKey, [this.props.counterTableAttributeName]: nextCounter, }, diff --git a/src/test.ts b/src/test.ts index da5380f..23ed577 100644 --- a/src/test.ts +++ b/src/test.ts @@ -59,66 +59,97 @@ afterEach(async () => { ) }) -describe('dynamoDBAutoIncrement', () => { - test.each([undefined, 1, 2, 3])( - 'creates a new item with the correct ID when the old ID was %o', - async (lastID) => { - let nextID: number - if (lastID === undefined) { - nextID = 1 - } else { - await doc.put({ - TableName: 'autoincrement', - Item: { tableName: 'widgets', counter: lastID }, - }) - nextID = lastID + 1 +describe.each([false, true])( + 'counterTableCopyItem=%p', + (counterTableCopyItem) => { + beforeAll(async () => { + const options: DynamoDBAutoIncrementProps = { + doc, + counterTableName: 'autoincrement', + counterTableKey: { tableName: 'widgets' }, + counterTableAttributeName: 'counter', + counterTableCopyItem, + tableName: 'widgets', + tableAttributeName: 'widgetID', + initialValue: 1, } + autoincrement = new DynamoDBAutoIncrement(options) + autoincrementDangerously = new DynamoDBAutoIncrement({ + ...options, + dangerously: true, + }) + }) - const result = await autoincrement.put({ widgetName: 'runcible spoon' }) - expect(result).toEqual(nextID) + describe('dynamoDBAutoIncrement', () => { + test.each([undefined, 1, 2, 3])( + 'creates a new item with the correct ID when the old ID was %o', + async (lastID) => { + let nextID: number + if (lastID === undefined) { + nextID = 1 + } else { + await doc.put({ + TableName: 'autoincrement', + Item: { tableName: 'widgets', counter: lastID }, + }) + nextID = lastID + 1 + } - expect(await autoincrement.getLast()).toEqual(nextID) + const result = await autoincrement.put({ + widgetName: 'runcible spoon', + }) + expect(result).toEqual(nextID) - const [widgetItems, autoincrementItems] = await Promise.all( - ['widgets', 'autoincrement'].map( - async (TableName) => (await doc.scan({ TableName })).Items - ) - ) + expect(await autoincrement.getLast()).toEqual(nextID) - expect(widgetItems).toEqual([ - { widgetID: nextID, widgetName: 'runcible spoon' }, - ]) - expect(autoincrementItems).toEqual([ - { - tableName: 'widgets', - counter: nextID, - }, - ]) - } - ) + const [widgetItems, autoincrementItems] = await Promise.all( + ['widgets', 'autoincrement'].map( + async (TableName) => (await doc.scan({ TableName })).Items + ) + ) - test('correctly handles a large number of parallel puts', async () => { - const ids = Array.from(Array(N).keys()).map((i) => i + 1) - const result = await Promise.all(ids.map(() => autoincrement.put({}))) - expect(result.sort()).toEqual(ids.sort()) - }) -}) + expect(widgetItems).toEqual([ + { widgetID: nextID, widgetName: 'runcible spoon' }, + ]) + expect(autoincrementItems).toEqual([ + counterTableCopyItem + ? { + tableName: 'widgets', + counter: nextID, + widgetName: 'runcible spoon', + } + : { + tableName: 'widgets', + counter: nextID, + }, + ]) + } + ) -describe('dynamoDBAutoIncrement dangerously', () => { - test('correctly handles a large number of serial puts', async () => { - const ids = Array.from(Array(N).keys()).map((i) => i + 1) - const result: number[] = [] - for (const item of ids) { - result.push(await autoincrementDangerously.put({ widgetName: item })) - } - expect(result.sort()).toEqual(ids.sort()) - }) + test('correctly handles a large number of parallel puts', async () => { + const ids = Array.from(Array(N).keys()).map((i) => i + 1) + const result = await Promise.all(ids.map(() => autoincrement.put({}))) + expect(result.sort()).toEqual(ids.sort()) + }) + }) - test('fails on a large number of parallel puts', async () => { - const ids = Array.from(Array(N).keys()).map((i) => i + 1) - await expect( - async () => - await Promise.all(ids.map(() => autoincrementDangerously.put({}))) - ).rejects.toThrow(ConditionalCheckFailedException) - }) -}) + describe('dynamoDBAutoIncrement dangerously', () => { + test('correctly handles a large number of serial puts', async () => { + const ids = Array.from(Array(N).keys()).map((i) => i + 1) + const result: number[] = [] + for (const item of ids) { + result.push(await autoincrementDangerously.put({ widgetName: item })) + } + expect(result.sort()).toEqual(ids.sort()) + }) + + test('fails on a large number of parallel puts', async () => { + const ids = Array.from(Array(N).keys()).map((i) => i + 1) + await expect( + async () => + await Promise.all(ids.map(() => autoincrementDangerously.put({}))) + ).rejects.toThrow(ConditionalCheckFailedException) + }) + }) + } +)