From d86787e4f5afd34b926d9a0eb552791b43892943 Mon Sep 17 00:00:00 2001 From: tachyonics Date: Thu, 19 Sep 2024 17:13:10 +1000 Subject: [PATCH] Remove Sendable conformance from entry types (#44) Remove Sendable conformance from PolymorphicWriteEntry and PolymorphicTransactionConstraintEntry --- README.md | 6 +- ...CompositePrimaryKeyTable+updateItems.swift | 65 ++++++++++--------- .../DynamoDBCompositePrimaryKeyTable.swift | 6 +- ...moryDynamoDBCompositePrimaryKeyTable.swift | 27 +++----- ...ynamoDBCompositePrimaryKeyTableStore.swift | 4 +- ...oDBCompositePrimaryKeyTableWithIndex.swift | 6 +- .../PolymorphicWriteEntry.swift | 2 +- ...encyDynamoDBCompositePrimaryKeyTable.swift | 6 +- .../DynamoDBTablesMacros/BaseEntryMacro.swift | 18 ----- ...rVersionedItemWithHistoricalRowTests.swift | 20 +++--- ...bleUpdateItemConditionallyAtKeyTests.swift | 54 +++++++-------- ...ynamoDBCompositePrimaryKeyTableTests.swift | 30 ++++----- ...ynamoDBCompositePrimaryKeyTableTests.swift | 4 +- .../String+DynamoDBKeyTests.swift | 6 +- .../TestConfiguration.swift | 4 +- ...Item+RowWithItemVersionProtocolTests.swift | 24 +++---- 16 files changed, 125 insertions(+), 157 deletions(-) diff --git a/README.md b/README.md index 1455fdd..94eebe9 100644 --- a/README.md +++ b/README.md @@ -370,7 +370,7 @@ and similarly for polymorphic queries, most conveniently by using the `@Polymorp typealias TestTypeBWriteEntry = StandardWriteEntry @PolymorphicWriteEntry -enum TestPolymorphicWriteEntry: Sendable { +enum TestPolymorphicWriteEntry { case testTypeA(TestTypeAWriteEntry) case testTypeB(TestTypeBWriteEntry) } @@ -407,7 +407,7 @@ typealias TestTypeAStandardTransactionConstraintEntry = StandardTransactionConst typealias TestTypeBStandardTransactionConstraintEntry = StandardTransactionConstraintEntry @PolymorphicTransactionConstraintEntry -enum TestPolymorphicTransactionConstraintEntry: Sendable { +enum TestPolymorphicTransactionConstraintEntry { case testTypeA(TestTypeAStandardTransactionConstraintEntry) case testTypeB(TestTypeBStandardTransactionConstraintEntry) } @@ -428,7 +428,7 @@ about failed transactions. This is enabled by default when using the `@Polymorph ```swift @PolymorphicWriteEntry(passCompositePrimaryKey: false) -enum TestPolymorphicWriteEntry: Sendable { +enum TestPolymorphicWriteEntry { case testTypeA(TestTypeAWriteEntry) case testTypeB(TestTypeBWriteEntry) } diff --git a/Sources/DynamoDBTables/AWSDynamoDBCompositePrimaryKeyTable+updateItems.swift b/Sources/DynamoDBTables/AWSDynamoDBCompositePrimaryKeyTable+updateItems.swift index 3b21756..6887bab 100644 --- a/Sources/DynamoDBTables/AWSDynamoDBCompositePrimaryKeyTable+updateItems.swift +++ b/Sources/DynamoDBTables/AWSDynamoDBCompositePrimaryKeyTable+updateItems.swift @@ -175,12 +175,12 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { _ = try await dynamodb.executeTransaction(input: transactionInput) } - private func writeTransactionItems( - _ entries: [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry]) async throws + private func getExecuteTransactionInput( + _ entries: [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry]) throws -> ExecuteTransactionInput? { // if there are no items, there is nothing to update guard entries.count > 0 else { - return + return nil } let context = StandardPolymorphicWriteEntryContext]) async throws { @@ -216,16 +214,29 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { retriesRemaining: self.retryConfiguration.numRetries) } - func polymorphicTransactWrite(_ entries: [some PolymorphicWriteEntry]) async throws { + func polymorphicTransactWrite(_ entries: sending [some PolymorphicWriteEntry]) async throws { let noConstraints: [EmptyPolymorphicTransactionConstraintEntry] = [] - return try await self.polymorphicTransactWrite(entries, constraints: noConstraints, - retriesRemaining: self.retryConfiguration.numRetries) + + guard let transactionInput = try getExecuteTransactionInput(entries, constraints: noConstraints) else { + // nothing to do + return + } + let inputKeys = entries.map(\.compositePrimaryKey) + + try await self.polymorphicTransactWrite(transactionInput, inputKeys: inputKeys, + retriesRemaining: self.retryConfiguration.numRetries) } func polymorphicTransactWrite( - _ entries: [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry]) async throws + _ entries: sending [some PolymorphicWriteEntry], constraints: sending [some PolymorphicTransactionConstraintEntry]) async throws { - try await self.polymorphicTransactWrite(entries, constraints: constraints, + guard let transactionInput = try getExecuteTransactionInput(entries, constraints: constraints) else { + // nothing to do + return + } + let inputKeys = entries.map(\.compositePrimaryKey) + constraints.map(\.compositePrimaryKey) + + try await self.polymorphicTransactWrite(transactionInput, inputKeys: inputKeys, retriesRemaining: self.retryConfiguration.numRetries) } @@ -336,20 +347,15 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { return try await self.transactWrite(entries, constraints: constraints, retriesRemaining: retriesRemaining - 1) } - private func polymorphicTransactWrite( - _ entries: [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry], - retriesRemaining: Int) async throws - { - let entryCount = entries.count + constraints.count - - if entryCount > AWSDynamoDBLimits.maximumUpdatesPerTransactionStatement { - throw DynamoDBTableError.transactionSizeExceeded(attemptedSize: entryCount, + private func polymorphicTransactWrite(_ transactionInput: ExecuteTransactionInput, inputKeys: [StandardCompositePrimaryKey?], retriesRemaining: Int) async throws { + if inputKeys.count > AWSDynamoDBLimits.maximumUpdatesPerTransactionStatement { + throw DynamoDBTableError.transactionSizeExceeded(attemptedSize: inputKeys.count, maximumSize: AWSDynamoDBLimits.maximumUpdatesPerTransactionStatement) } let result: Swift.Result do { - try await self.writeTransactionItems(entries, constraints: constraints) + _ = try await dynamodb.executeTransaction(input: transactionInput) result = .success(()) } catch let exception as TransactionCanceledException { @@ -357,10 +363,8 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { throw DynamoDBTableError.transactionCanceled(reasons: []) } - let keys = entries.map(\.compositePrimaryKey) + constraints.map(\.compositePrimaryKey) - var isTransactionConflict = false - let reasons = try zip(cancellationReasons, keys).compactMap { cancellationReason, entryKey -> DynamoDBTableError? in + let reasons = try zip(cancellationReasons, inputKeys).compactMap { cancellationReason, entryKey -> DynamoDBTableError? in let key: StandardCompositePrimaryKey? if let item = cancellationReason.item { key = try DynamoDBDecoder().decode(.m(item)) @@ -383,7 +387,7 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { return DynamoDBTableError.duplicateItem(partitionKey: partitionKey, sortKey: sortKey, message: cancellationReason.message) case "ItemCollectionSizeLimitExceeded": - return DynamoDBTableError.transactionSizeExceeded(attemptedSize: entryCount, + return DynamoDBTableError.transactionSizeExceeded(attemptedSize: inputKeys.count, maximumSize: AWSDynamoDBLimits.maximumUpdatesPerTransactionStatement) case "TransactionConflict": isTransactionConflict = true @@ -403,13 +407,13 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { } if isTransactionConflict, retriesRemaining > 0 { - return try await retryPolymorphicTransactWrite(entries, constraints: constraints, retriesRemaining: retriesRemaining) + return try await retryPolymorphicTransactWrite(transactionInput, inputKeys: inputKeys, retriesRemaining: retriesRemaining) } result = .failure(DynamoDBTableError.transactionCanceled(reasons: reasons)) } catch let exception as TransactionConflictException { if retriesRemaining > 0 { - return try await retryPolymorphicTransactWrite(entries, constraints: constraints, retriesRemaining: retriesRemaining) + return try await retryPolymorphicTransactWrite(transactionInput, inputKeys: inputKeys, retriesRemaining: retriesRemaining) } let reason = DynamoDBTableError.transactionConflict(message: exception.message) @@ -428,10 +432,7 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { } } - private func retryPolymorphicTransactWrite( - _ entries: [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry], - retriesRemaining: Int) async throws - { + private func retryPolymorphicTransactWrite(_ transactionInput: ExecuteTransactionInput, inputKeys: [StandardCompositePrimaryKey?], retriesRemaining: Int) async throws { // determine the required interval let retryInterval = Int(self.retryConfiguration.getRetryInterval(retriesRemaining: retriesRemaining)) @@ -440,7 +441,7 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { try await Task.sleep(nanoseconds: UInt64(retryInterval) * millisecondsToNanoSeconds) logger.trace("Reattempting request due to remaining retries: \(retryInterval)") - return try await self.polymorphicTransactWrite(entries, constraints: constraints, retriesRemaining: retriesRemaining - 1) + return try await self.polymorphicTransactWrite(transactionInput, inputKeys: inputKeys, retriesRemaining: retriesRemaining - 1) } private func writeChunkedItems(_ entries: [some PolymorphicWriteEntry]) async throws { @@ -464,7 +465,7 @@ public extension AWSDynamoDBCompositePrimaryKeyTable { try self.throwOnBatchExecuteStatementErrors(response: response) } - func polymorphicBulkWrite(_ entries: [some PolymorphicWriteEntry]) async throws { + func polymorphicBulkWrite(_ entries: sending [some PolymorphicWriteEntry]) async throws { // BatchExecuteStatement has a maximum of 25 statements // This function handles pagination internally. let chunkedEntries = entries.chunked(by: AWSDynamoDBLimits.maximumUpdatesPerExecuteStatement) diff --git a/Sources/DynamoDBTables/DynamoDBCompositePrimaryKeyTable.swift b/Sources/DynamoDBTables/DynamoDBCompositePrimaryKeyTable.swift index f8444dd..15fa124 100644 --- a/Sources/DynamoDBTables/DynamoDBCompositePrimaryKeyTable.swift +++ b/Sources/DynamoDBTables/DynamoDBCompositePrimaryKeyTable.swift @@ -140,7 +140,7 @@ public protocol DynamoDBCompositePrimaryKeyTable { func transactWrite(_ entries: [WriteEntry]) async throws func polymorphicTransactWrite( - _ entries: [WriteEntryType]) async throws + _ entries: sending [WriteEntryType]) async throws /** * Provides the ability to bulk write database rows in a transaction. @@ -153,7 +153,7 @@ public protocol DynamoDBCompositePrimaryKeyTable { _ entries: [WriteEntry], constraints: [TransactionConstraintEntry]) async throws func polymorphicTransactWrite( - _ entries: [WriteEntryType], constraints: [TransactionConstraintEntryType]) async throws + _ entries: sending [WriteEntryType], constraints: sending [TransactionConstraintEntryType]) async throws /** * Provides the ability to bulk write database rows @@ -165,7 +165,7 @@ public protocol DynamoDBCompositePrimaryKeyTable { func bulkWriteWithoutThrowing(_ entries: [WriteEntry]) async throws -> Set - func polymorphicBulkWrite(_ entries: [WriteEntryType]) async throws + func polymorphicBulkWrite(_ entries: sending [WriteEntryType]) async throws /** * Retrieves an item from the database table. Returns nil if the item doesn't exist. diff --git a/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTable.swift b/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTable.swift index 8f88601..bb450aa 100644 --- a/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTable.swift +++ b/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTable.swift @@ -46,19 +46,10 @@ public typealias ExecuteItemFilterType = @Sendable (String, String, String, Poly public protocol InMemoryTransactionDelegate { /** - Inject errors into a `transactWrite` call. + Inject errors into a `transactWrite` or `polymorphicTransactWrite` call. */ - func injectErrors( - _ entries: [WriteEntry], constraints: [TransactionConstraintEntry], - table: InMemoryDynamoDBCompositePrimaryKeyTable) async throws -> [DynamoDBTableError] - - /** - Inject errors into a `polymorphicTransactWrite` call. - */ - func injectErrors( - _ entries: [WriteEntryType], constraints: [TransactionConstraintEntryType], - table: InMemoryDynamoDBCompositePrimaryKeyTable) async throws -> [DynamoDBTableError] + func injectErrors( + inputKeys: [CompositePrimaryKey?], table: InMemoryDynamoDBCompositePrimaryKeyTable) async throws -> [DynamoDBTableError] } public struct InMemoryDynamoDBCompositePrimaryKeyTable: DynamoDBCompositePrimaryKeyTable { @@ -116,30 +107,32 @@ public struct InMemoryDynamoDBCompositePrimaryKeyTable: DynamoDBCompositePrimary constraints: [TransactionConstraintEntry]) async throws { // if there is a transaction delegate and it wants to inject errors - if let errors = try await transactionDelegate?.injectErrors(entries, constraints: constraints, table: self), !errors.isEmpty { + let inputKeys = entries.map(\.compositePrimaryKey) + constraints.map(\.compositePrimaryKey) + if let errors = try await transactionDelegate?.injectErrors(inputKeys: inputKeys, table: self), !errors.isEmpty { throw DynamoDBTableError.transactionCanceled(reasons: errors) } return try await self.storeWrapper.bulkWrite(entries, constraints: constraints, isTransaction: true) } - public func polymorphicTransactWrite(_ entries: [some PolymorphicWriteEntry]) async throws { + public func polymorphicTransactWrite(_ entries: sending [some PolymorphicWriteEntry]) async throws { let noConstraints: [EmptyPolymorphicTransactionConstraintEntry] = [] return try await self.polymorphicTransactWrite(entries, constraints: noConstraints) } public func polymorphicTransactWrite( - _ entries: [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry]) async throws + _ entries: sending [some PolymorphicWriteEntry], constraints: sending [some PolymorphicTransactionConstraintEntry]) async throws { // if there is a transaction delegate and it wants to inject errors - if let errors = try await transactionDelegate?.injectErrors(entries, constraints: constraints, table: self), !errors.isEmpty { + let inputKeys = entries.map(\.compositePrimaryKey) + constraints.map(\.compositePrimaryKey) + if let errors = try await transactionDelegate?.injectErrors(inputKeys: inputKeys, table: self), !errors.isEmpty { throw DynamoDBTableError.transactionCanceled(reasons: errors) } return try await self.storeWrapper.polymorphicBulkWrite(entries, constraints: constraints, isTransaction: true) } - public func polymorphicBulkWrite(_ entries: [some PolymorphicWriteEntry]) async throws { + public func polymorphicBulkWrite(_ entries: sending [some PolymorphicWriteEntry]) async throws { let noConstraints: [EmptyPolymorphicTransactionConstraintEntry] = [] return try await self.storeWrapper.polymorphicBulkWrite(entries, constraints: noConstraints, isTransaction: false) } diff --git a/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTableStore.swift b/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTableStore.swift index 622ccd9..061ba79 100644 --- a/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTableStore.swift +++ b/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTableStore.swift @@ -232,7 +232,7 @@ actor InMemoryDynamoDBCompositePrimaryKeyTableStore { } func polymorphicBulkWrite( - _ entries: [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry], + _ entries: sending [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry], isTransaction: Bool) throws { let entryCount = entries.count + constraints.count @@ -664,7 +664,7 @@ extension InMemoryDynamoDBCompositePrimaryKeyTableStore { } func handlePolymorphicEntries( - entries: [some PolymorphicWriteEntry], isTransaction: Bool, + entries: sending [some PolymorphicWriteEntry], isTransaction: Bool, context: StandardPolymorphicWriteEntryContext) -> DynamoDBTableError? diff --git a/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTableWithIndex.swift b/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTableWithIndex.swift index b3d7315..1bcba84 100644 --- a/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTableWithIndex.swift +++ b/Sources/DynamoDBTables/InMemoryDynamoDBCompositePrimaryKeyTableWithIndex.swift @@ -86,17 +86,17 @@ public struct InMemoryDynamoDBCompositePrimaryKeyTableWithIndex(context: Context) throws -> Context.WriteEntryTransformType var compositePrimaryKey: StandardCompositePrimaryKey? { get } diff --git a/Sources/DynamoDBTables/SimulateConcurrencyDynamoDBCompositePrimaryKeyTable.swift b/Sources/DynamoDBTables/SimulateConcurrencyDynamoDBCompositePrimaryKeyTable.swift index 9192f4e..29e228c 100644 --- a/Sources/DynamoDBTables/SimulateConcurrencyDynamoDBCompositePrimaryKeyTable.swift +++ b/Sources/DynamoDBTables/SimulateConcurrencyDynamoDBCompositePrimaryKeyTable.swift @@ -116,17 +116,17 @@ public class SimulateConcurrencyDynamoDBCompositePrimaryKeyTable: DynamoDBCompos try await self.wrappedDynamoDBTable.transactWrite(entries, constraints: constraints) } - public func polymorphicTransactWrite(_ entries: [some PolymorphicWriteEntry]) async throws { + public func polymorphicTransactWrite(_ entries: sending [some PolymorphicWriteEntry]) async throws { try await self.wrappedDynamoDBTable.polymorphicTransactWrite(entries) } public func polymorphicTransactWrite( - _ entries: [some PolymorphicWriteEntry], constraints: [some PolymorphicTransactionConstraintEntry]) async throws + _ entries: sending [some PolymorphicWriteEntry], constraints: sending [some PolymorphicTransactionConstraintEntry]) async throws { try await self.wrappedDynamoDBTable.polymorphicTransactWrite(entries, constraints: constraints) } - public func polymorphicBulkWrite(_ entries: [some PolymorphicWriteEntry]) async throws { + public func polymorphicBulkWrite(_ entries: sending [some PolymorphicWriteEntry]) async throws { try await self.wrappedDynamoDBTable.polymorphicBulkWrite(entries) } diff --git a/Sources/DynamoDBTablesMacros/BaseEntryMacro.swift b/Sources/DynamoDBTablesMacros/BaseEntryMacro.swift index 7603d4f..1fe9b9d 100644 --- a/Sources/DynamoDBTablesMacros/BaseEntryMacro.swift +++ b/Sources/DynamoDBTablesMacros/BaseEntryMacro.swift @@ -30,7 +30,6 @@ protocol MacroAttributes { enum BaseEntryDiagnostic: String, DiagnosticMessage { case notAttachedToEnumDeclaration - case enumMustHaveSendableConformance case enumMustNotHaveZeroCases case enumCasesMustHaveASingleParameter @@ -46,8 +45,6 @@ enum BaseEntryDiagnostic: String, DiagnosticMessage switch self { case .notAttachedToEnumDeclaration: return "@\(Attributes.macroName) must be attached to an enum declaration." - case .enumMustHaveSendableConformance: - return "@\(Attributes.macroName) decorated enum must conform to Sendable." case .enumMustNotHaveZeroCases: return "@\(Attributes.macroName) decorated enum must be have at least a singe case." case .enumCasesMustHaveASingleParameter: @@ -131,21 +128,6 @@ enum BaseEntryMacro: ExtensionMacro { return partialResult } - // make sure the type is conforming to Sendable - let hasSendableConformance = declaration.inheritanceClause?.inheritedTypes.reduce(false) { partialResult, inheritedType in - if let identifierTypeSyntax = inheritedType.type.as(IdentifierTypeSyntax.self), identifierTypeSyntax.name.text == "Sendable" { - return true - } - - return partialResult - } ?? false - - guard hasSendableConformance else { - context.diagnose(.init(node: declaration, message: BaseEntryDiagnostic.enumMustHaveSendableConformance)) - - return [] - } - let memberBlock = enumDeclaration.memberBlock.members let caseMembers: [EnumCaseDeclSyntax] = memberBlock.compactMap { member in diff --git a/Tests/DynamoDBTablesTests/DynamoDBCompositePrimaryKeyTableClobberVersionedItemWithHistoricalRowTests.swift b/Tests/DynamoDBTablesTests/DynamoDBCompositePrimaryKeyTableClobberVersionedItemWithHistoricalRowTests.swift index c975166..6bfe236 100644 --- a/Tests/DynamoDBTablesTests/DynamoDBCompositePrimaryKeyTableClobberVersionedItemWithHistoricalRowTests.swift +++ b/Tests/DynamoDBTablesTests/DynamoDBCompositePrimaryKeyTableClobberVersionedItemWithHistoricalRowTests.swift @@ -52,15 +52,15 @@ struct DynamoDBCompositePrimaryKeyTableClobberVersionedItemWithHistoricalRowTest // the v0 row, copy of version 1 let key1 = StandardCompositePrimaryKey(partitionKey: partitionKey, sortKey: generateSortKey(withVersion: 0)) let item1: StandardTypedDatabaseItem> = try await table.getItem(forKey: key1)! - #expect(1 == item1.rowValue.itemVersion) - #expect(1 == item1.rowStatus.rowVersion) + #expect(item1.rowValue.itemVersion == 1) + #expect(item1.rowStatus.rowVersion == 1) #expect(payload1 == item1.rowValue.rowValue) // the v1 row, has version 1 let key2 = StandardCompositePrimaryKey(partitionKey: historicalPartitionKey, sortKey: generateSortKey(withVersion: 1)) let item2: StandardTypedDatabaseItem> = try await table.getItem(forKey: key2)! - #expect(1 == item2.rowValue.itemVersion) - #expect(1 == item2.rowStatus.rowVersion) + #expect(item2.rowValue.itemVersion == 1) + #expect(item2.rowStatus.rowVersion == 1) #expect(payload1 == item2.rowValue.rowValue) let payload2 = TestTypeA(firstly: "thirdly", secondly: "fourthly") @@ -74,22 +74,22 @@ struct DynamoDBCompositePrimaryKeyTableClobberVersionedItemWithHistoricalRowTest // the v0 row, copy of version 2 let key3 = StandardCompositePrimaryKey(partitionKey: partitionKey, sortKey: generateSortKey(withVersion: 0)) let item3: StandardTypedDatabaseItem> = try await table.getItem(forKey: key3)! - #expect(2 == item3.rowValue.itemVersion) - #expect(2 == item3.rowStatus.rowVersion) + #expect(item3.rowValue.itemVersion == 2) + #expect(item3.rowStatus.rowVersion == 2) #expect(payload2 == item3.rowValue.rowValue) // the v1 row, still has version 1 let key4 = StandardCompositePrimaryKey(partitionKey: historicalPartitionKey, sortKey: generateSortKey(withVersion: 1)) let item4: StandardTypedDatabaseItem> = try await table.getItem(forKey: key4)! - #expect(1 == item4.rowValue.itemVersion) - #expect(1 == item4.rowStatus.rowVersion) + #expect(item4.rowValue.itemVersion == 1) + #expect(item4.rowStatus.rowVersion == 1) #expect(payload1 == item4.rowValue.rowValue) // the v2 row, has version 2 let key5 = StandardCompositePrimaryKey(partitionKey: historicalPartitionKey, sortKey: generateSortKey(withVersion: 2)) let item5: StandardTypedDatabaseItem> = try await table.getItem(forKey: key5)! - #expect(2 == item5.rowValue.itemVersion) - #expect(1 == item5.rowStatus.rowVersion) + #expect(item5.rowValue.itemVersion == 2) + #expect(item5.rowStatus.rowVersion == 1) #expect(payload2 == item5.rowValue.rowValue) } } diff --git a/Tests/DynamoDBTablesTests/DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests.swift b/Tests/DynamoDBTablesTests/DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests.swift index 7a56d25..e8a77ce 100644 --- a/Tests/DynamoDBTablesTests/DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests.swift +++ b/Tests/DynamoDBTablesTests/DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests.swift @@ -62,9 +62,9 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) - #expect("firstlyX2" == secondRetrievedItem.rowValue.firstly) - #expect("secondlyX2" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") + #expect(secondRetrievedItem.rowValue.firstly == "firstlyX2") + #expect(secondRetrievedItem.rowValue.secondly == "secondlyX2") } @Test @@ -88,9 +88,9 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) - #expect("firstlyX2" == secondRetrievedItem.rowValue.firstly) - #expect("secondlyX2" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") + #expect(secondRetrievedItem.rowValue.firstly == "firstlyX2") + #expect(secondRetrievedItem.rowValue.secondly == "secondlyX2") } @Test @@ -117,9 +117,9 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) - #expect("firstlyX2" == secondRetrievedItem.rowValue.firstly) - #expect("secondlyX2" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") + #expect(secondRetrievedItem.rowValue.firstly == "firstlyX2") + #expect(secondRetrievedItem.rowValue.secondly == "secondlyX2") } @Test @@ -146,9 +146,9 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) - #expect("firstlyX2" == secondRetrievedItem.rowValue.firstly) - #expect("secondlyX2" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") + #expect(secondRetrievedItem.rowValue.firstly == "firstlyX2") + #expect(secondRetrievedItem.rowValue.secondly == "secondlyX2") } @Test @@ -183,10 +183,10 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") // Check the item hasn't been updated - #expect("firstly" == secondRetrievedItem.rowValue.firstly) - #expect("secondly" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.rowValue.firstly == "firstly") + #expect(secondRetrievedItem.rowValue.secondly == "secondly") } @Test @@ -221,10 +221,10 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") // Check the item hasn't been updated - #expect("firstly" == secondRetrievedItem.rowValue.firstly) - #expect("secondly" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.rowValue.firstly == "firstly") + #expect(secondRetrievedItem.rowValue.secondly == "secondly") } @Test @@ -259,10 +259,10 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") // Check the item hasn't been updated - #expect("firstly" == secondRetrievedItem.rowValue.firstly) - #expect("secondly" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.rowValue.firstly == "firstly") + #expect(secondRetrievedItem.rowValue.secondly == "secondly") } enum TestError: Error { @@ -313,10 +313,10 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") // Check the item hasn't been updated - #expect("firstly" == secondRetrievedItem.rowValue.firstly) - #expect("secondly" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.rowValue.firstly == "firstly") + #expect(secondRetrievedItem.rowValue.secondly == "secondly") } @Test @@ -367,10 +367,10 @@ struct DynamoDBCompositePrimaryKeyTableUpdateItemConditionallyAtKeyTests { let secondRetrievedItem: TestTypeADatabaseItem = try await table.getItem(forKey: key)! - #expect("sortId" == secondRetrievedItem.compositePrimaryKey.sortKey) + #expect(secondRetrievedItem.compositePrimaryKey.sortKey == "sortId") // Check the item hasn't been updated - #expect("firstly" == secondRetrievedItem.rowValue.firstly) - #expect("secondly" == secondRetrievedItem.rowValue.secondly) + #expect(secondRetrievedItem.rowValue.firstly == "firstly") + #expect(secondRetrievedItem.rowValue.secondly == "secondly") } @Test diff --git a/Tests/DynamoDBTablesTests/InMemoryDynamoDBCompositePrimaryKeyTableTests.swift b/Tests/DynamoDBTablesTests/InMemoryDynamoDBCompositePrimaryKeyTableTests.swift index 6722996..2ee5323 100644 --- a/Tests/DynamoDBTablesTests/InMemoryDynamoDBCompositePrimaryKeyTableTests.swift +++ b/Tests/DynamoDBTablesTests/InMemoryDynamoDBCompositePrimaryKeyTableTests.swift @@ -570,7 +570,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.transactionCanceled(reasons: reasons) { // both required items are missing - #expect(2 == reasons.count) + #expect(reasons.count == 2) } catch { Issue.record() } @@ -675,7 +675,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.transactionCanceled(reasons: reasons) { // one required item exists, one has an incorrect version - #expect(1 == reasons.count) + #expect(reasons.count == 1) if let first = reasons.first { guard case .transactionConditionalCheckFailed = first else { @@ -723,7 +723,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.transactionCanceled(reasons: reasons) { // one required item exists, one has an incorrect version - #expect(1 == reasons.count) + #expect(reasons.count == 1) if let first = reasons.first { guard case .transactionConditionalCheckFailed = first else { @@ -810,7 +810,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.transactionCanceled(reasons: reasons) { // both required items are missing - #expect(2 == reasons.count) + #expect(reasons.count == 2) } catch { Issue.record() } @@ -915,7 +915,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.transactionCanceled(reasons: reasons) { // one required item exists, one has an incorrect version - #expect(1 == reasons.count) + #expect(reasons.count == 1) if let first = reasons.first { guard case .transactionConditionalCheckFailed = first else { @@ -961,7 +961,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.transactionCanceled(reasons: reasons) { // one required item exists, one has an incorrect version - #expect(1 == reasons.count) + #expect(reasons.count == 1) if let first = reasons.first { guard case .transactionConditionalCheckFailed = first else { @@ -981,16 +981,8 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { self.errors = errors } - func injectErrors( - _: [WriteEntry], constraints _: [TransactionConstraintEntry], - table _: InMemoryDynamoDBCompositePrimaryKeyTable) async throws -> [DynamoDBTableError] - { - self.errors - } - func injectErrors( - _: [some PolymorphicWriteEntry], constraints _: [some PolymorphicTransactionConstraintEntry], - table _: InMemoryDynamoDBCompositePrimaryKeyTable) async -> [DynamoDBTableError] + inputKeys _: [CompositePrimaryKey?], table _: InMemoryDynamoDBCompositePrimaryKeyTable) async throws -> [DynamoDBTableError] { self.errors } @@ -1080,7 +1072,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.transactionCanceled(reasons: reasons) { // one required item exists, one already exists - #expect(1 == reasons.count) + #expect(reasons.count == 1) if let first = reasons.first { guard case .duplicateItem = first else { @@ -1177,7 +1169,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.transactionCanceled(reasons: reasons) { // one required item exists, one already exists - #expect(1 == reasons.count) + #expect(reasons.count == 1) if let first = reasons.first { guard case .duplicateItem = first else { @@ -1251,7 +1243,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.batchErrorsReturned(errorCount, _) { // one required item exists, one already exists - #expect(1 == errorCount) + #expect(errorCount == 1) } catch { Issue.record() } @@ -1318,7 +1310,7 @@ struct InMemoryDynamoDBCompositePrimaryKeyTableTests { Issue.record() } catch let DynamoDBTableError.batchErrorsReturned(errorCount, _) { // one required item exists, one already exists - #expect(1 == errorCount) + #expect(errorCount == 1) } catch { Issue.record() } diff --git a/Tests/DynamoDBTablesTests/SimulateConcurrencyDynamoDBCompositePrimaryKeyTableTests.swift b/Tests/DynamoDBTablesTests/SimulateConcurrencyDynamoDBCompositePrimaryKeyTableTests.swift index 0b30dad..8967e67 100644 --- a/Tests/DynamoDBTablesTests/SimulateConcurrencyDynamoDBCompositePrimaryKeyTableTests.swift +++ b/Tests/DynamoDBTablesTests/SimulateConcurrencyDynamoDBCompositePrimaryKeyTableTests.swift @@ -157,7 +157,7 @@ struct SimulateConcurrencyDynamoDBCompositePrimaryKeyTableTests { } // should only fail five times - #expect(5 == errorCount) + #expect(errorCount == 5) try await table.deleteItem(forKey: key) @@ -202,7 +202,7 @@ struct SimulateConcurrencyDynamoDBCompositePrimaryKeyTableTests { } // should only fail five times - #expect(5 == errorCount) + #expect(errorCount == 5) try await table.deleteItem(forKey: key) diff --git a/Tests/DynamoDBTablesTests/String+DynamoDBKeyTests.swift b/Tests/DynamoDBTablesTests/String+DynamoDBKeyTests.swift index 471ef2f..621dead 100644 --- a/Tests/DynamoDBTablesTests/String+DynamoDBKeyTests.swift +++ b/Tests/DynamoDBTablesTests/String+DynamoDBKeyTests.swift @@ -39,9 +39,9 @@ struct StringDynamoDBKeyTests { @Test func dropAsDynamoDBKeyPrefix() { #expect(["one", "two"].dropAsDynamoDBKeyPrefix(from: "one.two.three.four.five.six")! == - "three.four.five.six") + "three.four.five.six") #expect([].dropAsDynamoDBKeyPrefix(from: "one.two.three.four.five.six")! == - "one.two.three.four.five.six") + "one.two.three.four.five.six") #expect(["four", "two"].dropAsDynamoDBKeyPrefix(from: "one.two.three.four.five.six") == nil) } @@ -59,7 +59,7 @@ struct StringDynamoDBKeyTests { #expect(["one"].dynamodbKeyWithPrefixedVersion(8, minimumFieldWidth: 5) == "v00008.one") #expect(["one", "two"].dynamodbKeyWithPrefixedVersion(8, minimumFieldWidth: 5) == "v00008.one.two") #expect(["one", "two", "three", "four", "five", "six"].dynamodbKeyWithPrefixedVersion(8, minimumFieldWidth: 5) == - "v00008.one.two.three.four.five.six") + "v00008.one.two.three.four.five.six") #expect(["one", "two"].dynamodbKeyWithPrefixedVersion(8, minimumFieldWidth: 2) == "v08.one.two") #expect(["one", "two"].dynamodbKeyWithPrefixedVersion(4888, minimumFieldWidth: 2) == "v4888.one.two") diff --git a/Tests/DynamoDBTablesTests/TestConfiguration.swift b/Tests/DynamoDBTablesTests/TestConfiguration.swift index 4906b28..6d9b482 100644 --- a/Tests/DynamoDBTablesTests/TestConfiguration.swift +++ b/Tests/DynamoDBTablesTests/TestConfiguration.swift @@ -82,13 +82,13 @@ typealias TestTypeAStandardTransactionConstraintEntry = StandardTransactionConst typealias TestTypeBStandardTransactionConstraintEntry = StandardTransactionConstraintEntry @PolymorphicWriteEntry -enum TestPolymorphicWriteEntry: Sendable { +enum TestPolymorphicWriteEntry { case testTypeA(TestTypeAWriteEntry) case testTypeB(TestTypeBWriteEntry) } @PolymorphicTransactionConstraintEntry -enum TestPolymorphicTransactionConstraintEntry: Sendable { +enum TestPolymorphicTransactionConstraintEntry { case testTypeA(TestTypeAStandardTransactionConstraintEntry) case testTypeB(TestTypeBStandardTransactionConstraintEntry) } diff --git a/Tests/DynamoDBTablesTests/TypedDatabaseItem+RowWithItemVersionProtocolTests.swift b/Tests/DynamoDBTablesTests/TypedDatabaseItem+RowWithItemVersionProtocolTests.swift index c88f2c4..d31c426 100644 --- a/Tests/DynamoDBTablesTests/TypedDatabaseItem+RowWithItemVersionProtocolTests.swift +++ b/Tests/DynamoDBTablesTests/TypedDatabaseItem+RowWithItemVersionProtocolTests.swift @@ -45,12 +45,12 @@ struct TypedDatabaseItemRowWithItemVersionProtocolTests { let updatedItem = try databaseItem.createUpdatedRowWithItemVersion(withValue: "Updated", conditionalStatusVersion: nil) - #expect(1 == databaseItem.rowStatus.rowVersion) - #expect(1 == databaseItem.rowValue.itemVersion) + #expect(databaseItem.rowStatus.rowVersion == 1) + #expect(databaseItem.rowValue.itemVersion == 1) #expect(ORIGINAL_PAYLOAD == databaseItem.rowValue.rowValue) #expect(databaseItem.timeToLive == nil) - #expect(2 == updatedItem.rowStatus.rowVersion) - #expect(2 == updatedItem.rowValue.itemVersion) + #expect(updatedItem.rowStatus.rowVersion == 2) + #expect(updatedItem.rowValue.itemVersion == 2) #expect(UPDATED_PAYLOAD == updatedItem.rowValue.rowValue) #expect(updatedItem.timeToLive == nil) } @@ -68,12 +68,12 @@ struct TypedDatabaseItemRowWithItemVersionProtocolTests { conditionalStatusVersion: nil, andTimeToLive: StandardTimeToLive(timeToLiveTimestamp: 234_567_890)) - #expect(1 == databaseItem.rowStatus.rowVersion) - #expect(1 == databaseItem.rowValue.itemVersion) + #expect(databaseItem.rowStatus.rowVersion == 1) + #expect(databaseItem.rowValue.itemVersion == 1) #expect(ORIGINAL_PAYLOAD == databaseItem.rowValue.rowValue) #expect(ORIGINAL_TIME_TO_LIVE == databaseItem.timeToLive?.timeToLiveTimestamp) - #expect(2 == updatedItem.rowStatus.rowVersion) - #expect(2 == updatedItem.rowValue.itemVersion) + #expect(updatedItem.rowStatus.rowVersion == 2) + #expect(updatedItem.rowValue.itemVersion == 2) #expect(UPDATED_PAYLOAD == updatedItem.rowValue.rowValue) #expect(UPDATED_TIME_TO_LIVE == updatedItem.timeToLive?.timeToLiveTimestamp) } @@ -88,11 +88,11 @@ struct TypedDatabaseItemRowWithItemVersionProtocolTests { let updatedItem = try databaseItem.createUpdatedRowWithItemVersion(withValue: "Updated", conditionalStatusVersion: 1) - #expect(1 == databaseItem.rowStatus.rowVersion) - #expect(1 == databaseItem.rowValue.itemVersion) + #expect(databaseItem.rowStatus.rowVersion == 1) + #expect(databaseItem.rowValue.itemVersion == 1) #expect(ORIGINAL_PAYLOAD == databaseItem.rowValue.rowValue) - #expect(2 == updatedItem.rowStatus.rowVersion) - #expect(2 == updatedItem.rowValue.itemVersion) + #expect(updatedItem.rowStatus.rowVersion == 2) + #expect(updatedItem.rowValue.itemVersion == 2) #expect(UPDATED_PAYLOAD == updatedItem.rowValue.rowValue) }