UNPKG

terriajs

Version:

Geospatial data visualization platform.

164 lines 6.29 kB
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) { var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d; if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc); else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r; return c > 3 && r && Object.defineProperty(target, key, r), r; }; import { Document } from "flexsearch"; import { action, makeObservable, observable, runInAction } from "mobx"; import { isJsonObject, isJsonString, isJsonStringArray } from "../../Core/Json"; import loadBlob, { isZip, parseZipJsonBlob } from "../../Core/loadBlob"; import loadJson from "../../Core/loadJson"; import CatalogIndexReference from "../Catalog/CatalogReferences/CatalogIndexReference"; import CommonStrata from "../Definition/CommonStrata"; import updateModelFromJson from "../Definition/updateModelFromJson"; import SearchResult from "./SearchResult"; export default class CatalogIndex { terria; url; /** Map from share key -> id */ shareKeysMap = observable.map(); _models; _searchIndex; // Flex-search document index _loadPromise; constructor(terria, url) { this.terria = terria; this.url = url; makeObservable(this); } get models() { return this._models; } get searchIndex() { return this._searchIndex; } get loadPromise() { return this._loadPromise; } getModelByIdOrShareKey(modelId) { if (this.models?.has(modelId)) { return this.models.get(modelId); } const shareKeyId = this.shareKeysMap.get(modelId); if (shareKeyId) { return this.models?.get(shareKeyId); } } load() { if (this._loadPromise) return this._loadPromise; runInAction(() => (this._loadPromise = this.loadCatalogIndex())); return this._loadPromise; } /** The catalog index is loaded automatically on startup. * It is loaded the first time loadInitSources is called (see Terria.forceLoadInitSources) */ async loadCatalogIndex() { // Load catalog index try { const url = this.terria.corsProxy.getURLProxyIfNecessary(this.url); const index = (isZip(url) ? await parseZipJsonBlob(await loadBlob(url)) : await loadJson(url)); this._models = new Map(); /** * https://github.com/nextapps-de/flexsearch * Create search index for fields "name" and "description" * - tokenize property * - "full" = index every possible combination * - "strict" = index whole words * - resolution property = score resolution * * Note: because we have set `worker: true`, we must use async calls */ this._searchIndex = new Document({ worker: true, document: { id: "id", index: [ { field: "name", tokenize: "full", resolution: 9 }, { field: "description", tokenize: "strict", resolution: 1 } ] } }); const indexModels = Object.entries(index); const promises = []; for (let idx = 0; idx < indexModels.length; idx++) { const [id, model] = indexModels[idx]; if (!isJsonObject(model, false)) return; const reference = new CatalogIndexReference(id, this.terria); updateModelFromJson(reference, CommonStrata.definition, model).logError("Error ocurred adding adding catalog model reference"); if (isJsonStringArray(model.shareKeys)) { model.shareKeys.map((s) => this.shareKeysMap.set(s, id)); } // Add model to CatalogIndexReference map this._models.set(id, reference); // Add document to search index promises.push(this._searchIndex.addAsync(id, { id, name: isJsonString(model.name) ? model.name : "", description: isJsonString(model.description) ? model.description : "" })); } await Promise.all(promises); } catch (error) { this.terria.raiseErrorToUser(error, "Failed to load catalog index"); } } async search(q) { const results = []; /** Example matches object ```json [ { "field": "name", "result": [ "some-id-1" ] }, { "field": "description", "result": [ "some-id-2" ] } ] ``` */ if (!this.searchIndex) return []; const matches = await this.searchIndex.searchAsync(q); const matchedIds = new Set(); matches.forEach((fieldResult) => { fieldResult.result.forEach((id) => { const indexReference = this.models?.get(id); if (indexReference && !matchedIds.has(id)) { matchedIds.add(id); results.push(runInAction(() => new SearchResult({ name: indexReference.name ?? indexReference.uniqueId, catalogItem: indexReference }))); } }); }); return results; } } __decorate([ observable ], CatalogIndex.prototype, "_loadPromise", void 0); __decorate([ action ], CatalogIndex.prototype, "loadCatalogIndex", null); //# sourceMappingURL=CatalogIndex.js.map