From 129a068b5cba0ce380cc35f1998d416068530b06 Mon Sep 17 00:00:00 2001 From: Joe Smith Date: Mon, 12 Aug 2019 18:19:09 -0700 Subject: [PATCH 1/4] First pass at query support --- Sources/FluentDynamoDB/DynamoConnection.swift | 17 +++++++++++++- .../FluentDynamoDB/Query/DynamoQuery.swift | 23 +++++++++++++++++-- 2 files changed, 37 insertions(+), 3 deletions(-) diff --git a/Sources/FluentDynamoDB/DynamoConnection.swift b/Sources/FluentDynamoDB/DynamoConnection.swift index 2e94105..c4b726e 100644 --- a/Sources/FluentDynamoDB/DynamoConnection.swift +++ b/Sources/FluentDynamoDB/DynamoConnection.swift @@ -86,11 +86,13 @@ extension DynamoConnection: DatabaseQueryable { return try handler(Output(attributes: output.attributes)) } case .delete: - let inputItem: DynamoDB.DeleteItemInput = DynamoDB.DeleteItemInput( + let inputItem = DynamoDB.DeleteItemInput( key: requestedKey, returnValues: .allOld, tableName: query.table) return try self.handle.deleteItem(inputItem).map { output in return try handler(DynamoValue(attributes: output.attributes)) } + case .filter: + return self.eventLoop.newFailedFuture(error: DynamoConnectionError.notImplementedYet) } } catch { return self.eventLoop.newFailedFuture(error: error) @@ -136,7 +138,20 @@ extension DynamoConnection: DatabaseQueryable { case .delete: throw DynamoConnectionError.notImplementedYet + case .filter: + let queryInput = DynamoDB.QueryInput( + expressionAttributeNames: query.expressionAttributeNames, + expressionAttributeValues: query.expressionAttributeValues, + indexName: query.index, + keyConditionExpression: query.keyConditionExpression, + tableName: query.table) + return try self.handle.query(queryInput).map { (output: DynamoDB.QueryOutput) in + return output.items?.compactMap { (item: [String: DynamoDB.AttributeValue]) -> DynamoValue in + return DynamoValue(attributes: item) + } ?? [DynamoValue]() + } } + } catch { return self.eventLoop.newFailedFuture(error: error) } diff --git a/Sources/FluentDynamoDB/Query/DynamoQuery.swift b/Sources/FluentDynamoDB/Query/DynamoQuery.swift index ea21242..2a2f5e1 100644 --- a/Sources/FluentDynamoDB/Query/DynamoQuery.swift +++ b/Sources/FluentDynamoDB/Query/DynamoQuery.swift @@ -5,9 +5,12 @@ // Created by Joe Smith on 4/12/19. // +// Good sign of abstraction leakage +import DynamoDB + /// What type of request to make to DynamoDB public enum DynamoQueryAction { - case set, get, delete + case set, get, delete, filter } /// 🔎 A DynamoDB operation @@ -20,12 +23,28 @@ public struct DynamoQuery { /// 🍴 The name of the table in DynamoDB to work on public let table: String + /// ↪️ An optional (Globlal Secondary or Local) Index to query against + public let index: String? + /// 💸 Which value(s) to perform the action upon public let keys: [DynamoValue] - public init(action: DynamoQueryAction, table: String, keys: [DynamoValue]) { + public init(action: DynamoQueryAction, table: String, keys: [DynamoValue], index: String? = nil, expressionAttributeNames: [String: String]? = nil, expressionAttributeValues: [String: DynamoDB.AttributeValue]? = nil, keyConditionExpression: String? = nil) { self.action = action self.table = table self.keys = keys + self.index = index + + self.expressionAttributeNames = expressionAttributeNames + self.expressionAttributeValues = expressionAttributeValues + self.keyConditionExpression = keyConditionExpression } + +// Need to clean these up and figure out a better/simpler way to do queries. + /// `ExpressionAttributeNames` used when `filter`ing + public let expressionAttributeNames: [String: String]? + /// ExpressionAttributeValues used when `filter`ing + public let expressionAttributeValues: [String: DynamoDB.AttributeValue]? + /// 🔀 [KeyConditionExpression](https://docs.aws.amazon.com/amazondynamodb/latest/APIReference/API_Query.html#API_Query_RequestSyntax) which tells DynamoDB which queries to filter for. Only used when performing a `filter` action. + public let keyConditionExpression: String? } From 11fd0fdda5c77922c16126ca8e8ec0cc9096ee02 Mon Sep 17 00:00:00 2001 From: Joe Smith Date: Fri, 27 Sep 2019 13:55:09 -0700 Subject: [PATCH 2/4] Update to work with 5.1 --- Package.swift | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Package.swift b/Package.swift index 8b73a16..8d27157 100644 --- a/Package.swift +++ b/Package.swift @@ -14,7 +14,7 @@ let package = Package( .package(url: "https://github.com/vapor/fluent", from: "3.1.0"), // 💫 AWS Client Library - .package(url: "https://github.com/swift-aws/aws-sdk-swift", from: "3.0.0"), + .package(url: "https://github.com/swift-aws/aws-sdk-swift", .branch("yasumoto-5.1")), ], targets: [ .target( From 0fa612aff09f9c3985c453f5a6077b8f4a230f0f Mon Sep 17 00:00:00 2001 From: Joe Smith Date: Fri, 27 Sep 2019 13:58:50 -0700 Subject: [PATCH 3/4] Proper versioning requirements --- Package.resolved | 37 ++++++++++++++----------------------- Package.swift | 5 ++++- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/Package.resolved b/Package.resolved index f41502f..7910f0d 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,17 +6,17 @@ "repositoryURL": "https://github.com/swift-aws/aws-sdk-swift", "state": { "branch": null, - "revision": "bc557114b6c16f63780d35ac2c5c21bf5c9b8f12", - "version": "3.0.0" + "revision": "ed9cba4149087e19569d470867c73eff4b7ef552", + "version": "3.2.0" } }, { "package": "AWSSDKSwiftCore", - "repositoryURL": "https://github.com/swift-aws/aws-sdk-swift-core.git", + "repositoryURL": "https://github.com/swift-aws/aws-sdk-swift-core", "state": { - "branch": null, - "revision": "254c1e3f85414bf0f529f47cc081be2bd0c12c1c", - "version": "3.0.1" + "branch": "yasumoto-5.1", + "revision": "516c1df2d523406ff3234334d924f7149a242e2e", + "version": null } }, { @@ -33,8 +33,8 @@ "repositoryURL": "https://github.com/vapor/core.git", "state": { "branch": null, - "revision": "2731f8ba0cf274a61c9bd6ab43550f692ffaf879", - "version": "3.9.0" + "revision": "18f2436bf7a6bc2224372c0885db2e0159af1649", + "version": "3.9.2" } }, { @@ -57,20 +57,20 @@ }, { "package": "HypertextApplicationLanguage", - "repositoryURL": "https://github.com/Yasumoto/HypertextApplicationLanguage.git", + "repositoryURL": "https://github.com/swift-aws/HypertextApplicationLanguage.git", "state": { "branch": null, - "revision": "2302002502fe573494577cc6e8df686e385519f8", - "version": "1.1.0" + "revision": "aa2c9141d491682f17b2310aed17b9adfc006256", + "version": "1.1.1" } }, { "package": "INIParser", - "repositoryURL": "https://github.com/PerfectlySoft/Perfect-INIParser.git", + "repositoryURL": "https://github.com/swift-aws/Perfect-INIParser.git", "state": { "branch": null, - "revision": "0952aac9ca54324ff25191569fd9c48eec424772", - "version": "3.0.2" + "revision": "42de0efc7a01105e19b80d533d3d282a98277f6c", + "version": "3.0.3" } }, { @@ -126,15 +126,6 @@ "revision": "37760e9a52030bb9011972c5213c3350fa9d41fd", "version": "1.0.0" } - }, - { - "package": "SwiftyJSON", - "repositoryURL": "https://github.com/IBM-Swift/SwiftyJSON.git", - "state": { - "branch": null, - "revision": "f2612ea3ac29996ae9601bdcb00cc1c29e26f104", - "version": "17.0.4" - } } ] }, diff --git a/Package.swift b/Package.swift index 8d27157..407c418 100644 --- a/Package.swift +++ b/Package.swift @@ -14,7 +14,10 @@ let package = Package( .package(url: "https://github.com/vapor/fluent", from: "3.1.0"), // 💫 AWS Client Library - .package(url: "https://github.com/swift-aws/aws-sdk-swift", .branch("yasumoto-5.1")), + .package(url: "https://github.com/swift-aws/aws-sdk-swift", from: "3.2.0"), + + // 💫 AWS Client Library + .package(url: "https://github.com/swift-aws/aws-sdk-swift-core", .branch("yasumoto-5.1")), ], targets: [ .target( From 071e24d3d79bd030b5dfc1c08653b2bffd593d06 Mon Sep 17 00:00:00 2001 From: Joe Smith Date: Mon, 14 Oct 2019 21:20:42 -0700 Subject: [PATCH 4/4] Update AWSSDKSwift and remove non-throwing try statements --- Package.resolved | 14 +++++++------- Package.swift | 5 +---- Sources/FluentDynamoDB/DynamoConnection.swift | 10 +++++----- 3 files changed, 13 insertions(+), 16 deletions(-) diff --git a/Package.resolved b/Package.resolved index 7910f0d..2584942 100644 --- a/Package.resolved +++ b/Package.resolved @@ -6,17 +6,17 @@ "repositoryURL": "https://github.com/swift-aws/aws-sdk-swift", "state": { "branch": null, - "revision": "ed9cba4149087e19569d470867c73eff4b7ef552", - "version": "3.2.0" + "revision": "028a16332df2212f82dc64ada4568131844a9e47", + "version": "3.3.0" } }, { "package": "AWSSDKSwiftCore", "repositoryURL": "https://github.com/swift-aws/aws-sdk-swift-core", "state": { - "branch": "yasumoto-5.1", - "revision": "516c1df2d523406ff3234334d924f7149a242e2e", - "version": null + "branch": null, + "revision": "14dc7e963b9889c57395cb280f634540da189501", + "version": "3.4.0" } }, { @@ -51,8 +51,8 @@ "repositoryURL": "https://github.com/vapor/fluent", "state": { "branch": null, - "revision": "b915c321c6f9e83743ee5efa35a30895e1b02e51", - "version": "3.2.0" + "revision": "783819d8838d15e1a05b459aa0fd1bde1e37ac26", + "version": "3.2.1" } }, { diff --git a/Package.swift b/Package.swift index 407c418..9b45864 100644 --- a/Package.swift +++ b/Package.swift @@ -14,10 +14,7 @@ let package = Package( .package(url: "https://github.com/vapor/fluent", from: "3.1.0"), // 💫 AWS Client Library - .package(url: "https://github.com/swift-aws/aws-sdk-swift", from: "3.2.0"), - - // 💫 AWS Client Library - .package(url: "https://github.com/swift-aws/aws-sdk-swift-core", .branch("yasumoto-5.1")), + .package(url: "https://github.com/swift-aws/aws-sdk-swift", from: "3.3.0"), ], targets: [ .target( diff --git a/Sources/FluentDynamoDB/DynamoConnection.swift b/Sources/FluentDynamoDB/DynamoConnection.swift index c4b726e..0253306 100644 --- a/Sources/FluentDynamoDB/DynamoConnection.swift +++ b/Sources/FluentDynamoDB/DynamoConnection.swift @@ -77,18 +77,18 @@ extension DynamoConnection: DatabaseQueryable { case .get: let inputItem = DynamoDB.GetItemInput( key: requestedKey, tableName: query.table) - return try self.handle.getItem(inputItem).map { output in + return self.handle.getItem(inputItem).map { output in return try handler(Output(attributes: output.item)) } case .set: let inputItem = DynamoDB.PutItemInput(item: requestedKey, returnValues: .allOld, tableName: query.table) - return try self.handle.putItem(inputItem).map { output in + return self.handle.putItem(inputItem).map { output in return try handler(Output(attributes: output.attributes)) } case .delete: let inputItem = DynamoDB.DeleteItemInput( key: requestedKey, returnValues: .allOld, tableName: query.table) - return try self.handle.deleteItem(inputItem).map { output in + return self.handle.deleteItem(inputItem).map { output in return try handler(DynamoValue(attributes: output.attributes)) } case .filter: @@ -129,7 +129,7 @@ extension DynamoConnection: DatabaseQueryable { // Note that DynamoDB allows batch operations to query multiple items. For simplicity, we're // always assuming we're querying one table at a time. We will always check the response for // the table name we've specified in the query itself. - return try self.handle.batchGetItem(batchInput).map { (output: DynamoDB.BatchGetItemOutput) -> [DynamoValue] in + return self.handle.batchGetItem(batchInput).map { (output: DynamoDB.BatchGetItemOutput) -> [DynamoValue] in guard let values: [[String : DynamoDB.AttributeValue]] = output.responses?[query.table] else { return [DynamoValue]() } return values.map { DynamoValue(attributes: $0) } } @@ -145,7 +145,7 @@ extension DynamoConnection: DatabaseQueryable { indexName: query.index, keyConditionExpression: query.keyConditionExpression, tableName: query.table) - return try self.handle.query(queryInput).map { (output: DynamoDB.QueryOutput) in + return self.handle.query(queryInput).map { (output: DynamoDB.QueryOutput) in return output.items?.compactMap { (item: [String: DynamoDB.AttributeValue]) -> DynamoValue in return DynamoValue(attributes: item) } ?? [DynamoValue]()