-
-
Notifications
You must be signed in to change notification settings - Fork 2k
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
Implement upsertOne() and upsertMany() for entity adapters #550
Conversation
Prior to this fix, collection methods in sorted_state_adapter ran in quadratic time, because they iterated over the collection with single-item mutators, each of which also running in linear time. Now, we first collect all modifications (each in constant time), then sort them in linearithmic time, and finally merge them with the existing sorted array linearly. As a result, we can improve performance of collection methods to N + M log M, where N is the number of existing items and M is the number of modifications. Single-item methods are now expressed through those for collections, still running linearly.
…_adapter Removing "holes" created by updateManyMutably() should be there instead of merge().
It should return "true" unconditionally (probably worth a test).
These methods ran in quadratic time by interating over the collection and applying a linear algorithm for each item. Now, we modify entity hashes first (each in constant time), and then update the array of their ids in linear time. As a result, all operations now occur linearly. We also simplified logic for single-item operations by expressing them through those for collections. The removal methods also apply to sorted collections (because they preserve their order).
CircleCI failed the build because includes() is not supported by its runtime yet. We use an alternative syntax to fix that.
This commit replaces earlier function effectMetadata() with a map accessor getEffectsMetadata() and associated EffectsMetadata class. This syntax enables enables more concise access to metadata in unit tests. This is particularly nice, as we can now test both the observables and their metadata in a similar way: ``` expect(effects.someSource$).toBeObservable(expected); expect(metadata.someSource$).toEqual({ dispatch: true }); ```
Earlier version contained incorrect function name.
This change converts EffectsMetadata to a generic type that requires its keys to be keys of the effects class. We also update getEffectsMetadata() accordingly.
These methods are used to update one ore more entities if they already exist in the state, or to add them if they don't. The signature of the methods is identical to that of the corresponding update...() methods.
} else { | ||
added.push({ | ||
...update.changes, | ||
id: update.id, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line is problematic: if selectId != entity => entity.id
, this insert will fail to create an entity with the same effective id. We may need to change the signature of the method to (updates: { id: string | number; changes: T}[], state: R)
, per #421 (comment)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Let's make this change.
@dinvlad this one will be ready to land once that changed is made and the conflicts are resolved |
Sorry, didn't notice @MikeRyanDev's comment from earlier. Will submit soon. |
Need some help ? |
Apologies, will make it happen this weekend. |
Anything I can do to assist with this? |
What is the state of this PR? Will it come soon? |
Any updates on this PR? |
Any news? |
I have look into the code and at this time, you can do this for same behaviour: import { Update } from '@ngrx/entity';
case '[Feature] Action':
const updates: Update[] = action.payload
.filter(item => item.unixTime in state.entities)
.map(item => ({ id: item.unixTime, changes: item }));
const inserts = action.payload.filter(item => !(item.unixTime in state.entities));
const newState = adapter.updateMany(updates, adapter.addMany(inserts, state));
return {
...newState
}; |
I certainly know everyone is busy and is working hard, but if you happen to have a rough estimate of when this may be rolled out that would be amazing. If it's coming soon I'll wait to work on my next thing, if not I'll write it by hand. Thanks for Entities -- it's amazing! |
i like @sandangel workaround alot! another workaround i thought of before seeing sandangel's:
enjoy. |
ngRx is MIT license. @dinvlad may take more time to finish this. Open source is open source. So I can make a new PR for this with the requested changes. |
@peterbsmith2 I actually forked the pull request in order to try and fix it but I couldn't figure out two things: 1) how do I push the changes back (dumb, I know) or do I push changes to my repo and then open a new pull request and 2) I was (indirectly) in dialog with @MikeRyanDev who explained that the I understand the idea but couldn't actually figure out what I was supposed to do :) In my branch is also a new |
@shahafal thanks for that function. one thing I did that not only assists with this issue but any others that might come up is I made a |
Hi folks, sorry for being silent on this and taking a long time to re-visit it. I've actually moved away from Angular to Vue (and possibly Vuex), but if everyone is happy with the signature |
There's a rebase to do first! |
@dinvlad i went over your pull request and i have a question: i am writing this as a comment on the pull request code (suggesting a clarifying test) too so it wont get missed. |
}, | ||
}, | ||
}); | ||
}); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in upsert we pass list of entities to be added if missing or updates if exists.
in your implementation - if an entity already exists will it get updated even if it is the same as the original element?
if the answer is yes - this raises a performance question, as entities that have no changes would get new references and reload in components with OnPush change detection strategy.
anyway whatever the answer is - perhaps a test that clarifies it would be a good idea:
so if an existing entity gets an update with no changes -
a) if the functionality is to recreate it the test will show that a new entity was created.
b) if the functionality is to ignore it the test will show that no new entity was created.
I'm going to go ahead and close this. @dinvlad or anyone else is welcome to open up a new PR! |
Sounds good @MikeRyanDev, @sandangel is more motivated and his PR LGTM. |
These methods are used to update one ore more entities
if they already exist in the state, or to add them
if they don't.
The signature of the methods is identical to that of
the corresponding update...() methods.
The commit for this PR is 9826793, others have been merged previously.
Relevant discussion: #421
EDIT: please don't merge until we agree on the signature.