From 3b88106073dbd290615dca2cee06763c54fe064f Mon Sep 17 00:00:00 2001
From: Michael Law <1365977+lawmicha@users.noreply.github.com>
Date: Thu, 8 Dec 2022 15:18:33 -0500
Subject: [PATCH 1/6] feat(cli): feature flag and migration guide iOS
LazyReference ModelPath
---
.../FeatureFlags/feature-flags.json | 20 +++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/src/components/FeatureFlags/feature-flags.json b/src/components/FeatureFlags/feature-flags.json
index ad8c9ec8353..b4e2750e860 100644
--- a/src/components/FeatureFlags/feature-flags.json
+++ b/src/components/FeatureFlags/feature-flags.json
@@ -659,6 +659,26 @@
"defaultExistingProject": true
}
]
+ },
+ "generateLazyReferenceAndModelPath": {
+ "description": "Generate models with LazyReference and ModelPath",
+ "type": "Feature",
+ "valueType": "Boolean",
+ "versionAdded": "x.x.x",
+ "values": [
+ {
+ "value": "true",
+ "description": "[Recommended] Add support for custom selection set and lazy loading.",
+ "defaultNewProject": true,
+ "defaultExistingProject": false
+ },
+ {
+ "value": "false",
+ "description": "iOS models will not support selection set customization and continue to eager load certain associations.",
+ "defaultNewProject": false,
+ "defaultExistingProject": true
+ }
+ ]
}
}
},
From 14dd570728cfa16ad6c1a23c518fd159d28825fd Mon Sep 17 00:00:00 2001
From: Michael Law <1365977+lawmicha@users.noreply.github.com>
Date: Wed, 28 Dec 2022 17:30:38 -0500
Subject: [PATCH 2/6] migration guide
---
.../FeatureFlags/feature-flags.json | 10 +-
src/directory/directory.js | 5 +
src/pages/cli/graphql/data-modeling.mdx | 5 -
.../lazy-load-custom-selection-set.mdx | 356 ++++++++++++++++++
4 files changed, 366 insertions(+), 10 deletions(-)
create mode 100644 src/pages/cli/migration/lazy-load-custom-selection-set.mdx
diff --git a/src/components/FeatureFlags/feature-flags.json b/src/components/FeatureFlags/feature-flags.json
index b4e2750e860..c5b79a9efd1 100644
--- a/src/components/FeatureFlags/feature-flags.json
+++ b/src/components/FeatureFlags/feature-flags.json
@@ -660,21 +660,21 @@
}
]
},
- "generateLazyReferenceAndModelPath": {
- "description": "Generate models with LazyReference and ModelPath",
+ "generateModelsForLazyLoadAndCustomSelectionSet": {
+ "description": "Generate models for lazy loading and custom selection set",
"type": "Feature",
"valueType": "Boolean",
"versionAdded": "x.x.x",
"values": [
{
"value": "true",
- "description": "[Recommended] Add support for custom selection set and lazy loading.",
- "defaultNewProject": true,
+ "description": "[Recommended] Add support for lazy loading and custom selection set.",
+ "defaultNewProject": false,
"defaultExistingProject": false
},
{
"value": "false",
- "description": "iOS models will not support selection set customization and continue to eager load certain associations.",
+ "description": "models will not support selection set customization and lazy loading.",
"defaultNewProject": false,
"defaultExistingProject": true
}
diff --git a/src/directory/directory.js b/src/directory/directory.js
index 2de85ae6f2b..1256e8ee5ed 100644
--- a/src/directory/directory.js
+++ b/src/directory/directory.js
@@ -1947,6 +1947,11 @@ const directory = {
migration: {
title: 'Migration & Backwards Compatibility',
items: [
+ {
+ title: 'Lazy Loading and Custom Selection Set',
+ route: '/cli/migration/lazy-load-custom-selection-set',
+ filters: []
+ },
{
title: 'GraphQL Transformer v1 to v2 migration',
route: '/cli/migration/transformer-migration',
diff --git a/src/pages/cli/graphql/data-modeling.mdx b/src/pages/cli/graphql/data-modeling.mdx
index 7865f3ec710..b23dee67855 100644
--- a/src/pages/cli/graphql/data-modeling.mdx
+++ b/src/pages/cli/graphql/data-modeling.mdx
@@ -316,11 +316,6 @@ mutation CreatePost {
### Belongs To relationship
-
-
-Bi-directional "has one" relationships currently cannot be represented on iOS due to Swift language limitations.
-
-
Make a "has one" or "has many" relationship bi-directional with the `@belongsTo` directive.
diff --git a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
new file mode 100644
index 00000000000..6eb0c047fbc
--- /dev/null
+++ b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
@@ -0,0 +1,356 @@
+export const meta = {
+ title: `Lazy Loading and Custom Selection Set`,
+ description: `Lazy Loading and Custom Selection Set`,
+};
+
+## **What is changing?**
+
+With the latest Amplify Swift library and Amplify Codegen, developers now have better query controls on connected models, described as lazy loading and eager loading a connected model.
+
+* **API (GraphQL)** now allows Selection Set customizations by providing the `includes` parameter to control the depth of the selection set specifying which connected model to eager load or lazy load.
+* **Models** now have extended support for lazy loading connected models to include has-one and belongs-to relations.
+* **DataStore (Swift)** now has better support for cross platform app development. Model updates from Amplify Studio and the Amplify Libraries including JavaScript and Android can be now observed in real-time by DataStore Swift apps.
+* **DataStore (Swift)** now supports the bi-directional has-one data modeling use case.
+
+
+## Custom Selection Sets
+
+Developers using **API (GraphQL)** can control the data returned from their GraphQL service. The request for a particular model can include or exclude connected models. Let’s take a look at the schema with Post and Comment models in the following examples. A comment belongs to a post and a post has many comments.
+
+```
+enum PostStatus {
+ ACTIVE
+ INACTIVE
+}
+
+type Post @model @auth(rules: [{allow: public}]) {
+ id: ID!
+ title: String!
+ rating: Int!
+ status: PostStatus!
+ comments: [Comment] @hasMany
+}
+
+type Comment @model @auth(rules: [{allow: public}]) {
+ id: ID!
+ content: String
+ post: Post @belongsTo
+}
+```
+
+Currently, developers querying for the Comment will contain the Post eager loaded:
+
+
+
+
+```swift
+let response = try await Amplify.API.query(.get(Comment.self, byId: "commentId"))
+if case .success(let graphQLResponse) = response,
+ case .success(let queriedComment) = graphQLResponse {
+ print("Queried Comment eager loaded post: \(queriedComment.post)")
+}
+```
+
+
+
+
+With the new model types and library changes, the same request will no longer eager load the post. The post is lazy loaded from the GraphQL service at the time the post is accessed.
+
+
+
+
+```swift
+let response = try await Amplify.API.query(.get(Comment.self, byId: "commentId"))
+
+if case .success(let graphQLResponse) = response,
+ case .success(let queriedComment) = graphQLResponse {
+ print("Queried Comment \(queriedComment)")
+ // Lazy Load the post
+ if let post = try await queriedComment.post {
+ print("Lazy loaded the post: \(post)")
+ }
+}
+```
+
+
+
+
+To achieve the previous behavior, specifying the model path using the new `includes` parameter:
+
+
+
+
+```swift
+let response = try await Amplify.API.query(request: .get(
+ Comment.self,
+ byId: "commentId",
+ includes: { comment in [comment.post] }))
+
+if case .success(let graphQLResponse) = response,
+ case .success(let queriedComment) = graphQLResponse {
+ if let post = try await queriedComment.post {
+ print("Loaded post: \(post)")
+ }
+}
+```
+
+This will populate the Selection Set of the post in the GraphQL document which indicates to your GraphQL service to retrieve the post model as part of the operation. Once you await on the post, the post model will immediately be returned without making a service call.
+
+
+
+
+This customization extends to has-many relationships as well. Let's take for example, the queried post.
+
+
+
+
+```swift
+let response = try await Amplify.API.query(request: .get(Post.self, byId: "postId"))
+
+if case .success(let graphQLResponse) = response,
+ case .success(let queriedPost) = graphQLResponse {
+ print("Queried Post \(queriedPost)")
+ // Lazy Load the comments
+ try await queriedPost.comments.fetch()
+ for comment in queriedPost.comments {
+ print("lazy loaded comment: \(comment)")
+ }
+}
+```
+The queried post allows you to lazy load the comments by calling `fetch()` and it will make a network request.
+
+
+
+
+The comments can be eager loaded by including the post’s model path to the comment:
+
+
+
+
+```swift
+let response = try await Amplify.API.query(request: .get(
+ Post.self,
+ byId: "postId",
+ includes: { post in [ post.comments] }))
+
+if case .success(let graphQLResponse) = response,
+ case .success(let queriedPost) = graphQLResponse {
+ print("Queried Post \(queriedPost)")
+ try await queriedPost.comments.fetch()
+ for comment in queriedPost.comments {
+ print("eager loaded comment: \(comment)")
+ }
+}
+```
+
+The network request for post includes the comments, eager loading the comments in a single network call.
+
+
+
+
+This customization can be extended to including or excluding deeply connected models. If the Post and Comment each belong to a User specified by the field “author”, then a single request can be constructed to retrieve its nested models.
+
+
+
+
+```swift
+let response = try await Amplify.API.query(request: .get(
+ Post.self,
+ byId: "postId",
+ includes: { post in [
+ post.author,
+ post.comments,
+ post.comments.author] }))
+```
+
+The post, its comments, and the author of the post and each of its comments will be retrieved in a single network call.
+
+
+
+
+## Lazy Loading connected models
+
+Whether you are using **DataStore** or **API**, once you have retrieved a model, you can traverse the model graph from a single model instance to its connected models through the APIs available.
+
+### belongs-to / has-one
+
+For has-one and belongs-to relations, access it by awaiting for the post. This will retrieve the model from your GraphQL service or local database in DataStore.
+
+
+
+```swift
+let comment = /* queried from Amplify.API or Amplify.DataStore, or lazy loaded from a post */
+let post = try await comment.post
+let authorOfPost = try await post.author
+```
+
+
+
+
+### has-many
+
+For has-many relations, call `fetch()` to load the posts. This will retrieve the list of models from your data source.
+
+
+
+
+```swift
+let post = /* queried from Amplify.API or Amplify.DataStore, or lazy loaded from a comment */
+try await post.comments.fetch()
+if let allCommentsForPost = post.comments {
+ for comment in allCommentsForPost {
+ print("Comment \(comment) for post \(post)")
+ }
+}
+```
+If there are additional pages of data available, `hasNextPage()` will return true. Call `getNextPage()` to get the next page of comments.
+
+```swift
+if allCommentsForPost.hasNextPage() {
+ let nextPageOfComments = try await allCommentsForPost.getNextPage()
+}
+```
+
+
+
+
+The following is a full example of lazy loading belongs-to and has-many connected models.
+
+
+
+
+
+```swift
+let comment = /* queried from Amplify.API or Amplify.DataStore, or lazy loaded from a post */
+let post = try await comment.post
+let authorOfPost = try await post.author
+try await post.comments.fetch()
+if let allCommentsForPost = post.comments {
+ for comment in allCommentsForPost {
+ let commentAuthor = try await comment.user
+ print("Author \(commentAuthor) wrote comment \(comment) for post \(post)")
+ }
+ if allCommentsForPost.hasNextPage() {
+ let nextPageOfComments = try await allCommentsForPost.getNextPage()
+ }
+}
+```
+
+The queried comment is used to lazy load its post. The author of the post is lazy loaded from the post. All of the comments for the post are lazy loaded as `allCommentsForPost`. For each comment, the author is loaded as `commentAuthor`. If there are more comments to load, `hasNextPage()` returns true and `getNextPage()` loads the next page from the underlying data source.
+
+
+
+
+
+## Cross platform app development with DataStore (Swift)
+
+Developers building with **DataStore (Swift)** can now receive real-time model updates coming from other platforms such as Amplify Studio and Amplify JavaScript and Android libraries. Previously, model updates (save/update/deletes) from other platforms will not be observed successfully by your iOS/macOS app running **DataStore (Swift)**. With the latest codegen and library changes, DataStore has been updated to successfully reconcile those model updates coming from other platforms, and will subsequently emit the event to your `DataStore.observe` API.
+
+To try this out, launch your iOS app with [verbose logging](https://docs.amplify.aws/lib/project-setup/create-application/q/platform/ios/#2-install-amplify-libraries) and [DataStore started](https://docs.amplify.aws/lib/datastore/other-methods/q/platform/ios/#start). Performing model updates using DataStore from any other platform will automatically synchronize data to your iOS/macOS app. You will see logs indicating that DataStore has successfully received and reconcile the model update immediately. To access the updates in your app, follow the [Real time guide to observe updates of data](https://docs.amplify.aws/lib/datastore/real-time/q/platform/ios/).
+
+## DataStore (Swift) Bi-directional “has one” relationship support
+
+**DataStore (Swift)** now supports [Bi-directional “has one” relationship](https://docs.amplify.aws/cli/graphql/data-modeling/#belongs-to-relationship). Previously, due to Swift language limitations the generated Swift model types will not compile.
+
+```
+type Project @model {
+ id: ID!
+ name: String
+ team: Team @hasOne
+}
+
+type Team @model {
+ id: ID!
+ name: String!
+ project: Project @belongsTo
+}
+```
+
+## Where do I make these changes?
+
+1. Update Amplify CLI to the latest version
+
+```
+amplify upgrade
+```
+
+2. The version should be at least x.x.x
+
+```
+amplify --v # at least x.x.x
+```
+
+3. Set the feature flag `generateModelsForLazyLoadAndCustomSelectionSet` to `true` in `cli.json` at the amplify project root.
+
+4. Run `amplify codegen models` to generate the latest models.
+
+5. Upgrade Amplify libraries to x.x.x or greater.
+
+6. Open the App and make sure the app compiles with the latest generated models.
+
+## What are the breaking changes?
+
+By explicitly enabling the feature flag `generateModelsForLazyLoadAndCustomSelectionSet` and using the latest Amplify Library, there are a few scenarios you may be in.
+
+### Scenario 1. Using API (GraphQL)
+
+**Amplify.API** will no longer eager load the belongs-to and has-one connected models when using the latest codegen. To allow your app backwards compatibility with previous versions of your app, specify the model path with `includes` for all belongs-to and has-one relationships. This is crucial to allow previous versions of the app to decode mutations sourced from new versions of the app successfully.
+
+
+
+
+Your released app makes subscription and mutation requests:
+
+```swift
+let subscription = Amplify.API.subscribe(request: .onCreate(Comment.self))
+```
+```swift
+let graphQLResponse = try await Amplify.API.mutate(.create(comment))
+```
+
+The selection set on the mutation request is aligned with the selection set on the subscription request. It will include the post fields and the response payload received by the subscription can be decoded to the previous Comment model type.
+
+
+
+
+If the model types have been replaced with the latest codegen for lazy loading, the same mutation will no longer include the post fields, causing the subscription in the previous app to fail decoding the response payload. To make sure the new version of the app works with previous versions, include the belongs-to and has-one connected models in the selection set using the `includes` parameter of your mutation request.
+
+
+
+
+```swift
+let graphQLResponse = try await Amplify.API.mutate(.create(comment, includes: { comment in [ comment.post ]}))
+```
+
+
+
+
+### Scenario 2. Using DataStore (Swift)
+
+DataStore will no longer eager load the belongs-to and has-one connected models when using the latest codegen. Your new app will continue to be backwards compatible with previous versions, however the call pattern to retrieve these connected models have changed. See the next scenario for the changes you have to make at the call site.
+
+### Scenario 3. Belongs-to / has-one access pattern
+
+
+
+
+Previously
+
+```swift
+let comment = /* queried Comment through DataStore or API */
+let post = comment.post
+```
+
+With the latest codegen
+
+```swift
+let comment = /* queried Comment through DataStore or API */
+let post = try await comment.post
+```
+
+
+
+
+
+
+
From 106446ea670238331862f1af54bce56a8eed81e5 Mon Sep 17 00:00:00 2001
From: Michael Law <1365977+lawmicha@users.noreply.github.com>
Date: Fri, 13 Jan 2023 11:03:40 -0500
Subject: [PATCH 3/6] fix code snippets
---
.../lazy-load-custom-selection-set.mdx | 131 +++++++++---------
1 file changed, 68 insertions(+), 63 deletions(-)
diff --git a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
index 6eb0c047fbc..be8c7db0b99 100644
--- a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
+++ b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
@@ -41,13 +41,12 @@ type Comment @model @auth(rules: [{allow: public}]) {
Currently, developers querying for the Comment will contain the Post eager loaded:
-
+
```swift
-let response = try await Amplify.API.query(.get(Comment.self, byId: "commentId"))
-if case .success(let graphQLResponse) = response,
- case .success(let queriedComment) = graphQLResponse {
- print("Queried Comment eager loaded post: \(queriedComment.post)")
+let response = try await Amplify.API.query(request: .get(Comment.self, byId: comment.id))
+if case .success(let queriedComment) = response {
+ print("Queried Comment eager loaded post: \(queriedComment?.post)")
}
```
@@ -57,18 +56,16 @@ if case .success(let graphQLResponse) = response,
With the new model types and library changes, the same request will no longer eager load the post. The post is lazy loaded from the GraphQL service at the time the post is accessed.
-
+
```swift
-let response = try await Amplify.API.query(.get(Comment.self, byId: "commentId"))
-
-if case .success(let graphQLResponse) = response,
- case .success(let queriedComment) = graphQLResponse {
- print("Queried Comment \(queriedComment)")
- // Lazy Load the post
- if let post = try await queriedComment.post {
- print("Lazy loaded the post: \(post)")
- }
+let response = try await Amplify.API.query(request: .get(Comment.self, byId: "commentId"))
+if case .success(let queriedComment) = response {
+ print("Queried Comment \(String(describing: queriedComment))")
+ // Lazy Load the post
+ if let post = try await queriedComment?.post {
+ print("Lazy loaded the post: \(post)")
+ }
}
```
@@ -78,19 +75,19 @@ if case .success(let graphQLResponse) = response,
To achieve the previous behavior, specifying the model path using the new `includes` parameter:
-
+
```swift
-let response = try await Amplify.API.query(request: .get(
- Comment.self,
- byId: "commentId",
- includes: { comment in [comment.post] }))
-
-if case .success(let graphQLResponse) = response,
- case .success(let queriedComment) = graphQLResponse {
- if let post = try await queriedComment.post {
- print("Loaded post: \(post)")
- }
+let response = try await Amplify.API.query(request:
+ .get(Comment.self,
+ byId: "commentId",
+ includes: { comment in [comment.post]} ))
+if case .success(let queriedComment) = response {
+ print("Queried Comment \(String(describing: queriedComment))")
+ // Lazy Load the post
+ if let post = try await queriedComment?.post {
+ print("Lazy loaded the post: \(post)")
+ }
}
```
@@ -102,19 +99,22 @@ This will populate the Selection Set of the post in the GraphQL document which i
This customization extends to has-many relationships as well. Let's take for example, the queried post.
-
+
```swift
-let response = try await Amplify.API.query(request: .get(Post.self, byId: "postId"))
-
-if case .success(let graphQLResponse) = response,
- case .success(let queriedPost) = graphQLResponse {
- print("Queried Post \(queriedPost)")
- // Lazy Load the comments
- try await queriedPost.comments.fetch()
- for comment in queriedPost.comments {
- print("lazy loaded comment: \(comment)")
- }
+let response = try await Amplify.API.query(request:
+ .get(Post.self,
+ byId: "postId"))
+
+if case .success(let queriedPost) = response {
+ print("Queried Post \(String(describing: queriedPost))")
+ if let comments = queriedPost?.comments {
+ // Lazy Load the comments
+ try await comments.fetch()
+ for comment in comments {
+ print("Lazy loaded comment: \(comment)")
+ }
+ }
}
```
The queried post allows you to lazy load the comments by calling `fetch()` and it will make a network request.
@@ -125,21 +125,21 @@ The queried post allows you to lazy load the comments by calling `fetch()` and i
The comments can be eager loaded by including the post’s model path to the comment:
-
+
```swift
-let response = try await Amplify.API.query(request: .get(
- Post.self,
- byId: "postId",
- includes: { post in [ post.comments] }))
-
-if case .success(let graphQLResponse) = response,
- case .success(let queriedPost) = graphQLResponse {
- print("Queried Post \(queriedPost)")
- try await queriedPost.comments.fetch()
- for comment in queriedPost.comments {
- print("eager loaded comment: \(comment)")
- }
+let response = try await Amplify.API.query(request:
+ .get(Post.self,
+ byId: "postId",
+ includes: { post in [ post.comments] }))
+
+if case .success(let queriedPost) = response {
+ print("Queried Post \(String(describing: queriedPost))")
+ if let comments = queriedPost?.comments {
+ for comment in comments {
+ print("Eager loaded comment: \(comment)")
+ }
+ }
}
```
@@ -151,7 +151,7 @@ The network request for post includes the comments, eager loading the comments i
This customization can be extended to including or excluding deeply connected models. If the Post and Comment each belong to a User specified by the field “author”, then a single request can be constructed to retrieve its nested models.
-
+
```swift
let response = try await Amplify.API.query(request: .get(
@@ -176,7 +176,7 @@ Whether you are using **DataStore** or **API**, once you have retrieved a model,
For has-one and belongs-to relations, access it by awaiting for the post. This will retrieve the model from your GraphQL service or local database in DataStore.
-
+
```swift
let comment = /* queried from Amplify.API or Amplify.DataStore, or lazy loaded from a post */
@@ -192,12 +192,12 @@ let authorOfPost = try await post.author
For has-many relations, call `fetch()` to load the posts. This will retrieve the list of models from your data source.
-
+
```swift
let post = /* queried from Amplify.API or Amplify.DataStore, or lazy loaded from a comment */
-try await post.comments.fetch()
if let allCommentsForPost = post.comments {
+ try await allCommentsForPost.fetch()
for comment in allCommentsForPost {
print("Comment \(comment) for post \(post)")
}
@@ -217,19 +217,24 @@ if allCommentsForPost.hasNextPage() {
The following is a full example of lazy loading belongs-to and has-many connected models.
-
+
```swift
let comment = /* queried from Amplify.API or Amplify.DataStore, or lazy loaded from a post */
-let post = try await comment.post
+guard let post = try await comment.post else {
+ print("No post associated with this comment")
+ return
+}
let authorOfPost = try await post.author
-try await post.comments.fetch()
+
if let allCommentsForPost = post.comments {
+ try await allCommentsForPost.fetch()
for comment in allCommentsForPost {
- let commentAuthor = try await comment.user
+ let commentAuthor = try await comment.author
print("Author \(commentAuthor) wrote comment \(comment) for post \(post)")
}
+
if allCommentsForPost.hasNextPage() {
let nextPageOfComments = try await allCommentsForPost.getNextPage()
}
@@ -297,7 +302,7 @@ By explicitly enabling the feature flag `generateModelsForLazyLoadAndCustomSelec
**Amplify.API** will no longer eager load the belongs-to and has-one connected models when using the latest codegen. To allow your app backwards compatibility with previous versions of your app, specify the model path with `includes` for all belongs-to and has-one relationships. This is crucial to allow previous versions of the app to decode mutations sourced from new versions of the app successfully.
-
+
Your released app makes subscription and mutation requests:
@@ -305,7 +310,7 @@ Your released app makes subscription and mutation requests:
let subscription = Amplify.API.subscribe(request: .onCreate(Comment.self))
```
```swift
-let graphQLResponse = try await Amplify.API.mutate(.create(comment))
+let graphQLResponse = try await Amplify.API.mutate(request: .create(comment))
```
The selection set on the mutation request is aligned with the selection set on the subscription request. It will include the post fields and the response payload received by the subscription can be decoded to the previous Comment model type.
@@ -316,10 +321,10 @@ The selection set on the mutation request is aligned with the selection set on t
If the model types have been replaced with the latest codegen for lazy loading, the same mutation will no longer include the post fields, causing the subscription in the previous app to fail decoding the response payload. To make sure the new version of the app works with previous versions, include the belongs-to and has-one connected models in the selection set using the `includes` parameter of your mutation request.
-
+
```swift
-let graphQLResponse = try await Amplify.API.mutate(.create(comment, includes: { comment in [ comment.post ]}))
+let graphQLResponse = try await Amplify.API.mutate(request: .create(comment, includes: { comment in [ comment.post ]}))
```
@@ -332,7 +337,7 @@ DataStore will no longer eager load the belongs-to and has-one connected models
### Scenario 3. Belongs-to / has-one access pattern
-
+
Previously
From de358960ac118de7413372a2558a8b46be1ed0ac Mon Sep 17 00:00:00 2001
From: Michael Law <1365977+lawmicha@users.noreply.github.com>
Date: Fri, 13 Jan 2023 20:11:03 -0500
Subject: [PATCH 4/6] fix code snippets
---
src/pages/cli/migration/lazy-load-custom-selection-set.mdx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
index be8c7db0b99..a270adb9b2f 100644
--- a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
+++ b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
@@ -44,7 +44,7 @@ Currently, developers querying for the Comment will contain the Post eager loade
```swift
-let response = try await Amplify.API.query(request: .get(Comment.self, byId: comment.id))
+let response = try await Amplify.API.query(request: .get(Comment.self, byId: "commentId"))
if case .success(let queriedComment) = response {
print("Queried Comment eager loaded post: \(queriedComment?.post)")
}
@@ -84,9 +84,9 @@ let response = try await Amplify.API.query(request:
includes: { comment in [comment.post]} ))
if case .success(let queriedComment) = response {
print("Queried Comment \(String(describing: queriedComment))")
- // Lazy Load the post
+
if let post = try await queriedComment?.post {
- print("Lazy loaded the post: \(post)")
+ print("Eager loaded post: \(post)")
}
}
```
From 2ae7a46f2cddd89930aebefad51dd0d518ba1ef9 Mon Sep 17 00:00:00 2001
From: Michael Law <1365977+lawmicha@users.noreply.github.com>
Date: Wed, 25 Jan 2023 13:14:12 -0500
Subject: [PATCH 5/6] address PR comments
---
.../lazy-load-custom-selection-set.mdx | 42 +++++++++----------
1 file changed, 19 insertions(+), 23 deletions(-)
diff --git a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
index a270adb9b2f..e3da7fcebb4 100644
--- a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
+++ b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
@@ -1,16 +1,16 @@
export const meta = {
- title: `Lazy Loading and Custom Selection Set`,
- description: `Lazy Loading and Custom Selection Set`,
+ title: `Amplify for Swift: Lazy Loading and Custom Selection Set`,
+ description: `Amplify library for Swift now supports custom selection sets through API (GraphQL). Models have extended support for lazy loading "has one" and "belongs to" relations. Cross platform model updates from Amplify Studio and Android can be observed in real-time by DataStore apps built with Swift. Amplify swift supports bi-directional "has one" data modeling use case.`
};
## **What is changing?**
-With the latest Amplify Swift library and Amplify Codegen, developers now have better query controls on connected models, described as lazy loading and eager loading a connected model.
+With the latest Amplify library for Swift, developers now have better query controls on connected models, described as lazy loading and eager loading a connected model.
-* **API (GraphQL)** now allows Selection Set customizations by providing the `includes` parameter to control the depth of the selection set specifying which connected model to eager load or lazy load.
-* **Models** now have extended support for lazy loading connected models to include has-one and belongs-to relations.
-* **DataStore (Swift)** now has better support for cross platform app development. Model updates from Amplify Studio and the Amplify Libraries including JavaScript and Android can be now observed in real-time by DataStore Swift apps.
-* **DataStore (Swift)** now supports the bi-directional has-one data modeling use case.
+* **API (GraphQL)** now allows selection set customizations via the `includes` parameter to control the depth of the selection set specifying which connected model to eager load or lazy load.
+* **Models** now have extended support for lazy loading connected models to include `@hasOne` and `@belongsTo` relations.
+* **DataStore (Swift)** now has better support for cross platform app development. Model updates from Amplify Studio and the Amplify Libraries including JavaScript and Android can be now observed in real-time by DataStore apps built with Swift.
+* **DataStore (Swift)** now supports the bi-directional `@hasOne` data modeling use case.
## Custom Selection Sets
@@ -38,7 +38,7 @@ type Comment @model @auth(rules: [{allow: public}]) {
}
```
-Currently, developers querying for the Comment will contain the Post eager loaded:
+Currently, developers querying for the `Comment` will contain the `Post` eager loaded:
@@ -91,12 +91,12 @@ if case .success(let queriedComment) = response {
}
```
-This will populate the Selection Set of the post in the GraphQL document which indicates to your GraphQL service to retrieve the post model as part of the operation. Once you await on the post, the post model will immediately be returned without making a service call.
+This will populate the selection set of the post in the GraphQL document which indicates to your GraphQL service to retrieve the post model as part of the operation. Once you await on the post, the post model will immediately be returned without making a network request.
-This customization extends to has-many relationships as well. Let's take for example, the queried post.
+This customization extends to `@hasMany` relationships as well. Let's take for example, the queried post.
@@ -168,13 +168,11 @@ The post, its comments, and the author of the post and each of its comments will
-## Lazy Loading connected models
+## Lazy loading connected models
Whether you are using **DataStore** or **API**, once you have retrieved a model, you can traverse the model graph from a single model instance to its connected models through the APIs available.
-### belongs-to / has-one
-
-For has-one and belongs-to relations, access it by awaiting for the post. This will retrieve the model from your GraphQL service or local database in DataStore.
+For `@hasOne` and `@belongsTo` relations, access it by awaiting for the post. This will retrieve the model from your GraphQL service or local database in DataStore.
@@ -187,9 +185,7 @@ let authorOfPost = try await post.author
-### has-many
-
-For has-many relations, call `fetch()` to load the posts. This will retrieve the list of models from your data source.
+For `@hasMany` relations, call `fetch()` to load the posts. This will retrieve the list of models from your data source.
@@ -214,7 +210,7 @@ if allCommentsForPost.hasNextPage() {
-The following is a full example of lazy loading belongs-to and has-many connected models.
+The following is a full example of lazy loading `@belongsTo` and `@hasMany` connected models.
@@ -251,7 +247,7 @@ The queried comment is used to lazy load its post. The author of the post is laz
Developers building with **DataStore (Swift)** can now receive real-time model updates coming from other platforms such as Amplify Studio and Amplify JavaScript and Android libraries. Previously, model updates (save/update/deletes) from other platforms will not be observed successfully by your iOS/macOS app running **DataStore (Swift)**. With the latest codegen and library changes, DataStore has been updated to successfully reconcile those model updates coming from other platforms, and will subsequently emit the event to your `DataStore.observe` API.
-To try this out, launch your iOS app with [verbose logging](https://docs.amplify.aws/lib/project-setup/create-application/q/platform/ios/#2-install-amplify-libraries) and [DataStore started](https://docs.amplify.aws/lib/datastore/other-methods/q/platform/ios/#start). Performing model updates using DataStore from any other platform will automatically synchronize data to your iOS/macOS app. You will see logs indicating that DataStore has successfully received and reconcile the model update immediately. To access the updates in your app, follow the [Real time guide to observe updates of data](https://docs.amplify.aws/lib/datastore/real-time/q/platform/ios/).
+To try this out, launch your iOS app with [verbose logging](https://docs.amplify.aws/lib/project-setup/create-application/q/platform/ios/#2-install-amplify-libraries) and [DataStore started](https://docs.amplify.aws/lib/datastore/other-methods/q/platform/ios/#start). Performing model updates using DataStore from any other platform and it will automatically be synchronized to your iOS/macOS app. You will see logs indicating that DataStore has successfully received and reconcile the model update immediately. To access the updates in your app, follow the [Real time guide to observe updates of data](https://docs.amplify.aws/lib/datastore/real-time/q/platform/ios/).
## DataStore (Swift) Bi-directional “has one” relationship support
@@ -299,7 +295,7 @@ By explicitly enabling the feature flag `generateModelsForLazyLoadAndCustomSelec
### Scenario 1. Using API (GraphQL)
-**Amplify.API** will no longer eager load the belongs-to and has-one connected models when using the latest codegen. To allow your app backwards compatibility with previous versions of your app, specify the model path with `includes` for all belongs-to and has-one relationships. This is crucial to allow previous versions of the app to decode mutations sourced from new versions of the app successfully.
+**Amplify.API** will no longer eager load the `@belongsTo` and `@hasOne` connected models when using the latest codegen. To allow your app backwards compatibility with previous versions of your app, specify the model path with `includes` for all `@belongsTo` and `@hasOne` relationships. This is crucial to allow previous versions of the app to decode mutations sourced from new versions of the app successfully.
@@ -318,7 +314,7 @@ The selection set on the mutation request is aligned with the selection set on t
-If the model types have been replaced with the latest codegen for lazy loading, the same mutation will no longer include the post fields, causing the subscription in the previous app to fail decoding the response payload. To make sure the new version of the app works with previous versions, include the belongs-to and has-one connected models in the selection set using the `includes` parameter of your mutation request.
+If the model types have been replaced with the latest codegen for lazy loading, the same mutation will no longer include the post fields, causing the subscription in the previous app to fail decoding the response payload. To make sure the new version of the app works with previous versions, include the `@belongsTo` and `@hasOne` connected models in the selection set using the `includes` parameter of your mutation request.
@@ -332,9 +328,9 @@ let graphQLResponse = try await Amplify.API.mutate(request: .create(comment, inc
### Scenario 2. Using DataStore (Swift)
-DataStore will no longer eager load the belongs-to and has-one connected models when using the latest codegen. Your new app will continue to be backwards compatible with previous versions, however the call pattern to retrieve these connected models have changed. See the next scenario for the changes you have to make at the call site.
+DataStore will no longer eager load the belongs-to and `@hasOne` connected models when using the latest codegen. Your new app will continue to be backwards compatible with previous versions, however the call pattern to retrieve these connected models have changed. See the next scenario for the changes you have to make at the call site.
-### Scenario 3. Belongs-to / has-one access pattern
+### Scenario 3. "Belongs to" / "Has One" access pattern
From 8fa95f63fd635487888f757e220475c337ed7a2f Mon Sep 17 00:00:00 2001
From: Michael Law <1365977+lawmicha@users.noreply.github.com>
Date: Tue, 7 Feb 2023 18:32:53 -0500
Subject: [PATCH 6/6] update CLI versions
---
src/pages/cli/migration/lazy-load-custom-selection-set.mdx | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
index e3da7fcebb4..bb7956fd399 100644
--- a/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
+++ b/src/pages/cli/migration/lazy-load-custom-selection-set.mdx
@@ -275,17 +275,17 @@ type Team @model {
amplify upgrade
```
-2. The version should be at least x.x.x
+2. The version should be at least 10.8.0
```
-amplify --v # at least x.x.x
+amplify --v # at least 10.8.0
```
3. Set the feature flag `generateModelsForLazyLoadAndCustomSelectionSet` to `true` in `cli.json` at the amplify project root.
4. Run `amplify codegen models` to generate the latest models.
-5. Upgrade Amplify libraries to x.x.x or greater.
+5. Upgrade Amplify libraries to 2.4.0 or greater.
6. Open the App and make sure the app compiles with the latest generated models.