diff --git a/lib/communeHelpers.js b/lib/communeHelpers.js index 1a80493..f2f02c4 100644 --- a/lib/communeHelpers.js +++ b/lib/communeHelpers.js @@ -1,5 +1,12 @@ const { initFields, initFormat } = require('./helpers'); +const abbreviations = { + 'st': 'saint', + 'ste': 'sainte', + 'cgne': 'campagne', +}; + + const initCommuneFields = initFields({ default: ['nom', 'code', 'codeDepartement', 'codeRegion', 'codesPostaux', 'population'], base: ['nom', 'code'], @@ -10,4 +17,4 @@ const initCommuneFormat = initFormat({ defaultGeometry: 'centre', }); -module.exports = { initCommuneFields, initCommuneFormat }; +module.exports = { initCommuneFields, initCommuneFormat, abbreviations }; diff --git a/lib/communes.js b/lib/communes.js index 66ccb4e..bd536a9 100644 --- a/lib/communes.js +++ b/lib/communes.js @@ -1,10 +1,12 @@ const SearchableCollection = require('./searchableCollection'); +const { abbreviations } = require('./communeHelpers.js'); const schema = { nom: { type: 'text', queryWith: 'nom', ref: 'code', + replacePatterns: abbreviations, boost: { population: (commune, score) => { if (commune.population) { diff --git a/lib/searchableCollection/indexes/text.js b/lib/searchableCollection/indexes/text.js index 9f9dc68..ae5cd8b 100644 --- a/lib/searchableCollection/indexes/text.js +++ b/lib/searchableCollection/indexes/text.js @@ -1,4 +1,5 @@ const normalizeString = require('../normalizeString'); +const replaceAbbreviations = require('../replaceAbbreviations'); const lunr = require('lunr'); const { clone, sortBy } = require('lodash'); @@ -7,6 +8,7 @@ class TextIndex { if (!key) throw new Error('key is required'); this._key = key; this._boost = options.boost || {}; + this._replacePatterns = options.replacePatterns; const refKey = this._refKey = options.ref || 'id'; this._refIndex = new Map(); this._index = lunr(function () { @@ -31,6 +33,11 @@ class TextIndex { find(terms, options = {}) { let boosted = false; + + if (this._replacePatterns) { + terms = replaceAbbreviations(terms, this._replacePatterns); + } + const results = this._index.search(terms) .map(result => { const item = clone(this._refIndex.get(result.ref)); diff --git a/lib/searchableCollection/replaceAbbreviations.js b/lib/searchableCollection/replaceAbbreviations.js new file mode 100644 index 0000000..1aae9ce --- /dev/null +++ b/lib/searchableCollection/replaceAbbreviations.js @@ -0,0 +1,12 @@ +function replaceAbbreviations(terms, patterns) { + if (!terms.includes(' ') && !terms.includes('-')) return terms; + + return terms + .toLocaleLowerCase() + .replace(/-/g, ' ') + .split(' ') + .map(token => token in patterns ? patterns[token] : token) + .join(' '); +} + +module.exports = replaceAbbreviations; diff --git a/test/replaceAbbreviations.js b/test/replaceAbbreviations.js new file mode 100644 index 0000000..9f40a8d --- /dev/null +++ b/test/replaceAbbreviations.js @@ -0,0 +1,64 @@ +/* eslint-env mocha */ +const expect = require('expect.js'); +const replaceAbbreviations = require('../lib/searchableCollection/replaceAbbreviations'); + +describe('replaceAbbreviations()', function () { + const abbreviations = { + 'st': 'saint', + 'ste': 'sainte', + 'cgne': 'campagne', + }; + + beforeEach(done => { + done(); + }); + + describe('Words separated by spaces', function () { + it('should replace Pattern', function () { + const str = 'st louis'; + const out = 'saint louis'; + + expect(replaceAbbreviations(str, abbreviations)).to.equal(out); + }); + + it('should replace Pattern', function () { + const str = 'marcilly la cgne'; + const out = 'marcilly la campagne'; + + expect(replaceAbbreviations(str, abbreviations)).to.equal(out); + }); + }); + + describe('Words separated by dashes', function () { + it('should replace Pattern', function () { + const str = 'st-louis'; + const out = 'saint louis'; + + expect(replaceAbbreviations(str, abbreviations)).to.equal(out); + }); + + it('should replace Pattern', function () { + const str = 'marcilly-la-cgne'; + const out = 'marcilly la campagne'; + + expect(replaceAbbreviations(str, abbreviations)).to.equal(out); + }); + }); + + describe('search contained only one word', () => { + it('should not replace Pattern', () => { + const str = 'st'; + + expect(replaceAbbreviations(str, abbreviations)).to.equal(str); + }); + }); + + describe('Pattern is contained in a word', () => { + it('should not replace Pattern', () => { + const str = 'le stinx'; + + expect(replaceAbbreviations(str, abbreviations)).to.equal(str); + }); + }); + +});