amplify-swift
amplify-swift copied to clipboard
Connections are null
Describe the bug Sub-selections for connected models are null when using the API plugin.
To Reproduce
- Create two models and a one-to-many connection.
type Store
@model
@auth(
rules: [
{allow: public, provider: iam, operations: [read]},
{allow: groups, groups: ["Free", "Paid"], operations: [read]},
{allow: groups, groups: ["Admin"], operations: [create, read, update, delete]}
]
)
{
id: ID!
active: Boolean!
name: String!
products: [Product!] @connection(keyName: "byStore", fields: ["id"])
# ...
}
type Product
@model(subscriptions: {level: public})
@searchable
@key(name: "byStore", fields: ["storeId"])
@auth(
rules: [
{allow: groups, groups: ["Free", "Paid"], operations: [read]},
{allow: groups, groups: ["Admin"], operations: [create, read, update, delete]}
]
)
{
id: ID!
@auth(rules: [
{allow: public, provider: iam, operations: [read]},
{allow: private, provider: userPools, operations: [read]}
])
groupsCanAccess: [String]!
@auth(rules: [
{allow: public, provider: iam, operations: [read]},
{allow: private, provider: userPools, operations: [read]}
])
name: String!
@auth(rules: [
{allow: public, provider: iam, operations: [read]},
{allow: private, provider: userPools, operations: [read]}
])
promoCode: String
@auth(rules: [
{allow: private, provider: iam, operations: [read]},
{allow: groups, groupsField: "groupsCanAccess", operations: [read]},
{allow: groups, groups: ["Admin"], operations: [create, read, update, delete]}
])
store: Store!
@connection(fields: ["storeId"])
@auth(rules: [
{allow: public, provider: iam, operations: [read]},
{allow: private, provider: userPools, operations: [read]}
])
storeId: ID!
@auth(rules: [
{allow: public, provider: iam, operations: [read]},
{allow: private, provider: userPools, operations: [read]}
])
# ...
}
-
Create a store and products for the store
-
Call
Amplify.API.query(request: .list(Store.self, where: Store.keys.active == true)) -
For the resulting stores,
store.productsisnull. (The query returns data in the console)
Expected behavior
store.products should contain a list of products
Environment:
- Amplify Framework Version: 4.22.0
- Dependency Manager: Cocoapods
- Swift Version : 5.2.4
Device Information:
- Device: iPhone 6S
- iOS Version: iOS 13.5.1
@royjit @drochetti @lawmicha Hi, is there any update on this issue? Thanks
Hi @TheBenck, using Amplify.API with the .list GraphQLRequest builder currently only generates the first level of fields in the selection set, which is why you do not see products being returned. I'll mark this as an feature request to add support for fetching nested levels of data.
When using DataStore, there is already support for lazy loading the list of products you have there. When you access the products, it will fetch the data from local store. If you would like to try out DataStore, you will have to amplify update api and choose Enable for DataStore, then amplify push, and use the DataStore plugin to save/query for data. DataStore docs
A workaround for API is to construct the GraphQLRequest yourself with the document containing selection set of products so the service will return that data and it will be deserialized into the list of Products
@TheBenck just to add to what @lawmicha already said, when you use models with Amplify.API, either via .get() or .list() we attempt to generate an optimal query so we don't end up automatic loading too many records at once (e.g. a store with 20,000 products).
Therefore, in a one-to-many relationship like you have, we automatically load the one side, but not the many side. We do intend to add more knobs so you can control exactly the relationships you want, in the meantime, there are some workarounds you can attempt:
- Create your own
GraphQLRequest<R>extension and provide your query:
extension GraphQLRequest {
static func getStoreWithProducts(byId id: String) -> GraphQLRequest<Store> {
// instantiate a new GraphQLRequest
// pass you own GraphQL query with the products selection set
}
}
// then
Amplify.API.query(request: .getStoreWithProducts(byId: "store-id")) {
// handle result
}
- Query products by a store id:
Amplify.API.query(request: .list(Product.self, where: Product.keys.storeId == store.id)) {
// handle result
}
@lawmicha @drochetti Thanks for the explanation! It's more clear to me now 👍 The nested query feature would be nice as well but this is a good work around too
Hello,
Custom selection sets are now supported. Please refer the updated docs below to get started with this feature. https://docs.amplify.aws/cli/migration/lazy-load-custom-selection-set/#custom-selection-sets