UNPKG

@gooddata/gooddata-js

Version:
519 lines (518 loc) • 24.9 kB
"use strict"; var __assign = (this && this.__assign) || function () { __assign = Object.assign || function(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); // (C) 2007-2020 GoodData Corporation var md5_1 = __importDefault(require("md5")); var invariant_1 = __importDefault(require("invariant")); var cloneDeep_1 = __importDefault(require("lodash/cloneDeep")); var compact_1 = __importDefault(require("lodash/compact")); var filter_1 = __importDefault(require("lodash/filter")); var first_1 = __importDefault(require("lodash/first")); var find_1 = __importDefault(require("lodash/find")); var map_1 = __importDefault(require("lodash/map")); var merge_1 = __importDefault(require("lodash/merge")); var every_1 = __importDefault(require("lodash/every")); var get_1 = __importDefault(require("lodash/get")); var isEmpty_1 = __importDefault(require("lodash/isEmpty")); var negate_1 = __importDefault(require("lodash/negate")); var partial_1 = __importDefault(require("lodash/partial")); var flatten_1 = __importDefault(require("lodash/flatten")); var set_1 = __importDefault(require("lodash/set")); var rules_1 = require("../utils/rules"); var definitions_1 = require("../utils/definitions"); var attributesMapLoader_1 = require("../utils/attributesMapLoader"); var visualizationObjectHelper_1 = require("../utils/visualizationObjectHelper"); var notEmpty = negate_1.default(isEmpty_1.default); function findHeaderForMappingFn(mapping, header) { return ((mapping.element === header.id || mapping.element === header.uri) && header.measureIndex === undefined); } function wrapMeasureIndexesFromMappings(metricMappings, headers) { if (metricMappings) { metricMappings.forEach(function (mapping) { var header = find_1.default(headers, partial_1.default(findHeaderForMappingFn, mapping)); if (header) { header.measureIndex = mapping.measureIndex; header.isPoP = mapping.isPoP; } }); } return headers; } var emptyResult = { extendedTabularDataResult: { values: [], warnings: [], }, }; var MAX_TITLE_LENGTH = 1000; function getMetricTitle(suffix, title) { var maxLength = MAX_TITLE_LENGTH - suffix.length; if (title && title.length > maxLength) { if (title[title.length - 1] === ")") { return title.substring(0, maxLength - 2) + "\u2026)" + suffix; } return title.substring(0, maxLength - 1) + "\u2026" + suffix; } return "" + title + suffix; } var getBaseMetricTitle = partial_1.default(getMetricTitle, ""); var CONTRIBUTION_METRIC_FORMAT = "#,##0.00%"; function getPoPDefinition(measure) { return get_1.default(measure, ["definition", "popMeasureDefinition"], {}); } function getAggregation(measure) { return get_1.default(visualizationObjectHelper_1.getDefinition(measure), "aggregation", "").toLowerCase(); } function isEmptyFilter(metricFilter) { if (get_1.default(metricFilter, "positiveAttributeFilter")) { return isEmpty_1.default(get_1.default(metricFilter, ["positiveAttributeFilter", "in"])); } if (get_1.default(metricFilter, "negativeAttributeFilter")) { return isEmpty_1.default(get_1.default(metricFilter, ["negativeAttributeFilter", "notIn"])); } if (get_1.default(metricFilter, "absoluteDateFilter")) { return (get_1.default(metricFilter, ["absoluteDateFilter", "from"]) === undefined && get_1.default(metricFilter, ["absoluteDateFilter", "to"]) === undefined); } return (get_1.default(metricFilter, ["relativeDateFilter", "from"]) === undefined && get_1.default(metricFilter, ["relativeDateFilter", "to"]) === undefined); } function allFiltersEmpty(item) { return every_1.default(map_1.default(visualizationObjectHelper_1.getMeasureFilters(item), function (f) { return isEmptyFilter(f); })); } function isDerived(measure) { var aggregation = getAggregation(measure); return aggregation !== "" || !allFiltersEmpty(measure); } function getAttrTypeFromMap(dfUri, attributesMap) { return get_1.default(get_1.default(attributesMap, [dfUri], {}), ["attribute", "content", "type"]); } function getAttrUriFromMap(dfUri, attributesMap) { return get_1.default(get_1.default(attributesMap, [dfUri], {}), ["attribute", "meta", "uri"]); } function isAttrFilterNegative(attributeFilter) { return get_1.default(attributeFilter, "negativeAttributeFilter") !== undefined; } function getAttrFilterElements(attributeFilter) { var isNegative = isAttrFilterNegative(attributeFilter); var pathToElements = isNegative ? ["negativeAttributeFilter", "notIn"] : ["positiveAttributeFilter", "in"]; return get_1.default(attributeFilter, pathToElements, []); } function getAttrFilterExpression(measureFilter, attributesMap) { var isNegative = get_1.default(measureFilter, "negativeAttributeFilter", false); var detailPath = isNegative ? "negativeAttributeFilter" : "positiveAttributeFilter"; var attributeUri = getAttrUriFromMap(get_1.default(measureFilter, [detailPath, "displayForm", "uri"]), attributesMap); var elements = getAttrFilterElements(measureFilter); if (isEmpty_1.default(elements)) { return null; } var elementsForQuery = map_1.default(elements, function (e) { return "[" + e + "]"; }); var negative = isNegative ? "NOT " : ""; return "[" + attributeUri + "] " + negative + "IN (" + elementsForQuery.join(",") + ")"; } function getDateFilterExpression() { // measure date filter was never supported return ""; } function getFilterExpression(attributesMap, measureFilter) { if (visualizationObjectHelper_1.isAttributeMeasureFilter(measureFilter)) { return getAttrFilterExpression(measureFilter, attributesMap); } return getDateFilterExpression(); } function getGeneratedMetricExpression(item, attributesMap) { var aggregation = getAggregation(item).toUpperCase(); var objectUri = get_1.default(visualizationObjectHelper_1.getDefinition(item), "item.uri"); var where = filter_1.default(map_1.default(visualizationObjectHelper_1.getMeasureFilters(item), partial_1.default(getFilterExpression, attributesMap)), function (e) { return !!e; }); return "SELECT " + (aggregation ? aggregation + "([" + objectUri + "])" : "[" + objectUri + "]") + (notEmpty(where) ? " WHERE " + where.join(" AND ") : ""); } function getPercentMetricExpression(category, attributesMap, measure) { var metricExpressionWithoutFilters = "SELECT [" + get_1.default(visualizationObjectHelper_1.getDefinition(measure), "item.uri") + "]"; if (isDerived(measure)) { metricExpressionWithoutFilters = getGeneratedMetricExpression(set_1.default(cloneDeep_1.default(measure), ["definition", "measureDefinition", "filters"], []), attributesMap); } var attributeUri = getAttrUriFromMap(get_1.default(category, "displayForm.uri"), attributesMap); var whereFilters = filter_1.default(map_1.default(visualizationObjectHelper_1.getMeasureFilters(measure), partial_1.default(getFilterExpression, attributesMap)), function (e) { return !!e; }); var whereExpression = notEmpty(whereFilters) ? " WHERE " + whereFilters.join(" AND ") : ""; // tslint:disable-next-line:max-line-length return "SELECT (" + metricExpressionWithoutFilters + whereExpression + ") / (" + metricExpressionWithoutFilters + " BY ALL [" + attributeUri + "]" + whereExpression + ")"; } function getPoPExpression(attributeUri, metricExpression) { return "SELECT " + metricExpression + " FOR PREVIOUS ([" + attributeUri + "])"; } function getGeneratedMetricHash(title, format, expression) { return md5_1.default(expression + "#" + title + "#" + format); } function getMeasureType(measure) { var aggregation = getAggregation(measure); if (aggregation === "") { return "metric"; } else if (aggregation === "count") { return "attribute"; } return "fact"; } function getGeneratedMetricIdentifier(item, aggregation, expressionCreator, hasher, attributesMap) { var _a = get_1.default(visualizationObjectHelper_1.getDefinition(item), "item.uri", "").split("/"), prjId = _a[3], id = _a[5]; var identifier = prjId + "_" + id; var hash = hasher(expressionCreator(item, attributesMap)); var hasNoFilters = isEmpty_1.default(visualizationObjectHelper_1.getMeasureFilters(item)); var type = getMeasureType(item); var prefix = hasNoFilters || allFiltersEmpty(item) ? "" : "_filtered"; return type + "_" + identifier + ".generated." + hash + prefix + "_" + aggregation; } function isDateAttribute(attribute, attributesMap) { if (attributesMap === void 0) { attributesMap = {}; } return getAttrTypeFromMap(get_1.default(attribute, ["displayForm", "uri"]), attributesMap) !== undefined; } function getMeasureSorting(measure, mdObj) { var sorting = get_1.default(mdObj, ["properties", "sortItems"], []); var matchedSorting = sorting.find(function (sortItem) { var measureSortItem = get_1.default(sortItem, ["measureSortItem"]); if (measureSortItem) { // only one item now, we support only 2d data var identifier = get_1.default(measureSortItem, [ "locators", 0, "measureLocatorItem", "measureIdentifier", ]); return identifier === get_1.default(measure, "localIdentifier"); } return false; }); if (matchedSorting) { return get_1.default(matchedSorting, ["measureSortItem", "direction"], null); } return null; } function getCategorySorting(category, mdObj) { var sorting = get_1.default(mdObj, ["properties", "sortItems"], []); var matchedSorting = sorting.find(function (sortItem) { var attributeSortItem = get_1.default(sortItem, ["attributeSortItem"]); if (attributeSortItem) { var identifier = get_1.default(attributeSortItem, ["attributeIdentifier"]); return identifier === get_1.default(category, "localIdentifier"); } return false; }); if (matchedSorting) { return get_1.default(matchedSorting, ["attributeSortItem", "direction"], null); } return null; } var createPureMetric = function (measure, mdObj, measureIndex) { return ({ element: get_1.default(measure, ["definition", "measureDefinition", "item", "uri"]), sort: getMeasureSorting(measure, mdObj), meta: { measureIndex: measureIndex }, }); }; function createDerivedMetric(measure, mdObj, measureIndex, attributesMap) { var format = measure.format; var sort = getMeasureSorting(measure, mdObj); var title = getBaseMetricTitle(measure.title); var hasher = partial_1.default(getGeneratedMetricHash, title, format); var aggregation = getAggregation(measure); var element = getGeneratedMetricIdentifier(measure, aggregation.length ? aggregation : "base", getGeneratedMetricExpression, hasher, attributesMap); var definition = { metricDefinition: { identifier: element, expression: getGeneratedMetricExpression(measure, attributesMap), title: title, format: format, }, }; return { element: element, definition: definition, sort: sort, meta: { measureIndex: measureIndex, }, }; } function createContributionMetric(measure, mdObj, measureIndex, attributesMap) { var attribute = first_1.default(visualizationObjectHelper_1.getAttributes(mdObj)); var getMetricExpression = partial_1.default(getPercentMetricExpression, attribute, attributesMap); var title = getBaseMetricTitle(get_1.default(measure, "title")); var hasher = partial_1.default(getGeneratedMetricHash, title, CONTRIBUTION_METRIC_FORMAT); var identifier = getGeneratedMetricIdentifier(measure, "percent", getMetricExpression, hasher, attributesMap); return { element: identifier, definition: { metricDefinition: { identifier: identifier, expression: getMetricExpression(measure), title: title, format: CONTRIBUTION_METRIC_FORMAT, }, }, sort: getMeasureSorting(measure, mdObj), meta: { measureIndex: measureIndex, }, }; } function getOriginalMeasureForPoP(popMeasure, mdObj) { return visualizationObjectHelper_1.getMeasures(mdObj).find(function (measure) { return get_1.default(measure, "localIdentifier") === get_1.default(getPoPDefinition(popMeasure), ["measureIdentifier"]); }); } function createPoPMetric(popMeasure, mdObj, measureIndex, attributesMap) { var title = getBaseMetricTitle(get_1.default(popMeasure, "title")); var format = get_1.default(popMeasure, "format"); var hasher = partial_1.default(getGeneratedMetricHash, title, format); var attributeUri = get_1.default(popMeasure, "definition.popMeasureDefinition.popAttribute.uri"); var originalMeasure = getOriginalMeasureForPoP(popMeasure, mdObj); var originalMeasureExpression = "[" + get_1.default(visualizationObjectHelper_1.getDefinition(originalMeasure), ["item", "uri"]) + "]"; var metricExpression = getPoPExpression(attributeUri, originalMeasureExpression); if (isDerived(originalMeasure)) { var generated = createDerivedMetric(originalMeasure, mdObj, measureIndex, attributesMap); var generatedMeasureExpression = "(" + get_1.default(generated, [ "definition", "metricDefinition", "expression", ]) + ")"; metricExpression = getPoPExpression(attributeUri, generatedMeasureExpression); } var identifier = getGeneratedMetricIdentifier(originalMeasure, "pop", function () { return metricExpression; }, hasher, attributesMap); return { element: identifier, definition: { metricDefinition: { identifier: identifier, expression: metricExpression, title: title, format: format, }, }, sort: getMeasureSorting(popMeasure, mdObj), meta: { measureIndex: measureIndex, isPoP: true, }, }; } function createContributionPoPMetric(popMeasure, mdObj, measureIndex, attributesMap) { var attributeUri = get_1.default(popMeasure, ["definition", "popMeasureDefinition", "popAttribute", "uri"]); var originalMeasure = getOriginalMeasureForPoP(popMeasure, mdObj); var generated = createContributionMetric(originalMeasure, mdObj, measureIndex, attributesMap); var title = getBaseMetricTitle(get_1.default(popMeasure, "title")); var format = CONTRIBUTION_METRIC_FORMAT; var hasher = partial_1.default(getGeneratedMetricHash, title, format); var generatedMeasureExpression = "(" + get_1.default(generated, [ "definition", "metricDefinition", "expression", ]) + ")"; var metricExpression = getPoPExpression(attributeUri, generatedMeasureExpression); var identifier = getGeneratedMetricIdentifier(originalMeasure, "pop", function () { return metricExpression; }, hasher, attributesMap); return { element: identifier, definition: { metricDefinition: { identifier: identifier, expression: metricExpression, title: title, format: format, }, }, sort: getMeasureSorting(), meta: { measureIndex: measureIndex, isPoP: true, }, }; } function categoryToElement(attributesMap, mdObj, category) { var element = getAttrUriFromMap(get_1.default(category, ["displayForm", "uri"]), attributesMap); return { element: element, sort: getCategorySorting(category, mdObj), }; } function isPoP(_a) { var definition = _a.definition; return get_1.default(definition, "popMeasureDefinition") !== undefined; } function isContribution(_a) { var definition = _a.definition; return get_1.default(definition, ["measureDefinition", "computeRatio"]); } function isPoPContribution(popMeasure, mdObj) { if (isPoP(popMeasure)) { var originalMeasure = getOriginalMeasureForPoP(popMeasure, mdObj); return isContribution(originalMeasure); } return false; } function isCalculatedMeasure(_a) { var definition = _a.definition; return get_1.default(definition, ["measureDefinition", "aggregation"]) === undefined; } var rules = new rules_1.Rules(); rules.addRule([isPoPContribution], createContributionPoPMetric); rules.addRule([isPoP], createPoPMetric); rules.addRule([isContribution], createContributionMetric); rules.addRule([isDerived], createDerivedMetric); rules.addRule([isCalculatedMeasure], createPureMetric); function getMetricFactory(measure, mdObj) { var factory = rules.match(measure, mdObj); invariant_1.default(factory, "Unknown factory for: " + measure); return factory; } function getExecutionDefinitionsAndColumns(mdObj, options, attributesMap) { var measures = visualizationObjectHelper_1.getMeasures(mdObj); var attributes = visualizationObjectHelper_1.getAttributes(mdObj); var metrics = flatten_1.default(map_1.default(measures, function (measure, index) { return getMetricFactory(measure, mdObj)(measure, mdObj, index, attributesMap); })); if (options.removeDateItems) { attributes = filter_1.default(attributes, function (attribute) { return !isDateAttribute(attribute, attributesMap); }); } attributes = map_1.default(attributes, partial_1.default(categoryToElement, attributesMap, mdObj)); var columns = compact_1.default(map_1.default(attributes.concat(metrics), "element")); return { columns: columns, definitions: definitions_1.sortDefinitions(compact_1.default(map_1.default(metrics, "definition"))), }; } /** * Module for execution on experimental execution resource * * @class execution * @module execution * @deprecated The module is in maintenance mode only (just the the compilation issues are being fixed when * referenced utilities and interfaces are being changed) and is not being extended when AFM executor * have new functionality added. */ var ExperimentalExecutionsModule = /** @class */ (function () { function ExperimentalExecutionsModule(xhr, loadAttributesMap) { this.xhr = xhr; this.loadAttributesMap = loadAttributesMap; } /** * For the given projectId it returns table structure with the given * elements in column headers. * * @method getData * @param {String} projectId - GD project identifier * @param {Array} columns - An array of attribute or metric identifiers. * @param {Object} executionConfiguration - Execution configuration - can contain for example * property "where" containing query-like filters * property "orderBy" contains array of sorted properties to order in form * [{column: 'identifier', direction: 'asc|desc'}] * @param {Object} settings - Supports additional settings accepted by the underlying * xhr.ajax() calls * * @return {Object} Structure with `headers` and `rawData` keys filled with values from execution. */ ExperimentalExecutionsModule.prototype.getData = function (projectId, columns, executionConfiguration, settings) { var _this = this; if (executionConfiguration === void 0) { executionConfiguration = {}; } if (settings === void 0) { settings = {}; } if (process.env.NODE_ENV !== "test") { // tslint:disable-next-line:no-console console.warn("ExperimentalExecutionsModule is deprecated and is no longer being maintained. " + "Please migrate to the ExecuteAfmModule."); } var executedReport = { isLoaded: false, }; // Create request and result structures var request = { execution: { columns: columns }, }; // enrich configuration with supported properties such as // where clause with query-like filters ["where", "orderBy", "definitions"].forEach(function (property) { if (executionConfiguration[property]) { request.execution[property] = executionConfiguration[property]; } }); // Execute request return this.xhr .post("/gdc/internal/projects/" + projectId + "/experimental/executions", __assign({}, settings, { body: JSON.stringify(request) })) .then(function (r) { return r.getData(); }) .then(function (response) { executedReport.headers = wrapMeasureIndexesFromMappings(get_1.default(executionConfiguration, "metricMappings"), get_1.default(response, ["executionResult", "headers"], [])); // Start polling on url returned in the executionResult for tabularData return _this.loadExtendedDataResults(response.executionResult.extendedTabularDataResult, settings); }) .then(function (r) { var result = r.result, status = r.status; return __assign({}, executedReport, { rawData: get_1.default(result, "extendedTabularDataResult.values", []), warnings: get_1.default(result, "extendedTabularDataResult.warnings", []), isLoaded: true, isEmpty: status === 204 }); }); }; ExperimentalExecutionsModule.prototype.mdToExecutionDefinitionsAndColumns = function (projectId, mdObj, options) { if (options === void 0) { options = {}; } var allDfUris = visualizationObjectHelper_1.getAttributesDisplayForms(mdObj); var attributesMapPromise = this.getAttributesMap(options, allDfUris, projectId); return attributesMapPromise.then(function (attributesMap) { return getExecutionDefinitionsAndColumns(mdObj, options, attributesMap); }); }; ExperimentalExecutionsModule.prototype.getAttributesMap = function (options, displayFormUris, projectId) { var attributesMap = get_1.default(options, "attributesMap", {}); var missingUris = attributesMapLoader_1.getMissingUrisInAttributesMap(displayFormUris, attributesMap); return this.loadAttributesMap(projectId, missingUris).then(function (result) { return __assign({}, attributesMap, result); }); }; ExperimentalExecutionsModule.prototype.loadExtendedDataResults = function (uri, settings, prevResult) { var _this = this; if (prevResult === void 0) { prevResult = emptyResult; } return new Promise(function (resolve, reject) { _this.xhr .ajax(uri, settings) .then(function (r) { var response = r.response; if (response.status === 204) { return { status: response.status, result: "", }; } return { status: response.status, result: r.getData(), }; }) .then(function (_a) { var status = _a.status, result = _a.result; var values = get_1.default(prevResult, "extendedTabularDataResult.values", []).concat(get_1.default(result, "extendedTabularDataResult.values", [])); var warnings = get_1.default(prevResult, "extendedTabularDataResult.warnings", []).concat(get_1.default(result, "extendedTabularDataResult.warnings", [])); var updatedResult = merge_1.default({}, prevResult, { extendedTabularDataResult: { values: values, warnings: warnings, }, }); var nextUri = get_1.default(result, "extendedTabularDataResult.paging.next"); if (nextUri) { resolve(_this.loadExtendedDataResults(nextUri, settings, updatedResult)); } else { resolve({ status: status, result: updatedResult }); } }, reject); }); }; return ExperimentalExecutionsModule; }()); exports.ExperimentalExecutionsModule = ExperimentalExecutionsModule;