amplify-swift
amplify-swift copied to clipboard
Datastore HasOne connection never populated
Describe the bug When specifying a HasOne connection as described in the documentation (https://docs.amplify.aws/cli/graphql-transformer/connection#has-one), the linked child object is never populated when querying from AppSync.
To Reproduce Defined as model as shown:
type NomadUser @model @auth(rules: [{ allow: owner, ownerField: "cognitoId", operations: [create, update, delete] },
{ allow: private, provider: iam, operations: [create, update, delete] }])
@key(fields: ["cognitoId", "id"], name: "NomadUsersByCognitoId") {
id: ID!
screenName: String
fullName: String!
aboutMe: String
website: AWSURL
facebookLink: AWSURL
twitterLink: String
instagramLink: String
youTubeLink: AWSURL
childrenAges: [String]
interests: [String]
}
type NomadBlockedUser @model @auth(rules: [{ allow: owner, ownerField: "owner", operations: [read, create, delete] },
{ allow: private, provider: iam, operations: [create, update, delete] }])
@key(fields: ["owner", "id"], name: "blockedUsersbyOwner")
@key(fields: ["blockedProfileID", "id"], name: "blocksByBlockedProfileID")
{
id: ID!
owner: String
blockedProfileID: ID!
blockedProfile: NomadUser @connection(fields: ["blockedProfileID"])
blockedCognitoId: String
}
After codgen completed I am able to insert objects into the datastore and DynamoDB successfully. I can query the child object from the AppSync Query tool as well
However, when I query the DataStore as shown:
Amplify.DataStore.query(NomadBlockedUser.self, where: keys.owner == SecurityManager.shared.currentUserSub, sort: nil, paginate: nil) { (result) in
switch result{
case.success(let data):
onCompletion(data, nil)
if let profile = data[0].blockedProfile
{
print(profile.aboutMe)
}
case .failure(let error):
print("Error")
}
}
}
the child profile object is always nil. I have confirmed that even if the data is being lazy-loaded from the local store, this should still work because the NomadUser that I have blocked is in the local data store.
Expected behavior I expect the BlockedProfile object to be populated when querying the datastore.
Environment(please complete the following information): Amplify Framework 1.6.1 Dependency Manager Cocoapods Swift 5.0 Amplify version 4.45.2
Device Information (please complete the following information):
- Device: iPhone 12pro Simulator
- iOS Version: iOS 14
Additional context Add any other context about the problem here.
Experiencing this as well :(
Summary from @diegocstn
- couldn't repro with the simplest scheme possible (no auth rules)
- couldn't repro with following schema
type Team @model @auth(rules: [{ allow: owner, operations: [create, update, delete] }]) {
id: ID!
name: String!
}
type Project @model @auth(rules: [{ allow: owner, operations: [read, create, delete] }]) {
id: ID!
name: String
team: Team @connection
}
Next Steps
- Check status of sqlite: Is the data even there?
- Assuming it's not (which seems like a safe assumption), progressively add rules using @kneekey23's schema & auth config as a guide, until we find a config that reproduces the issue
This issue is stale because it has been open for 14 days with no activity. Please, provide an update or it will be automatically closed in 7 days.
Also experienced this! The connection works with
type Project @model @auth(rules: [{ allow: owner, operations: [read, create, delete] }]) {
id: ID!
name: String
team: Team @connection
}
but fails with
type Project @model @auth(rules: [{ allow: owner, operations: [read, create, delete] }]) {
id: ID!
name: String
teamID: String!
team: Team @connection(fields: ["teamID"]
}
is this being fixed?
Thanks for taking the time to comment. We’re working on ways to make DataStore relationships simpler. Once we get that done, we may need to adjust code in the DataStore plugin to properly handle the situation above. We’ll update this issue when we have more information.
Also experienced this! The connection works with
type Project @model @auth(rules: [{ allow: owner, operations: [read, create, delete] }]) { id: ID! name: String team: Team @connection }
but fails with
type Project @model @auth(rules: [{ allow: owner, operations: [read, create, delete] }]) { id: ID! name: String teamID: String! team: Team @connection(fields: ["teamID"] }
is this being fixed?
@palpatim @diegocstn - I think it is worth noting that the second schema creates a .hasOne
ModelAssociation
, whereas the first schema actually creates a .belongsTo
ModelAssociation
(see screenshot below that shows this). It is not always transparent to the consumer what type of ModelAssociation
is being used. But the fact that one schema works and the other does not is consistent with the original issue. The data only seems to return for .belongsTo
associations, and not .hasOne
associations.
Probably adding to the confusion/issue is that both of these schemas are called out as examples of hasOne relations in the CLI docs. It seems like either the docs need to be updated or the ModelAssociation used should be updated.
Note: the first schema being represented with .belongsTo
and the second with .hasOne
is consistent with amplify-android from what I have observed.
Screenshot of first schema being represented with a .belongsTo
ModelAssociation
:
Is there any update on this issue?
Hello, Thank you for your patience in this and we apologize for our delay in response. We have made several improvements in Datastore and API in recent releases, mainly the feature called Lazy Loading. Please upgrade your CLI version to >10.8.0 and Amplify version >2.4.0 to use this feature. Follow the steps here : https://docs.amplify.aws/cli/migration/lazy-load-custom-selection-set/#lazy-loading-connected-models
For reference, I used the following schema and code snippet. I was able to fetch the blockedProfile
inside NomadBlockedUser
. I have attached a screenshot of the console log as well.
type NomadUser @model
@auth(rules: [{ allow: public }]){
id: ID!
screenName: String
fullName: String!
aboutMe: String
}
type NomadBlockedUser @model
@auth(rules: [{ allow: public }])
{
id: ID!
owner: String
blockedProfileID: ID!
blockedProfile: NomadUser @hasOne(fields: ["blockedProfileID"])
blockedCognitoId: String
}
func createUserAndQuery() async {
do {
let nomadUser = NomadUser(fullName: "dummyUser")
let savedNomadUser = try await Amplify.DataStore.save(nomadUser)
print("[GH1107]Saved user: \(savedNomadUser)")
let nomadBlockedUser = NomadBlockedUser(blockedProfileID: nomadUser.id)
let savedNomadBlockedUser = try await Amplify.DataStore.save(nomadBlockedUser)
print("[GH1107]Saved blocked user: \(savedNomadBlockedUser)")
let queriedBlockedUsers = try await Amplify.DataStore.query(NomadBlockedUser.self)
print("[GH1107]Queried blocked user list count: \(queriedBlockedUsers.count)")
let blockedUser = queriedBlockedUsers[0]
let containedUser = try await blockedUser.blockedProfile
print("[GH1107]Contained user: \(String(describing: containedUser))")
} catch {
print("[GH1107]Failed with error : \(error)")
}
}