Can't figure out how to generate keys for use with recursive data
dgattey opened this issue · comments
match-sorter
version: 6.3.1node
version: 16.11.1
Relevant code or config
What you did:
I'm trying to write a fuzzy text filter for use with some rows from a react-table
instance. Working great! I'm able to pass rows with a generic type of data for each row (TableDataType
), and create keys for each of the columns I'm searching on. My ids
array are the column names. Some of them have nested keys like name.first
, so I'm using a function to generate keys, looking inside the row's values
array, then at the column inside it named whatever is in id
. So far so good, I'm searching across all columns, even if they have dot notation names, via the functions I return here in topLevelKeys
:
export const fuzzyTextFilter = <TableDataType extends PanamaTable.CellDataCollection>(
rows: Array<Row<TableDataType>>,
ids: Array<IdType<TableDataType>>,
filterValue: string,
): Row<TableDataType>[] => {
if (!ids || !filterValue) {
return rows;
}
/**
* Map the array of properties to search into an array of functions that take a row and return
* the value at that id (inside the `values` object on a row).
*/
const topLevelKeys: Array<ValueGetterKey<Row<TableDataType>>> = ids.map(
(id) => (item: Row<TableDataType>) => item.values[id] as string,
);
// We may have sub rows, so generate nested keys for those too
const subRowKeys = generateKeysForSubRows(rows, ids)
return matchSorter(rows, filterValue, { keys: [...topLevelKeys, ...subRowKeys] });
};
You may notice a subRowKeys
and that's where I'm running into problems. Essentially, each of the row's data objects (of type TableDataType
here) may have subRows
, of type Array<Row<TableDataType>>
inside it. I'd ALSO like to generate functions to access the columns in each of those subRows.
Problem description:
Unfortunately, the nesting is theoretically infinite, and because of the possibility of having dots in the column names, I can't just use simple strings recursively till I run into the bottom row. I need to use functions. I've been struggling to figure out a way I can recursively pass a partially curried object that I want to keep pulling objects out of down the recursive stack. I can generate keys at any level (change the item.values[id]
to item.subRows.map(subRow => subRow.values[id])
, but I can't make that generalized.
So, my long-winded question is, is there a simpler way to do this? All I'm trying to do is search for values within an array, but be able to do so recursively.
Solution:
If it were possible to use the string notation syntax, key: `item.values.${id}`
would be possible, and then I could just use a string recursively. However, that breaks because one of the values for id
is name.first
, which creates item.values.name.first
instead of the valid accessor item.values[name.first]
. If the array syntax was supported, my problem is solved.
Thanks so much for reading!!
@kentcdodds I took a stab at fixing this within the library, let me know if there's anything I completely missed! Added a new test for the array syntax. Things like key: `item.values[name.first]`
works perfectly, as does item.values[0]
/etc. Basically anything except the wildcard character can be put into array notation.
const results = matchSorter(searchObjects, filterValue, {
keys: [(item) => ids.map((id) => item.values[id])],
});
This ended up solving it - I mapped my rows
to searchObjects
by attaching some metadata to them, then was able to use this with react-table's filter to get the relevant search objects out, then used the metadata to return the correct data. More my code, less matchSorter
code, but the callback version of the keys
was key. Thanks @kentcdodds for the help!
I should have suggested that from the start. Thanks!