Comparing version 4.3.1 to 4.4.0
// Copyright (C) 2007-2017, GoodData(R) Corporation. All rights reserved. | ||
import { AFM, Execution } from '@gooddata/typings'; | ||
@@ -344,2 +345,4 @@ export type SortDirection = 'asc' | 'desc'; | ||
export function getData(projectId: string, columns: string[], executionConfiguration: IExecutionConfiguration, settings: any): Promise<ISimpleExecutorResult>; | ||
export function executeAfm(projectId: string, execution: AFM.IExecution): Promise<Execution.IExecutionResponses>; | ||
} | ||
@@ -346,0 +349,0 @@ |
@@ -16,3 +16,3 @@ 'use strict'; | ||
var _execution = require('./execution'); | ||
var _experimentalExecutions = require('./execution/experimental-executions'); | ||
@@ -46,3 +46,3 @@ var REQUEST_DEFAULTS = { | ||
var categories = parseCategories(bucketItems); | ||
var executionConfig = (0, _execution.mdToExecutionConfiguration)({ | ||
var executionConfig = (0, _experimentalExecutions.mdToExecutionConfiguration)({ | ||
buckets: _extends({}, bucketItems, { | ||
@@ -49,0 +49,0 @@ categories: categories |
'use strict'; | ||
Object.defineProperty(exports, "__esModule", { | ||
value: true | ||
value: true | ||
}); | ||
exports.getDataForVis = exports.mdToExecutionConfiguration = undefined; | ||
var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); | ||
var _experimentalExecutions = require('./execution/experimental-executions'); | ||
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; | ||
var _executeAfm = require('./execution/execute-afm'); | ||
exports.getData = getData; | ||
var _executeAfm2 = _interopRequireDefault(_executeAfm); | ||
var _md = require('md5'); | ||
var _md2 = _interopRequireDefault(_md); | ||
var _invariant = require('invariant'); | ||
var _invariant2 = _interopRequireDefault(_invariant); | ||
var _lodash = require('lodash'); | ||
var _xhr = require('./xhr'); | ||
var _rules = require('./utils/rules'); | ||
var _rules2 = _interopRequireDefault(_rules); | ||
var _definitions = require('./utils/definitions'); | ||
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } | ||
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } | ||
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } | ||
function _toConsumableArray(arr) { if (Array.isArray(arr)) { for (var i = 0, arr2 = Array(arr.length); i < arr.length; i++) { arr2[i] = arr[i]; } return arr2; } else { return Array.from(arr); } } // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. | ||
var notEmpty = (0, _lodash.negate)(_lodash.isEmpty); | ||
var findHeaderForMappingFn = function findHeaderForMappingFn(mapping, header) { | ||
return (mapping.element === header.id || mapping.element === header.uri) && header.measureIndex === undefined; | ||
}; | ||
var wrapMeasureIndexesFromMappings = function wrapMeasureIndexesFromMappings(metricMappings, headers) { | ||
if (metricMappings) { | ||
metricMappings.forEach(function (mapping) { | ||
var header = (0, _lodash.find)(headers, (0, _lodash.partial)(findHeaderForMappingFn, mapping)); | ||
if (header) { | ||
header.measureIndex = mapping.measureIndex; | ||
header.isPoP = mapping.isPoP; | ||
} | ||
}); | ||
} | ||
return headers; | ||
}; | ||
var emptyResult = { | ||
extendedTabularDataResult: { | ||
values: [], | ||
warnings: [] | ||
} | ||
}; | ||
function loadExtendedDataResults(uri, settings) { | ||
var prevResult = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : emptyResult; | ||
return new Promise(function (resolve, reject) { | ||
(0, _xhr.ajax)(uri, settings).then(function (r) { | ||
if (r.status === 204) { | ||
return { | ||
status: r.status, | ||
result: '' | ||
}; | ||
} | ||
return r.json().then(function (result) { | ||
return { | ||
status: r.status, | ||
result: result | ||
}; | ||
}); | ||
}).then(function (_ref) { | ||
var status = _ref.status, | ||
result = _ref.result; | ||
var values = [].concat(_toConsumableArray((0, _lodash.get)(prevResult, 'extendedTabularDataResult.values', [])), _toConsumableArray((0, _lodash.get)(result, 'extendedTabularDataResult.values', []))); | ||
var warnings = [].concat(_toConsumableArray((0, _lodash.get)(prevResult, 'extendedTabularDataResult.warnings', [])), _toConsumableArray((0, _lodash.get)(result, 'extendedTabularDataResult.warnings', []))); | ||
var updatedResult = (0, _lodash.merge)({}, prevResult, { | ||
extendedTabularDataResult: { | ||
values: values, | ||
warnings: warnings | ||
} | ||
}); | ||
var nextUri = (0, _lodash.get)(result, 'extendedTabularDataResult.paging.next'); | ||
if (nextUri) { | ||
resolve(loadExtendedDataResults(nextUri, settings, updatedResult)); | ||
} else { | ||
resolve({ status: status, result: updatedResult }); | ||
} | ||
}, reject); | ||
}); | ||
} | ||
/** | ||
* Module for execution on experimental execution resource | ||
* Execution endpoints | ||
* | ||
* @module execution | ||
* @class execution | ||
* @module execution | ||
*/ | ||
/** | ||
* 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. | ||
*/ | ||
function getData(projectId, columns) { | ||
var executionConfiguration = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; | ||
var settings = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {}; | ||
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 (0, _xhr.post)('/gdc/internal/projects/' + projectId + '/experimental/executions', _extends({}, settings, { | ||
body: JSON.stringify(request) | ||
})).then(_xhr.parseJSON).then(function (result) { | ||
executedReport.headers = wrapMeasureIndexesFromMappings((0, _lodash.get)(executionConfiguration, 'metricMappings'), result.executionResult.headers); | ||
// Start polling on url returned in the executionResult for tabularData | ||
return loadExtendedDataResults(result.executionResult.extendedTabularDataResult, settings); | ||
}).then(function (r) { | ||
var result = r.result, | ||
status = r.status; | ||
return Object.assign({}, executedReport, { | ||
rawData: (0, _lodash.get)(result, 'extendedTabularDataResult.values', []), | ||
warnings: (0, _lodash.get)(result, 'extendedTabularDataResult.warnings', []), | ||
isLoaded: true, | ||
isEmpty: status === 204 | ||
}); | ||
}); | ||
} | ||
var MAX_TITLE_LENGTH = 1000; | ||
var getMetricTitle = 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 = (0, _lodash.partial)(getMetricTitle, ''); | ||
var POP_SUFFIX = ' - previous year'; | ||
var getPoPMetricTitle = (0, _lodash.partial)(getMetricTitle, POP_SUFFIX); | ||
var CONTRIBUTION_METRIC_FORMAT = '#,##0.00%'; | ||
var allFiltersEmpty = function allFiltersEmpty(item) { | ||
return (0, _lodash.every)((0, _lodash.map)((0, _lodash.get)(item, 'measureFilters', []), function (f) { | ||
return (0, _lodash.isEmpty)((0, _lodash.get)(f, 'listAttributeFilter.default.attributeElements', [])); | ||
})); | ||
}; | ||
var isDerived = function isDerived(measure) { | ||
var type = (0, _lodash.get)(measure, 'type'); | ||
return type === 'fact' || type === 'attribute' || !allFiltersEmpty(measure); | ||
}; | ||
var getFilterExpression = function getFilterExpression(listAttributeFilter) { | ||
var attributeUri = (0, _lodash.get)(listAttributeFilter, 'listAttributeFilter.attribute'); | ||
var elements = (0, _lodash.get)(listAttributeFilter, 'listAttributeFilter.default.attributeElements', []); | ||
if ((0, _lodash.isEmpty)(elements)) { | ||
return null; | ||
} | ||
var elementsForQuery = (0, _lodash.map)(elements, function (e) { | ||
return '[' + e + ']'; | ||
}); | ||
var negative = (0, _lodash.get)(listAttributeFilter, 'listAttributeFilter.default.negativeSelection') ? 'NOT ' : ''; | ||
return '[' + attributeUri + '] ' + negative + 'IN (' + elementsForQuery.join(',') + ')'; | ||
}; | ||
var getGeneratedMetricExpression = function getGeneratedMetricExpression(item) { | ||
var aggregation = (0, _lodash.get)(item, 'aggregation', '').toUpperCase(); | ||
var objectUri = (0, _lodash.get)(item, 'objectUri'); | ||
var where = (0, _lodash.filter)((0, _lodash.map)((0, _lodash.get)(item, 'measureFilters'), getFilterExpression), function (e) { | ||
return !!e; | ||
}); | ||
return 'SELECT ' + (aggregation ? aggregation + '([' + objectUri + '])' : '[' + objectUri + ']') + (notEmpty(where) ? ' WHERE ' + where.join(' AND ') : ''); | ||
}; | ||
var getPercentMetricExpression = function getPercentMetricExpression(_ref2, measure) { | ||
var category = _ref2.category; | ||
var metricExpressionWithoutFilters = 'SELECT [' + (0, _lodash.get)(measure, 'objectUri') + ']'; | ||
if (isDerived(measure)) { | ||
metricExpressionWithoutFilters = getGeneratedMetricExpression((0, _lodash.omit)(measure, 'measureFilters')); | ||
} | ||
var attributeUri = (0, _lodash.get)(category, 'attribute'); | ||
var whereFilters = (0, _lodash.filter)((0, _lodash.map)((0, _lodash.get)(measure, 'measureFilters'), getFilterExpression), function (e) { | ||
return !!e; | ||
}); | ||
var whereExpression = notEmpty(whereFilters) ? ' WHERE ' + whereFilters.join(' AND ') : ''; | ||
return 'SELECT (' + metricExpressionWithoutFilters + whereExpression + ') / (' + metricExpressionWithoutFilters + ' BY ALL [' + attributeUri + ']' + whereExpression + ')'; | ||
}; | ||
var getPoPExpression = function getPoPExpression(attribute, metricExpression) { | ||
var attributeUri = (0, _lodash.get)(attribute, 'attribute'); | ||
return 'SELECT ' + metricExpression + ' FOR PREVIOUS ([' + attributeUri + '])'; | ||
}; | ||
var getGeneratedMetricHash = function getGeneratedMetricHash(title, format, expression) { | ||
return (0, _md2.default)(expression + '#' + title + '#' + format); | ||
}; | ||
var getGeneratedMetricIdentifier = function getGeneratedMetricIdentifier(item, aggregation, expressionCreator, hasher) { | ||
var _get$split = (0, _lodash.get)(item, 'objectUri').split('/'), | ||
_get$split2 = _slicedToArray(_get$split, 6), | ||
prjId = _get$split2[3], | ||
id = _get$split2[5]; | ||
var identifier = prjId + '_' + id; | ||
var hash = hasher(expressionCreator(item)); | ||
var hasNoFilters = (0, _lodash.isEmpty)((0, _lodash.get)(item, 'measureFilters', [])); | ||
var type = (0, _lodash.get)(item, 'type'); | ||
var prefix = hasNoFilters || allFiltersEmpty(item) ? '' : '_filtered'; | ||
return type + '_' + identifier + '.generated.' + hash + prefix + '_' + aggregation; | ||
}; | ||
var isDateCategory = function isDateCategory(_ref3) { | ||
var category = _ref3.category; | ||
return category.type === 'date'; | ||
}; | ||
var isDateFilter = function isDateFilter(_ref4) { | ||
var dateFilter = _ref4.dateFilter; | ||
return dateFilter; | ||
}; | ||
var getCategories = function getCategories(_ref5) { | ||
var categories = _ref5.categories; | ||
return categories; | ||
}; | ||
var getFilters = function getFilters(_ref6) { | ||
var filters = _ref6.filters; | ||
return filters; | ||
}; | ||
var getDateCategory = function getDateCategory(mdObj) { | ||
var category = (0, _lodash.find)(getCategories(mdObj), isDateCategory); | ||
return (0, _lodash.get)(category, 'category'); | ||
}; | ||
var getDateFilter = function getDateFilter(mdObj) { | ||
var dateFilter = (0, _lodash.find)(getFilters(mdObj), isDateFilter); | ||
return (0, _lodash.get)(dateFilter, 'dateFilter'); | ||
}; | ||
var getDate = function getDate(mdObj) { | ||
return getDateCategory(mdObj) || getDateFilter(mdObj); | ||
}; | ||
var getMetricSort = function getMetricSort(sort, isPoPMetric) { | ||
if ((0, _lodash.isString)(sort)) { | ||
// TODO: backward compatibility, remove when not used plain "sort: asc | desc" in measures | ||
return sort; | ||
} | ||
var sortByPoP = (0, _lodash.get)(sort, 'sortByPoP'); | ||
if (isPoPMetric && sortByPoP || !isPoPMetric && !sortByPoP) { | ||
return (0, _lodash.get)(sort, 'direction'); | ||
} | ||
return null; | ||
}; | ||
var createPureMetric = function createPureMetric(measure, mdObj, measureIndex) { | ||
return { | ||
element: (0, _lodash.get)(measure, 'objectUri'), | ||
sort: getMetricSort((0, _lodash.get)(measure, 'sort')), | ||
meta: { measureIndex: measureIndex } | ||
}; | ||
}; | ||
var createDerivedMetric = function createDerivedMetric(measure, mdObj, measureIndex) { | ||
var format = measure.format, | ||
sort = measure.sort; | ||
var title = getBaseMetricTitle(measure.title); | ||
var hasher = (0, _lodash.partial)(getGeneratedMetricHash, title, format); | ||
var aggregation = (0, _lodash.get)(measure, 'aggregation', 'base').toLowerCase(); | ||
var element = getGeneratedMetricIdentifier(measure, aggregation, getGeneratedMetricExpression, hasher); | ||
var definition = { | ||
metricDefinition: { | ||
identifier: element, | ||
expression: getGeneratedMetricExpression(measure), | ||
title: title, | ||
format: format | ||
} | ||
}; | ||
return { | ||
element: element, | ||
definition: definition, | ||
sort: getMetricSort(sort), | ||
meta: { | ||
measureIndex: measureIndex | ||
} | ||
}; | ||
}; | ||
var createContributionMetric = function createContributionMetric(measure, mdObj, measureIndex) { | ||
var category = (0, _lodash.first)(getCategories(mdObj)); | ||
var getMetricExpression = (0, _lodash.partial)(getPercentMetricExpression, category); | ||
var title = getBaseMetricTitle((0, _lodash.get)(measure, 'title')); | ||
var hasher = (0, _lodash.partial)(getGeneratedMetricHash, title, CONTRIBUTION_METRIC_FORMAT); | ||
return { | ||
element: getGeneratedMetricIdentifier(measure, 'percent', getMetricExpression, hasher), | ||
definition: { | ||
metricDefinition: { | ||
identifier: getGeneratedMetricIdentifier(measure, 'percent', getMetricExpression, hasher), | ||
expression: getMetricExpression(measure), | ||
title: title, | ||
format: CONTRIBUTION_METRIC_FORMAT | ||
} | ||
}, | ||
sort: getMetricSort((0, _lodash.get)(measure, 'sort')), | ||
meta: { | ||
measureIndex: measureIndex | ||
} | ||
}; | ||
}; | ||
var createPoPMetric = function createPoPMetric(measure, mdObj, measureIndex) { | ||
var title = getPoPMetricTitle((0, _lodash.get)(measure, 'title')); | ||
var format = (0, _lodash.get)(measure, 'format'); | ||
var hasher = (0, _lodash.partial)(getGeneratedMetricHash, title, format); | ||
var date = getDate(mdObj); | ||
var generated = void 0; | ||
var getMetricExpression = (0, _lodash.partial)(getPoPExpression, date, '[' + (0, _lodash.get)(measure, 'objectUri') + ']'); | ||
if (isDerived(measure)) { | ||
generated = createDerivedMetric(measure, mdObj, measureIndex); | ||
getMetricExpression = (0, _lodash.partial)(getPoPExpression, date, '(' + (0, _lodash.get)(generated, 'definition.metricDefinition.expression') + ')'); | ||
} | ||
var identifier = getGeneratedMetricIdentifier(measure, 'pop', getMetricExpression, hasher); | ||
var result = [{ | ||
element: identifier, | ||
definition: { | ||
metricDefinition: { | ||
identifier: identifier, | ||
expression: getMetricExpression(), | ||
title: title, | ||
format: format | ||
} | ||
}, | ||
sort: getMetricSort((0, _lodash.get)(measure, 'sort'), true), | ||
meta: { | ||
measureIndex: measureIndex, | ||
isPoP: true | ||
} | ||
}]; | ||
if (generated) { | ||
result.push(generated); | ||
} else { | ||
result.push(createPureMetric(measure, mdObj, measureIndex)); | ||
} | ||
return result; | ||
}; | ||
var createContributionPoPMetric = function createContributionPoPMetric(measure, mdObj, measureIndex) { | ||
var date = getDate(mdObj); | ||
var generated = createContributionMetric(measure, mdObj, measureIndex); | ||
var title = getPoPMetricTitle((0, _lodash.get)(measure, 'title')); | ||
var format = CONTRIBUTION_METRIC_FORMAT; | ||
var hasher = (0, _lodash.partial)(getGeneratedMetricHash, title, format); | ||
var getMetricExpression = (0, _lodash.partial)(getPoPExpression, date, '(' + (0, _lodash.get)(generated, 'definition.metricDefinition.expression') + ')'); | ||
var identifier = getGeneratedMetricIdentifier(measure, 'pop', getMetricExpression, hasher); | ||
var result = [{ | ||
element: identifier, | ||
definition: { | ||
metricDefinition: { | ||
identifier: identifier, | ||
expression: getMetricExpression(), | ||
title: title, | ||
format: format | ||
} | ||
}, | ||
sort: getMetricSort((0, _lodash.get)(measure, 'sort'), true), | ||
meta: { | ||
measureIndex: measureIndex, | ||
isPoP: true | ||
} | ||
}]; | ||
result.push(generated); | ||
return result; | ||
}; | ||
var categoryToElement = function categoryToElement(_ref7) { | ||
var category = _ref7.category; | ||
return { element: (0, _lodash.get)(category, 'displayForm'), sort: (0, _lodash.get)(category, 'sort') }; | ||
}; | ||
var attributeFilterToWhere = function attributeFilterToWhere(f) { | ||
var elements = (0, _lodash.get)(f, 'listAttributeFilter.default.attributeElements', []); | ||
var elementsForQuery = (0, _lodash.map)(elements, function (e) { | ||
return { id: (0, _lodash.last)(e.split('=')) }; | ||
}); | ||
var dfUri = (0, _lodash.get)(f, 'listAttributeFilter.displayForm'); | ||
var negative = (0, _lodash.get)(f, 'listAttributeFilter.default.negativeSelection'); | ||
return negative ? _defineProperty({}, dfUri, { $not: { $in: elementsForQuery } }) : _defineProperty({}, dfUri, { $in: elementsForQuery }); | ||
}; | ||
var getFromFilter = function getFromFilter(f, property) { | ||
return (0, _lodash.get)(f, 'dateFilter.' + property); | ||
}; | ||
var toInteger = function toInteger(value) { | ||
return parseInt(value, 10); | ||
}; | ||
var dateFilterToWhere = function dateFilterToWhere(f) { | ||
var dateUri = getFromFilter(f, 'dimension') || getFromFilter(f, 'dataSet') || getFromFilter(f, 'dataset'); // dataset with lowercase 's' is deprecated; kept here for backwards compatibility | ||
var granularity = getFromFilter(f, 'granularity'); | ||
var isRelative = getFromFilter(f, 'type') === 'relative'; | ||
var filterFrom = getFromFilter(f, 'from'); | ||
var filterTo = getFromFilter(f, 'to'); | ||
var from = isRelative ? toInteger(filterFrom) : filterFrom; | ||
var to = isRelative ? toInteger(filterTo) : filterTo; | ||
var between = [from, to]; | ||
return _defineProperty({}, dateUri, { $between: between, $granularity: granularity }); | ||
}; | ||
var isPoP = function isPoP(_ref11) { | ||
var showPoP = _ref11.showPoP; | ||
return showPoP; | ||
}; | ||
var isContribution = function isContribution(_ref12) { | ||
var showInPercent = _ref12.showInPercent; | ||
return showInPercent; | ||
}; | ||
var isCalculatedMeasure = function isCalculatedMeasure(_ref13) { | ||
var type = _ref13.type; | ||
return type === 'metric'; | ||
}; | ||
var rules = new _rules2.default(); | ||
rules.addRule([isPoP, isContribution], createContributionPoPMetric); | ||
rules.addRule([isPoP], createPoPMetric); | ||
rules.addRule([isContribution], createContributionMetric); | ||
rules.addRule([isDerived], createDerivedMetric); | ||
rules.addRule([isCalculatedMeasure], createPureMetric); | ||
function getMetricFactory(measure) { | ||
var factory = rules.match(measure); | ||
(0, _invariant2.default)(factory, 'Unknown factory for: ' + measure); | ||
return factory; | ||
} | ||
var isDateFilterExecutable = function isDateFilterExecutable(dateFilter) { | ||
return (0, _lodash.get)(dateFilter, 'from') !== undefined && (0, _lodash.get)(dateFilter, 'to') !== undefined; | ||
}; | ||
var isAttributeFilterExecutable = function isAttributeFilterExecutable(listAttributeFilter) { | ||
return notEmpty((0, _lodash.get)(listAttributeFilter, ['default', 'attributeElements'])); | ||
}; | ||
function getWhere(filters) { | ||
var executableFilters = (0, _lodash.filter)(filters, function (_ref14) { | ||
var listAttributeFilter = _ref14.listAttributeFilter; | ||
return isAttributeFilterExecutable(listAttributeFilter); | ||
}); | ||
var attributeFilters = (0, _lodash.map)(executableFilters, attributeFilterToWhere); | ||
var dateFilters = (0, _lodash.map)((0, _lodash.filter)(filters, function (_ref15) { | ||
var dateFilter = _ref15.dateFilter; | ||
return isDateFilterExecutable(dateFilter); | ||
}), dateFilterToWhere); | ||
var resultDate = [].concat(_toConsumableArray(dateFilters)).reduce(_lodash.assign, {}); | ||
var resultAttribute = { | ||
$and: attributeFilters | ||
}; | ||
return _extends({}, resultDate, resultAttribute); | ||
} | ||
var sortToOrderBy = function sortToOrderBy(item) { | ||
return { column: (0, _lodash.get)(item, 'element'), direction: (0, _lodash.get)(item, 'sort') }; | ||
}; | ||
var getOrderBy = function getOrderBy(metrics, categories, type) { | ||
// For bar chart we always override sorting to sort by values (first metric) | ||
if (type === 'bar' && notEmpty(metrics)) { | ||
return [{ | ||
column: (0, _lodash.first)((0, _lodash.compact)((0, _lodash.map)(metrics, 'element'))), | ||
direction: 'desc' | ||
}]; | ||
} | ||
return (0, _lodash.map)((0, _lodash.filter)([].concat(_toConsumableArray(categories), _toConsumableArray(metrics)), function (item) { | ||
return item.sort; | ||
}), sortToOrderBy); | ||
}; | ||
var mdToExecutionConfiguration = exports.mdToExecutionConfiguration = function mdToExecutionConfiguration(mdObj) { | ||
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}; | ||
var buckets = (0, _lodash.get)(mdObj, 'buckets'); | ||
var measures = (0, _lodash.map)(buckets.measures, function (_ref16) { | ||
var measure = _ref16.measure; | ||
return measure; | ||
}); | ||
var metrics = (0, _lodash.flatten)((0, _lodash.map)(measures, function (measure, index) { | ||
return getMetricFactory(measure)(measure, buckets, index); | ||
})); | ||
var categories = getCategories(buckets); | ||
var filters = getFilters(buckets); | ||
if (options.removeDateItems) { | ||
categories = (0, _lodash.filter)(categories, function (_ref17) { | ||
var category = _ref17.category; | ||
return category.type !== 'date'; | ||
}); | ||
filters = (0, _lodash.filter)(filters, function (item) { | ||
return !item.dateFilter; | ||
}); | ||
} | ||
categories = (0, _lodash.map)(categories, categoryToElement); | ||
var columns = (0, _lodash.compact)((0, _lodash.map)([].concat(_toConsumableArray(categories), _toConsumableArray(metrics)), 'element')); | ||
return { | ||
columns: columns, | ||
orderBy: getOrderBy(metrics, categories, (0, _lodash.get)(mdObj, 'type')), | ||
definitions: (0, _definitions.sortDefinitions)((0, _lodash.compact)((0, _lodash.map)(metrics, 'definition'))), | ||
where: columns.length ? getWhere(filters) : {}, | ||
metricMappings: (0, _lodash.map)(metrics, function (m) { | ||
return _extends({ element: m.element }, m.meta); | ||
}) | ||
}; | ||
}; | ||
var getOriginalMetricFormats = function getOriginalMetricFormats(mdObj) { | ||
// for metrics with showPoP or measureFilters.length > 0 roundtrip for original metric format | ||
return Promise.all((0, _lodash.map)((0, _lodash.map)((0, _lodash.get)(mdObj, 'buckets.measures'), function (_ref18) { | ||
var measure = _ref18.measure; | ||
return measure; | ||
}), function (measure) { | ||
if (measure.showPoP === true || measure.measureFilters.length > 0) { | ||
return (0, _xhr.get)(measure.objectUri).then(function (obj) { | ||
return _extends({}, measure, { | ||
format: (0, _lodash.get)(obj, 'metric.content.format', measure.format) | ||
}); | ||
}); | ||
} | ||
return Promise.resolve(measure); | ||
})); | ||
}; | ||
var getDataForVis = function getDataForVis(projectId, mdObj, settings) { | ||
return getOriginalMetricFormats(mdObj).then(function (measures) { | ||
var metadata = mdObj; | ||
metadata.buckets.measures = (0, _lodash.map)(measures, function (measure) { | ||
return { measure: measure }; | ||
}); | ||
var _mdToExecutionConfigu = mdToExecutionConfiguration(mdObj), | ||
columns = _mdToExecutionConfigu.columns, | ||
executionConfiguration = _objectWithoutProperties(_mdToExecutionConfigu, ['columns']); | ||
return getData(projectId, columns, executionConfiguration, settings); | ||
}); | ||
}; | ||
exports.getDataForVis = getDataForVis; | ||
// Copyright (C) 2007-2017, GoodData(R) Corporation. All rights reserved. | ||
exports.default = { | ||
getData: _experimentalExecutions.getData, | ||
getDataForVis: _experimentalExecutions.getDataForVis, | ||
executeAfm: _executeAfm2.default | ||
}; |
@@ -21,3 +21,3 @@ 'use strict'; | ||
var execution = _interopRequireWildcard(_execution); | ||
var _execution2 = _interopRequireDefault(_execution); | ||
@@ -62,5 +62,5 @@ var _project = require('./project'); | ||
// Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. | ||
var gooddata = { config: config, xhr: xhr, user: user, md: md, execution: execution, project: project, catalogue: catalogue, admin: _admin2.default }; | ||
var gooddata = { config: config, xhr: xhr, user: user, md: md, execution: _execution2.default, project: project, catalogue: catalogue, admin: _admin2.default }; | ||
exports.default = gooddata; | ||
module.exports = gooddata; |
@@ -109,5 +109,7 @@ 'use strict'; | ||
return (0, _xhr.get)(uri).then(function (r) { | ||
items.push.apply(items, _toConsumableArray(r.objects.items)); | ||
var nextUri = r.objects.paging.next; | ||
return (0, _xhr.get)(uri).then(function (_ref) { | ||
var objects = _ref.objects; | ||
items.push.apply(items, _toConsumableArray(objects.items)); | ||
var nextUri = objects.paging.next; | ||
return nextUri ? getOnePage(nextUri, items) : items; | ||
@@ -275,7 +277,7 @@ }); | ||
default: | ||
return Promise.all([getFolderEntries(projectId, 'fact'), getFolderEntries(projectId, 'metric'), getDimensions(projectId)]).then(function (_ref) { | ||
var _ref2 = _slicedToArray(_ref, 3), | ||
facts = _ref2[0], | ||
metrics = _ref2[1], | ||
attributes = _ref2[2]; | ||
return Promise.all([getFolderEntries(projectId, 'fact'), getFolderEntries(projectId, 'metric'), getDimensions(projectId)]).then(function (_ref2) { | ||
var _ref3 = _slicedToArray(_ref2, 3), | ||
facts = _ref3[0], | ||
metrics = _ref3[1], | ||
attributes = _ref3[2]; | ||
@@ -282,0 +284,0 @@ return { fact: facts, metric: metrics, attribute: attributes }; |
@@ -205,3 +205,3 @@ 'use strict'; | ||
// If response.status id 401 and it was a login request there is no need | ||
// to cycle back for token - login does not need token and this meand you | ||
// to cycle back for token - login does not need token and this meant you | ||
// are not authorized | ||
@@ -208,0 +208,0 @@ if (response.status === 401) { |
{ | ||
"name": "gooddata", | ||
"version": "4.3.1", | ||
"version": "4.4.0", | ||
"author": "GoodData", | ||
@@ -66,2 +66,3 @@ "description": "GoodData JavaScript SDK", | ||
"dependencies": { | ||
"@gooddata/typings": "0.0.3", | ||
"es6-promise": "3.0.2", | ||
@@ -72,4 +73,5 @@ "fetch-cookie": "0.4.0", | ||
"lodash": "4.17.4", | ||
"md5": "2.2.1" | ||
"md5": "2.2.1", | ||
"qs": "6.5.1" | ||
} | ||
} |
import { get, find, omit, cloneDeep } from 'lodash'; | ||
import { post, parseJSON } from './xhr'; | ||
import { mdToExecutionConfiguration } from './execution'; | ||
import { mdToExecutionConfiguration } from './execution/experimental-executions'; | ||
@@ -5,0 +5,0 @@ const REQUEST_DEFAULTS = { |
@@ -1,588 +0,16 @@ | ||
// Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. | ||
import md5 from 'md5'; | ||
import invariant from 'invariant'; | ||
import { | ||
compact, | ||
filter, | ||
first, | ||
find, | ||
map, | ||
merge, | ||
every, | ||
get, | ||
isEmpty, | ||
isString, | ||
negate, | ||
last, | ||
assign, | ||
partial, | ||
flatten, | ||
omit | ||
} from 'lodash'; | ||
// Copyright (C) 2007-2017, GoodData(R) Corporation. All rights reserved. | ||
import { getData, getDataForVis } from './execution/experimental-executions'; | ||
import executeAfm from './execution/execute-afm'; | ||
import { | ||
ajax, | ||
post, | ||
get as xhrGet, | ||
parseJSON | ||
} from './xhr'; | ||
import Rules from './utils/rules'; | ||
import { sortDefinitions } from './utils/definitions'; | ||
const notEmpty = negate(isEmpty); | ||
const findHeaderForMappingFn = (mapping, header) => | ||
((mapping.element === header.id || mapping.element === header.uri) && | ||
header.measureIndex === undefined); | ||
const wrapMeasureIndexesFromMappings = (metricMappings, headers) => { | ||
if (metricMappings) { | ||
metricMappings.forEach((mapping) => { | ||
const header = find(headers, partial(findHeaderForMappingFn, mapping)); | ||
if (header) { | ||
header.measureIndex = mapping.measureIndex; | ||
header.isPoP = mapping.isPoP; | ||
} | ||
}); | ||
} | ||
return headers; | ||
}; | ||
const emptyResult = { | ||
extendedTabularDataResult: { | ||
values: [], | ||
warnings: [] | ||
} | ||
}; | ||
function loadExtendedDataResults(uri, settings, prevResult = emptyResult) { | ||
return new Promise((resolve, reject) => { | ||
ajax(uri, settings) | ||
.then((r) => { | ||
if (r.status === 204) { | ||
return { | ||
status: r.status, | ||
result: '' | ||
}; | ||
} | ||
return r.json().then((result) => { | ||
return { | ||
status: r.status, | ||
result | ||
}; | ||
}); | ||
}) | ||
.then(({ status, result }) => { | ||
const values = [ | ||
...get(prevResult, 'extendedTabularDataResult.values', []), | ||
...get(result, 'extendedTabularDataResult.values', []) | ||
]; | ||
const warnings = [ | ||
...get(prevResult, 'extendedTabularDataResult.warnings', []), | ||
...get(result, 'extendedTabularDataResult.warnings', []) | ||
]; | ||
const updatedResult = merge({}, prevResult, { | ||
extendedTabularDataResult: { | ||
values, | ||
warnings | ||
} | ||
}); | ||
const nextUri = get(result, 'extendedTabularDataResult.paging.next'); | ||
if (nextUri) { | ||
resolve(loadExtendedDataResults(nextUri, settings, updatedResult)); | ||
} else { | ||
resolve({ status, result: updatedResult }); | ||
} | ||
}, reject); | ||
}); | ||
} | ||
/** | ||
* Module for execution on experimental execution resource | ||
* Execution endpoints | ||
* | ||
* @module execution | ||
* @class execution | ||
* @module execution | ||
*/ | ||
/** | ||
* 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. | ||
*/ | ||
export function getData(projectId, columns, executionConfiguration = {}, settings = {}) { | ||
const executedReport = { | ||
isLoaded: false | ||
}; | ||
// Create request and result structures | ||
const request = { | ||
execution: { columns } | ||
}; | ||
// enrich configuration with supported properties such as | ||
// where clause with query-like filters | ||
['where', 'orderBy', 'definitions'].forEach((property) => { | ||
if (executionConfiguration[property]) { | ||
request.execution[property] = executionConfiguration[property]; | ||
} | ||
}); | ||
// Execute request | ||
return post(`/gdc/internal/projects/${projectId}/experimental/executions`, { | ||
...settings, | ||
body: JSON.stringify(request) | ||
}) | ||
.then(parseJSON) | ||
.then((result) => { | ||
executedReport.headers = wrapMeasureIndexesFromMappings( | ||
get(executionConfiguration, 'metricMappings'), result.executionResult.headers); | ||
// Start polling on url returned in the executionResult for tabularData | ||
return loadExtendedDataResults(result.executionResult.extendedTabularDataResult, settings); | ||
}) | ||
.then((r) => { | ||
const { result, status } = r; | ||
return Object.assign({}, executedReport, { | ||
rawData: get(result, 'extendedTabularDataResult.values', []), | ||
warnings: get(result, 'extendedTabularDataResult.warnings', []), | ||
isLoaded: true, | ||
isEmpty: status === 204 | ||
}); | ||
}); | ||
} | ||
const MAX_TITLE_LENGTH = 1000; | ||
const getMetricTitle = (suffix, title) => { | ||
const maxLength = MAX_TITLE_LENGTH - suffix.length; | ||
if (title && title.length > maxLength) { | ||
if (title[title.length - 1] === ')') { | ||
return `${title.substring(0, maxLength - 2)}…)${suffix}`; | ||
} | ||
return `${title.substring(0, maxLength - 1)}…${suffix}`; | ||
} | ||
return `${title}${suffix}`; | ||
export default { | ||
getData, | ||
getDataForVis, | ||
executeAfm | ||
}; | ||
const getBaseMetricTitle = partial(getMetricTitle, ''); | ||
const POP_SUFFIX = ' - previous year'; | ||
const getPoPMetricTitle = partial(getMetricTitle, POP_SUFFIX); | ||
const CONTRIBUTION_METRIC_FORMAT = '#,##0.00%'; | ||
const allFiltersEmpty = item => every(map( | ||
get(item, 'measureFilters', []), | ||
f => isEmpty(get(f, 'listAttributeFilter.default.attributeElements', [])) | ||
)); | ||
const isDerived = (measure) => { | ||
const type = get(measure, 'type'); | ||
return (type === 'fact' || type === 'attribute' || !allFiltersEmpty(measure)); | ||
}; | ||
const getFilterExpression = (listAttributeFilter) => { | ||
const attributeUri = get(listAttributeFilter, 'listAttributeFilter.attribute'); | ||
const elements = get(listAttributeFilter, 'listAttributeFilter.default.attributeElements', []); | ||
if (isEmpty(elements)) { | ||
return null; | ||
} | ||
const elementsForQuery = map(elements, e => `[${e}]`); | ||
const negative = get(listAttributeFilter, 'listAttributeFilter.default.negativeSelection') ? 'NOT ' : ''; | ||
return `[${attributeUri}] ${negative}IN (${elementsForQuery.join(',')})`; | ||
}; | ||
const getGeneratedMetricExpression = (item) => { | ||
const aggregation = get(item, 'aggregation', '').toUpperCase(); | ||
const objectUri = get(item, 'objectUri'); | ||
const where = filter(map(get(item, 'measureFilters'), getFilterExpression), e => !!e); | ||
return `SELECT ${aggregation ? `${aggregation}([${objectUri}])` : `[${objectUri}]` | ||
}${notEmpty(where) ? ` WHERE ${where.join(' AND ')}` : ''}`; | ||
}; | ||
const getPercentMetricExpression = ({ category }, measure) => { | ||
let metricExpressionWithoutFilters = `SELECT [${get(measure, 'objectUri')}]`; | ||
if (isDerived(measure)) { | ||
metricExpressionWithoutFilters = getGeneratedMetricExpression(omit(measure, 'measureFilters')); | ||
} | ||
const attributeUri = get(category, 'attribute'); | ||
const whereFilters = filter(map(get(measure, 'measureFilters'), getFilterExpression), e => !!e); | ||
const whereExpression = notEmpty(whereFilters) ? ` WHERE ${whereFilters.join(' AND ')}` : ''; | ||
return `SELECT (${metricExpressionWithoutFilters}${whereExpression}) / (${metricExpressionWithoutFilters} BY ALL [${attributeUri}]${whereExpression})`; | ||
}; | ||
const getPoPExpression = (attribute, metricExpression) => { | ||
const attributeUri = get(attribute, 'attribute'); | ||
return `SELECT ${metricExpression} FOR PREVIOUS ([${attributeUri}])`; | ||
}; | ||
const getGeneratedMetricHash = (title, format, expression) => md5(`${expression}#${title}#${format}`); | ||
const getGeneratedMetricIdentifier = (item, aggregation, expressionCreator, hasher) => { | ||
const [, , , prjId, , id] = get(item, 'objectUri').split('/'); | ||
const identifier = `${prjId}_${id}`; | ||
const hash = hasher(expressionCreator(item)); | ||
const hasNoFilters = isEmpty(get(item, 'measureFilters', [])); | ||
const type = get(item, 'type'); | ||
const prefix = (hasNoFilters || allFiltersEmpty(item)) ? '' : '_filtered'; | ||
return `${type}_${identifier}.generated.${hash}${prefix}_${aggregation}`; | ||
}; | ||
const isDateCategory = ({ category }) => category.type === 'date'; | ||
const isDateFilter = ({ dateFilter }) => dateFilter; | ||
const getCategories = ({ categories }) => categories; | ||
const getFilters = ({ filters }) => filters; | ||
const getDateCategory = (mdObj) => { | ||
const category = find(getCategories(mdObj), isDateCategory); | ||
return get(category, 'category'); | ||
}; | ||
const getDateFilter = (mdObj) => { | ||
const dateFilter = find(getFilters(mdObj), isDateFilter); | ||
return get(dateFilter, 'dateFilter'); | ||
}; | ||
const getDate = mdObj => (getDateCategory(mdObj) || getDateFilter(mdObj)); | ||
const getMetricSort = (sort, isPoPMetric) => { | ||
if (isString(sort)) { | ||
// TODO: backward compatibility, remove when not used plain "sort: asc | desc" in measures | ||
return sort; | ||
} | ||
const sortByPoP = get(sort, 'sortByPoP'); | ||
if ((isPoPMetric && sortByPoP) || (!isPoPMetric && !sortByPoP)) { | ||
return get(sort, 'direction'); | ||
} | ||
return null; | ||
}; | ||
const createPureMetric = (measure, mdObj, measureIndex) => ({ | ||
element: get(measure, 'objectUri'), | ||
sort: getMetricSort(get(measure, 'sort')), | ||
meta: { measureIndex } | ||
}); | ||
const createDerivedMetric = (measure, mdObj, measureIndex) => { | ||
const { format, sort } = measure; | ||
const title = getBaseMetricTitle(measure.title); | ||
const hasher = partial(getGeneratedMetricHash, title, format); | ||
const aggregation = get(measure, 'aggregation', 'base').toLowerCase(); | ||
const element = getGeneratedMetricIdentifier(measure, aggregation, getGeneratedMetricExpression, hasher); | ||
const definition = { | ||
metricDefinition: { | ||
identifier: element, | ||
expression: getGeneratedMetricExpression(measure), | ||
title, | ||
format | ||
} | ||
}; | ||
return { | ||
element, | ||
definition, | ||
sort: getMetricSort(sort), | ||
meta: { | ||
measureIndex | ||
} | ||
}; | ||
}; | ||
const createContributionMetric = (measure, mdObj, measureIndex) => { | ||
const category = first(getCategories(mdObj)); | ||
const getMetricExpression = partial(getPercentMetricExpression, category); | ||
const title = getBaseMetricTitle(get(measure, 'title')); | ||
const hasher = partial(getGeneratedMetricHash, title, CONTRIBUTION_METRIC_FORMAT); | ||
return { | ||
element: getGeneratedMetricIdentifier(measure, 'percent', getMetricExpression, hasher), | ||
definition: { | ||
metricDefinition: { | ||
identifier: getGeneratedMetricIdentifier(measure, 'percent', getMetricExpression, hasher), | ||
expression: getMetricExpression(measure), | ||
title, | ||
format: CONTRIBUTION_METRIC_FORMAT | ||
} | ||
}, | ||
sort: getMetricSort(get(measure, 'sort')), | ||
meta: { | ||
measureIndex | ||
} | ||
}; | ||
}; | ||
const createPoPMetric = (measure, mdObj, measureIndex) => { | ||
const title = getPoPMetricTitle(get(measure, 'title')); | ||
const format = get(measure, 'format'); | ||
const hasher = partial(getGeneratedMetricHash, title, format); | ||
const date = getDate(mdObj); | ||
let generated; | ||
let getMetricExpression = partial(getPoPExpression, date, `[${get(measure, 'objectUri')}]`); | ||
if (isDerived(measure)) { | ||
generated = createDerivedMetric(measure, mdObj, measureIndex); | ||
getMetricExpression = partial(getPoPExpression, date, `(${get(generated, 'definition.metricDefinition.expression')})`); | ||
} | ||
const identifier = getGeneratedMetricIdentifier(measure, 'pop', getMetricExpression, hasher); | ||
const result = [{ | ||
element: identifier, | ||
definition: { | ||
metricDefinition: { | ||
identifier, | ||
expression: getMetricExpression(), | ||
title, | ||
format | ||
} | ||
}, | ||
sort: getMetricSort(get(measure, 'sort'), true), | ||
meta: { | ||
measureIndex, | ||
isPoP: true | ||
} | ||
}]; | ||
if (generated) { | ||
result.push(generated); | ||
} else { | ||
result.push(createPureMetric(measure, mdObj, measureIndex)); | ||
} | ||
return result; | ||
}; | ||
const createContributionPoPMetric = (measure, mdObj, measureIndex) => { | ||
const date = getDate(mdObj); | ||
const generated = createContributionMetric(measure, mdObj, measureIndex); | ||
const title = getPoPMetricTitle(get(measure, 'title')); | ||
const format = CONTRIBUTION_METRIC_FORMAT; | ||
const hasher = partial(getGeneratedMetricHash, title, format); | ||
const getMetricExpression = partial(getPoPExpression, date, `(${get(generated, 'definition.metricDefinition.expression')})`); | ||
const identifier = getGeneratedMetricIdentifier(measure, 'pop', getMetricExpression, hasher); | ||
const result = [{ | ||
element: identifier, | ||
definition: { | ||
metricDefinition: { | ||
identifier, | ||
expression: getMetricExpression(), | ||
title, | ||
format | ||
} | ||
}, | ||
sort: getMetricSort(get(measure, 'sort'), true), | ||
meta: { | ||
measureIndex, | ||
isPoP: true | ||
} | ||
}]; | ||
result.push(generated); | ||
return result; | ||
}; | ||
const categoryToElement = ({ category }) => | ||
({ element: get(category, 'displayForm'), sort: get(category, 'sort') }); | ||
const attributeFilterToWhere = (f) => { | ||
const elements = get(f, 'listAttributeFilter.default.attributeElements', []); | ||
const elementsForQuery = map(elements, e => ({ id: last(e.split('=')) })); | ||
const dfUri = get(f, 'listAttributeFilter.displayForm'); | ||
const negative = get(f, 'listAttributeFilter.default.negativeSelection'); | ||
return negative ? | ||
{ [dfUri]: { $not: { $in: elementsForQuery } } } : | ||
{ [dfUri]: { $in: elementsForQuery } }; | ||
}; | ||
const getFromFilter = (f, property) => get(f, `dateFilter.${property}`); | ||
const toInteger = value => parseInt(value, 10); | ||
const dateFilterToWhere = (f) => { | ||
const dateUri = | ||
getFromFilter(f, 'dimension') || | ||
getFromFilter(f, 'dataSet') || | ||
getFromFilter(f, 'dataset'); // dataset with lowercase 's' is deprecated; kept here for backwards compatibility | ||
const granularity = getFromFilter(f, 'granularity'); | ||
const isRelative = getFromFilter(f, 'type') === 'relative'; | ||
const filterFrom = getFromFilter(f, 'from'); | ||
const filterTo = getFromFilter(f, 'to'); | ||
const from = isRelative ? toInteger(filterFrom) : filterFrom; | ||
const to = isRelative ? toInteger(filterTo) : filterTo; | ||
const between = [from, to]; | ||
return { [dateUri]: { $between: between, $granularity: granularity } }; | ||
}; | ||
const isPoP = ({ showPoP }) => showPoP; | ||
const isContribution = ({ showInPercent }) => showInPercent; | ||
const isCalculatedMeasure = ({ type }) => type === 'metric'; | ||
const rules = new Rules(); | ||
rules.addRule( | ||
[isPoP, isContribution], | ||
createContributionPoPMetric | ||
); | ||
rules.addRule( | ||
[isPoP], | ||
createPoPMetric | ||
); | ||
rules.addRule( | ||
[isContribution], | ||
createContributionMetric | ||
); | ||
rules.addRule( | ||
[isDerived], | ||
createDerivedMetric | ||
); | ||
rules.addRule( | ||
[isCalculatedMeasure], | ||
createPureMetric | ||
); | ||
function getMetricFactory(measure) { | ||
const factory = rules.match(measure); | ||
invariant(factory, `Unknown factory for: ${measure}`); | ||
return factory; | ||
} | ||
const isDateFilterExecutable = dateFilter => | ||
get(dateFilter, 'from') !== undefined && | ||
get(dateFilter, 'to') !== undefined; | ||
const isAttributeFilterExecutable = listAttributeFilter => | ||
notEmpty(get(listAttributeFilter, ['default', 'attributeElements'])); | ||
function getWhere(filters) { | ||
const executableFilters = filter( | ||
filters, ({ listAttributeFilter }) => isAttributeFilterExecutable(listAttributeFilter) | ||
); | ||
const attributeFilters = map(executableFilters, attributeFilterToWhere); | ||
const dateFilters = map(filter(filters, ({ dateFilter }) => isDateFilterExecutable(dateFilter)), dateFilterToWhere); | ||
const resultDate = [...dateFilters].reduce(assign, {}); | ||
const resultAttribute = { | ||
$and: attributeFilters | ||
}; | ||
return { | ||
...resultDate, | ||
...resultAttribute | ||
}; | ||
} | ||
const sortToOrderBy = item => ({ column: get(item, 'element'), direction: get(item, 'sort') }); | ||
const getOrderBy = (metrics, categories, type) => { | ||
// For bar chart we always override sorting to sort by values (first metric) | ||
if (type === 'bar' && notEmpty(metrics)) { | ||
return [{ | ||
column: first(compact(map(metrics, 'element'))), | ||
direction: 'desc' | ||
}]; | ||
} | ||
return map(filter([...categories, ...metrics], item => item.sort), sortToOrderBy); | ||
}; | ||
export const mdToExecutionConfiguration = (mdObj, options = {}) => { | ||
const buckets = get(mdObj, 'buckets'); | ||
const measures = map(buckets.measures, ({ measure }) => measure); | ||
const metrics = flatten(map(measures, (measure, index) => getMetricFactory(measure)(measure, buckets, index))); | ||
let categories = getCategories(buckets); | ||
let filters = getFilters(buckets); | ||
if (options.removeDateItems) { | ||
categories = filter(categories, ({ category }) => category.type !== 'date'); | ||
filters = filter(filters, item => !item.dateFilter); | ||
} | ||
categories = map(categories, categoryToElement); | ||
const columns = compact(map([...categories, ...metrics], 'element')); | ||
return { | ||
columns, | ||
orderBy: getOrderBy(metrics, categories, get(mdObj, 'type')), | ||
definitions: sortDefinitions(compact(map(metrics, 'definition'))), | ||
where: columns.length ? getWhere(filters) : {}, | ||
metricMappings: map(metrics, m => ({ element: m.element, ...m.meta })) | ||
}; | ||
}; | ||
const getOriginalMetricFormats = (mdObj) => { | ||
// for metrics with showPoP or measureFilters.length > 0 roundtrip for original metric format | ||
return Promise.all(map( | ||
map(get(mdObj, 'buckets.measures'), ({ measure }) => measure), | ||
(measure) => { | ||
if (measure.showPoP === true || measure.measureFilters.length > 0) { | ||
return xhrGet(measure.objectUri).then((obj) => { | ||
return { | ||
...measure, | ||
format: get(obj, 'metric.content.format', measure.format) | ||
}; | ||
}); | ||
} | ||
return Promise.resolve(measure); | ||
} | ||
)); | ||
}; | ||
export const getDataForVis = (projectId, mdObj, settings) => { | ||
return getOriginalMetricFormats(mdObj).then((measures) => { | ||
const metadata = mdObj; | ||
metadata.buckets.measures = map(measures, measure => ({ measure })); | ||
const { columns, ...executionConfiguration } = mdToExecutionConfiguration(mdObj); | ||
return getData(projectId, columns, executionConfiguration, settings); | ||
}); | ||
}; |
@@ -5,3 +5,3 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. | ||
import * as md from './metadata'; | ||
import * as execution from './execution'; | ||
import execution from './execution'; | ||
import * as project from './project'; | ||
@@ -8,0 +8,0 @@ import * as config from './config'; |
@@ -72,5 +72,5 @@ // Copyright (C) 2007-2014, GoodData(R) Corporation. All rights reserved. | ||
return get(uri) | ||
.then((r) => { | ||
items.push(...r.objects.items); | ||
const nextUri = r.objects.paging.next; | ||
.then(({ objects }) => { | ||
items.push(...objects.items); | ||
const nextUri = objects.paging.next; | ||
return nextUri ? getOnePage(nextUri, items) : items; | ||
@@ -77,0 +77,0 @@ }); |
@@ -188,3 +188,3 @@ // Copyright (C) 2007-2013, GoodData(R) Corporation. All rights reserved. | ||
// If response.status id 401 and it was a login request there is no need | ||
// to cycle back for token - login does not need token and this meand you | ||
// to cycle back for token - login does not need token and this meant you | ||
// are not authorized | ||
@@ -191,0 +191,0 @@ if (response.status === 401) { |
Sorry, the diff of this file is too big to display
Sorry, the diff of this file is too big to display
1130695
62
26522
8
+ Added@gooddata/typings@0.0.3
+ Addedqs@6.5.1
+ Added@gooddata/typings@0.0.3(transitive)
+ Addedqs@6.5.1(transitive)