Skip to content

Commit 5164956

Browse files
authored
chore: kickoff release
2 parents a01dfe5 + 048e003 commit 5164956

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2525
-18
lines changed

.github/workflows/integ_test_datastore_cpk.yml

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ on:
55

66
permissions:
77
id-token: write
8-
contents: read
8+
contents: read
99

1010
jobs:
1111
datastore-integration-cpk-test:
1212
timeout-minutes: 30
13-
runs-on: macos-12
13+
runs-on: macos-13
1414
environment: IntegrationTest
1515
steps:
1616
- uses: actions/checkout@2541b1294d2704b0964813337f33b291d3f8596b
@@ -33,5 +33,6 @@ jobs:
3333
with:
3434
project_path: ./AmplifyPlugins/DataStore/Tests/DataStoreHostApp
3535
scheme: AWSDataStorePluginCPKTests
36+
destination: 'platform=iOS Simulator,name=iPhone 14,OS=latest'
37+
xcode_path: '/Applications/Xcode_14.3.app'
3638

37-

AmplifyPlugins/Core/AWSPluginsCore/Model/Decorator/ModelIdDecorator.swift

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import Amplify
1111
/// Decorate the GraphQLDocument with the value of `ModelIdentifier` for a "delete" mutation or "get" query.
1212
public struct ModelIdDecorator: ModelBasedGraphQLDocumentDecorator {
1313
/// Array of model fields and their stringified value
14-
private var identifierFields: [(name: String, value: String, type: String)] = [(name: String, value: String, type: String)]()
14+
private var identifierFields = [(name: String, value: GraphQLDocumentValueRepresentable, type: String)]()
1515

1616
public init(model: Model, schema: ModelSchema) {
1717

@@ -33,7 +33,7 @@ public struct ModelIdDecorator: ModelBasedGraphQLDocumentDecorator {
3333
public init(identifierFields: [(name: String, value: Persistable)]) {
3434
var firstField = true
3535
identifierFields.forEach { name, value in
36-
self.identifierFields.append((name: name, value: "\(value)", type: firstField == true ? "ID!" : "String!"))
36+
self.identifierFields.append((name: name, value: Self.convert(persistable: value), type: firstField == true ? "ID!" : "String!"))
3737
firstField = false
3838
}
3939
}
@@ -76,17 +76,41 @@ public struct ModelIdDecorator: ModelBasedGraphQLDocumentDecorator {
7676
if case .mutation = document.operationType {
7777
var inputMap = [String: String]()
7878
for (name, value, _) in identifierFields {
79-
inputMap[name] = value
79+
inputMap[name] = value.graphQLDocumentValue
8080
}
8181
inputs["input"] = GraphQLDocumentInput(type: "\(document.name.pascalCased())Input!",
8282
value: .object(inputMap))
8383

8484
} else if case .query = document.operationType {
8585
for (name, value, type) in identifierFields {
86-
inputs[name] = GraphQLDocumentInput(type: type, value: .scalar(value))
86+
inputs[name] = GraphQLDocumentInput(
87+
type: type,
88+
value: identifierFields.count > 1 ? .inline(value) : .scalar(value)
89+
)
8790
}
8891
}
8992

9093
return document.copy(inputs: inputs)
9194
}
9295
}
96+
97+
fileprivate extension ModelIdDecorator {
98+
private static func convert(persistable: Persistable) -> GraphQLDocumentValueRepresentable {
99+
switch persistable {
100+
case let data as Double:
101+
return data
102+
case let data as Int:
103+
return data
104+
case let data as Bool:
105+
return data
106+
case let data as Temporal.DateTime:
107+
return data.iso8601String
108+
case let data as Temporal.Date:
109+
return data.iso8601String
110+
case let data as Temporal.Time:
111+
return data.iso8601String
112+
default:
113+
return "\(persistable)"
114+
}
115+
}
116+
}

AmplifyPlugins/Core/AWSPluginsCore/Model/GraphQLDocument/SingleDirectiveGraphQLDocument.swift

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,8 @@ extension SingleDirectiveGraphQLDocument {
7474
variables.updateValue(values, forKey: input.key)
7575
case .scalar(let value):
7676
variables.updateValue(value, forKey: input.key)
77+
case .inline:
78+
break
7779
}
7880

7981
}
@@ -95,13 +97,22 @@ extension SingleDirectiveGraphQLDocument {
9597
}
9698
"""
9799
}
100+
98101
let sortedInputs = inputs.sorted { $0.0 < $1.0 }
99-
let inputTypes = sortedInputs.map { "$\($0.key): \($0.value.type)" }.joined(separator: ", ")
100-
let inputParameters = sortedInputs.map { "\($0.key): $\($0.key)" }.joined(separator: ", ")
102+
let variableInputs = sortedInputs.filter { !$0.value.value.isInline() }
103+
let inlineInputs = sortedInputs.filter { $0.value.value.isInline() }
104+
let variableInputTypes = variableInputs.map { "$\($0.key): \($0.value.type)" }.joined(separator: ", ")
105+
106+
var inputParameters = variableInputs.map { ($0.key, "$\($0.key)") }
107+
for input in inlineInputs {
108+
if case .inline(let document) = input.value.value {
109+
inputParameters.append((input.key, document.graphQLInlineValue))
110+
}
111+
}
101112

102113
return """
103-
\(operationType.rawValue) \(name.pascalCased())(\(inputTypes)) {
104-
\(name)(\(inputParameters)) {
114+
\(operationType.rawValue) \(name.pascalCased())\(variableInputTypes.isEmpty ? "" : "(\(variableInputTypes))") {
115+
\(name)(\(inputParameters.map({ "\($0.0): \($0.1)"}).joined(separator: ", "))) {
105116
\(selectionSetString)
106117
}
107118
}

AmplifyPlugins/Core/AWSPluginsCore/Model/Support/GraphQLDocumentnputValue.swift renamed to AmplifyPlugins/Core/AWSPluginsCore/Model/Support/GraphQLDocumentInputValue.swift

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,34 +10,69 @@ import Foundation
1010
/// A container to hold either an object or a value, useful for storing document inputs and allowing manipulation at
1111
/// the first level of the object
1212
public enum GraphQLDocumentInputValue {
13+
case inline(GraphQLDocumentValueRepresentable)
1314
case scalar(GraphQLDocumentValueRepresentable)
1415
case object([String: Any?])
16+
17+
public func isInline() -> Bool {
18+
if case .inline = self {
19+
return true
20+
}
21+
return false
22+
}
1523
}
1624

1725
public protocol GraphQLDocumentValueRepresentable {
1826
var graphQLDocumentValue: String { get }
27+
var graphQLInlineValue: String { get }
1928
}
2029

2130
extension Int: GraphQLDocumentValueRepresentable {
2231
public var graphQLDocumentValue: String {
2332
return "\(self)"
2433
}
34+
35+
public var graphQLInlineValue: String {
36+
return "\(self)"
37+
}
2538
}
2639

2740
extension String: GraphQLDocumentValueRepresentable {
2841
public var graphQLDocumentValue: String {
2942
return self
3043
}
44+
45+
public var graphQLInlineValue: String {
46+
return "\"\(self)\""
47+
}
3148
}
3249

3350
extension Bool: GraphQLDocumentValueRepresentable {
3451
public var graphQLDocumentValue: String {
3552
return "\(self)"
3653
}
54+
55+
public var graphQLInlineValue: String {
56+
return "\(self)"
57+
}
3758
}
3859

3960
extension Decimal: GraphQLDocumentValueRepresentable {
4061
public var graphQLDocumentValue: String {
4162
return "\(self)"
4263
}
64+
65+
public var graphQLInlineValue: String {
66+
return "\(self)"
67+
}
68+
}
69+
70+
extension Double: GraphQLDocumentValueRepresentable {
71+
public var graphQLDocumentValue: String {
72+
return "\(self)"
73+
}
74+
75+
public var graphQLInlineValue: String {
76+
return "\(self)"
77+
}
4378
}

AmplifyPlugins/Core/AWSPluginsCoreTests/Model/GraphQLRequest/GraphQLRequestSyncCustomPrimaryKeyTests.swift

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,8 @@ class GraphQLRequestSyncCustomPrimaryKeyTests: XCTestCase {
2929
documentBuilder.add(decorator: ConflictResolutionDecorator(graphQLType: .query))
3030
let document = documentBuilder.build()
3131
let documentStringValue = """
32-
query GetCustomerOrder($id: ID!, $orderId: String!) {
33-
getCustomerOrder(id: $id, orderId: $orderId) {
32+
query GetCustomerOrder {
33+
getCustomerOrder(id: "\(order.id)", orderId: "\(order.orderId)") {
3434
orderId
3535
id
3636
email
@@ -56,8 +56,7 @@ class GraphQLRequestSyncCustomPrimaryKeyTests: XCTestCase {
5656
return
5757
}
5858

59-
XCTAssertEqual(variables["id"] as? String, order.id)
60-
XCTAssertEqual(variables["orderId"] as? String, order.orderId)
59+
XCTAssertTrue(variables.isEmpty)
6160
}
6261

6362
func testCreateMutationGraphQLRequest() throws {
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
//
2+
// Copyright Amazon.com Inc. or its affiliates.
3+
// All Rights Reserved.
4+
//
5+
// SPDX-License-Identifier: Apache-2.0
6+
//
7+
8+
/** Model Schema
9+
type Post11 @model {
10+
postId: ID! @primaryKey(sortKeyFields: ["sk"])
11+
sk: Int!
12+
}
13+
*/
14+
15+
import Foundation
16+
import Combine
17+
import XCTest
18+
import AWSAPIPlugin
19+
import AWSDataStorePlugin
20+
21+
@testable import Amplify
22+
@testable import DataStoreHostApp
23+
24+
fileprivate struct TestModels: AmplifyModelRegistration {
25+
func registerModels(registry: ModelRegistry.Type) {
26+
ModelRegistry.register(modelType: Post11.self)
27+
}
28+
29+
var version: String = "test"
30+
}
31+
32+
class AWSDataStoreIntSortKeyTest: XCTestCase {
33+
let configFile = "testconfiguration/AWSDataStoreCategoryPluginPrimaryKeyIntegrationTests-amplifyconfiguration"
34+
35+
override func setUp() async throws {
36+
continueAfterFailure = true
37+
let config = try TestConfigHelper.retrieveAmplifyConfiguration(forResource: configFile)
38+
try Amplify.add(plugin: AWSAPIPlugin(
39+
sessionFactory: AmplifyURLSessionFactory())
40+
)
41+
try Amplify.add(plugin: AWSDataStorePlugin(
42+
modelRegistration: TestModels(),
43+
configuration: .custom(syncMaxRecords: 100)
44+
))
45+
Amplify.Logging.logLevel = .verbose
46+
try Amplify.configure(config)
47+
}
48+
49+
override func tearDown() async throws {
50+
try await Amplify.DataStore.clear()
51+
await Amplify.reset()
52+
try await Task.sleep(seconds: 1)
53+
}
54+
55+
func waitDataStoreReady() async throws {
56+
let ready = expectation(description: "DataStore is ready")
57+
var requests: Set<AnyCancellable> = []
58+
Amplify.Hub.publisher(for: .dataStore)
59+
.filter { $0.eventName == HubPayload.EventName.DataStore.ready }
60+
.sink { _ in
61+
ready.fulfill()
62+
}
63+
.store(in: &requests)
64+
65+
try await Amplify.DataStore.start()
66+
await fulfillment(of: [ready], timeout: 60)
67+
}
68+
69+
func testCreateModel_withSortKeyInIntegerType_success() async throws {
70+
try await waitDataStoreReady()
71+
var requests: Set<AnyCancellable> = []
72+
let post = Post11(postId: UUID().uuidString, sk: 15)
73+
let postCreated = expectation(description: "Post is created")
74+
postCreated.assertForOverFulfill = false
75+
Amplify.Hub.publisher(for: .dataStore)
76+
.filter { $0.eventName == HubPayload.EventName.DataStore.syncReceived }
77+
.compactMap { $0.data as? MutationEvent }
78+
.filter { $0.modelId == post.identifier }
79+
.sink { _ in
80+
postCreated.fulfill()
81+
}.store(in: &requests)
82+
83+
try await Amplify.DataStore.save(post)
84+
await fulfillment(of: [postCreated], timeout: 5)
85+
}
86+
87+
func testQueryCreatedModel_withSortKeyInIntegerType_success() async throws {
88+
try await waitDataStoreReady()
89+
var requests: Set<AnyCancellable> = []
90+
let post = Post11(postId: UUID().uuidString, sk: 15)
91+
let postCreated = expectation(description: "Post is created")
92+
postCreated.assertForOverFulfill = false
93+
Amplify.Hub.publisher(for: .dataStore)
94+
.filter { $0.eventName == HubPayload.EventName.DataStore.syncReceived }
95+
.compactMap { $0.data as? MutationEvent }
96+
.filter { $0.modelId == post.identifier }
97+
.sink { _ in
98+
postCreated.fulfill()
99+
}.store(in: &requests)
100+
101+
try await Amplify.DataStore.save(post)
102+
await fulfillment(of: [postCreated], timeout: 5)
103+
104+
let queryResult = try await Amplify.API.query(
105+
request: .get(
106+
Post11.self,
107+
byIdentifier: .identifier(postId: post.postId, sk: post.sk)
108+
)
109+
)
110+
111+
switch queryResult {
112+
case .success(let queriedPost):
113+
XCTAssertEqual(post.identifier, queriedPost!.identifier)
114+
case .failure(let error):
115+
XCTFail("Failed to query comment \(error)")
116+
}
117+
}
118+
119+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// swiftlint:disable all
2+
import Amplify
3+
import Foundation
4+
5+
extension Post11 {
6+
// MARK: - CodingKeys
7+
public enum CodingKeys: String, ModelKey {
8+
case postId
9+
case sk
10+
case createdAt
11+
case updatedAt
12+
}
13+
14+
public static let keys = CodingKeys.self
15+
// MARK: - ModelSchema
16+
17+
public static let schema = defineSchema { model in
18+
let post11 = Post11.keys
19+
20+
model.pluralName = "Post11s"
21+
22+
model.attributes(
23+
.index(fields: ["postId", "sk"], name: nil),
24+
.primaryKey(fields: [post11.postId, post11.sk])
25+
)
26+
27+
model.fields(
28+
.field(post11.postId, is: .required, ofType: .string),
29+
.field(post11.sk, is: .required, ofType: .int),
30+
.field(post11.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime),
31+
.field(post11.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime)
32+
)
33+
}
34+
}
35+
36+
extension Post11: ModelIdentifiable {
37+
public typealias IdentifierFormat = ModelIdentifierFormat.Custom
38+
public typealias IdentifierProtocol = ModelIdentifier<Self, ModelIdentifierFormat.Custom>
39+
}
40+
41+
extension Post11.IdentifierProtocol {
42+
public static func identifier(postId: String,
43+
sk: Int) -> Self {
44+
.make(fields:[(name: "postId", value: postId), (name: "sk", value: sk)])
45+
}
46+
}

0 commit comments

Comments
 (0)