Skip to content

Commit 5a248eb

Browse files
authored
Make monomorphic APIs the default by swapping the changing convention. (#22)
1 parent 64dbe05 commit 5a248eb

17 files changed

+599
-576
lines changed

README.md

Lines changed: 82 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,43 @@ The `deleteItem` operation will succeed even if the specified row doesn't exist
170170

171171
## Queries and Batch
172172

173-
All or a subset of the rows from a partition can be retrieved using a query-
173+
All or a subset of the rows from a partition can be retrieved using a query.
174+
175+
```swift
176+
let (queryItems, nextPageToken): ([StandardTypedDatabaseItem<TestTypeA>], String?) =
177+
try await table.query(forPartitionKey: "partitionId",
178+
sortKeyCondition: nil,
179+
limit: 100,
180+
exclusiveStartKey: exclusiveStartKey)
181+
182+
for databaseItem in queryItems {
183+
...
184+
}
185+
```
186+
187+
1. The sort key condition can restrict the query to a subset of the partition rows. A nil condition will return all rows in the partition.
188+
2. The `query` operation will fail if any of the rows being returned are not of type `TestTypeA`.
189+
3. The optional String returned by the `query` operation can be used as the `exclusiveStartKey` in another request to retrieve the next "page" of results from DynamoDB.
190+
4. There is an overload of the `query` operation that doesn't accept a `limit` or `exclusiveStartKey`. This overload will internally handle the API pagination, making multiple calls to DynamoDB if necessary.
191+
192+
There is also an equivalent `getItems` call that uses DynamoDB's BatchGetItem API-
193+
194+
```swift
195+
let batch: [StandardCompositePrimaryKey: StandardTypedDatabaseItem<TestTypeA>]
196+
= try await table.getItems(forKeys: [key1, key2])
197+
198+
guard let retrievedDatabaseItem1 = batch[key1] else {
199+
...
200+
}
201+
202+
guard let retrievedDatabaseItem2 = batch[key2] else {
203+
...
204+
}
205+
```
206+
207+
## Polymorphic Queries and Batch
208+
209+
In addition to the `query` operation, there is a more complex API that allows retrieval of multiple rows that have different types.
174210

175211
```swift
176212
enum TestPolymorphicOperationReturnType: PolymorphicOperationReturnType {
@@ -186,10 +222,10 @@ enum TestPolymorphicOperationReturnType: PolymorphicOperationReturnType {
186222
}
187223

188224
let (queryItems, nextPageToken): ([TestPolymorphicOperationReturnType], String?) =
189-
try await table.query(forPartitionKey: partitionId,
190-
sortKeyCondition: nil,
191-
limit: 100,
192-
exclusiveStartKey: exclusiveStartKey)
225+
try await table.polymorphicQuery(forPartitionKey: partitionId,
226+
sortKeyCondition: nil,
227+
limit: 100,
228+
exclusiveStartKey: exclusiveStartKey)
193229

194230
for item in queryItems {
195231
switch item {
@@ -200,15 +236,12 @@ for item in queryItems {
200236
}
201237
```
202238

203-
1. The sort key condition can restrict the query to a subset of the partition rows. A nil condition will return all rows in the partition.
204-
2. The `query` operation will fail if the partition contains rows that are not specified in the output `PolymorphicOperationReturnType` type.
205-
3. The optional String returned by the `query` operation can be used as the `exclusiveStartKey` in another request to retrieve the next "page" of results from DynamoDB.
206-
4. There is an overload of the `query` operation that doesn't accept a `limit` or `exclusiveStartKey`. This overload will internally handle the API pagination, making multiple calls to DynamoDB if necessary.
239+
1. The `polymorphicQuery` operation will fail if any of the rows being returned are not specified in the output `PolymorphicOperationReturnType` type.
207240

208241
A similar operation utilises DynamoDB's BatchGetItem API, returning items in a dictionary keyed by the provided `CompositePrimaryKey` instance-
209242

210243
```swift
211-
let batch: [StandardCompositePrimaryKey: TestPolymorphicOperationReturnType] = try await table.getItems(forKeys: [key1, key2])
244+
let batch: [StandardCompositePrimaryKey: TestPolymorphicOperationReturnType] = try await table.polymorphicGetItems(forKeys: [key1, key2])
212245

213246
guard case .testTypeA(let retrievedDatabaseItem1) = batch[key1] else {
214247
...
@@ -221,37 +254,6 @@ guard case .testTypeB(let retrievedDatabaseItem2) = batch[key2] else {
221254

222255
This operation will automatically handle retrying unprocessed items (with exponential backoff) if the table doesn't have the capacity during the initial request.
223256

224-
## Monomorphic Queries
225-
226-
In addition to the `query` operation, there is a seperate set of operations that provide a simpler API when a query will only retrieve rows of the same type.
227-
228-
```swift
229-
let (queryItems, nextPageToken): ([StandardTypedDatabaseItem<TestTypeA>], String?) =
230-
try await table.monomorphicQuery(forPartitionKey: "partitionId",
231-
sortKeyCondition: nil,
232-
limit: 100,
233-
exclusiveStartKey: exclusiveStartKey)
234-
235-
for databaseItem in queryItems {
236-
...
237-
}
238-
```
239-
240-
There is also an equivalent `monomorphicGetItems` DynamoDB's BatchGetItem API-
241-
242-
```swift
243-
let batch: [StandardCompositePrimaryKey: StandardTypedDatabaseItem<TestTypeA>]
244-
= try await table.monomorphicGetItems(forKeys: [key1, key2])
245-
246-
guard let retrievedDatabaseItem1 = batch[key1] else {
247-
...
248-
}
249-
250-
guard let retrievedDatabaseItem2 = batch[key2] else {
251-
...
252-
}
253-
```
254-
255257
## Queries on Indices
256258

257259
There are two mechanisms for querying on indices depending on if you have any projected attributes.
@@ -273,6 +275,20 @@ public struct GSI1PrimaryKeyAttributes: PrimaryKeyAttributes {
273275
}
274276
}
275277

278+
let (queryItems, nextPageToken): ([TypedDatabaseItem<GSI1PrimaryKeyAttributes, TestTypeA>], String?) =
279+
try await table.query(forPartitionKey: "partitionId",
280+
sortKeyCondition: nil,
281+
limit: 100,
282+
exclusiveStartKey: exclusiveStartKey)
283+
284+
for databaseItem in queryItems {
285+
...
286+
}
287+
```
288+
289+
and similarly for polymorphic queries-
290+
291+
```swift
276292
enum TestPolymorphicOperationReturnType: PolymorphicOperationReturnType {
277293
typealias AttributesType = GSI1PrimaryKeyAttributes
278294

@@ -286,7 +302,7 @@ enum TestPolymorphicOperationReturnType: PolymorphicOperationReturnType {
286302
}
287303

288304
let (queryItems, nextPageToken): ([TestPolymorphicOperationReturnType], String?) =
289-
try await table.query(forPartitionKey: partitionId,
305+
try await table.polymorphicQuery(forPartitionKey: partitionId,
290306
sortKeyCondition: nil,
291307
limit: 100,
292308
exclusiveStartKey: exclusiveStartKey)
@@ -300,20 +316,6 @@ for item in queryItems {
300316
}
301317
```
302318

303-
and similarly for monomorphic queries-
304-
305-
```swift
306-
let (queryItems, nextPageToken): ([TypedDatabaseItem<GSI1PrimaryKeyAttributes, TestTypeA>], String?) =
307-
try await table.monomorphicQuery(forPartitionKey: "partitionId",
308-
sortKeyCondition: nil,
309-
limit: 100,
310-
exclusiveStartKey: exclusiveStartKey)
311-
312-
for databaseItem in queryItems {
313-
...
314-
}
315-
```
316-
317319
### Using No Projected Attributes
318320

319321
To simply query a partition on an index that has no projected attributes, you can use the `DynamoDBCompositePrimaryKeysProjection` protocol and conforming types like ` AWSDynamoDBCompositePrimaryKeysProjection`. This type is created using a generator class in the same way as the primary table type-
@@ -347,6 +349,19 @@ You can write multiple database rows using either a bulk or [transaction](https:
347349

348350
```swift
349351
typealias TestTypeAWriteEntry = StandardWriteEntry<TestTypeA>
352+
353+
let entryList: [TestTypeAWriteEntry] = [
354+
.insert(new: databaseItem1),
355+
.insert(new: databaseItem2)
356+
]
357+
358+
try await table.bulkWrite(entryList)
359+
//try await table.transactWrite(entryList) <<-- When implemented
360+
```
361+
362+
and similarly for polymorphic queries-
363+
364+
```swift
350365
typealias TestTypeBWriteEntry = StandardWriteEntry<TestTypeB>
351366

352367
enum TestPolymorphicWriteEntry: PolymorphicWriteEntry {
@@ -365,17 +380,24 @@ enum TestPolymorphicWriteEntry: PolymorphicWriteEntry {
365380

366381
let entryList: [TestPolymorphicWriteEntry] = [
367382
.testTypeA(.insert(new: databaseItem1)),
368-
.testTypeB(.insert(new: databaseItem2))
383+
.testTypeB(.insert(new: databaseItem3))
369384
]
370385

371-
try await table.bulkWrite(entryList)
372-
try await table.transactWrite(entryList)
386+
try await table.polymorphicBulkWrite(entryList)
387+
try await table.polymorphicTransactWrite(entryList)
373388
```
374389

375390
For transactions, you can additionally specify a set of constraints to be part of the transaction-
376391

377392
```swift
378393
typealias TestTypeAStandardTransactionConstraintEntry = StandardTransactionConstraintEntry<TestTypeA>
394+
395+
// Update when `transactWrite` API implemented
396+
```
397+
398+
and similarly for polymorphic queries-
399+
400+
```swift
379401
typealias TestTypeBStandardTransactionConstraintEntry = StandardTransactionConstraintEntry<TestTypeB>
380402

381403
enum TestPolymorphicTransactionConstraintEntry: PolymorphicTransactionConstraintEntry {
@@ -397,7 +419,7 @@ let constraintList: [TestPolymorphicTransactionConstraintEntry] = [
397419
.testTypeB(.required(existing: databaseItem4))
398420
]
399421

400-
try await table.transactWrite(entryList, constraints: constraintList)
422+
try await table.polymorphicTransactWrite(entryList, constraints: constraintList)
401423
```
402424

403425
Both the `PolymorphicWriteEntry` and `PolymorphicTransactionConstraintEntry` conforming types can

Sources/DynamoDBTables/AWSDynamoDBCompositePrimaryKeyTable+DynamoDBTableAsync.swift

Lines changed: 53 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -96,36 +96,36 @@ public extension AWSDynamoDBCompositePrimaryKeyTable {
9696
_ = try await self.dynamodb.deleteItem(input: deleteItemInput)
9797
}
9898

99-
func query<ReturnedType: PolymorphicOperationReturnType>(forPartitionKey partitionKey: String,
100-
sortKeyCondition: AttributeCondition?,
101-
consistentRead: Bool) async throws
99+
func polymorphicQuery<ReturnedType: PolymorphicOperationReturnType>(forPartitionKey partitionKey: String,
100+
sortKeyCondition: AttributeCondition?,
101+
consistentRead: Bool) async throws
102102
-> [ReturnedType]
103103
{
104-
try await self.partialQuery(forPartitionKey: partitionKey,
105-
sortKeyCondition: sortKeyCondition,
106-
exclusiveStartKey: nil,
107-
consistentRead: consistentRead)
104+
try await self.polymorphicPartialQuery(forPartitionKey: partitionKey,
105+
sortKeyCondition: sortKeyCondition,
106+
exclusiveStartKey: nil,
107+
consistentRead: consistentRead)
108108
}
109109

110110
// function to return a future with the results of a query call and all future paginated calls
111-
private func partialQuery<ReturnedType: PolymorphicOperationReturnType>(
111+
private func polymorphicPartialQuery<ReturnedType: PolymorphicOperationReturnType>(
112112
forPartitionKey partitionKey: String,
113113
sortKeyCondition: AttributeCondition?,
114114
exclusiveStartKey: String?,
115115
consistentRead: Bool) async throws -> [ReturnedType]
116116
{
117117
let paginatedItems: ([ReturnedType], String?) =
118-
try await query(forPartitionKey: partitionKey,
119-
sortKeyCondition: sortKeyCondition,
120-
limit: nil,
121-
scanIndexForward: true,
122-
exclusiveStartKey: exclusiveStartKey,
123-
consistentRead: consistentRead)
118+
try await polymorphicQuery(forPartitionKey: partitionKey,
119+
sortKeyCondition: sortKeyCondition,
120+
limit: nil,
121+
scanIndexForward: true,
122+
exclusiveStartKey: exclusiveStartKey,
123+
consistentRead: consistentRead)
124124

125125
// if there are more items
126126
if let lastEvaluatedKey = paginatedItems.1 {
127127
// returns a future with all the results from all later paginated calls
128-
let partialResult: [ReturnedType] = try await self.partialQuery(
128+
let partialResult: [ReturnedType] = try await self.polymorphicPartialQuery(
129129
forPartitionKey: partitionKey,
130130
sortKeyCondition: sortKeyCondition,
131131
exclusiveStartKey: lastEvaluatedKey,
@@ -139,27 +139,27 @@ public extension AWSDynamoDBCompositePrimaryKeyTable {
139139
}
140140
}
141141

142-
func query<ReturnedType: PolymorphicOperationReturnType>(forPartitionKey partitionKey: String,
143-
sortKeyCondition: AttributeCondition?,
144-
limit: Int?,
145-
exclusiveStartKey: String?,
146-
consistentRead: Bool) async throws
142+
func polymorphicQuery<ReturnedType: PolymorphicOperationReturnType>(forPartitionKey partitionKey: String,
143+
sortKeyCondition: AttributeCondition?,
144+
limit: Int?,
145+
exclusiveStartKey: String?,
146+
consistentRead: Bool) async throws
147147
-> (items: [ReturnedType], lastEvaluatedKey: String?)
148148
{
149-
try await self.query(forPartitionKey: partitionKey,
150-
sortKeyCondition: sortKeyCondition,
151-
limit: limit,
152-
scanIndexForward: true,
153-
exclusiveStartKey: exclusiveStartKey,
154-
consistentRead: consistentRead)
149+
try await self.polymorphicQuery(forPartitionKey: partitionKey,
150+
sortKeyCondition: sortKeyCondition,
151+
limit: limit,
152+
scanIndexForward: true,
153+
exclusiveStartKey: exclusiveStartKey,
154+
consistentRead: consistentRead)
155155
}
156156

157-
func query<ReturnedType: PolymorphicOperationReturnType>(forPartitionKey partitionKey: String,
158-
sortKeyCondition: AttributeCondition?,
159-
limit: Int?,
160-
scanIndexForward: Bool,
161-
exclusiveStartKey: String?,
162-
consistentRead: Bool) async throws
157+
func polymorphicQuery<ReturnedType: PolymorphicOperationReturnType>(forPartitionKey partitionKey: String,
158+
sortKeyCondition: AttributeCondition?,
159+
limit: Int?,
160+
scanIndexForward: Bool,
161+
exclusiveStartKey: String?,
162+
consistentRead: Bool) async throws
163163
-> (items: [ReturnedType], lastEvaluatedKey: String?)
164164
{
165165
let queryInput = try AWSDynamoDB.QueryInput.forSortKeyCondition(partitionKey: partitionKey, targetTableName: targetTableName,
@@ -230,36 +230,36 @@ public extension AWSDynamoDBCompositePrimaryKeyTable {
230230
}
231231
}
232232

233-
func monomorphicQuery<AttributesType, ItemType>(forPartitionKey partitionKey: String,
234-
sortKeyCondition: AttributeCondition?,
235-
consistentRead: Bool) async throws
233+
func query<AttributesType, ItemType>(forPartitionKey partitionKey: String,
234+
sortKeyCondition: AttributeCondition?,
235+
consistentRead: Bool) async throws
236236
-> [TypedDatabaseItem<AttributesType, ItemType>]
237237
{
238-
try await self.monomorphicPartialQuery(forPartitionKey: partitionKey,
239-
sortKeyCondition: sortKeyCondition,
240-
exclusiveStartKey: nil,
241-
consistentRead: consistentRead)
238+
try await self.partialQuery(forPartitionKey: partitionKey,
239+
sortKeyCondition: sortKeyCondition,
240+
exclusiveStartKey: nil,
241+
consistentRead: consistentRead)
242242
}
243243

244244
// function to return a future with the results of a query call and all future paginated calls
245-
private func monomorphicPartialQuery<AttributesType, ItemType>(
245+
private func partialQuery<AttributesType, ItemType>(
246246
forPartitionKey partitionKey: String,
247247
sortKeyCondition: AttributeCondition?,
248248
exclusiveStartKey: String?,
249249
consistentRead: Bool) async throws -> [TypedDatabaseItem<AttributesType, ItemType>]
250250
{
251251
let paginatedItems: ([TypedDatabaseItem<AttributesType, ItemType>], String?) =
252-
try await monomorphicQuery(forPartitionKey: partitionKey,
253-
sortKeyCondition: sortKeyCondition,
254-
limit: nil,
255-
scanIndexForward: true,
256-
exclusiveStartKey: nil,
257-
consistentRead: consistentRead)
252+
try await query(forPartitionKey: partitionKey,
253+
sortKeyCondition: sortKeyCondition,
254+
limit: nil,
255+
scanIndexForward: true,
256+
exclusiveStartKey: nil,
257+
consistentRead: consistentRead)
258258

259259
// if there are more items
260260
if let lastEvaluatedKey = paginatedItems.1 {
261261
// returns a future with all the results from all later paginated calls
262-
let partialResult: [TypedDatabaseItem<AttributesType, ItemType>] = try await self.monomorphicPartialQuery(
262+
let partialResult: [TypedDatabaseItem<AttributesType, ItemType>] = try await self.partialQuery(
263263
forPartitionKey: partitionKey,
264264
sortKeyCondition: sortKeyCondition,
265265
exclusiveStartKey: lastEvaluatedKey,
@@ -273,12 +273,12 @@ public extension AWSDynamoDBCompositePrimaryKeyTable {
273273
}
274274
}
275275

276-
func monomorphicQuery<AttributesType, ItemType>(forPartitionKey partitionKey: String,
277-
sortKeyCondition: AttributeCondition?,
278-
limit: Int?,
279-
scanIndexForward: Bool,
280-
exclusiveStartKey: String?,
281-
consistentRead: Bool) async throws
276+
func query<AttributesType, ItemType>(forPartitionKey partitionKey: String,
277+
sortKeyCondition: AttributeCondition?,
278+
limit: Int?,
279+
scanIndexForward: Bool,
280+
exclusiveStartKey: String?,
281+
consistentRead: Bool) async throws
282282
-> (items: [TypedDatabaseItem<AttributesType, ItemType>], lastEvaluatedKey: String?)
283283
{
284284
let queryInput = try AWSDynamoDB.QueryInput.forSortKeyCondition(

0 commit comments

Comments
 (0)