@sublet/typesense-instantsearch-adapter
Version:
Adapter to use InstantSearch UI widgets with Typesense Search
192 lines (164 loc) • 8.44 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.SearchResponseAdapter = void 0;
var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
var _utils = require("./support/utils");
function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) { symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); } keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { (0, _defineProperty2["default"])(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; }
var SearchResponseAdapter = /*#__PURE__*/function () {
function SearchResponseAdapter(typesenseResponse, instantsearchRequest, configuration) {
(0, _classCallCheck2["default"])(this, SearchResponseAdapter);
this.typesenseResponse = typesenseResponse;
this.instantsearchRequest = instantsearchRequest;
this.configuration = configuration;
}
(0, _createClass2["default"])(SearchResponseAdapter, [{
key: "_adaptGroupedHits",
value: function _adaptGroupedHits(typesenseGroupedHits) {
var _this = this;
var adaptedResult = [];
adaptedResult = typesenseGroupedHits.map(function (groupedHit) {
return _this._adaptHits(groupedHit.hits);
}); // adaptedResult is now in the form of [[{}, {}], [{}, {}], ...]
// where each element in the outer most array corresponds to a group.
// We now flatten it to [{}, {}, {}]
adaptedResult = adaptedResult.flat();
return adaptedResult;
}
}, {
key: "_adaptHits",
value: function _adaptHits(typesenseHits) {
var _this2 = this;
var adaptedResult = [];
adaptedResult = typesenseHits.map(function (typesenseHit) {
var adaptedHit = _objectSpread({}, typesenseHit.document);
adaptedHit.objectID = typesenseHit.document.id;
adaptedHit._snippetResult = _this2._adaptHighlightResult(typesenseHit, "snippet");
adaptedHit._highlightResult = _this2._adaptHighlightResult(typesenseHit, "value"); // Add text_match score to result, if a field with that name doesn't already exist
if (!adaptedHit.text_match) {
adaptedHit.text_match = typesenseHit.text_match;
}
var geoLocationValue = adaptedHit[_this2.configuration.geoLocationField];
if (geoLocationValue) {
adaptedHit._geoloc = {
lat: geoLocationValue[0],
lng: geoLocationValue[1]
};
}
return adaptedHit;
});
return adaptedResult;
}
}, {
key: "_adaptHighlightResult",
value: function _adaptHighlightResult(typesenseHit, snippetOrValue) {
var _this3 = this;
// Algolia lists all searchable attributes in this key, even if there are no matches
// So do the same and then override highlights
var result = Object.assign.apply(Object, [{}].concat((0, _toConsumableArray2["default"])(Object.entries(typesenseHit.document).map(function (_ref) {
var _ref2 = (0, _slicedToArray2["default"])(_ref, 2),
attribute = _ref2[0],
value = _ref2[1];
return (0, _defineProperty2["default"])({}, attribute, {
value: value,
matchLevel: "none",
matchedWords: []
});
}))));
typesenseHit.highlights.forEach(function (highlight) {
result[highlight.field] = {
value: highlight[snippetOrValue] || highlight["".concat(snippetOrValue, "s")],
matchLevel: "full",
matchedWords: highlight.matched_tokens
};
if (highlight.indices) {
result[highlight.field]["matchedIndices"] = highlight.indices;
}
}); // Now convert any values that have an array value
// Also, replace highlight tag
Object.entries(result).forEach(function (_ref4) {
var _ref5 = (0, _slicedToArray2["default"])(_ref4, 2),
k = _ref5[0],
v = _ref5[1];
var attribute = k;
var value = v.value,
matchLevel = v.matchLevel,
matchedWords = v.matchedWords,
matchedIndices = v.matchedIndices;
if (Array.isArray(value)) {
// Algolia lists all values of the key in highlights, even those that don't have any highlights
// So add all values of the array field, including highlights
result[attribute] = [];
typesenseHit.document[attribute].forEach(function (unhighlightedValueFromArray, index) {
if (matchedIndices && matchedIndices.includes(index)) {
result[attribute].push({
value: _this3._adaptHighlightTag("".concat(value[matchedIndices.indexOf(index)]), _this3.instantsearchRequest.params.highlightPreTag, _this3.instantsearchRequest.params.highlightPostTag),
matchLevel: matchLevel,
matchedWords: matchedWords[index]
});
} else {
result[attribute].push({
value: "".concat(unhighlightedValueFromArray),
matchLevel: "none",
matchedWords: []
});
}
});
} else {
// Convert all values to strings
result[attribute].value = _this3._adaptHighlightTag("".concat(value), _this3.instantsearchRequest.params.highlightPreTag, _this3.instantsearchRequest.params.highlightPostTag);
}
});
return result;
}
}, {
key: "_adaptFacets",
value: function _adaptFacets(typesenseFacetCounts) {
var adaptedResult = {};
typesenseFacetCounts.forEach(function (facet) {
Object.assign(adaptedResult, (0, _defineProperty2["default"])({}, facet.field_name, Object.assign.apply(Object, [{}].concat((0, _toConsumableArray2["default"])(facet.counts.map(function (count) {
return (0, _defineProperty2["default"])({}, count.value, count.count);
}))))));
});
return adaptedResult;
}
}, {
key: "_adaptFacetStats",
value: function _adaptFacetStats(typesenseFacetCounts) {
var adaptedResult = {};
typesenseFacetCounts.forEach(function (facet) {
if (Object.keys(facet.stats).length > 0) {
Object.assign(adaptedResult, (0, _defineProperty2["default"])({}, facet.field_name, facet.stats));
}
});
return adaptedResult;
}
}, {
key: "adapt",
value: function adapt() {
var adaptedResult = {
hits: this.typesenseResponse.grouped_hits ? this._adaptGroupedHits(this.typesenseResponse.grouped_hits) : this._adaptHits(this.typesenseResponse.hits),
nbHits: this.typesenseResponse.found,
page: this.typesenseResponse.page - 1,
nbPages: this._adaptNumberOfPages(),
hitsPerPage: this.typesenseResponse.request_params.per_page,
facets: this._adaptFacets(this.typesenseResponse.facet_counts || []),
facets_stats: this._adaptFacetStats(this.typesenseResponse.facet_counts || {}),
query: this.typesenseResponse.request_params.q,
processingTimeMS: this.typesenseResponse.search_time_ms
}; // console.log(adaptedResult);
return adaptedResult;
}
}]);
return SearchResponseAdapter;
}();
exports.SearchResponseAdapter = SearchResponseAdapter;
Object.assign(SearchResponseAdapter.prototype, _utils.utils);
//# sourceMappingURL=SearchResponseAdapter.js.map