-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathindex.js
102 lines (93 loc) · 2.33 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
var nlp = require('./nlp'),
andStream = require('and-stream'),
orStream = require('joiner-stream'),
tokenizeWords = nlp.tokenizeWords;
module.exports = fulltextEngine;
function fulltextEngine(opts) {
if (typeof opts === 'boolean') { // backwards compatibility
opts = {
fuzzy: opts
};
}
opts = opts || {};
opts.fuzzy = opts.fuzzy || false;
opts.stopwords = opts.stopwords || null;
return {
options: opts,
query: query,
match: match,
plans: {
'fulltext': fulltextPlan,
}
};
}
module.exports.index = index;
function index(prop) {
return function (key, value, emit, options) {
var db = this;
var _prop = prop || (options && options.name);
var val;
if (value && _prop &&
(val = fetchProp(value, _prop.split('.'))) !== undefined) {
tokenizeWords(val, db.query.engine.options).forEach(emit);
}
};
}
function keyfn(index) {
return index.key[index.key.length - 1];
}
function fulltextPlan(idx, tokens, type) {
var db = this;
var s = (type === 'and') ? andStream(keyfn) : orStream();
if (tokens.length === 0) {
tokens.push('');
}
tokens.forEach(function (token) {
idx.createIndexStream({
start: [token, null],
end: [token, undefined]
})
.pipe(type === 'and' ? s.stream() : s);
});
return s;
}
function query(prop, q, type) {
type = type || 'and';
type = type.toLowerCase();
var db = this;
var idx = db.indexes[prop];
if (idx && idx.type in db.query.engine.plans) {
var path = prop.split('.');
var tokens = tokenizeWords(q, db.query.engine.options);
return db.query.engine.plans[idx.type].call(db, idx, tokens, type);
} else {
return null;
}
}
function match(obj, prop, q, type) {
type = type || 'and';
var db = this;
var path = prop.split('.');
var needles = tokenizeWords(q, db.query.engine.options);
var haystack = tokenizeWords(fetchProp(obj, path), db.query.engine.options);
var hits = needles.reduce(
function (acc, needle) {
return acc + (~haystack.indexOf(needle) ? 1 : 0);
}, 0);
if (type === 'and') {
return hits === needles.length;
} else {
return hits > 0;
}
}
function fetchProp(obj, path) {
while (path.length > 0) {
var prop = path.shift();
if (obj[prop] !== undefined) {
obj = obj[prop];
} else {
return;
}
}
return obj;
}