"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.Mapping = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _lodash = _interopRequireDefault(require("lodash")); var _rxjs = require("rxjs"); var _constants = require("../../../common/constants"); var _expand_aliases = require("./expand_aliases"); /* * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one * or more contributor license agreements. Licensed under the Elastic License * 2.0 and the Server Side Public License, v 1; you may not use this file except * in compliance with, at your election, the Elastic License 2.0 or the Server * Side Public License, v 1. */ function getFieldNamesFromProperties(properties = {}) { const fieldList = Object.entries(properties).flatMap(([fieldName, fieldMapping]) => { return getFieldNamesFromFieldMapping(fieldName, fieldMapping); }); // deduping return _lodash.default.uniqBy(fieldList, function (f) { return f.name + ':' + f.type; }); } function getFieldNamesFromFieldMapping(fieldName, fieldMapping) { if (fieldMapping.enabled === false) { return []; } let nestedFields; function applyPathSettings(nestedFieldNames) { const pathType = fieldMapping.path || 'full'; if (pathType === 'full') { return nestedFieldNames.map(f => { f.name = fieldName + '.' + f.name; return f; }); } return nestedFieldNames; } if (fieldMapping.properties) { // derived object type nestedFields = getFieldNamesFromProperties(fieldMapping.properties); return applyPathSettings(nestedFields); } const fieldType = fieldMapping.type; const ret = { name: fieldName, type: fieldType }; if (fieldMapping.index_name) { ret.name = fieldMapping.index_name; } if (fieldMapping.fields) { nestedFields = Object.entries(fieldMapping.fields).flatMap(([name, mapping]) => { return getFieldNamesFromFieldMapping(name, mapping); }); nestedFields = applyPathSettings(nestedFields); nestedFields.unshift(ret); return nestedFields; } return [ret]; } class Mapping { constructor() { (0, _defineProperty2.default)(this, "http", void 0); (0, _defineProperty2.default)(this, "settings", void 0); /** * Map of the mappings of actual ES indices. */ (0, _defineProperty2.default)(this, "perIndexTypes", {}); /** * Map of the user-input wildcards and actual indices. */ (0, _defineProperty2.default)(this, "perWildcardIndices", {}); (0, _defineProperty2.default)(this, "_isLoading$", new _rxjs.BehaviorSubject(false)); /** * Indicates if mapping fetching is in progress. */ (0, _defineProperty2.default)(this, "isLoading$", this._isLoading$.asObservable()); /** * Map of the currently loading mappings for index patterns specified by a user. * @private */ (0, _defineProperty2.default)(this, "loadingState", {}); (0, _defineProperty2.default)(this, "getMappings", (indices, types, autoCompleteContext) => { // get fields for indices and types. Both can be a list, a string or null (meaning all). let ret = []; if (!this.settings.getAutocomplete().fields) return ret; indices = (0, _expand_aliases.expandAliases)(indices); if (typeof indices === 'string') { const typeDict = this.perIndexTypes[indices]; if (!typeDict || Object.keys(typeDict).length === 0) { if (!autoCompleteContext) return ret; // Mappings fetching for the index is already in progress if (this.loadingState[indices]) return ret; this.loadingState[indices] = true; if (!autoCompleteContext.asyncResultsState) { autoCompleteContext.asyncResultsState = {}; } autoCompleteContext.asyncResultsState.isLoading = true; autoCompleteContext.asyncResultsState.results = new Promise((resolve, reject) => { this._isLoading$.next(true); this.fetchMappings(indices).then(mapping => { this._isLoading$.next(false); autoCompleteContext.asyncResultsState.isLoading = false; autoCompleteContext.asyncResultsState.lastFetched = Date.now(); const mappingsIndices = Object.keys(mapping); if (mappingsIndices.length > 1 || mappingsIndices[0] && mappingsIndices[0] !== indices) { this.perWildcardIndices[indices] = Object.keys(mapping); } // cache mappings this.loadMappings(mapping); const mappings = this.getMappings(indices, types, autoCompleteContext); delete this.loadingState[indices]; resolve(mappings); }).catch(error => { // eslint-disable-next-line no-console console.error(error); this._isLoading$.next(false); delete this.loadingState[indices]; }); }); return []; } if (typeof types === 'string') { const f = typeDict[types]; if (Array.isArray(f)) { ret = f; } } else { // filter what we need Object.entries(typeDict).forEach(([type, fields]) => { if (!types || types.length === 0 || types.includes(type)) { ret.push(fields); } }); ret = [].concat.apply([], ret); } } else { // multi index mode. Object.keys(this.perIndexTypes).forEach(index => { if (!indices || indices.length === 0 || indices.includes(index)) { ret.push(this.getMappings(index, types, autoCompleteContext)); } }); ret = [].concat.apply([], ret); } return _lodash.default.uniqBy(ret, function (f) { return f.name + ':' + f.type; }); }); (0, _defineProperty2.default)(this, "loadMappings", mappings => { Object.entries(mappings).forEach(([index, indexMapping]) => { const normalizedIndexMappings = {}; let transformedMapping = indexMapping; // Migrate 1.0.0 mappings. This format has changed, so we need to extract the underlying mapping. if (indexMapping.mappings && Object.keys(indexMapping).length === 1) { transformedMapping = indexMapping.mappings; } Object.entries(transformedMapping).forEach(([typeName, typeMapping]) => { if (typeName === 'properties') { const fieldList = getFieldNamesFromProperties(typeMapping); normalizedIndexMappings[typeName] = fieldList; } else { normalizedIndexMappings[typeName] = []; } }); this.perIndexTypes[index] = normalizedIndexMappings; }); }); (0, _defineProperty2.default)(this, "clearMappings", () => { this.perIndexTypes = {}; }); } setup(http, settings) { this.http = http; this.settings = settings; } /** * Fetches mappings of the requested indices. * @param index */ async fetchMappings(index) { const response = await this.http.get(`${_constants.API_BASE_PATH}/autocomplete_entities`, { query: { fields: true, fieldsIndices: index } }); return response.mappings; } } exports.Mapping = Mapping;