-
-
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
feat(Entity): add updateMany by predicate #907
feat(Entity): add updateMany by predicate #907
Conversation
Implementation seems reasonable. What are your opinions on this: Instead of a predicate with a list of changes the signature is updated to use a filter/map function: // Name is bad but it illustrated the interface
interface Updater<T> {
(entity: T): false | Change<T>;
}
function updateMany(updater: Updater<T>, state: EntityState<T>); |
I don't think I get the idea.
|
Yes, that's right. |
I must say your proposal feels a bit weird at first but after seeing it in action, it is better in my opinion. If someone got a better name than EDIT: I just realized that with your signature, it is also possible to have a second change. |
modules/entity/src/models.ts
Outdated
@@ -38,6 +38,10 @@ export type UpdateNum<T> = { | |||
|
|||
export type Update<T> = UpdateStr<T> | UpdateNum<T>; | |||
|
|||
export type Map<T> = { |
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.
Recommend renaming this to something more specific. Maybe UpdateMap
?
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.
LGTM!
const updates: Update<T>[] = | ||
updatesOrMap instanceof Array | ||
? updatesOrMap | ||
: state.ids.map((id: string | number) => ({ |
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.
I think that creating an Update
object for each entity means even entities that shouldn't change will lose referential equality. I think this map
should be a reduce
instead that shrinks the ids
array into a smaller array of Update
s for only changed entities.
: state.ids.reduce((changes: Update<T>[], id: string | number) => { | ||
const change = updatesOrMap(state.entities[id]); | ||
if (change && Object.keys(change).length > 0) { | ||
return [ |
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.
Recommend changing this line to:
changes.push({ id, changes: change });
return changes;
That way we don't allocate and deallocate an array for every item we are upserting.
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.
Done, thanks for the feedback/reviews!
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.
@tdeschryver Thanks for all of the hard work! We really appreciate it! 😄
One minor change. Otherwise this is looking good to me! |
Hi, how about adding this feature to upsert too? When predicate function is provided, upsert will call update with predicate under the hood |
@timdeschryver will you rebase this so it can land? |
cc1b99b
to
def18cb
Compare
✔️ |
I wonder if we could just have |
That would make sense, since this is what we're actually doing. {
predicate: entity => boolean,
changes: Partial<Entity>
} |
Ha, now I see we started with the above API 😄 - 149042b |
def18cb
to
cf9023d
Compare
I've updated the PR to be a Let me know your thoughts about this one. |
modules/entity/src/models.ts
Outdated
@@ -38,6 +38,10 @@ export type UpdateNum<T> = { | |||
|
|||
export type Update<T> = UpdateStr<T> | UpdateNum<T>; | |||
|
|||
export type EntityMap<T> = { |
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.
Update type to match export type ComparerStr<T> = (a: T, b: T) => string;
Minor nit, otherwise changes LGTM |
68c47a7
to
03a85fa
Compare
There we go 😄 |
@timdeschryver rebase pls |
03a85fa
to
3c24b3d
Compare
EntityState, | ||
EntityAdapter, | ||
Update, | ||
EntityMap, |
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.
I did also add EntityMap
and Predicate
here.
modules/store/src/store.ts
Outdated
@@ -19,9 +19,6 @@ export class Store<T> extends Observable<T> implements Observer<Action> { | |||
this.source = state$; | |||
} | |||
|
|||
/** |
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.
Revert this change because its in a separate PR
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.
Doh, I was using 2 VSCode instances and was wondering what was happening.
Sorry... 😅
3680a79
to
3c24b3d
Compare
This PR allows to edit entities based on a predicate.
See #672, in the issue it was mentioned to update the entities via multiple predicates - see my comment as why I don't think thats a good idea. If needed I can implement it that way tho.
I do got one question about the implementation of the sorted state adapter.
Why does this have an own implementation?
In my head the sorted adapter should call the unsorted adapter and do the sorting afterwards, but I must be missing someting 😅