Skip to content

Commit 6672b2a

Browse files
authored
fix(datastore): Setting nil values for empty associated models (#2358)
* fix(datastore): Setting nil values for empty associated models * address PR comments * test clean up
1 parent 74d80bd commit 6672b2a

File tree

2 files changed

+46
-11
lines changed

2 files changed

+46
-11
lines changed

AmplifyPlugins/Core/AWSPluginsCore/Model/Support/Model+GraphQL.swift

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,12 +41,28 @@ extension Model {
4141
let name = modelField.name
4242

4343
guard let value = modelFieldValue else {
44-
// don't invalidate fields of type .model
45-
// as we'll take care of this later on (see line 61)
44+
// Special case for associated models when the value is `nil`, by setting all of the associated
45+
// model's primary key fields (targetNames) to `nil`.
4646
if case .model = modelField.type {
47-
continue
47+
let fieldNames = getFieldNameForAssociatedModels(modelField: modelField)
48+
for fieldName in fieldNames {
49+
// Only set to `nil` if it has not been set already. For hasOne relationships, where the
50+
// target name of the associated model is explicitly on this model as a field property, we
51+
// cannot guarantee which field is processed first, thus if there is a value for the explicit
52+
// field and was already set, don't overwrite it.
53+
if input[fieldName] == nil {
54+
// Always setting the value to `nil` is not necessary for create mutations, since leaving it
55+
// out will also reflect that there's no associated model. However, we always set it to `nil`
56+
// to account for the update mutation use cases where the caller may be de-associating the
57+
// model from the associated model, which is why the `nil` is required in input variables
58+
// to persist the removal the association.
59+
input.updateValue(nil, forKey: fieldName)
60+
}
61+
}
62+
} else {
63+
input.updateValue(nil, forKey: name)
4864
}
49-
input.updateValue(nil, forKey: name)
65+
5066
continue
5167
}
5268

AmplifyPlugins/DataStore/AWSDataStoreCategoryPluginIntegrationTests/TransformerV2/DataStoreConnectionOptionalAssociations.swift

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -199,19 +199,38 @@ class DataStoreConnectionOptionalAssociations: SyncEngineIntegrationV2TestBase {
199199
XCTAssertEqual(queriedPost.blog?.id, blog.id)
200200

201201
queriedComment.post = nil
202-
queriedPost.blog = nil
203-
guard savePost(queriedPost) != nil,
204-
saveComment(queriedComment) != nil else {
205-
XCTFail("Failed to update comment and post")
202+
// A mock GraphQL request is created to assert that the request variables contains the "postId"
203+
// with the value `nil` which is sent to the API to persist the removal of the association.
204+
let request = GraphQLRequest<Comment8>.createMutation(of: queriedComment, version: 1)
205+
guard let variables = request.variables,
206+
let input = variables["input"] as? [String: Any?],
207+
let postValue = input["postId"],
208+
postValue == nil else {
209+
XCTFail("Failed to retrieve input object from GraphQL variables")
206210
return
207211
}
208-
guard let queriedCommentWithoutPost = queryComment(id: comment.id),
209-
let queriedPostWithoutBlog = queryPost(id: post.id) else {
210-
XCTFail("Failed to query comment and post")
212+
213+
guard saveComment(queriedComment) != nil else {
214+
XCTFail("Failed to update comment")
215+
return
216+
}
217+
guard let queriedCommentWithoutPost = queryComment(id: comment.id) else {
218+
XCTFail("Failed to query comment without post")
211219
return
212220
}
213221

214222
XCTAssertNil(queriedCommentWithoutPost.post)
223+
224+
queriedPost.blog = nil
225+
guard savePost(queriedPost) != nil else {
226+
XCTFail("Failed to update comment and post")
227+
return
228+
}
229+
230+
guard let queriedPostWithoutBlog = queryPost(id: post.id) else {
231+
XCTFail("Failed to query post")
232+
return
233+
}
215234
XCTAssertNil(queriedPostWithoutBlog.blog)
216235
}
217236

0 commit comments

Comments
 (0)