@gooddata/gooddata-js
Version:
GoodData JavaScript SDK
519 lines (518 loc) • 24.9 kB
JavaScript
;
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;