redux-toolkit icon indicating copy to clipboard operation
redux-toolkit copied to clipboard

upsertMany with multiple updates with the same id throws away updates

Open johannaljunggren opened this issue 2 years ago • 5 comments

I'm using upsertMany to push multiple updates with the same id. If the id previously didn't exist only the last update in the array of updates is added to the store. Example using the books example from the createEntityAdapter documentation https://redux-toolkit.js.org/api/createEntityAdapter:

const booksAdapter = createEntityAdapter({
  selectId: (book) => book.customId,
  sortComparer: (a, b) => (a.customId > b.customId ? 1 : -1)
});

const booksSlice = createSlice({
  name: "books",
  initialState: booksAdapter.getInitialState(),
  reducers: {
    booksUpserted: booksAdapter.upsertMany,
  }
});

const { booksUpserted } = booksSlice.actions;

const store = configureStore({
  reducer: {
    books: booksSlice.reducer
  }
});

store.dispatch(booksUpserted([
    { customId: "a", title: "First" },
    { customId: "a", author: "Author" },
    { customId: "a", description: "Description" }
  ])
);

After dispatching dispatching I expected the state to look like this: {"ids":["a"],"entities":{"a":{"customId":"a", title: "First", author: "Author", "description":"Description"}}} Instead it looks like this: {"ids":["a"],"entities":{"a":{"customId":"a","description":"Description"}}} I created a codesandbox example to demonstrate the issue https://codesandbox.io/s/upsertmany-test-lwmfy4?file=/src/App.js

johannaljunggren avatar May 09 '23 08:05 johannaljunggren

Hmm. Currently the logic is:

  function upsertManyMutably(
    newEntities: readonly T[] | Record<EntityId, T>,
    state: R
  ): void {
    const [added, updated] = splitAddedUpdatedEntities<T>(
      newEntities,
      selectId,
      state
    )

    updateManyMutably(updated, state)
    addManyMutably(added, state)
  }

I wonder what would happen if we just flip the update and add steps?

markerikson avatar May 09 '23 15:05 markerikson

probably the same - the splitAddedUpdatedEntities only checks if they're in the current state, not the state after each update has been applied

all of the entries get counted as "added" and therefore only the first takes effect

EskiMojo14 avatar May 09 '23 15:05 EskiMojo14

Ah, good point. (Been a while since I've looked at this code :) )

Not immediately sure what a good solution is here without digging into it further.

markerikson avatar May 09 '23 15:05 markerikson

@markerikson any updates on this?

dlarroder avatar Jun 19 '24 06:06 dlarroder

@dlarroder there's been no comments since I wrote one a year ago, and the issue is still open, so no :)

markerikson avatar Jun 19 '24 20:06 markerikson