Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Assertion after saving a new relational record and tried to forget it #9229

Open
Jopie01 opened this issue Feb 20, 2024 · 4 comments
Open

Assertion after saving a new relational record and tried to forget it #9229

Jopie01 opened this issue Feb 20, 2024 · 4 comments

Comments

@Jopie01
Copy link

Jopie01 commented Feb 20, 2024

Today I upgraded to the bleeding edge 5.4.0-alpha.22 version and after a small change (replacing the __storeWrapper with _capabilities) in my code everything seemed still to work.

Creating a new relational record (hasMany) in the store works perfectly well and I can save it successfully to the backend. Because the new record is a relational one (one or more levels deeper then the main record) the backend doesn't return an id, just an empty array to let know that everything was successful.

So after the successful save action, I walk over the saved records and records with a negative id (all new records I create will get a negative id) I will forget them by doing this.identifierCache.forgetRecordIdentifier(identifier) which worked well in 5.5.0-alpha.11. Then I reloaded the main record with a force reload from the backend so the cache got refreshed.

However, somehow this doesn't work anymore and the record with the negative id stays in the store. When I reload the main record with it's relational fields I get Uncaught (in promise) Error: Assertion Failed: Expected to receive a stable Identifier to subscribe to. Placing a debugger shows that the list of records are loaded from the backend including the new one with the right id but the record with the negative id is also in the list which should have been removed.

@runspired
Copy link
Contributor

might need to pair with you to debug this one. There's things happening here we don't particularly support but the general flow is something we do support.

@Jopie01
Copy link
Author

Jopie01 commented Feb 21, 2024

I want to add some more context to understand the issue a bit better.

I'm using my own CRUD functions inside the store to request data from the backend. I also use my own tracker to track relationship changes (I hope it will be the Ember Data one day). When creating or saving a record I loop over all the changed fields in the model. When a field is a relational field, I go to that model and loop over all those fields as well and continue to do so until we are at the 'bottom'. During this process I build the data structure for the backend.

As an example, I have a product model which has a supplier field which is a hasMany. The supplier also have a hasMany field for prices for certain quantities.

product
  |
  |-> name
  |-> code
  |-> supplier
        |
        |-> supplier_name
        |-> product_code
        |-> product
        |-> price
             |
             |-> product_supplier
             |-> unit_price
             |-> quantity

I have an existing product with an existing supplier which I want to change. I also want to add a new supplier. When everything is done, I save the product, hence save because the product already exists. The save function starts at the product model and goes down until the price model and get all the changes and put them in the data structure.

{
  "method": "model.product.write",
  "params": [
    [4950],                   <-- actual product id in the backend
    {
      "supplier": [           <-- hasMany on the product model
        ["write",             <-- changes to an existing record in the backend
          [1094],             <-- the id of that record
          {
            "code": "3422",
            "price": [        <-- hasMany on the supplier model
              ["create",      <-- create a new record for the price 
                [
                  {
                    "product_supplier": 1094,
                    "quantity": 10,
                    "unit_price": 23
                  }
                ]
              ]
            ]
          }
        ],
        ["create",            <-- create a new record for the supplier
          [
            {
              "code": "Code for supplier",
              "name": "Name of product of supplier",
              "price": [
                ["create",    <-- create two new records for the new supplier
                  [
                    {
                      "product_supplier": -3,
                      "quantity": 5,
                      "unit_price": 10,
                    },
                    {
                      "product_supplier": -3,
                      "quantity": 10,
                      "unit_price": 4
                    }
                  ]
                ]
              ],
              "product": 4950
            }
          ]
        ]
      ]
    },
  ]
}

The structure seems a bit weird, but it just works perfectly and the backend return null when everything is successfully stored.

Because I know which records are new, I want to forget them and fetch them again from the backend. So after everything is stored I walk over them and do this.identifierCache.forgetRecordIdentifier(identifier). Then I return back from my save record function (resolve the promise) and do a this.store.findRecord from the product model with the right id and a force reload to refresh the cache. This step errors now because the identifier with negative id still exists.

I don't know it it helps but it seems it is something somewhere between commit bfc69de and commit e5c79aa (my bad, it isn't) I will see if I can narrow it down to one particular commit.

@Jopie01
Copy link
Author

Jopie01 commented Feb 21, 2024

Ok, I was thinking that I messed up my installation, but as it turned out, the issue existed a bit longer than I expected. I'm not going into the messy details about it, it already took me too much time.

I cloned this repo and linked the different packages:

    "@ember-data/debug": "link:../data/packages/debug",
    "@ember-data/graph": "link:../data/packages/graph",
    "@ember-data/json-api": "link:../data/packages/json-api",
    "@ember-data/request": "link:../data/packages/request",
    "@ember-data/store": "link:../data/packages/store",
    "@ember-data/tracking": "5.4.0-alpha.22",
    "@warp-drive/core-types": "0.0.0-alpha.8",

I wasn't able to link the tracking package because then something about private_infrastucture pops up and errors. I also needed the last one to get a successful build. Doing this didn't influence the result.

After some rough testing of several commits, I came across commit be9f3a8 which didn't had the error. However the commit above it (3473596) did have the error and is linked to PR #8807. I didn't dig further.

@Jopie01
Copy link
Author

Jopie01 commented Feb 21, 2024

I was able to narrow it down to the resetOnRemoteUpdate key in the field options. Because when not set (default is true), I got a deprecation warning linked to https://deprecations.emberjs.com/ember-data/v5.x#toc_ember-data-deprecate-relationship-remote-update-clearing-local-state (BTW the link in the deprecation itself is missing the #toc_ part). Setting it to false, removes the deprecation, but gives me the assertion error. Keeping true shows the deprecation but the rest is loaded correctly.

For now, I will keep resetOnRemoteUpdate as true and ignore the deprecation warning.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Status: needs triage
Development

No branches or pull requests

2 participants