-
Notifications
You must be signed in to change notification settings - Fork 130
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: handle nested arrays with wildcard keys #120
feat: handle nested arrays with wildcard keys #120
Conversation
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.
Thanks for your work on this. I'm worried that this is adding a little too much magic to the library, especially when you can already work around this limitation in a pretty reasonable way using "Property Callbacks" (see the README).
Thanks for your feedback. I understand the concern, but to me it seems that this library is already doing quite a bit of "magic" when it comes to sorting the results, and supporting nested keys in the first place. Of course that "magic" is well documented but so can this. Since the applications I'm working on use the pattern of nested objects in arrays relatively often, writing similar property callbacks all the time isn't really DRY nor as performant as this can be. But if I'm the outlier in this, I'm more than happy to keep using a fork. |
Fair points. Luckily the added code isn't all that complex which is nice. I think this will be ok, but I'd like to see what this looks like documented first. Also, could you make sure we hit 100% test coverage with your new changes. Thanks! |
2b5a576
to
eb19d72
Compare
eb19d72
to
0195d3e
Compare
Codecov Report
@@ Coverage Diff @@
## master #120 +/- ##
=========================================
Coverage 100.00% 100.00%
=========================================
Files 1 1
Lines 137 163 +26
Branches 31 38 +7
=========================================
+ Hits 137 163 +26
Continue to review full report at Codecov.
|
Thanks. The coverage is now back up to 100% again. And I've documented the changes more clearly. While doing this I also found a few simple performance improvements that end up to matching about 20% faster. The biggest improvements were
I can't directly share the data that I used for benchmarking this, but I can look for something similar if you want? |
src/index.ts
Outdated
return value | ||
} | ||
|
||
return value.reduce((values: Array<object | string>, arrayValue: object | null): |
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 looks a lot like the first part of the function. I wonder if we could use recursion instead of duplication here. Could you try it out and see whether it's any simpler?
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.
Sure, see the last commit which is my attempt at doing so. It seems possible without any performance implications.
However, there is the downside that the implicit wildcard no longer works, except if the array is a top-level property of the object. So {favoriteIceCream: ['mint', 'chocolate']}
is fine when matching 'favoriteIceCream'
, but {favorite: {iceCream: ['mint', 'chocolate']}}
won't work with 'favorite.iceCream'
and instead needs 'favorite.iceCream.*'
. I personally don't care about implicit wildcards: I never added this intentionally. It just worked due to the checks that made this new feature backwards compatible with all tests. And it's these checks that caused the duplication and are now gone. Supporting nested array values without explicit wildcards again would require more duplication I'm afraid.
The README doesn't explicitly say that nested array values are supported. It says that array values are supported and nested values are supported, but nothing about combining that. But as a user I'd assume that they would be, so now this new feature would be a breaking change.
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 we should be able to make this work with recursion. Care to take another whack at it?
{favorite: {iceCream: ['birthday cake', 'rocky road', 'strawberry']}}, | ||
], | ||
'cc', | ||
{keys: ['favorite.iceCream.*']}, |
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'm fine with this working, but I'd also like to support favorite.iceCream
here as well. We should be able to process an item
of String | Array<String>
and favorite.icCream
is Array<String>
.
src/__tests__/index.ts
Outdated
null, | ||
], | ||
'ba', | ||
{keys: ['aliases.name.first']}, |
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 don't want to support this. It's too much magic. So I'm glad that it's gone.
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.
Me too.
Yeah, I'll have another go at it. |
How do you feel about the use of |
I'm fine with flat. Folks should have standard polyfills by now |
tsconfig.json
Outdated
"extends": "./node_modules/kcd-scripts/shared-tsconfig.json" | ||
"extends": "./node_modules/kcd-scripts/shared-tsconfig.json", | ||
"compilerOptions": { | ||
"lib": ["es2019"] |
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'm not sure if this is the best way / place / solution, but without this addition type checking fails with the error Property 'flat' does not exist on type 'string[]'. Do you need to change your target library? Try changing the
lib compiler option to 'es2019' or later.
.
OK, it now supports |
Let's use the small polyfill idea 👍 |
3030099
to
895c231
Compare
There you go. I'm kinda stumped by the typing of the result, so I had to expect a few more errors than I'd like. Also, I've added a check to see if flattening is needed because it's quite expensive for the performance. |
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 made a couple commits to hopefully improve things a bit. I think it'll help perf, but I'm pretty sure removing the reduces and using for..of loops improves readability.
I also removed all // @ts-expect-error
s in favor of casting which I think is the lesser of the two evils.
I'd love your feedback. I'm happy to make adjustments to my changes before we merge this.
Thanks again for all your work on this!
That's perfect, it's much more readable indeed. I've never been a big fan of functional programming because it typically comes with a large performance penalty. But in this case I just stuck with how you had coded it. Looking at the performance there was some degradation due to the use of My basic benchmark now gives the following results, comparing the last variations this branch to the master:
So I'm perfectly happy with merging it like this. On a side note: I can make pull request for a benchmark like this if you'd want? And, looking at my use-case of this module, I see room for more performance improvements by doing some memoization. My apps show 1000+ rows that are recursively processed multiple times while users type, or when just a few of those rows change due to server updates. Memoizing |
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.
Looks great to me. Thank you!
If you'd like to add a benchmark test in the future that would be welcome 👍
@all-contributors please add @mart-jansink for code, tests, and docs |
I've put up a pull request to add @mart-jansink! 🎉 |
Thanks so much for your help! I've added you as a collaborator on the project. Please make sure that you review the |
🎉 This PR is included in version 6.1.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
What: Handle nested arrays with one or more wildcard keys. As an example
Why: Arrays like the above are relatively common in some applications that I'm working on. I really like the intuitive sorting of match-sorter so I'd love to be able to use this. However, using property callbacks for such a common case isn't ideal. So I thought I'd try making a pull request, hoping that this is something you might consider for merging.
How: The
.reduce
callback inside thegetNestedValue
function has gotten a lot more logic to possibly handle arrays. The callinggetItemValues
function now always returns an array, which simplifies the logic that returns the value a bit. Both the explicit'aliases.*.name.first'
and implicit'aliases.name.first'
wildcards are supported with this implementation; it was simpler to implement the latter while the former is clearer in use.Checklist:
I sadly had some trouble running
npm run test:update
: it complains that not all branches are covered by the test cases. However, the lines that it says are uncovered are actually called, as far as I can tell, so I couldn't fix this..