Picking up from where we were in the Parser:
MyBasicParser(
`some random string something "quoted here" not here 'here again' tag:value something alone: and other:tag :value`
);
// it returns:
/*
{
singleValues: [ 'some','random','string','something','not','here','something','alone:','and',':value' ],
quotedValues: [ 'quoted here', 'here again' ],
tagValues: [['tag', 'value'], ['other', 'tag']]
}
*/
Now... how do we use it?
Here's a draft of what we need:
function MyBasicFilter(arrayToBeFiltered) {
function doFilter(parsedObject) {
return arrayToBeFiltered.filter(
(item) => FilterMagic({ item, parsedObject })
);
}
function FilterMagic({ item, parsedObject }){'???'}
return {
filter: (parsedObject) => doFilter(parsedObject)
};
}
// To use this:
const myArray = [/* ... values ... */];
const basicFilter = MyBasicFilter(myArray);
const parsedSearch = MyBasicParser(/* that big string */);
const filterResult = basicFilter.filter(parsedSearch);
Here we will use a closure, just so we can prepare the function and then just call it afterwards.
Filter Magic
For that we will be needing:
function FilterMagic({
item,
parsedObject,
}) {
// check the single values
// check the quoted values
// check the tag values
return boolean;
}
While writing this, I've made it in a way I didn't even though about using in EasyFilter!
function FilterMagic({ item, parsedObject }) {
// this concatenates all strings in the item
const stringValue = Object.values(item).join(' ');
// using an object we avoid having to use a switch statement
// the code is more clear and easier to read
// and should we need to add more filters we can add them here in a simple way
const myMagicFunctions = {
// this is basically the "base case", it will check if the baseString have the values we are looking for with Regex using the case insensitive flag
// we pass the stringValue of the item as default, but doing this allows other functions to override it
singleValues: (string, baseString = stringValue) => Boolean(baseString.match(RegExp(string, 'i'))),
// for the quoted values, we split them at the space and then call the sibling function "singleValues" for each value
// and by using the "every" function we check if all the substrings are found
// we could also had just called the "singleValues" function without splitting the string
// but that would mean the it would check if it matched the exact string in order
// it would look like this:
// quotedValues: (string) => myMagicFunctions.singleValues(string),
quotedValues: (string) => string.split(' ').every((subString) => myMagicFunctions.singleValues(subString)),
// finally, the tags we spread the tag/value and override the default baseString of "singleValues" with the value of the tag
tagValues: ([tag, value]) => myMagicFunctions.singleValues(value, item[tag]),
}
// we break down the parsedObject and with "some" check if any of the single, quoted or tag values have any match
return Object.entries(parsedObject).some(
([parsedType, values]) => {
// since each can hold an array, we loop through them using "some"
// also, by using "some", it already stops in the first match!
return values.some((payload) =>
// and if this isn't magic, I don't know what is!
// we use the types coming from the parsedObject,
// if there's a match, we call the function that matches the type
// and pass the payload (that can be either a string or a tuple)
// if there's no match, it will return false by default
myMagicFunctions[parsedType]?.(payload) ?? false
);
})
}
// If you want to play around with the FilterMagic
// here's a mockItem for you to test
const mockItem = {
ghosts: "Are spooky?",
regex: "More spooky?",
happy: "Halloween"
};
// and here's a mockParsedObject
const mockParsedObject = {
singleValues: ['spooky', 'spoolk'],
quotedValues: ['spooky more', 'morr spook'],
tagValues: [['happy', 'halloween']]
};
// invalidate some of the values to see what's called and what's not
// as is, it will stop at the very first one because "spooky" is in the item!
The Final Result
function MyBasicFilter(arrayToBeFiltered) {
function doFilter(parsedObject) {
return arrayToBeFiltered.filter(
(item) => FilterMagic({ item, parsedObject })
);
}
function FilterMagic({ item, parsedObject }) {
const stringValue = Object.values(item).join(' ');
const myMagicFunctions = {
singleValues: (string, baseString = stringValue) => Boolean(baseString.match(RegExp(string, 'i'))),
quotedValues: (string) => string.split(' ').every((subString) => myMagicFunctions.singleValues(subString)),
tagValues: ([tag, value]) => myMagicFunctions.singleValues(value, item[tag]),
};
return Object.entries(parsedObject).some(
([parsedType, values]) => {
return values.some((payload) =>
myMagicFunctions[parsedType]?.(payload) ?? false
);
});
}
return {
filter: (parsedObject) => doFilter(parsedObject)
};
}
Fortunately, the filter is the easiest part...
Unfortunately... it's more straight forward code.
I'm happy that I've managed to do something totally different than what I've used in EasyFilter, but this is a way simpler version of that one...
Although I actually might think about using what we did here in there!
Hey... how about it?
Check if YOU can can do it... fork the project and then send a PR!
Cover Photo by Wade Austin Ellis on Unsplash