import { ResolverOptions, IntermediateSearchResults, SearchResults, EnrichedSearchResults, HighlightOptions } from "./type.js"; import Index from "./index.js"; import Document from "./document.js"; import WorkerIndex from "./worker.js"; import default_resolver from "./resolve/default.js"; import "./resolve/handler.js"; import "./resolve/or.js"; import "./resolve/and.js"; import "./resolve/xor.js"; import "./resolve/not.js"; import { apply_enrich } from "./document/search.js"; import { highlight_fields } from "./document/highlight.js"; /** * @param {IntermediateSearchResults|ResolverOptions=} result * @param {Index|Document|WorkerIndex=} index * @return {Resolver} * @constructor */ export default function Resolver(result, index) { if (!this || this.constructor !== Resolver) { return new Resolver(result, index); } let boost = 0, promises, query, field, highlight, _await, _return; if (result && result.index) { const options = /** @type {ResolverOptions} */result; index = options.index; boost = options.boost || 0; if (query = options.query) { field = options.field || options.pluck; highlight = options.highlight; const resolve = options.resolve, async = options.async || options.queue; options.resolve = !1; options.highlight = ""; options.index = null; result = async ? index.searchAsync(options) : index.search(options); options.resolve = resolve; options.highlight = highlight; options.index = index; result = result.result || result; } else { result = []; } } if (result && result.then) { const self = this; result = result.then(function (result) { self.promises[0] = self.result = result.result || result; self.execute(); }); promises = [result]; result = []; _await = new Promise(function (resolve) { _return = resolve; }); } /** @type {Index|Document|WorkerIndex|null} */ this.index = index || null; /** @type {IntermediateSearchResults} */ this.result = /** @type {IntermediateSearchResults} */result || []; /** @type {number} */ this.boostval = boost; /** @type {Array|IntermediateSearchResults|Function>} */ this.promises = promises || []; /** @type {Promise} */ this.await = _await || null; /** @type {Function} */ this.return = _return || null; /** @type {HighlightOptions|null} */ this.highlight = /** @type {HighlightOptions|null} */highlight || null; /** @type {string} */ this.query = query || ""; /** @type {string} */ this.field = field || ""; } /** * @param {number} limit */ Resolver.prototype.limit = function (limit) { if (this.await) { const self = this; this.promises.push(function () { return self.limit(limit).result; }); } else { if (this.result.length) { /** @type {IntermediateSearchResults} */ const final = []; for (let j = 0, ids; j < this.result.length; j++) { if (ids = this.result[j]) { if (ids.length <= limit) { final[j] = ids; limit -= ids.length; if (!limit) break; } else { final[j] = ids.slice(0, limit); break; } } } this.result = final; } } return this; }; /** * @param {number} offset */ Resolver.prototype.offset = function (offset) { if (this.await) { const self = this; this.promises.push(function () { return self.offset(offset).result; }); } else { if (this.result.length) { /** @type {IntermediateSearchResults} */ const final = []; for (let j = 0, ids; j < this.result.length; j++) { if (ids = this.result[j]) { if (ids.length <= offset) { offset -= ids.length; } else { final[j] = ids.slice(offset); offset = 0; } } } this.result = final; } } return this; }; /** * @param {number} boost */ Resolver.prototype.boost = function (boost) { if (this.await) { const self = this; this.promises.push(function () { return self.boost(boost).result; }); } else { this.boostval += boost; } return this; }; /** * @param {boolean=} _skip_callback * @this {Resolver} */ Resolver.prototype.execute = function (_skip_callback) { let result = this.result, execute = this.await; this.await = null; for (let i = 0, promise; i < this.promises.length; i++) { if (promise = this.promises[i]) { if ("function" == typeof promise) { result = promise(); this.promises[i] = result = result.result || result; i--; } else if (promise._fn) { result = promise._fn(); this.promises[i] = result = result.result || result; i--; } else if (promise.then) { return this.await = execute; } } } const fn = this.return; this.promises = []; this.return = null; _skip_callback || fn(result); return result; }; /** * @param {number|ResolverOptions=} limit * @param {number=} offset * @param {boolean=} enrich * @param {string|HighlightOptions|boolean=} highlight * @param {boolean=} _resolved */ Resolver.prototype.resolve = function (limit, offset, enrich, highlight, _resolved) { let result = this.await ? this.execute(!0) : this.result; if (result.then) { const self = this; return result.then(function () { return self.resolve(limit, offset, enrich, highlight, _resolved); }); } if (result.length) { if ("object" == typeof limit) { highlight = limit.highlight || this.highlight; enrich = !!highlight || limit.enrich; offset = limit.offset; limit = limit.limit; } else { highlight = highlight || this.highlight; enrich = !!highlight || enrich; } result = _resolved ? enrich ? apply_enrich.call( /** @type {Document} */this.index, /** @type {SearchResults} */result) : result : default_resolver.call(this.index, result, limit || 100, offset, enrich); } return this.finalize(result, highlight); }; Resolver.prototype.finalize = function (result, highlight) { if (result.then) { const self = this; return result.then(function (result) { return self.finalize(result, highlight); }); } if (highlight && !this.query) { console.warn('There was no query specified for highlighting. Please specify a query within the highlight resolver stage like { query: "...", highlight: ... }.'); } if (highlight && result.length && this.query) { result = highlight_fields(this.query, result, this.index.index, this.field, highlight); } const fn = this.return; this.index = this.result = this.promises = this.await = this.return = null; this.highlight = null; this.query = this.field = ""; fn && fn(result); return result; };