Skip to content

Instantly share code, notes, and snippets.

@tricinel
Created March 30, 2021 06:42
Show Gist options
  • Save tricinel/85a0ba3333c36a20196728340df9ec26 to your computer and use it in GitHub Desktop.
Save tricinel/85a0ba3333c36a20196728340df9ec26 to your computer and use it in GitHub Desktop.
Creating a lunr index
import lunr from 'lunr';
import { pick, propEq, map, filter, prop } from 'ramda';
interface FieldConfigAttributes {
boost: number;
}
interface FieldConfig<T> {
name: keyof T;
store: boolean;
attributes?: FieldConfigAttributes;
}
interface SearchOptions<T> {
fields: FieldConfig<T>[];
key?: string;
nodes: T[];
}
type LunrStore<T> = Record<
string,
Pick<T, Exclude<keyof T, Exclude<keyof T, keyof T>>>
>;
export interface LunrIndex<T> {
index: lunr.Index;
store: LunrStore<T>;
}
function pickStoredFields<T>(fields: FieldConfig<T>[]): (keyof T)[] {
const getName = prop('name');
const isStored = propEq('store', true);
const onlyStoredFields = filter(isStored)(fields);
return map(getName, onlyStoredFields);
}
export default function createIndex<T extends Record<string, unknown>>({
fields,
key = '_id',
nodes = []
}: SearchOptions<T>): LunrIndex<T> {
const storedFields = pickStoredFields(fields);
const store: LunrStore<T> = {};
const index = lunr(function createLunrIndex() {
this.ref(key);
fields.forEach(({ name, attributes = {} }) => {
this.field(name, attributes);
});
nodes.forEach((node) => {
this.add(node);
store[String(node[key])] = pick(storedFields, node);
});
});
return { index, store };
}
import fs from 'fs';
import { join } from 'path';
import createIndex from './createIndex';
export default function createIndexFile(filename = 'search_index.json') {
/* Get the articles in here somehow */
/* I'm using https://npm.im/cuddy to query */
const publishedPosts = getPosts({
filters: { eq: { status: 'published' } },
select: ['_id', 'title', 'teaser', 'slug']
});
const lunrIndex = createIndex({
fields: [
{ name: 'title', store: true, attributes: { boost: 20 } },
{ name: 'teaser', store: true, attributes: { boost: 10 } },
{ name: 'slug', store: true }
],
nodes: publishedPosts
});
const folderPath = join(process.cwd(), 'public');
// We write the index to a file in the created directory
fs.writeFileSync(join(folderPath, filename), JSON.stringify(lunrIndex));
}
import lunr from 'lunr';
import type { LunrIndex } from './createIndex';
export default function loadIndex<T>({
index,
store
}: LunrIndex<T>): LunrIndex<T> {
return {
index: lunr.Index.load(index),
store
};
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment