@@ -255,6 +255,73 @@ extension GenericAWSDynamoDBCompositePrimaryKeyTable {
255255 )
256256 }
257257
258+ private func getErrorReasons< AttributesType> (
259+ cancellationReasons: [ DynamoDBClientTypes . CancellationReason ] ,
260+ keys: [ CompositePrimaryKey < AttributesType > ] ,
261+ entryCount: Int
262+ ) throws -> ( reasons: [ DynamoDBTableError ] , isTransactionConflict: Bool ) {
263+ var isTransactionConflict = false
264+ let reasons = try zip ( cancellationReasons, keys) . compactMap {
265+ cancellationReason,
266+ entryKey -> DynamoDBTableError ? in
267+ let key : CompositePrimaryKey < AttributesType > ? =
268+ if let item = cancellationReason. item {
269+ try DynamoDBDecoder ( ) . decode ( . m( item) )
270+ } else {
271+ nil
272+ }
273+
274+ let partitionKey = key? . partitionKey ?? entryKey. partitionKey
275+ let sortKey = key? . sortKey ?? entryKey. sortKey
276+
277+ // https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ExecuteTransaction.html
278+ switch cancellationReason. code {
279+ case " None " :
280+ return nil
281+ case " ConditionalCheckFailed " :
282+ return DynamoDBTableError . conditionalCheckFailed (
283+ partitionKey: partitionKey,
284+ sortKey: sortKey,
285+ message: cancellationReason. message
286+ )
287+ case " DuplicateItem " :
288+ return DynamoDBTableError . duplicateItem (
289+ partitionKey: partitionKey,
290+ sortKey: sortKey,
291+ message: cancellationReason. message
292+ )
293+ case " ItemCollectionSizeLimitExceeded " :
294+ return DynamoDBTableError . itemCollectionSizeLimitExceeded (
295+ attemptedSize: entryCount,
296+ maximumSize: AWSDynamoDBLimits . maximumUpdatesPerTransactionStatement
297+ )
298+ case " TransactionConflict " :
299+ isTransactionConflict = true
300+
301+ return DynamoDBTableError . transactionConflict ( message: cancellationReason. message)
302+ case " ProvisionedThroughputExceeded " :
303+ return DynamoDBTableError . provisionedThroughputExceeded ( message: cancellationReason. message)
304+ case " ThrottlingError " :
305+ return DynamoDBTableError . throttling ( message: cancellationReason. message)
306+ case " ValidationError " :
307+ return DynamoDBTableError . validation (
308+ partitionKey: partitionKey,
309+ sortKey: sortKey,
310+ message: cancellationReason. message
311+ )
312+ default :
313+ return DynamoDBTableError . unknown (
314+ code: cancellationReason. code,
315+ partitionKey: partitionKey,
316+ sortKey: sortKey,
317+ message: cancellationReason. message
318+ )
319+ }
320+ }
321+
322+ return ( reasons, isTransactionConflict)
323+ }
324+
258325 private func transactWrite< AttributesType, ItemType, TimeToLiveAttributesType> (
259326 _ entries: [ WriteEntry < AttributesType , ItemType , TimeToLiveAttributesType > ] ,
260327 constraints: [ TransactionConstraintEntry < AttributesType , ItemType , TimeToLiveAttributesType > ] ,
@@ -281,64 +348,11 @@ extension GenericAWSDynamoDBCompositePrimaryKeyTable {
281348
282349 let keys = entries. map ( \. compositePrimaryKey) + constraints. map ( \. compositePrimaryKey)
283350
284- var isTransactionConflict = false
285- let reasons = try zip ( cancellationReasons, keys) . compactMap {
286- cancellationReason,
287- entryKey -> DynamoDBTableError ? in
288- let key : CompositePrimaryKey < AttributesType > ? =
289- if let item = cancellationReason. item {
290- try DynamoDBDecoder ( ) . decode ( . m( item) )
291- } else {
292- nil
293- }
294-
295- let partitionKey = key? . partitionKey ?? entryKey. partitionKey
296- let sortKey = key? . sortKey ?? entryKey. sortKey
297-
298- // https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ExecuteTransaction.html
299- switch cancellationReason. code {
300- case " None " :
301- return nil
302- case " ConditionalCheckFailed " :
303- return DynamoDBTableError . conditionalCheckFailed (
304- partitionKey: partitionKey,
305- sortKey: sortKey,
306- message: cancellationReason. message
307- )
308- case " DuplicateItem " :
309- return DynamoDBTableError . duplicateItem (
310- partitionKey: partitionKey,
311- sortKey: sortKey,
312- message: cancellationReason. message
313- )
314- case " ItemCollectionSizeLimitExceeded " :
315- return DynamoDBTableError . itemCollectionSizeLimitExceeded (
316- attemptedSize: entryCount,
317- maximumSize: AWSDynamoDBLimits . maximumUpdatesPerTransactionStatement
318- )
319- case " TransactionConflict " :
320- isTransactionConflict = true
321-
322- return DynamoDBTableError . transactionConflict ( message: cancellationReason. message)
323- case " ProvisionedThroughputExceeded " :
324- return DynamoDBTableError . provisionedThroughputExceeded ( message: cancellationReason. message)
325- case " ThrottlingError " :
326- return DynamoDBTableError . throttling ( message: cancellationReason. message)
327- case " ValidationError " :
328- return DynamoDBTableError . validation (
329- partitionKey: partitionKey,
330- sortKey: sortKey,
331- message: cancellationReason. message
332- )
333- default :
334- return DynamoDBTableError . unknown (
335- code: cancellationReason. code,
336- partitionKey: partitionKey,
337- sortKey: sortKey,
338- message: cancellationReason. message
339- )
340- }
341- }
351+ let ( reasons, isTransactionConflict) = try getErrorReasons (
352+ cancellationReasons: cancellationReasons,
353+ keys: keys,
354+ entryCount: entryCount
355+ )
342356
343357 if isTransactionConflict, retriesRemaining > 0 {
344358 return try await retryTransactWrite (
@@ -413,64 +427,11 @@ extension GenericAWSDynamoDBCompositePrimaryKeyTable {
413427 throw DynamoDBTableError . transactionCanceled ( reasons: [ ] )
414428 }
415429
416- var isTransactionConflict = false
417- let reasons = try zip ( cancellationReasons, inputKeys) . compactMap {
418- cancellationReason,
419- entryKey -> DynamoDBTableError ? in
420- let key : CompositePrimaryKey < AttributesType > ? =
421- if let item = cancellationReason. item {
422- try DynamoDBDecoder ( ) . decode ( . m( item) )
423- } else {
424- nil
425- }
426-
427- let partitionKey = key? . partitionKey ?? entryKey. partitionKey
428- let sortKey = key? . sortKey ?? entryKey. sortKey
429-
430- // https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_ExecuteTransaction.html
431- switch cancellationReason. code {
432- case " None " :
433- return nil
434- case " ConditionalCheckFailed " :
435- return DynamoDBTableError . conditionalCheckFailed (
436- partitionKey: partitionKey,
437- sortKey: sortKey,
438- message: cancellationReason. message
439- )
440- case " DuplicateItem " :
441- return DynamoDBTableError . duplicateItem (
442- partitionKey: partitionKey,
443- sortKey: sortKey,
444- message: cancellationReason. message
445- )
446- case " ItemCollectionSizeLimitExceeded " :
447- return DynamoDBTableError . itemCollectionSizeLimitExceeded (
448- attemptedSize: inputKeys. count,
449- maximumSize: AWSDynamoDBLimits . maximumUpdatesPerTransactionStatement
450- )
451- case " TransactionConflict " :
452- isTransactionConflict = true
453-
454- return DynamoDBTableError . transactionConflict ( message: cancellationReason. message)
455- case " ProvisionedThroughputExceeded " :
456- return DynamoDBTableError . provisionedThroughputExceeded ( message: cancellationReason. message)
457- case " ThrottlingError " :
458- return DynamoDBTableError . throttling ( message: cancellationReason. message)
459- case " ValidationError " :
460- return DynamoDBTableError . validation (
461- partitionKey: partitionKey,
462- sortKey: sortKey,
463- message: cancellationReason. message
464- )
465- default :
466- return DynamoDBTableError . unknown (
467- code: cancellationReason. code,
468- partitionKey: partitionKey,
469- sortKey: sortKey,
470- message: cancellationReason. message
471- )
472- }
473- }
430+ let ( reasons, isTransactionConflict) = try getErrorReasons (
431+ cancellationReasons: cancellationReasons,
432+ keys: inputKeys,
433+ entryCount: inputKeys. count
434+ )
474435
475436 if isTransactionConflict, retriesRemaining > 0 {
476437 return try await retryPolymorphicTransactWrite (
0 commit comments