Skip to content

Commit

Permalink
feat(core): update client v2 to explicitely parse transaction response
Browse files Browse the repository at this point in the history
  • Loading branch information
whimzyLive committed Mar 14, 2022
1 parent 129b2f8 commit 824e808
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 149 deletions.
9 changes: 2 additions & 7 deletions packages/core/src/classes/manager/transaction-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import {
TRANSACTION_WRITE_ITEMS_LIMIT,
WriteTransactionItemLimitExceededError,
} from '@typedorm/common';
import {handleTransactionResult} from '../../helpers/handle-transaction-result';
import {ReadTransaction} from '../transaction/read-transaction';
import {MetadataOptions} from '../transformer/base-transformer';
import {getUniqueRequestId} from '../../helpers/get-unique-request-id';
Expand Down Expand Up @@ -128,12 +127,10 @@ export class TransactionManager {
ReturnConsumedCapacity: metadataOptions?.returnConsumedCapacity,
};

const transactionResult = this.connection.documentClient.transactGetRaw(
const response = await this.connection.documentClient.transactGet(
transactionInput
);

const response = await handleTransactionResult(transactionResult);

// log stats
if (response?.ConsumedCapacity) {
this.connection.logger.logStats({
Expand Down Expand Up @@ -187,12 +184,10 @@ export class TransactionManager {
log: `Running a transaction write request for ${transactItems.length} items.`,
});

const transactionRequest = this.connection.documentClient.transactWriteRaw(
const response = await this.connection.documentClient.transactWrite(
transactionInput
);

const response = await handleTransactionResult(transactionRequest);

// log stats
if (response?.ConsumedCapacity) {
this.connection.logger.logStats({
Expand Down

This file was deleted.

38 changes: 0 additions & 38 deletions packages/core/src/helpers/handle-transaction-result.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import {DynamoDB} from 'aws-sdk';
import {TransactionCancelledException} from './../../exceptions/transaction-cancelled-exception';
import {DynamoDB, Response} from 'aws-sdk';
import {DocumentClientV2} from '../document-client-v2';
import {DocumentClient} from '../base-document-client';

let dc: DocumentClient;
let dc: DocumentClientV2;

const awsDcMock = {
put: jest.fn(),
Expand All @@ -15,3 +15,62 @@ beforeEach(() => {
test('registers a valid documentClient instance', async () => {
expect(dc.version).toEqual(2);
});

test('handles dynamodb success response', async () => {
const request = {
on: jest.fn(),
send: jest.fn().mockImplementation(cb => {
cb(null, {
ConsumedCapacity: [{}],
ItemCollectionMetrics: [{}],
});
}),
} as any;
const parsedResponse = await (dc as any).handleTransactionResult(request);
expect(parsedResponse).toEqual({
ConsumedCapacity: [{}],
ItemCollectionMetrics: [{}],
});
});

test('correctly aggregates cancellation reasons', async () => {
const request = {
on: jest.fn().mockImplementation((type, cb) => {
const response = new Response();
response.httpResponse.body = Buffer.from(
JSON.stringify({
CancellationReasons: [
{
Code: 'ConditionalCheckFailed',
Message: 'Failed',
},
{
Code: 'TransactionConflict',
Message: 'Conflict',
},
],
})
);
cb(response);
}),
send: jest.fn().mockImplementation(cb => {
cb({code: 500});
}),
} as any;

try {
await (dc as any).handleTransactionResult(request);
} catch (err) {
expect(err).toBeInstanceOf(TransactionCancelledException);
expect((err as TransactionCancelledException).cancellationReasons).toEqual([
{
code: 'ConditionalCheckFailed',
message: 'Failed',
},
{
code: 'TransactionConflict',
message: 'Conflict',
},
]);
}
});
8 changes: 0 additions & 8 deletions packages/document-client/src/classes/base-document-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,18 +30,10 @@ export abstract class DocumentClient {
input: DocumentClientTypes.BatchGetItemInput
): Promise<DocumentClientTypes.BatchGetItemOutput>;

abstract transactGetRaw(
input: DocumentClientTypes.TransactGetItemInput
): DocumentClientTypes.Request<DocumentClientTypes.TransactGetItemOutput>;

abstract transactGet(
input: DocumentClientTypes.TransactGetItemInput
): Promise<DocumentClientTypes.TransactGetItemOutput>;

abstract transactWriteRaw(
input: DocumentClientTypes.TransactWriteItemInput
): DocumentClientTypes.Request<DocumentClientTypes.TransactWriteItemOutput>;

abstract transactWrite(
input: DocumentClientTypes.TransactWriteItemInput
): Promise<DocumentClientTypes.TransactWriteItemOutput>;
Expand Down
64 changes: 50 additions & 14 deletions packages/document-client/src/classes/document-client-v2.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {AWSError, DynamoDB, Request} from 'aws-sdk';
import {TransactionCancelledException} from '../exceptions';
import {DocumentClient} from './base-document-client';
export class DocumentClientV2<
DocumentClientType extends DynamoDB.DocumentClient = DynamoDB.DocumentClient
Expand Down Expand Up @@ -53,33 +54,68 @@ export class DocumentClientV2<
return this.documentClient.batchGet(input).promise();
}

transactGetRaw(
input: DynamoDB.DocumentClient.TransactGetItemsInput
): Request<DynamoDB.DocumentClient.TransactGetItemsOutput, AWSError> {
return this.documentClient.transactGet(input);
}

async transactGet(
input: DynamoDB.DocumentClient.TransactGetItemsInput
): Promise<DynamoDB.DocumentClient.TransactGetItemsOutput> {
return this.transactGetRaw(input).promise();
}

transactWriteRaw(
input: DynamoDB.DocumentClient.TransactWriteItemsInput
): Request<DynamoDB.DocumentClient.TransactWriteItemsOutput, AWSError> {
return this.documentClient.transactWrite(input);
const transactionResult = this.transactGetRaw(input);
return this.handleTransactionResult(transactionResult);
}

async transactWrite(
input: DynamoDB.DocumentClient.TransactWriteItemsInput
): Promise<DynamoDB.DocumentClient.TransactWriteItemsOutput> {
return this.transactWriteRaw(input).promise();
const transactionResult = this.transactWriteRaw(input);
return this.handleTransactionResult(transactionResult);
}

async scan(
input: DynamoDB.DocumentClient.ScanInput
): Promise<DynamoDB.DocumentClient.ScanOutput> {
return this.documentClient.scan(input).promise();
}

///
/// Private Methods
///
private transactGetRaw(
input: DynamoDB.DocumentClient.TransactGetItemsInput
): Request<DynamoDB.DocumentClient.TransactGetItemsOutput, AWSError> {
return this.documentClient.transactGet(input);
}

private transactWriteRaw(
input: DynamoDB.DocumentClient.TransactWriteItemsInput
): Request<DynamoDB.DocumentClient.TransactWriteItemsOutput, AWSError> {
return this.documentClient.transactWrite(input);
}

private handleTransactionResult<T>(transactionRequest: Request<T, AWSError>) {
let cancellationReasons: {Code: string; Message: string}[];
transactionRequest.on('extractError', response => {
try {
cancellationReasons = JSON.parse(response.httpResponse.body.toString())
.CancellationReasons;
} catch (err) {
// suppress this just in case some types of errors aren't JSON parsable
console.error('Error extracting cancellation error', err);
}
});

return new Promise((resolve, reject) => {
transactionRequest.send((err, response) => {
if (err) {
// pull all reasons from response and map them to errors
const reasons = cancellationReasons.map(reason => {
return {
code: reason.Code,
message: reason.Message,
};
});
return reject(new TransactionCancelledException(err.code, reasons));
}

return resolve(response);
});
}) as Promise<T>;
}
}
16 changes: 0 additions & 16 deletions packages/document-client/src/classes/document-client-v3.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ import {
TransactWriteCommand,
UpdateCommand,
} from '@aws-sdk/lib-dynamodb';
import {DocumentClientTypes} from '../types/document-client-types';
import {DocumentClient} from './base-document-client';

export class DocumentClientV3<
Expand Down Expand Up @@ -90,25 +89,10 @@ export class DocumentClientV3<
return this.documentClient.send(new BatchWriteCommand(input));
}

// TODO: Fix types declared for the responses and keys
async batchGet(input: BatchGetItemInput): Promise<BatchGetItemOutput> {
return this.documentClient.send(new BatchGetCommand(input));
}

// FIXME: implement transact raw methods for SDKv3
transactGetRaw(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
input: DocumentClientTypes.TransactGetItemInput
): DocumentClientTypes.Request<DocumentClientTypes.TransactGetItemOutput> {
throw new Error('Method not implemented.');
}
transactWriteRaw(
// eslint-disable-next-line @typescript-eslint/no-unused-vars
input: DocumentClientTypes.TransactWriteItemInput
): DocumentClientTypes.Request<DocumentClientTypes.TransactWriteItemOutput> {
throw new Error('Method not implemented.');
}

async transactGet(
input: TransactGetItemsInput
): Promise<TransactGetItemsOutput> {
Expand Down

0 comments on commit 824e808

Please sign in to comment.