amplify-swift icon indicating copy to clipboard operation
amplify-swift copied to clipboard

Deleting a parent in datastore doesn't delete the children

Open depthzadmin opened this issue 2 years ago • 3 comments

Describe the bug

In iOS, when you delete a parent object with a one to many relationship, the children are not removed from the DataStore.

Note that the expected behavior of deleting the children does work outside the iOS context. As an example, when I perform the same delete action in the Amplify Studio Content tab, the children are removed.

Steps To Reproduce

Steps to reproduce the behavior:
1. Setup a schema with a 1:M relationship

extension User {
  // MARK: - CodingKeys 
   public enum CodingKeys: String, ModelKey {
    case id
    case username
    case email
    case Tests
    case createdAt
    case updatedAt
  }
  
  public static let keys = CodingKeys.self
  //  MARK: - ModelSchema 
  
  public static let schema = defineSchema { model in
    let user = User.keys
    
    model.authRules = [
      rule(allow: .private, operations: [.create, .update, .delete, .read])
    ]
    
    model.pluralName = "Users"
    
    model.fields(
      .id(),
      .field(user.username, is: .required, ofType: .string),
      .field(user.email, is: .optional, ofType: .string),
      .hasMany(user.Tests, is: .optional, ofType: Test.self, associatedWith: Test.keys.userID),
      .field(user.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime),
      .field(user.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime)
    )
    }
}

extension Test {
  // MARK: - CodingKeys 
   public enum CodingKeys: String, ModelKey {
    case id
    case test
    case userID
    case createdAt
    case updatedAt
  }
  
  public static let keys = CodingKeys.self
  //  MARK: - ModelSchema 
  
  public static let schema = defineSchema { model in
    let test = Test.keys
    
    model.authRules = [
      rule(allow: .private, operations: [.create, .update, .delete, .read])
    ]
    
    model.pluralName = "Tests"
    
    model.attributes(
      .index(fields: ["userID"], name: "byUser")
    )
    
    model.fields(
      .id(),
      .field(test.test, is: .optional, ofType: .string),
      .field(test.userID, is: .required, ofType: .string),
      .field(test.createdAt, is: .optional, isReadOnly: true, ofType: .dateTime),
      .field(test.updatedAt, is: .optional, isReadOnly: true, ofType: .dateTime)
    )
    }
}


2. In iOS, use the method:

    Amplify.DataStore.delete(model) { result in
       ...
    }


3. Let datastore perform sync
4. See that parent object is deleted but the children objects remain

Expected behavior

From the Amplify documentation:

When you delete a parent object in a one to many relationship, the children will also be removed from the DataStore and mutations for this deletion will be sent over the network.

Amplify Framework Version

1.27.1

Amplify Categories

DataStore

Dependency manager

Swift PM

Swift version

5.0

CLI version

9.1.0

Xcode version

13.4.1

Relevant log output

<details>
<summary>Log Messages</summary>


INSERT LOG MESSAGES HERE
```

Is this a regression?

No

Regression additional context

I have not tried before

Device

iPhone 13 Pro

iOS Version

15.5

Specific to simulators

No response

Additional context

No response

depthzadmin avatar Jul 29 '22 19:07 depthzadmin

Sadly enough, I'm also still seeing it.

At this point, I don't have a way to reproduce it, but users have complained about the syncing going bad. I've determined the cause to be exactly that. This starts to be a nightmare to be honest as this has been going on forever.

anatomybook avatar Aug 05 '22 19:08 anatomybook

@depthzadmin can you share your schema so that we can reproduce this on our end as well?

chrisbonifacio avatar Sep 09 '22 18:09 chrisbonifacio

type User @model @auth(rules: [{allow: private}]) {
  id: ID!
  username: String!
  email: String
  Tests: [Test] @hasMany(indexName: "byUser", fields: ["id"])
}

type Test @model @auth(rules: [{allow: private}]) {
  id: ID!
  test: String
  userID: ID! @index(name: "byUser")
}

depthzadmin avatar Sep 10 '22 16:09 depthzadmin

Does the schema I added help you reproduce the problem?

depthzadmin avatar Oct 15 '22 21:10 depthzadmin

Hi @depthzadmin, thank you for the schema. I believe I have encountered this issue during some my recent testing and the problem occurs when using uni-directional hasMany, without the belongsTo, is failing to retrieve all the Test models when a User is deleted. Cascade delete works by querying for all the Test models by the model being deleted (user's id) and syncing the children models before the parent (sync Test then sync User delete). I believe this is a bug we need to investigate further and see how cascade delete is operating against an unidirectional hasMany and see if there's something that can be done to successfully get the children models. One workaround is to create a bi-directional relationship and add that the Test belongs to User.

lawmicha avatar Oct 31 '22 19:10 lawmicha

Hi @depthzadmin , When you deleting the parent resource, are some of the children get successfully deleted or none of the children are deleted?

We managed to reproduce a similar issue that some of the children become dangling resource as the mutation is not executed correctly. Could you verify whether the fix is also fixing your issue?

5d avatar Feb 24 '23 23:02 5d

I have moved to release 2.11.4. Is the fix included in this release? If so, I will test.

depthzadmin avatar May 25 '23 03:05 depthzadmin

@depthzadmin , I'm happy to know that you've upgraded to v2, and version 2.11.4 has the necessary fix. Can you please confirm whether the problem still persists?

5d avatar May 30 '23 07:05 5d

@5d I have tested the change in my app and can confirm that the problem has been resolved. Thank you!

depthzadmin avatar Jun 29 '23 23:06 depthzadmin

Unfortunately my testing was wrong. I do still see the incorrect behavior of dependent data not getting deleted. I was tricked when testing by looking at the Content in the Amplify Studio project. When the delete first happens the data is removed. However, after refreshing the Amplify Studio page, the dependent data reappears. This is the same as before.

Can this issue be reopened?

depthzadmin avatar Aug 14 '23 20:08 depthzadmin

Hi @depthzadmin ,

Feel free to reopen it if the data schema and reproduce steps are the same as documented in this issue. Otherwise, please create a new one. Also, could you please attach more information such as verbose log and version?

5d avatar Aug 25 '23 18:08 5d