diff --git a/README.md b/README.md index 71c329e..1003b52 100644 --- a/README.md +++ b/README.md @@ -72,7 +72,15 @@ const objList = [ matchSorter(objList, 'g', {keys: ['name', 'color']}) // [{name: 'George', color: 'Blue'}, {name: 'Janice', color: 'Green'}] matchSorter(objList, 're', {keys: ['color', 'name']}) // [{name: 'Jen', color: 'Red'}, {name: 'Janice', color: 'Green'}, {name: 'Fred', color: 'Orange'}] -//this also works with **nested keys** +// You can specify a key that is an array of values and the best match from that value is the one that's used for the ranking +const iceCreamYum = [ + {favoriteIceCream: ['mint', 'chocolate']}, + {favoriteIceCream: ['candy cane', 'brownie']}, + {favoriteIceCream: ['birthday cake', 'rocky road', 'strawberry']}, +] +matchSorter(iceCreamYum, 'cc', {keys: 'favoriteIceCream'}) // [{favoriteIceCream: ['candy cane', 'brownie']}, {favoriteIceCream: ['mint', 'chocolate']}] + +// this also works with **nested keys** const nestedObjList = [ {name: {first: 'Janice'}}, {name: {first: 'Fred'}}, diff --git a/src/index.js b/src/index.js index 5f9c69b..4625871 100644 --- a/src/index.js +++ b/src/index.js @@ -36,8 +36,8 @@ function getHighestRanking(item, keys, value) { if (!keys) { return {rank: getMatchRanking(item, value), keyIndex: -1} } - return keys.reduce(({rank, keyIndex}, key, i) => { - const itemValue = getItemValue(item, key) + const valuesToRank = getAllValuesToRank(item, keys) + return valuesToRank.reduce(({rank, keyIndex}, itemValue, i) => { const newRank = getMatchRanking(itemValue, value) if (newRank > rank) { rank = newRank @@ -186,4 +186,14 @@ function getItemValue(item, key) { return key.split('.').reduce((itemObj, nestedKey) => itemObj[nestedKey], item) } +/** + * Gets all the values for the given keys in the given item and returns an array of those values + * @param {Object} item - the item from which the values will be retrieved + * @param {Array} keys - the keys to use to retrieve the values + * @return {Array} the values in an array + */ +function getAllValuesToRank(item, keys) { + return keys.reduce((allVals, key) => allVals.concat(getItemValue(item, key)), []) +} + module.exports = exports.default // CommonJS compat diff --git a/src/index.test.js b/src/index.test.js index 76b2c25..bad7fe7 100644 --- a/src/index.test.js +++ b/src/index.test.js @@ -130,6 +130,35 @@ const tests = { {name: {first: 'bat'}}, ], }, + 'can handle keys that are an array of values': { + input: [ + [ + {favoriteIceCream: ['mint', 'chocolate']}, + {favoriteIceCream: ['candy cane', 'brownie']}, + {favoriteIceCream: ['birthday cake', 'rocky road', 'strawberry']}, + ], + 'cc', + {keys: ['favoriteIceCream']}, + ], + output: [ + {favoriteIceCream: ['candy cane', 'brownie']}, + {favoriteIceCream: ['mint', 'chocolate']}, + ], + }, + 'when using arrays of values, when things are equal, the one with the higher index wins': { + input: [ + [ + {favoriteIceCream: ['mint', 'chocolate']}, + {favoriteIceCream: ['chocolate', 'brownie']}, + ], + 'chocolate', + {keys: ['favoriteIceCream']}, + ], + output: [ + {favoriteIceCream: ['chocolate', 'brownie']}, + {favoriteIceCream: ['mint', 'chocolate']}, + ], + }, 'when providing a rank threshold of NO_MATCH, it returns all of the items': { input: [ ['orange', 'apple', 'grape', 'banana'],