Mutation and update cache

Now let's do the integration part. Open Todo/TodoVC.swift and add the following code at the bottom of the file:

githubTodo/TodoVC.swift
// Toggle Todos to Cloud
private func toggleTodosMutationCloud(checked: Bool, index: Int!){
apollo.perform(mutation: ToggleTodoMutation(id: filteredTodos[index].id, isCompleted: checked)) { (result, error) in
guard let data = result?.data else { return }
if data.updateTodos?.affectedRows == 1 { return } else {
// With some error - revert to original state : Watcher will update the table anyways on local cache update
self.toggleTodosMutationLocal(id: index, checked: checked)
}
}
}

Lets also, add the function for adding the mutation to the local cache,

// Toggle Todos local cache
private func toggleTodosMutationLocal(id: Int, checked: Bool){
_ = apollo.store.withinReadWriteTransaction{ transaction in
let query = GetMyTodosQuery()
try transaction.update(query: query) { (data: inout GetMyTodosQuery.Data) in
let todos = data.todos
guard let index = todos.firstIndex(where: {$0.id == id}) else {return}
data.todos[index].isCompleted = checked
_ = self.apollo.store.load(query: query).andThen({ (data) in
// Watch your data in local cache
// dump(data.data?.resultMap)
// Look for errors
// dump(data.errors)
})
}
}
}

We need to modify our todoQueryCloud to todoQueryWacther to watch for changes in a particular query on the local cache. To make sure, it is initialized properly and discarded we need to update our viewWillAppear and viewWillDisapper:

// Todo Query Watcher from local cache
- private func todoQueryCloud(){
- apollo.fetch(query: GetMyTodosQuery()){ (result, error) in
+ private func todoQueryWatcher() -> GraphQLQueryWatcher<GetMyTodosQuery>{
+ return apollo.watch(query: GetMyTodosQuery(), resultHandler: {(result, error) in
if ((error) != nil) {
if SessionManager.shared.logout() {
self.performSegue(withIdentifier: "loginVC", sender: self)
}
return
}
guard let data = result?.data else { return }
self.todos = data.todos
- self.filteredTodos = data.todos
+ self.filteredTodos = self.getFilteredTodos(segmentIndex: self.todoFilter.selectedSegmentIndex)
self.setupUI()
self.todoTable.reloadData()
})
}
override func viewWillAppear(_ animated: Bool) {
if( SessionManager.shared.credentials?.idToken! != nil ) {
apollo = NetworkManager.shared.apolloClient
// Initialize a Watcher to check for updates
- todoQueryCloud()
+ todoWatcher = todoQueryWatcher()
}
}
+ override func viewWillDisappear(_ animated: Bool) {
+ todoWatcher?.cancel()
+ }

todoWatcher will update the todos and filteredTodos when there is any update in the cache.

We already have the onChange handler checkBox for the tablecell. Let's update the function to make a mutation.

// OnClick of Checkbox
func checkBox(checked: Bool, index: Int!) {
// Optimistic update & Change UI
toggleTodosMutationLocal(id: filteredTodos[index].id, checked: checked)
let index = self.todos.firstIndex{$0.id == filteredTodos[index].id}!
todos[index].isCompleted = checked
filteredTodos[index].isCompleted = checked
todoTable.reloadRows(at: [IndexPath(row: index, section: 0)], with: UITableView.RowAnimation.automatic)
// Update Network
toggleTodosMutationCloud(checked: checked, index: index)
}

The above code will just make a mutation, updating the todo's isCompleted property in the local cache. After updating the cache, we update the UI to make this change visible. And then call the toggleTodosMutationCloud to update the cloud. If there was any error, in updating the cloud, it will inturn update the local cache and through watcher, it will automatically revert to the original state.

Did you find this page helpful?
Start with GraphQL on Hasura for Free
  • ArrowBuild apps and APIs 10x faster
  • ArrowBuilt-in authorization and caching
  • Arrow8x more performant than hand-rolled APIs
Promo
footer illustration
Brand logo
© 2024 Hasura Inc. All rights reserved
Github
Titter
Discord
Facebook
Instagram
Youtube
Linkedin
graphql-handbook