Skip to content

Instantly share code, notes, and snippets.

@nilsmehlhorn
Last active January 31, 2020 17:31
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nilsmehlhorn/143bd091533709c41cb7d973d7c232c2 to your computer and use it in GitHub Desktop.
Save nilsmehlhorn/143bd091533709c41cb7d973d7c232c2 to your computer and use it in GitHub Desktop.
Small and configurable full-text search on objects in TypeScript
export type Matcher<T> = (query: string) => T[];
export type ValueProject<T> = (target: T) => Array<string | number>;
export type MatcherFactory = <T>(targets: T[], project: ValueProject<T>) => Matcher<T>;
export const defaultProject = <T>(target: T) => Object.values(target);
const isMatchable = prop => typeof prop == 'number' || typeof prop == 'string'
export const matcher: MatcherFactory = <T>(targets, project = defaultProject) => {
const matchEntries: Array<[string, T]> = targets
.map(target => {
const matchString = project(target)
.filter(property => property && isMatchable(property))
.join('').toLowerCase();
return [matchString, target];
});
return (query: string): T[] => {
if (!query) {
return targets;
}
const words = query.trim().toLowerCase().split(' ');
return matchEntries
.filter(([matchString, target]) => words
.every(word => matchString.includes(word))
)
.map(([matchString, target]) => target);
};
};
import { matcher } from './matcher';
interface User {
id: number
username: string
mail: string
company: {
name: string
address: string
}
}
const users: User[] = [/* fill with users */]
const match = matcher(users, user => [
// only match these properties
user.id, user.username, user.mail, user.company.name
])
// returns every user containing both words in any of
// the configured properties
const result = match('Andrew Twi')
@jsonberry
Copy link

Cool work, thanks for sharing, I look forward to trying this one out sometime :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment