Skip to content

Commit

Permalink
feat: provide alternative array notation for nested paths
Browse files Browse the repository at this point in the history
Closes #432
  • Loading branch information
krisk committed Jun 23, 2020
1 parent a3892ec commit 7077fbe
Show file tree
Hide file tree
Showing 12 changed files with 356 additions and 152 deletions.
186 changes: 111 additions & 75 deletions dist/fuse.js
Original file line number Diff line number Diff line change
Expand Up @@ -269,53 +269,33 @@

_classCallCheck(this, KeyStore);

this._keys = {};
this._keyNames = [];
this._keys = [];
this._keyMap = {};
var totalWeight = 0;
keys.forEach(function (key) {
var keyName;
var weight = 1;
var obj = createKey(key);
totalWeight += obj.weight;

if (isString(key)) {
keyName = key;
} else {
if (!hasOwn.call(key, 'name')) {
throw new Error(MISSING_KEY_PROPERTY('name'));
}

keyName = key.name;

if (hasOwn.call(key, 'weight')) {
weight = key.weight;
_this._keys.push(obj);

if (weight <= 0) {
throw new Error(INVALID_KEY_WEIGHT_VALUE(keyName));
}
}
}

_this._keyNames.push(keyName);

_this._keys[keyName] = {
weight: weight
};
totalWeight += weight;
_this._keyMap[obj.id] = obj;
totalWeight += obj.weight;
}); // Normalize weights so that their sum is equal to 1

this._keyNames.forEach(function (key) {
_this._keys[key].weight /= totalWeight;
this._keys.forEach(function (key) {
key.weight /= totalWeight;
});
}

_createClass(KeyStore, [{
key: "get",
value: function get(key, name) {
return this._keys[key] && this._keys[key][name];
value: function get(keyId) {
return this._keyMap[keyId];
}
}, {
key: "keys",
value: function keys() {
return this._keyNames;
return this._keys;
}
}, {
key: "toJSON",
Expand All @@ -326,47 +306,82 @@

return KeyStore;
}();
function createKey(key) {
var path = null;
var id = null;
var src = null;
var weight = 1;

if (isString(key) || isArray(key)) {
src = key;
path = createKeyPath(key);
id = createKeyId(key);
} else {
if (!hasOwn.call(key, 'name')) {
throw new Error(MISSING_KEY_PROPERTY('name'));
}

var name = key.name;
src = name;

if (hasOwn.call(key, 'weight')) {
weight = key.weight;

if (weight <= 0) {
throw new Error(INVALID_KEY_WEIGHT_VALUE(name));
}
}

path = createKeyPath(name);
id = createKeyId(name);
}

return {
path: path,
id: id,
weight: weight,
src: src
};
}
function createKeyPath(key) {
return isArray(key) ? key : key.split('.');
}
function createKeyId(key) {
return isArray(key) ? key.join('.') : key;
}

function get(obj, path) {
var list = [];
var arr = false;

var deepGet = function deepGet(obj, path) {
if (!path) {
var deepGet = function deepGet(obj, path, index) {
if (!path[index]) {
// If there's no path left, we've arrived at the object we care about.
list.push(obj);
} else {
var dotIndex = path.indexOf('.');
var key = path;
var remaining = null;

if (dotIndex !== -1) {
key = path.slice(0, dotIndex);
remaining = path.slice(dotIndex + 1);
}

var key = path[index];
var value = obj[key];

if (!isDefined(value)) {
return;
}

if (!remaining && (isString(value) || isNumber(value))) {
if (index === path.length - 1 && (isString(value) || isNumber(value))) {
list.push(toString(value));
} else if (isArray(value)) {
arr = true; // Search each item in the array.

for (var i = 0, len = value.length; i < len; i += 1) {
deepGet(value[i], remaining);
deepGet(value[i], path, index + 1);
}
} else if (remaining) {
} else if (path.length) {
// An object. Recurse further.
deepGet(value, remaining);
deepGet(value, path, index + 1);
}
}
};

deepGet(obj, path);
deepGet(obj, path, 0);
return arr ? list : list[0];
}

Expand Down Expand Up @@ -479,13 +494,19 @@
}, {
key: "setKeys",
value: function setKeys() {
var _this = this;

var keys = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
this.keys = keys;
this._keysMap = {};
keys.forEach(function (key, idx) {
_this._keysMap[key.id] = idx;
});
}
}, {
key: "create",
value: function create() {
var _this = this;
var _this2 = this;

if (this.isCreated || !this.docs.length) {
return;
Expand All @@ -495,12 +516,12 @@

if (isString(this.docs[0])) {
this.docs.forEach(function (doc, docIndex) {
_this._addString(doc, docIndex);
_this2._addString(doc, docIndex);
});
} else {
// List is Array<Object>
this.docs.forEach(function (doc, docIndex) {
_this._addObject(doc, docIndex);
_this2._addObject(doc, docIndex);
});
}

Expand Down Expand Up @@ -528,6 +549,11 @@
this.records[i].i -= 1;
}
}
}, {
key: "getValueForItemAtKeyId",
value: function getValueForItemAtKeyId(item, keyId) {
return item[this._keysMap[keyId]];
}
}, {
key: "size",
value: function size() {
Expand All @@ -550,15 +576,16 @@
}, {
key: "_addObject",
value: function _addObject(doc, docIndex) {
var _this2 = this;
var _this3 = this;

var record = {
i: docIndex,
$: {}
}; // Iterate over every key (i.e, path), and fetch the value at that key

this.keys.forEach(function (key, keyIndex) {
var value = _this2.getFn(doc, key);
// console.log(key)
var value = _this3.getFn(doc, key.path);

if (!isDefined(value)) {
return;
Expand All @@ -585,7 +612,7 @@
var subRecord = {
v: _value,
i: nestedArrIndex,
n: _this2.norm.get(_value)
n: _this3.norm.get(_value)
};
subRecords.push(subRecord);
} else if (isArray(_value)) {
Expand All @@ -603,7 +630,7 @@
} else if (!isBlank(value)) {
var subRecord = {
v: value,
n: _this2.norm.get(value)
n: _this3.norm.get(value)
};
record.$[keyIndex] = subRecord;
}
Expand All @@ -630,8 +657,9 @@
var myIndex = new FuseIndex({
getFn: getFn
});
var keyStore = new KeyStore(keys);
myIndex.setKeys(keyStore.keys());
myIndex.setKeys(keys.map(function (key) {
return createKey(key);
}));
myIndex.setSources(docs);
myIndex.create();
return myIndex;
Expand Down Expand Up @@ -672,7 +700,7 @@
};

if (match.key) {
obj.key = match.key;
obj.key = match.key.src;
}

if (match.idx > -1) {
Expand Down Expand Up @@ -1664,11 +1692,19 @@
AND: '$and',
OR: '$or'
};
var KeyType = {
PATH: '$path',
PATTERN: '$val'
};

var isExpression = function isExpression(query) {
return !!(query[LogicalOperator.AND] || query[LogicalOperator.OR]);
};

var isPath = function isPath(query) {
return !!query[KeyType.PATH];
};

var isLeaf = function isLeaf(query) {
return !isArray(query) && isObject(query) && !isExpression(query);
};
Expand All @@ -1688,22 +1724,22 @@

var next = function next(query) {
var keys = Object.keys(query);
var isQueryPath = isPath(query);

if (keys.length > 1 && !isExpression(query)) {
if (!isQueryPath && keys.length > 1 && !isExpression(query)) {
return next(convertToExplicit(query));
}

var key = keys[0];

if (isLeaf(query)) {
var pattern = query[key];
var key = isQueryPath ? query[KeyType.PATH] : keys[0];
var pattern = isQueryPath ? query[KeyType.PATTERN] : query[key];

if (!isString(pattern)) {
throw new Error(LOGICAL_SEARCH_INVALID_QUERY_FOR_KEY(key));
}

var obj = {
key: key,
keyId: createKeyId(key),
pattern: pattern
};

Expand All @@ -1716,7 +1752,7 @@

var node = {
children: [],
operator: key
operator: keys[0]
};
keys.forEach(function (key) {
var value = query[key];
Expand Down Expand Up @@ -1763,7 +1799,7 @@
throw new Error(INCORRECT_INDEX_TYPE);
}

this._myIndex = index || createIndex(this._keyStore.keys(), this._docs, {
this._myIndex = index || createIndex(this.options.keys, this._docs, {
getFn: this.options.getFn
});
}
Expand Down Expand Up @@ -1886,9 +1922,7 @@
var _this = this;

var expression = parse(query, this.options);
var _this$_myIndex = this._myIndex,
keys = _this$_myIndex.keys,
records = _this$_myIndex.records;
var records = this._myIndex.records;
var resultMap = {};
var results = [];

Expand Down Expand Up @@ -1921,11 +1955,13 @@

return res;
} else {
var key = node.key,
var keyId = node.keyId,
searcher = node.searcher;
var value = item[keys.indexOf(key)];

var value = _this._myIndex.getValueForItemAtKeyId(item, keyId);

return _this._findMatches({
key: key,
key: _this._keyStore.get(keyId),
value: value,
searcher: searcher
});
Expand Down Expand Up @@ -1968,9 +2004,9 @@
var _this2 = this;

var searcher = createSearcher(query, this.options);
var _this$_myIndex2 = this._myIndex,
keys = _this$_myIndex2.keys,
records = _this$_myIndex2.records;
var _this$_myIndex = this._myIndex,
keys = _this$_myIndex.keys,
records = _this$_myIndex.records;
var results = []; // List is Array<Object>

records.forEach(function (_ref5) {
Expand Down Expand Up @@ -2076,7 +2112,7 @@
var key = _ref9.key,
norm = _ref9.norm,
score = _ref9.score;
var weight = keyStore.get(key, 'weight');
var weight = key ? key.weight : null;
totalScore *= Math.pow(score === 0 && weight ? Number.EPSILON : score, (weight || 1) * (ignoreFieldNorm ? 1 : norm));
});
result.score = totalScore;
Expand Down
Loading

0 comments on commit 7077fbe

Please sign in to comment.