Skip to content

Commit

Permalink
fix(api): selection set with optional association
Browse files Browse the repository at this point in the history
  • Loading branch information
lawmicha committed Jun 5, 2020
1 parent a29bb23 commit 4112598
Show file tree
Hide file tree
Showing 11 changed files with 423 additions and 4 deletions.
32 changes: 30 additions & 2 deletions Amplify.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@
2144226E234BDE23009357F7 /* StorageUploadFileOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2144226D234BDE23009357F7 /* StorageUploadFileOperation.swift */; };
214F49CD24898E8500DA616C /* Article.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F49CB24898E8400DA616C /* Article.swift */; };
214F49CE24898E8500DA616C /* Article+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F49CC24898E8500DA616C /* Article+Schema.swift */; };
214F49772486D8A200DA616C /* UserFollowers+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F49712486D8A100DA616C /* UserFollowers+Schema.swift */; };
214F49782486D8A200DA616C /* UserFollowing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F49722486D8A200DA616C /* UserFollowing.swift */; };
214F49792486D8A200DA616C /* UserFollowing+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F49732486D8A200DA616C /* UserFollowing+Schema.swift */; };
214F497A2486D8A200DA616C /* User.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F49742486D8A200DA616C /* User.swift */; };
214F497B2486D8A200DA616C /* User+Schema.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F49752486D8A200DA616C /* User+Schema.swift */; };
214F497C2486D8A200DA616C /* UserFollowers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F49762486D8A200DA616C /* UserFollowers.swift */; };
214F497E2486DA5000DA616C /* GraphQLRequestOptionalAssociationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 214F497D2486DA5000DA616C /* GraphQLRequestOptionalAssociationTests.swift */; };
21558E3E237BB4BF0032A5BB /* GraphQLRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21558E3D237BB4BF0032A5BB /* GraphQLRequest.swift */; };
21558E40237CB8640032A5BB /* GraphQLError.swift in Sources */ = {isa = PBXBuildFile; fileRef = 21558E3F237CB8640032A5BB /* GraphQLError.swift */; };
216879FE23636A0A004A056E /* RepeatingTimer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 216879FD23636A0A004A056E /* RepeatingTimer.swift */; };
Expand Down Expand Up @@ -707,6 +714,13 @@
2144226D234BDE23009357F7 /* StorageUploadFileOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StorageUploadFileOperation.swift; sourceTree = "<group>"; };
214F49CB24898E8400DA616C /* Article.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Article.swift; sourceTree = "<group>"; };
214F49CC24898E8500DA616C /* Article+Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "Article+Schema.swift"; sourceTree = "<group>"; };
214F49712486D8A100DA616C /* UserFollowers+Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserFollowers+Schema.swift"; sourceTree = "<group>"; };
214F49722486D8A200DA616C /* UserFollowing.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserFollowing.swift; sourceTree = "<group>"; };
214F49732486D8A200DA616C /* UserFollowing+Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UserFollowing+Schema.swift"; sourceTree = "<group>"; };
214F49742486D8A200DA616C /* User.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = User.swift; sourceTree = "<group>"; };
214F49752486D8A200DA616C /* User+Schema.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "User+Schema.swift"; sourceTree = "<group>"; };
214F49762486D8A200DA616C /* UserFollowers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = UserFollowers.swift; sourceTree = "<group>"; };
214F497D2486DA5000DA616C /* GraphQLRequestOptionalAssociationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLRequestOptionalAssociationTests.swift; sourceTree = "<group>"; };
21558E3D237BB4BF0032A5BB /* GraphQLRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLRequest.swift; sourceTree = "<group>"; };
21558E3F237CB8640032A5BB /* GraphQLError.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GraphQLError.swift; sourceTree = "<group>"; };
215F4BCAAB89FA54AA121BDE /* Pods-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin.release.xcconfig"; path = "Target Support Files/Pods-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin/Pods-AmplifyAWSPlugins-AWSPluginsCore-AWSPinpointAnalyticsPlugin.release.xcconfig"; sourceTree = "<group>"; };
Expand Down Expand Up @@ -1503,6 +1517,7 @@
2129BE322394828B006363A1 /* GraphQLRequestModelTests.swift */,
219A888623EB89C200BBC5F2 /* GraphQLRequestAnyModelWithSyncTests.swift */,
21A3FDB8246494CD00E76120 /* GraphQLRequestAuthRuleTests.swift */,
214F497D2486DA5000DA616C /* GraphQLRequestOptionalAssociationTests.swift */,
);
path = GraphQLRequest;
sourceTree = "<group>";
Expand Down Expand Up @@ -2185,18 +2200,24 @@
B952182D237E21B900F53237 /* Models */ = {
isa = PBXGroup;
children = (
B952182F237E21B900F53237 /* schema.graphql */,
FAF512AD23986791001ADF4E /* AmplifyModels.swift */,
214F49CB24898E8400DA616C /* Article.swift */,
214F49CC24898E8500DA616C /* Article+Schema.swift */,
B9FAA10C23878BD6009414B4 /* Associations */,
B9521830237E21B900F53237 /* Comment.swift */,
B952182E237E21B900F53237 /* Comment+Schema.swift */,
FAA2E8BB239FFC7700E420EA /* MockModels.swift */,
B9521832237E21B900F53237 /* Post.swift */,
B9521831237E21B900F53237 /* Post+Schema.swift */,
2129BE002394627B006363A1 /* PostCommentModelRegistration.swift */,
B9AA09F02473CA29000E6FBB /* PostStatus.swift */,
B9FAA10C23878BD6009414B4 /* Associations */,
B952182F237E21B900F53237 /* schema.graphql */,
214F49742486D8A200DA616C /* User.swift */,
214F49752486D8A200DA616C /* User+Schema.swift */,
214F49762486D8A200DA616C /* UserFollowers.swift */,
214F49712486D8A100DA616C /* UserFollowers+Schema.swift */,
214F49722486D8A200DA616C /* UserFollowing.swift */,
214F49732486D8A200DA616C /* UserFollowing+Schema.swift */,
);
path = Models;
sourceTree = "<group>";
Expand Down Expand Up @@ -3961,6 +3982,7 @@
2183A56823EA4A8E00232880 /* GraphQLDeleteMutationTests.swift in Sources */,
21A3FDB42463C49F00E76120 /* ModelReadUpdateAuthRuleTests.swift in Sources */,
2183A56323EA4A7800232880 /* GraphQLSubscriptionTests.swift in Sources */,
214F497E2486DA5000DA616C /* GraphQLRequestOptionalAssociationTests.swift in Sources */,
2129BE562395CAF9006363A1 /* PaginatedListTests.swift in Sources */,
2183A56723EA4A8B00232880 /* GraphQLCreateMutationTests.swift in Sources */,
2183A56623EA4A8700232880 /* GraphQLSyncQueryTests.swift in Sources */,
Expand Down Expand Up @@ -4418,20 +4440,26 @@
B9FAA11823879A57009414B4 /* Author+Schema.swift in Sources */,
B9521836237E21BA00F53237 /* Post+Schema.swift in Sources */,
FA4A955F239ADEBD008E876E /* MockResponder.swift in Sources */,
214F497A2486D8A200DA616C /* User.swift in Sources */,
B9FAA11223878C96009414B4 /* UserAccount+Schema.swift in Sources */,
FACA36152327FC39000E74F6 /* MessageReporter.swift in Sources */,
FAF512AE23986791001ADF4E /* AmplifyModels.swift in Sources */,
B9FAA11C23879B35009414B4 /* Book.swift in Sources */,
214F49772486D8A200DA616C /* UserFollowers+Schema.swift in Sources */,
B9FAA11423878CEA009414B4 /* UserProfile+Schema.swift in Sources */,
214F49792486D8A200DA616C /* UserFollowing+Schema.swift in Sources */,
FACA361D2327FC84000E74F6 /* MockAPICategoryPlugin.swift in Sources */,
B9FAA11023878C5E009414B4 /* UserProfile.swift in Sources */,
B9AA09F12473CA29000E6FBB /* PostStatus.swift in Sources */,
214F497B2486D8A200DA616C /* User+Schema.swift in Sources */,
B9FAA12023879BD0009414B4 /* BookAuthor+Schema.swift in Sources */,
21F40A4023A295470074678E /* TestCommonConstants.swift in Sources */,
214F497C2486D8A200DA616C /* UserFollowers.swift in Sources */,
B9521835237E21BA00F53237 /* Comment.swift in Sources */,
FACA361E2327FC8E000E74F6 /* MockAnalyticsCategoryPlugin.swift in Sources */,
2129BE012394627B006363A1 /* PostCommentModelRegistration.swift in Sources */,
B9FAA10E23878BF3009414B4 /* UserAccount.swift in Sources */,
214F49782486D8A200DA616C /* UserFollowing.swift in Sources */,
21F40A3C23A2952C0074678E /* AuthHelper.swift in Sources */,
B4F3E9FA24314ECC00F23296 /* MockAuthCategoryPlugin.swift in Sources */,
214F49CE24898E8500DA616C /* Article+Schema.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ extension SelectionSet {

func withModelFields(_ fields: [ModelField]) {
fields.forEach { field in
let isRequiredAssociation = field.isRequired && field.isAssociationOwner
if isRequiredAssociation, let associatedModel = field.associatedModel {
if field.isAssociationOwner, let associatedModel = field.associatedModel {
let child = SelectionSet(value: .init(name: field.name, fieldType: .model))
child.withModelFields(associatedModel.schema.graphQLFields)
self.addChild(settingParentOf: child)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
//
// Copyright 2018-2020 Amazon.com,
// Inc. or its affiliates. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

import XCTest

@testable import Amplify
@testable import AmplifyTestCommon
@testable import AWSPluginsCore

class GraphQLRequestOptionalAssociationTests: XCTestCase {
override func setUp() {
ModelRegistry.register(modelType: User.self)
ModelRegistry.register(modelType: UserFollowing.self)
ModelRegistry.register(modelType: UserFollowers.self)
}

override func tearDown() {
ModelRegistry.reset()
}

func testCreateUserGraphQLRequest() {
let user = User(name: "username")
let documentStringValue = """
mutation CreateUser($input: CreateUserInput!) {
createUser(input: $input) {
id
name
__typename
}
}
"""
let request = GraphQLRequest<User>.create(user)
XCTAssertEqual(documentStringValue, request.document)

guard let variables = request.variables else {
XCTFail("The request doesn't contain variables")
return
}
guard let input = variables["input"] as? [String: Any] else {
XCTFail("The document variables property doesn't contain a valid input")
return
}
XCTAssertEqual(input["id"] as? String, user.id)
XCTAssertEqual(input["name"] as? String, user.name)
}

func testCreateUserFollowingGraphQLRequest() {
let user1 = User(name: "user1")
let user2 = User(name: "user2")
let userFollowing = UserFollowing(user: user1, followingUser: user2)
let documentStringValue = """
mutation CreateUserFollowing($input: CreateUserFollowingInput!) {
createUserFollowing(input: $input) {
id
followingUser {
id
name
__typename
}
user {
id
name
__typename
}
__typename
}
}
"""
let request = GraphQLRequest<User>.create(userFollowing)
XCTAssertEqual(documentStringValue, request.document)
guard let variables = request.variables else {
XCTFail("The request doesn't contain variables")
return
}
guard let input = variables["input"] as? [String: Any] else {
XCTFail("The document variables property doesn't contain a valid input")
return
}
XCTAssertEqual(input["id"] as? String, userFollowing.id)
XCTAssertEqual(input["userFollowingUserId"] as? String, user1.id)
XCTAssertEqual(input["userFollowingFollowingUserId"] as? String, user2.id)
}

func testQueryUserFollowingGraphQLRequest() {
let documentStringValue = """
query GetUserFollowing($id: ID!) {
getUserFollowing(id: $id) {
id
followingUser {
id
name
__typename
}
user {
id
name
__typename
}
__typename
}
}
"""
let request = GraphQLRequest<UserFollowing>.get(UserFollowing.self, byId: "id")
XCTAssertEqual(documentStringValue, request.document)
guard let variables = request.variables else {
XCTFail("The request doesn't contain variables")
return
}
XCTAssertEqual(variables["id"] as? String, "id")
}

func testQueryUserGraphQLRequest() {
let documentStringValue = """
query GetUser($id: ID!) {
getUser(id: $id) {
id
name
__typename
}
}
"""
let request = GraphQLRequest<UserFollowing>.get(User.self, byId: "id")
XCTAssertEqual(documentStringValue, request.document)
guard let variables = request.variables else {
XCTFail("The request doesn't contain variables")
return
}
XCTAssertEqual(variables["id"] as? String, "id")
}

func testListUserFollowingGraphQLRequest() {
let documentStringValue = """
query ListUserFollowings($limit: Int) {
listUserFollowings(limit: $limit) {
items {
id
followingUser {
id
name
__typename
}
user {
id
name
__typename
}
__typename
}
nextToken
}
}
"""
let request = GraphQLRequest<UserFollowing>.list(UserFollowing.self)
XCTAssertEqual(documentStringValue, request.document)
guard let variables = request.variables else {
XCTFail("The request doesn't contain variables")
return
}
XCTAssertEqual(variables["limit"] as? Int, 1_000)
}

func testSubscribeToUserFollowingGraphQLRequest() {
let documentStringValue = """
subscription OnCreateUserFollowing {
onCreateUserFollowing {
id
followingUser {
id
name
__typename
}
user {
id
name
__typename
}
__typename
}
}
"""
let request = GraphQLRequest<UserFollowing>.subscription(of: UserFollowing.self, type: .onCreate)
XCTAssertEqual(documentStringValue, request.document)
XCTAssertNil(request.variables)
}
}
4 changes: 4 additions & 0 deletions AmplifyTestCommon/Models/AmplifyModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,9 @@ final public class AmplifyModels: AmplifyModelRegistration {
public func registerModels(registry: ModelRegistry.Type) {
ModelRegistry.register(modelType: Post.self)
ModelRegistry.register(modelType: Comment.self)
ModelRegistry.register(modelType: Blog.self)
ModelRegistry.register(modelType: User.self)
ModelRegistry.register(modelType: UserFollowers.self)
ModelRegistry.register(modelType: UserFollowing.self)
}
}
36 changes: 36 additions & 0 deletions AmplifyTestCommon/Models/User+Schema.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//
// Copyright 2018-2020 Amazon.com,
// Inc. or its affiliates. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

// swiftlint:disable all
import Amplify
import Foundation

extension User {
// MARK: - CodingKeys
public enum CodingKeys: String, ModelKey {
case id
case name
case following
case followers
}

public static let keys = CodingKeys.self
// MARK: - ModelSchema

public static let schema = defineSchema { model in
let user = User.keys

model.pluralName = "Users"

model.fields(
.id(),
.field(user.name, is: .required, ofType: .string),
.hasMany(user.following, is: .optional, ofType: UserFollowing.self, associatedWith: UserFollowing.keys.user),
.hasMany(user.followers, is: .optional, ofType: UserFollowers.self, associatedWith: UserFollowers.keys.user)
)
}
}
27 changes: 27 additions & 0 deletions AmplifyTestCommon/Models/User.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//
// Copyright 2018-2020 Amazon.com,
// Inc. or its affiliates. All Rights Reserved.
//
// SPDX-License-Identifier: Apache-2.0
//

// swiftlint:disable all
import Amplify
import Foundation

public struct User: Model {
public let id: String
public var name: String
public var following: List<UserFollowing>?
public var followers: List<UserFollowers>?

public init(id: String = UUID().uuidString,
name: String,
following: List<UserFollowing>? = [],
followers: List<UserFollowers>? = []) {
self.id = id
self.name = name
self.following = following
self.followers = followers
}
}
Loading

0 comments on commit 4112598

Please sign in to comment.