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

Add ability to set a threshold per key #50

Merged
merged 4 commits into from
Aug 29, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .all-contributorsrc
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@
"contributions": [
"code"
]
},
{
"login": "tikotzky",
"name": "Mordy Tikotzky",
"avatar_url": "https://avatars3.githubusercontent.com/u/200528?v=4",
"profile": "https://github.com/tikotzky",
"contributions": [
"code",
"doc",
"test"
]
}
],
"repoType": "github"
Expand Down
60 changes: 34 additions & 26 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
[![downloads][downloads-badge]][npm-stat]
[![MIT License][license-badge]][license]

[![All Contributors](https://img.shields.io/badge/all_contributors-9-orange.svg?style=flat-square)](#contributors)
[![All Contributors](https://img.shields.io/badge/all_contributors-10-orange.svg?style=flat-square)](#contributors)
[![PRs Welcome][prs-badge]][prs]
[![Donate][donate-badge]][donate]
[![Code of Conduct][coc-badge]][coc]
Expand Down Expand Up @@ -54,21 +54,20 @@ To explain the ranking system, I'll use countries as an example:
This ranking seems to make sense in people's minds. At least it does in mine. Feedback welcome!

<!-- START doctoc generated TOC please keep comment here to allow auto update -->

<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->

* [Getting Started](#getting-started)
* [Installation](#installation)
* [Usage](#usage)
* [Advanced options](#advanced-options)
* [keys: `[string]`](#keys-string)
* [threshold: `number`](#threshold-number)
* [keepDiacritics: `boolean`](#keepdiacritics-boolean)
* [Using ES6?](#using-es6)
* [Inspiration](#inspiration)
* [Other Solutions](#other-solutions)
* [Contributors](#contributors)
* [LICENSE](#license)
- [Getting Started](#getting-started)
- [Installation](#installation)
- [Usage](#usage)
- [Advanced options](#advanced-options)
- [keys: `[string]`](#keys-string)
- [threshold: `number`](#threshold-number)
- [keepDiacritics: `boolean`](#keepdiacritics-boolean)
- [Using ES6?](#using-es6)
- [Inspiration](#inspiration)
- [Other Solutions](#other-solutions)
- [Contributors](#contributors)
- [LICENSE](#license)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -160,6 +159,16 @@ matchSorter(list, 'j', {keys: [item => item.name]})
// [{name: 'Janice'}, {name: 'Jen'}]
```

**Threshold**: You may specify an individual threshold for specific keys. A key will only match if it meets the specified threshold. _For more information regarding thresholds [see below](#threshold-number)_

```javascript
const list = [{name: 'Fred', color: 'Orange'}, {name: 'Jen', color: 'Red'}]
matchSorter(list, 'ed', {
keys: [{threshold: rankings.STARTS_WITH, key: 'name'}, 'color'],
})
//[{name: 'Jen', color: 'Red'}]
```

**Min and Max Ranking**: You may restrict specific keys to a minimum or maximum ranking by passing in an object. A key with a minimum rank will only get promoted if there is at least a simple match.

```javascript
Expand Down Expand Up @@ -198,16 +207,16 @@ _Default: `MATCHES`_
Thresholds can be used to specify the criteria used to rank the results.
Available thresholds (from top to bottom) are:

* CASE_SENSITIVE_EQUAL
* EQUAL
* STARTS_WITH
* WORD_STARTS_WITH
* STRING_CASE
* STRING_CASE_ACRONYM
* CONTAINS
* ACRONYM
* MATCHES _(default value)_
* NO_MATCH
- CASE_SENSITIVE_EQUAL
- EQUAL
- STARTS_WITH
- WORD_STARTS_WITH
- STRING_CASE
- STRING_CASE_ACRONYM
- CONTAINS
- ACRONYM
- MATCHES _(default value)_
- NO_MATCH

```javascript
const fruit = ['orange', 'apple', 'grape', 'banana']
Expand Down Expand Up @@ -269,11 +278,10 @@ You might try [Fuse.js](https://github.com/krisk/Fuse). It uses advanced math fa
Thanks goes to these people ([emoji key][emojis]):

<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->

<!-- prettier-ignore -->
| [<img src="https://avatars.githubusercontent.com/u/1500684?v=3" width="100px;"/><br /><sub><b>Kent C. Dodds</b></sub>](https://kentcdodds.com)<br />[💻](https://github.com/kentcdodds/match-sorter/commits?author=kentcdodds "Code") [📖](https://github.com/kentcdodds/match-sorter/commits?author=kentcdodds "Documentation") [🚇](#infra-kentcdodds "Infrastructure (Hosting, Build-Tools, etc)") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=kentcdodds "Tests") [👀](#review-kentcdodds "Reviewed Pull Requests") | [<img src="https://avatars.githubusercontent.com/u/8263298?v=3" width="100px;"/><br /><sub><b>Conor Hastings</b></sub>](http://conorhastings.com)<br />[💻](https://github.com/kentcdodds/match-sorter/commits?author=conorhastings "Code") [📖](https://github.com/kentcdodds/match-sorter/commits?author=conorhastings "Documentation") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=conorhastings "Tests") [👀](#review-conorhastings "Reviewed Pull Requests") | [<img src="https://avatars.githubusercontent.com/u/574806?v=3" width="100px;"/><br /><sub><b>Rogelio Guzman</b></sub>](https://github.com/rogeliog)<br />[📖](https://github.com/kentcdodds/match-sorter/commits?author=rogeliog "Documentation") | [<img src="https://avatars.githubusercontent.com/u/1416436?v=3" width="100px;"/><br /><sub><b>Claudéric Demers</b></sub>](http://ced.io)<br />[💻](https://github.com/kentcdodds/match-sorter/commits?author=clauderic "Code") [📖](https://github.com/kentcdodds/match-sorter/commits?author=clauderic "Documentation") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=clauderic "Tests") | [<img src="https://avatars3.githubusercontent.com/u/4150097?v=3" width="100px;"/><br /><sub><b>Kevin Davis</b></sub>](kevindav.us)<br />[💻](https://github.com/kentcdodds/match-sorter/commits?author=osfan501 "Code") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=osfan501 "Tests") | [<img src="https://avatars1.githubusercontent.com/u/19157735?v=3" width="100px;"/><br /><sub><b>Denver Chen</b></sub>](https://github.com/nfdjps)<br />[💻](https://github.com/kentcdodds/match-sorter/commits?author=nfdjps "Code") [📖](https://github.com/kentcdodds/match-sorter/commits?author=nfdjps "Documentation") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=nfdjps "Tests") | [<img src="https://avatars0.githubusercontent.com/u/12719057?v=4" width="100px;"/><br /><sub><b>Christian Ruigrok</b></sub>](http://ruigrok.info)<br />[🐛](https://github.com/kentcdodds/match-sorter/issues?q=author%3AChrisRu "Bug reports") [💻](https://github.com/kentcdodds/match-sorter/commits?author=ChrisRu "Code") [📖](https://github.com/kentcdodds/match-sorter/commits?author=ChrisRu "Documentation") |
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
| [<img src="https://avatars1.githubusercontent.com/u/2084833?v=4" width="100px;"/><br /><sub><b>Hozefa</b></sub>](https://github.com/hozefaj)<br />[🐛](https://github.com/kentcdodds/match-sorter/issues?q=author%3Ahozefaj "Bug reports") [💻](https://github.com/kentcdodds/match-sorter/commits?author=hozefaj "Code") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=hozefaj "Tests") [🤔](#ideas-hozefaj "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/9403361?v=4" width="100px;"/><br /><sub><b>pushpinder107</b></sub>](https://github.com/pushpinder107)<br />[💻](https://github.com/kentcdodds/match-sorter/commits?author=pushpinder107 "Code") |
| [<img src="https://avatars1.githubusercontent.com/u/2084833?v=4" width="100px;"/><br /><sub><b>Hozefa</b></sub>](https://github.com/hozefaj)<br />[🐛](https://github.com/kentcdodds/match-sorter/issues?q=author%3Ahozefaj "Bug reports") [💻](https://github.com/kentcdodds/match-sorter/commits?author=hozefaj "Code") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=hozefaj "Tests") [🤔](#ideas-hozefaj "Ideas, Planning, & Feedback") | [<img src="https://avatars3.githubusercontent.com/u/9403361?v=4" width="100px;"/><br /><sub><b>pushpinder107</b></sub>](https://github.com/pushpinder107)<br />[💻](https://github.com/kentcdodds/match-sorter/commits?author=pushpinder107 "Code") | [<img src="https://avatars3.githubusercontent.com/u/200528?v=4" width="100px;"/><br /><sub><b>Mordy Tikotzky</b></sub>](https://github.com/tikotzky)<br />[💻](https://github.com/kentcdodds/match-sorter/commits?author=tikotzky "Code") [📖](https://github.com/kentcdodds/match-sorter/commits?author=tikotzky "Documentation") [⚠️](https://github.com/kentcdodds/match-sorter/commits?author=tikotzky "Tests") |

<!-- ALL-CONTRIBUTORS-LIST:END -->

Expand Down
21 changes: 21 additions & 0 deletions src/__tests__/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -373,6 +373,27 @@ const tests = {
{tea: 'Green', alias: 'C'},
],
},
'only match when key meets threshold': {
input: [
[{name: 'Fred', color: 'Orange'}, {name: 'Jen', color: 'Red'}],
'ed',
{
keys: [{threshold: rankings.STARTS_WITH, key: 'name'}, 'color'],
},
],
output: [{name: 'Jen', color: 'Red'}],
},
'should match when key threshold is lower than the default threshold': {
input: [
[{name: 'Fred', color: 'Orange'}, {name: 'Jen', color: 'Red'}],
'ed',
{
keys: ['name', {threshold: rankings.CONTAINS, key: 'color'}],
threshold: rankings.STARTS_WITH,
},
],
output: [{name: 'Jen', color: 'Red'}],
},
}

Object.keys(tests).forEach(title => {
Expand Down
26 changes: 18 additions & 8 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,13 @@ function matchSorter(items, value, options = {}) {
return matchedItems.sort(sortRankedItems).map(({item}) => item)

function reduceItemsToRanked(matches, item, index) {
const {rank, keyIndex} = getHighestRanking(item, keys, value, options)
if (rank >= threshold) {
const {rank, keyIndex, keyThreshold = threshold} = getHighestRanking(
item,
keys,
value,
options,
)
if (rank >= keyThreshold) {
matches.push({item, rank, index, keyIndex})
}
return matches
Expand All @@ -60,17 +65,21 @@ function matchSorter(items, value, options = {}) {
* @param {Array} keys - the keys to get values from the item for the ranking
* @param {String} value - the value to rank against
* @param {Object} options - options to control the ranking
* @return {{rank: Number, keyIndex: Number}} - the highest ranking
* @return {{rank: Number, keyIndex: Number, keyThreshold: Number}} - the highest ranking
*/
function getHighestRanking(item, keys, value, options) {
if (!keys) {
return {rank: getMatchRanking(item, value, options), keyIndex: -1}
return {
rank: getMatchRanking(item, value, options),
keyIndex: -1,
keyThreshold: options.threshold,
}
}
const valuesToRank = getAllValuesToRank(item, keys)
return valuesToRank.reduce(
({rank, keyIndex}, {itemValue, attributes}, i) => {
({rank, keyIndex, keyThreshold}, {itemValue, attributes}, i) => {
let newRank = getMatchRanking(itemValue, value, options)
const {minRanking, maxRanking} = attributes
const {minRanking, maxRanking, threshold} = attributes
if (newRank < minRanking && newRank >= rankings.MATCHES) {
newRank = minRanking
} else if (newRank > maxRanking) {
Expand All @@ -79,10 +88,11 @@ function getHighestRanking(item, keys, value, options) {
if (newRank > rank) {
rank = newRank
keyIndex = i
keyThreshold = threshold
}
return {rank, keyIndex}
return {rank, keyIndex, keyThreshold}
},
{rank: rankings.NO_MATCH, keyIndex: -1},
{rank: rankings.NO_MATCH, keyIndex: -1, keyThreshold: options.threshold},
)
}

Expand Down