Skip to content

Commit 876475f

Browse files
committed
chore(api): swift graphQL relational models code snippets
1 parent b7e427a commit 876475f

File tree

1 file changed

+234
-6
lines changed
  • src/pages/[platform]/build-a-backend/graphqlapi/relational-models

1 file changed

+234
-6
lines changed

src/pages/[platform]/build-a-backend/graphqlapi/relational-models/index.mdx

Lines changed: 234 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ export const meta = {
44
title: 'Relational models',
55
description:
66
'Learn more about how API (GraphQL) handles relationships between Models, such as "has one", "has many", "belongs to".',
7-
platforms: ['android']
7+
platforms: [
8+
'android',
9+
'swift'
10+
]
811
};
912

1013
export const getStaticPaths = async () => {
@@ -20,7 +23,7 @@ export function getStaticProps(context) {
2023
};
2124
}
2225

23-
<InlineFilter filters={["android"]}>
26+
<InlineFilter filters={["android", "swift"]}>
2427

2528
API (GraphQL) has the capability to handle relationships between Models, such as _has one_, _has many_, and _belongs to_. In Amplify GraphQL APIs, this is done with the `@hasOne`, `@hasMany` and `@belongsTo` directives as defined in the [GraphQL data modeling documentation](/[platform]/build-a-backend/graphqlapi/data-modeling/).
2629

@@ -44,6 +47,20 @@ If you already have relational models in your project, you must re-run `amplify
4447

4548
</InlineFilter>
4649

50+
<InlineFilter filters={["swift"]}>
51+
52+
- Amplify CLI v10.8.0
53+
- Amplify Library for Swift v2.4.0
54+
- This guide uses updated model types generated by the Amplify CLI. To follow this guide, locate `"generatemodelsforlazyloadandcustomselectionset"` in `{project-directory}/amplify/cli.json` and set the value to `true`.
55+
56+
<Callout>
57+
58+
If you already have relational models in your project, you must re-run `amplify codegen models` after updating the feature flag. After the models have been updated, breaking changes will need to be addressed because some relationships have changed to `async`. Follow the rest of the guide on this page information on how to use the new lazy supported models.
59+
60+
</Callout>
61+
62+
</InlineFilter>
63+
4764
## Create a GraphQL schema with relationships between models
4865

4966
For the following example, let's add a Post and Comment model to the [schema](/[platform]/build-a-backend/graphqlapi/set-up-graphql-api/#creating-your-first-api-and-database-table):
@@ -157,6 +174,37 @@ try {
157174

158175
</InlineFilter>
159176

177+
<InlineFilter filters={["swift"]}>
178+
179+
<Block>
180+
181+
```swift
182+
do {
183+
let post = Post(title: "My post with comments",
184+
rating: 10)
185+
let comment = Comment(content: "Loving Amplify API!",
186+
post: post) // Directly pass in the post instance
187+
188+
let createPostResult = try await Amplify.API.mutate(request: .create(post))
189+
guard case .success = createPostResult else {
190+
print("API response: \(createPostResult)")
191+
return
192+
}
193+
print("Post created.")
194+
let createCommentResult = try await Amplify.API.mutate(request: .create(comment))
195+
guard case .success = createCommentResult else {
196+
print("API response: \(createCommentResult)")
197+
return
198+
}
199+
print("Comment created.")
200+
} catch {
201+
print("Create post or comment failed", error)
202+
}
203+
```
204+
205+
</Block>
206+
</InlineFilter>
207+
160208
## Querying relationships
161209

162210
This example demonstrates an initial load of a Post with a subsequent fetch to load a page of comments for the post.
@@ -439,6 +487,32 @@ suspend fun getCommentsForPost(post: Post) {
439487

440488
</InlineFilter>
441489

490+
<InlineFilter filters={["swift"]}>
491+
492+
<Block>
493+
494+
```swift
495+
do {
496+
let queryPostResult = try await Amplify.API.query(request: .get(Post.self, byIdentifier: "123"))
497+
guard case .success(let queriedPostOptional) = queryPostResult,
498+
let queriedPost = queriedPostOptional,
499+
let comments = queriedPost.comments else {
500+
print("API response: \(queryPostResult)")
501+
return
502+
}
503+
try await comments.fetch()
504+
print("Fetched \(comments.count) comments")
505+
} catch {
506+
print("Failed to query post or fetch comments", error)
507+
}
508+
```
509+
510+
</Block>
511+
512+
Always call `fetch()` to load or retrieve the comments. If the comments were loaded as part of the query, it will return immediately. See [Customizing Query Depth](#customizing-query-depth-with-custom-selection-sets) to learn how to eagerly load connected relationships.
513+
514+
</InlineFilter>
515+
442516
## Deleting relationships
443517

444518
When you delete a parent object in a one-to-many relationship, the children will not be removed. Delete the children before deleting the parent to prevent orphaned data.
@@ -502,6 +576,33 @@ try {
502576

503577
</InlineFilter>
504578

579+
<InlineFilter filters={["swift"]}>
580+
581+
<Block>
582+
583+
```swift
584+
do {
585+
let deleteCommentResult = try await Amplify.API.mutate(request: .delete(comment))
586+
guard case .success = deleteCommentResult else {
587+
print("API response: \(deleteCommentResult)")
588+
return
589+
}
590+
// Once all comments for a post are deleted, the post can be deleted.
591+
let deletePostResult = try await Amplify.API.mutate(request: .delete(post))
592+
guard case .success = deletePostResult else {
593+
print("API response: \(deletePostResult)")
594+
return
595+
}
596+
print("Deleted comment and post")
597+
} catch {
598+
print("Failed to delete comment or post", error)
599+
}
600+
```
601+
602+
</Block>
603+
604+
</InlineFilter>
605+
505606
## Many-to-many relationships
506607

507608
For many-to-many relationships, you can use the `@manyToMany` directive and specify a `relationName`. Under the hood, Amplify creates a join table and a one-to-many relationship from both models.
@@ -645,6 +746,40 @@ This example illustrates the complexity of working with multiple sequential crea
645746
646747
</InlineFilter>
647748
749+
<InlineFilter filters={["swift"]}>
750+
751+
<Block>
752+
753+
```swift
754+
do {
755+
let post = Post(title: "My Post", rating: 10)
756+
let user = User(username: "User")
757+
let postEditor = PostEditor(post: post, user: user)
758+
759+
let createPostResult = try await Amplify.API.mutate(request: .create(post))
760+
guard case .success = createPostResult else {
761+
print("API response: \(createPostResult)")
762+
return
763+
}
764+
let createUserResult = try await Amplify.API.mutate(request: .create(user))
765+
guard case .success = createUserResult else {
766+
print("API response: \(createUserResult)")
767+
return
768+
}
769+
let createPostEditorResult = try await Amplify.API.mutate(request: .create(postEditor))
770+
guard case .success = createPostEditorResult else {
771+
print("API response: \(createPostEditorResult)")
772+
return
773+
}
774+
} catch {
775+
print("Failed to create post, user, or post editor", error)
776+
}
777+
```
778+
779+
</Block>
780+
781+
</InlineFilter>
782+
648783
## Customizing query depth with custom selection sets
649784
650785
You can perform a nested query through one network request, by specifying which connected models to include. This is achieved by using the optional `includes` parameter for a GraphQL request.
@@ -726,6 +861,36 @@ This will populate the selection set of the post in the GraphQL document which i
726861
727862
</InlineFilter>
728863
864+
<InlineFilter filters={["swift"]}>
865+
866+
<Block>
867+
868+
```swift
869+
do {
870+
let queryCommentResult = try await Amplify.API.query(request:
871+
.get(Comment.self,
872+
byIdentifier: "c1",
873+
includes: { comment in
874+
[comment.post]
875+
}))
876+
guard case .success(let queriedCommentOptional) = queryCommentResult,
877+
let queriedComment = queriedCommentOptional,
878+
let loadedPost = try await queriedComment.post else {
879+
print("API response: \(queryCommentResult)")
880+
return
881+
}
882+
883+
print("Post: ", loadedPost)
884+
} catch {
885+
print("Failed to query comment with post", error)
886+
}
887+
```
888+
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 the comment is loaded, the post model is immediately available in-memory without requiring an additional network request.
889+
890+
</Block>
891+
892+
</InlineFilter>
893+
729894
Query for the `Post` and the first page of comments for the post:
730895
731896
<InlineFilter filters={["android"]}>
@@ -836,11 +1001,11 @@ This query fetches a comment, eagerly loading the parent post and first page of
8361001
8371002
```java
8381003
ModelQuery.get<PostEditor, PostEditorPath>(PostEditor::class.java, "pe1") { postEditorPath ->
839-
includes(postEditorPath.post, postEditorPath.comments)
1004+
includes(postEditorPath.post, postEditorPath.user)
8401005
}
8411006
```
8421007
843-
This query fetches a postEditor and eagerly loads its post and comments
1008+
This query fetches a postEditor and eagerly loads its post and user
8441009
8451010
</Block>
8461011
<Block name="Kotlin">
@@ -850,15 +1015,78 @@ ModelQuery.get<PostEditor, PostEditorPath>(
8501015
PostEditor::class.java,
8511016
"pe1"
8521017
) { postEditorPath ->
853-
includes(postEditorPath.post, postEditorPath.comments)
1018+
includes(postEditorPath.post, postEditorPath.user)
8541019
}
8551020
```
8561021
857-
This query fetches a postEditor and eagerly loads its post and comments
1022+
This query fetches a postEditor and eagerly loads its post and user
8581023
8591024
</Block>
8601025
</BlockSwitcher>
8611026
8621027
</InlineFilter>
8631028
1029+
<InlineFilter filters={["swift"]}>
1030+
1031+
<Block>
1032+
1033+
```swift
1034+
do {
1035+
let queryPostResult = try await Amplify.API.query(request:
1036+
.get(Post.self,
1037+
byIdentifier: "p1",
1038+
includes: { post in
1039+
[post.comments]
1040+
}))
1041+
guard case .success(let queriedPostOptional) = queryPostResult,
1042+
let queriedPost = queriedPostOptional,
1043+
let comments = queriedPost.comments else {
1044+
print("API response: \(queryPostResult)")
1045+
return
1046+
}
1047+
1048+
try await comments.fetch()
1049+
print("Comments: ", comments)
1050+
} catch {
1051+
print("Failed to query post with comments", error)
1052+
}
1053+
```
1054+
1055+
The network request for post includes the comments, eagerly loading the first page of comments in a single network call.
1056+
1057+
</Block>
1058+
1059+
You can generate complex nested queries through the includes parameter.
1060+
1061+
<Block>
1062+
1063+
```swift
1064+
let queryCommentResult = try await Amplify.API.query(request:
1065+
.get(Comment.self,
1066+
byIdentifier: "p1",
1067+
includes: { comment in
1068+
[comment.post.comments]
1069+
}))
1070+
```
1071+
1072+
This query fetches a comment, eagerly loading the parent post and first page of comments for the post.
1073+
1074+
</Block>
1075+
1076+
<Block>
1077+
1078+
```swift
1079+
let queryCommentResult = try await Amplify.API.query(request:
1080+
.get(PostEditor.self,
1081+
byIdentifier: "pe1",
1082+
includes: { postEditor in
1083+
[postEditor.post, postEditor.user]
1084+
}))
1085+
```
1086+
1087+
This query fetches a postEditor and eagerly loads its post and user
1088+
1089+
</Block>
1090+
</InlineFilter>
1091+
8641092
</InlineFilter>

0 commit comments

Comments
 (0)