IRUtils.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583
  1. 'use strict';
  2. 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; };
  3. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  4. /*
  5. *+------------------------------------------------------------------------+
  6. *| Licensed Materials - Property of IBM
  7. *| IBM Cognos Products: Dashboard
  8. *| (C) Copyright IBM Corp. 2018, 2019
  9. *|
  10. *| US Government Users Restricted Rights - Use, duplication or disclosure
  11. *| restricted by GSA ADP Schedule Contract with IBM Corp.
  12. *+------------------------------------------------------------------------+
  13. */
  14. define([], function () {
  15. 'use strict';
  16. // widget spec notation => IR spec notation
  17. var FILTER_AGGREGATION_MAP = {
  18. sum: 'SUM'
  19. };
  20. var FILTER_PREPOST_MAP = {
  21. pre: 'PRE',
  22. post: 'POST',
  23. PRE: 'pre',
  24. POST: 'post'
  25. };
  26. /*
  27. * This has utility helpers related to conversion between dashboard 'specs' and IR
  28. */
  29. var IRUtils = function () {
  30. function IRUtils() {
  31. _classCallCheck(this, IRUtils);
  32. }
  33. /**
  34. * find an dataItem entry using provided filter function
  35. * @param {object} spec widget spec
  36. * @param {function} filter
  37. * @return {{viewIndex: number, viewItemIndex: number}}
  38. */
  39. IRUtils.findDataItem = function findDataItem(spec, filter) {
  40. var targetDataViewIndex = -1;
  41. var targetDataViewItemIndex = -1;
  42. for (var dataViewIndex in spec.data.dataViews || []) {
  43. var viewItem = spec.data.dataViews[dataViewIndex];
  44. var dataItems = viewItem.dataItems || [];
  45. for (var dataViewItemIndex in dataItems) {
  46. if (filter(dataItems[dataViewItemIndex], dataViewItemIndex)) {
  47. targetDataViewIndex = dataViewIndex;
  48. targetDataViewItemIndex = dataViewItemIndex;
  49. }
  50. }
  51. }
  52. if (targetDataViewIndex === -1 || targetDataViewItemIndex === -1) {
  53. // nothing found...
  54. return;
  55. }
  56. return {
  57. viewIndex: targetDataViewIndex,
  58. viewItemIndex: targetDataViewItemIndex
  59. };
  60. };
  61. IRUtils.getColumnInfo = function getColumnInfo(currentColumnCombinations, visualization, itemId) {
  62. var columnEntry = currentColumnCombinations.find(function (combination) {
  63. return combination.itemId === itemId;
  64. });
  65. var isProjected = true;
  66. if (!columnEntry) {
  67. isProjected = false;
  68. var metadataColumn = visualization.getDataSource().getMetadataColumn(itemId);
  69. columnEntry = {
  70. id: metadataColumn.getId(),
  71. label: metadataColumn.getLabel()
  72. };
  73. }
  74. return _extends({}, columnEntry, {
  75. isProjected: isProjected
  76. });
  77. };
  78. IRUtils.IRAggregateType = function IRAggregateType(dashboardAggType) {
  79. return {
  80. sum: 'SUM',
  81. countdistinct: 'COUNT_DISTINCT',
  82. count: 'COUNT',
  83. avg: 'AVERAGE',
  84. min: 'MINIMUM',
  85. max: 'MAXIMUM'
  86. }[dashboardAggType];
  87. };
  88. IRUtils.fromIRAggregateType = function fromIRAggregateType(IRAggregateType) {
  89. return {
  90. SUM: 'sum',
  91. COUNT_DISTINCT: 'countdistinct',
  92. COUNT: 'count',
  93. AVERAGE: 'avg',
  94. MINIMUM: 'min',
  95. MAXIMUM: 'max'
  96. }[IRAggregateType];
  97. };
  98. IRUtils.IRTopBottomType = function IRTopBottomType(ty) {
  99. return ty === 'topcount' || ty === 'toppercent' ? 'TOP' : 'BOTTOM';
  100. };
  101. IRUtils.IRTopBottomMethod = function IRTopBottomMethod(ty) {
  102. return ty === 'bottompercent' || ty === 'toppercent' ? 'PERCENTAGE' : 'COUNT'; //?
  103. };
  104. IRUtils.IRToTopBottomType = function IRToTopBottomType(ty, method) {
  105. var _ty = { BOTTOM: 'bottom', TOP: 'top' };
  106. var _suffix = { PERCENTAGE: 'percent', COUNT: 'count' }; //TODO
  107. return _ty[ty] + _suffix[method];
  108. };
  109. /**
  110. * converts dashboard local filters to IR form
  111. * @param {array} filters input dashboard filters
  112. * @param {array} filtersForRequest output IR filters
  113. * @param {visualization} visualization - visualization API
  114. */
  115. IRUtils.localFilters2IRFilters = function localFilters2IRFilters(filters, filtersForRequest, visualization) {
  116. filters.forEach(function (filter) {
  117. var entry = {};
  118. entry.filterId = filter.id;
  119. entry.columnId = filter.columnId;
  120. entry.label = filter.binsLabel;
  121. if (!entry.label && visualization) {
  122. entry.label = visualization.getDataSource().getMetadataColumn(filter.columnId).getLabel();
  123. }
  124. if (filter.operator === 'in' || filter.operator === 'notin') {
  125. var inclusionValues = (filter.values || []).map(function (val) {
  126. return {
  127. uniqueValue: val.u,
  128. displayValue: val.d
  129. };
  130. });
  131. var exclusionValues = (filter.excludedValues || []).map(function (val) {
  132. return {
  133. uniqueValue: val.u,
  134. displayValue: val.d
  135. };
  136. });
  137. if (filter.conditions && (filter.conditions.or || filter.conditions.and)) {
  138. //TODO support for conditions will be added later
  139. //Not supported for now, will revisit this once dashboard filtering issues are resolved
  140. } else if (filter.conditions && filter.conditions.not) {
  141. //TODO support for conditions will be added later
  142. } else if (!filter.conditions) {
  143. entry.type = 'INCLUSION_EXCLUSION';
  144. entry.inclusionValues = inclusionValues;
  145. entry.exclusionValues = exclusionValues;
  146. entry.invertFlag = filter.operator !== 'in';
  147. }
  148. } else if (filter.operator === 'between' || filter.operator === 'notbetween') {
  149. entry.lowValue = {
  150. value: filter.values[0].u,
  151. inclusive: false // TODO
  152. };
  153. entry.highValue = {
  154. value: filter.values[1].u,
  155. inclusive: false // TODO
  156. };
  157. entry.invertFlag = filter.operator === 'notbetween';
  158. entry.type = 'NUMERICRANGE';
  159. entry.filterAggregation = {
  160. aggregationType: FILTER_AGGREGATION_MAP[filter.aggregationType],
  161. preOrPostAggregation: FILTER_PREPOST_MAP[filter.preOrPost]
  162. };
  163. } else {
  164. entry.type = 'GENERIC';
  165. entry.expression = '';
  166. }
  167. if (entry.type) {
  168. filtersForRequest.push(entry);
  169. }
  170. });
  171. };
  172. /**
  173. * converts dashboard topbottom filters to IR form
  174. * @param {array} topBottom input topBottom filters
  175. * @param {array} filtersForRequest output IR filters
  176. */
  177. IRUtils.topBottomToIRFilters = function topBottomToIRFilters(topBottom, filtersForRequest) {
  178. topBottom.forEach(function (tbEntry) {
  179. var entry = {};
  180. entry.filterId = tbEntry.id;
  181. entry.columnId = tbEntry.itemId;
  182. entry.topBottomType = IRUtils.IRTopBottomType(tbEntry.selection.topBottom.type);
  183. entry.method = IRUtils.IRTopBottomMethod(tbEntry.selection.topBottom.type);
  184. entry.domainSize = tbEntry.selection.topBottom.value;
  185. if (tbEntry.selection.context) {
  186. entry.byColumn = tbEntry.selection.context[0].itemId;
  187. }
  188. entry.type = 'TOP_BOTTOM';
  189. filtersForRequest.push(entry);
  190. });
  191. };
  192. /**
  193. * converts IR top bottom filters to dashboard form
  194. * @param {object} irFilter input IR filter
  195. * @param {object} widgetSpec
  196. * @return {object} dataItem with top bottom
  197. *
  198. * example IR top Bottom filter
  199. * {
  200. * "id" : "Movies.Genre",
  201. * "filterId" : "0",
  202. * "topBottomType" : "TOP",
  203. * "method" : "PERCENTAGE",
  204. * "byColumn" : "Movies.Budget",
  205. * "domainSize" : 10,
  206. * "type" : "TOP_BOTTOM"
  207. * }
  208. * example dashboard top bottom filter
  209. * {
  210. * "id":"id643437162",
  211. * "itemId":"HollywoodMovies_csv.Budget",
  212. * "itemLabel":"Budget",
  213. * "selection":[
  214. * {
  215. * "operation":"keep",
  216. * "topBottom":{
  217. * "type":"topcount",
  218. * "value":10
  219. * }
  220. * }
  221. *
  222. */
  223. IRUtils.IRFilters2TopBottom = function IRFilters2TopBottom(irFilter, widgetSpec, currentColumnCombinations, details, visualization) {
  224. if (details.reason === 'RECOMMEND_FILTER') {
  225. details.type = 'PART_TO_WHOLE';
  226. } else if (details.reason === 'INVERT_FILTER') {
  227. details.type = 'INVERT_FILTER_TOP_BOTTOM';
  228. }
  229. var dataItemRef = IRUtils.findDataItem(widgetSpec, function (dataItem) {
  230. return dataItem.id === irFilter.filterId;
  231. });
  232. var itemLabel = void 0;
  233. var selectionAggregate = void 0;
  234. if (dataItemRef) {
  235. var originalDataItem = widgetSpec.data.dataViews[dataItemRef.viewIndex].dataItems[dataItemRef.viewItemIndex];
  236. itemLabel = originalDataItem.itemLabel;
  237. var selection = originalDataItem.selection[0];
  238. // TODO: find a better way
  239. if (selection && selection.context && selection.context[0] && selection.context[0].aggregate) {
  240. selectionAggregate = selection.context[0].aggregate;
  241. }
  242. } else {
  243. var columnIdParts = (irFilter.columnId || '').split('.');
  244. itemLabel = columnIdParts[columnIdParts.length - 1];
  245. }
  246. var dataItem = {};
  247. dataItem.id = irFilter.filterId; //TODO
  248. dataItem.itemId = irFilter.columnId; // irFilter.byColumn ??;
  249. dataItem.itemLabel = itemLabel; //TODO
  250. var columnEntry = IRUtils.getColumnInfo(currentColumnCombinations, visualization, irFilter.columnId);
  251. details.column = columnEntry;
  252. var selectionItem = {
  253. operation: 'keep',
  254. topBottom: {
  255. type: IRUtils.IRToTopBottomType(irFilter.topBottomType, irFilter.method),
  256. value: irFilter.domainSize
  257. }
  258. };
  259. details.info = selectionItem.topBottom;
  260. if (irFilter.byColumn) {
  261. selectionItem.context = [{
  262. aggregate: selectionAggregate,
  263. itemId: irFilter.byColumn
  264. }];
  265. var byColumnEntry = IRUtils.getColumnInfo(currentColumnCombinations, visualization, irFilter.byColumn);
  266. details.byColumn = byColumnEntry;
  267. }
  268. dataItem.selection = [selectionItem];
  269. return dataItem;
  270. };
  271. /**
  272. * converts IR local filters to dashboard form
  273. * @param {object} irFilter input IR filter
  274. * @param {object} widgetSpec
  275. * @return {object} local filter
  276. *
  277. * example IR local filter
  278. * "filters" : [ {
  279. * "id" : "Movies.Budget",
  280. * "filterId" : "0",
  281. * "lowValue" : "5",
  282. * "highValue" : "10",
  283. * "invertFlag" : false,
  284. * "type" : "NUMERIC",
  285. * "numericOperator" : "LESS_THAN"
  286. * }
  287. *
  288. * example dashboard range local filter
  289. * "columnId": "Hollywood_Movies_csv.Budget",
  290. * "values": [
  291. * {
  292. * "d": 3511.265923566879,
  293. * "u": 3511.265923566879
  294. * },
  295. * {
  296. * "d": 12870,
  297. * "u": 12870
  298. * }
  299. * ],
  300. * "excludedValues": [],
  301. * "operator": "notbetween",
  302. * "aggregationType": "sum",
  303. * "preOrPost": "post
  304. *
  305. * example dashboard inclusion/exclusion local filter
  306. * {
  307. * "id": "Hollywood_Movies_csv.Movie_Genre",
  308. * "columnId": "Hollywood_Movies_csv.Movie_Genre",
  309. * "values": [
  310. * {
  311. * "d": "Action",
  312. * "u": "Hollywood_Movies_csv.Movie_Genre->[Action]"
  313. * }
  314. * ],
  315. * "excludedValues": [
  316. * {
  317. * "d": "Biopic",
  318. * "u": "Hollywood_Movies_csv.Movie_Genre->[Biopic]"
  319. * }
  320. * ],
  321. * "conditions": {
  322. * "operator": "containsignorecase",
  323. * "itemId": "Hollywood_Movies_csv.Movie_Genre",
  324. * "ignoreCase": true,
  325. * "values": [
  326. * "Bio"
  327. * ],
  328. * "valueType": "display"
  329. * },
  330. * "operator": "in",
  331. * "type": null,
  332. * "binsLabel": "Movie Genre"
  333. * }
  334. */
  335. IRUtils.IRFilters2LocalFilter = function IRFilters2LocalFilter(irFilter, widgetSpec) {
  336. var currentColumnCombinations = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  337. var details = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : {};
  338. var visualization = arguments[4];
  339. if (details.reason === 'INVERT_FILTER') {
  340. details.type = 'INVERT_FILTER_LOCAL';
  341. }
  342. var filter = {};
  343. filter.id = irFilter.filterId; //TODO
  344. filter.columnId = irFilter.columnId;
  345. var columnEntry = currentColumnCombinations.find(function (combination) {
  346. return combination.itemId === irFilter.columnId;
  347. });
  348. if (columnEntry) {
  349. details.column = {
  350. id: irFilter.columnId,
  351. label: columnEntry.label
  352. };
  353. } else if (visualization) {
  354. details.column = {
  355. id: irFilter.columnId,
  356. label: visualization.getDataSource().getMetadataColumn(irFilter.columnId).getLabel()
  357. };
  358. }
  359. if (irFilter.type === 'NUMERICRANGE') {
  360. if (irFilter.invertFlag) {
  361. filter.operator = 'notbetween';
  362. } else {
  363. filter.operator = 'between';
  364. }
  365. filter.values = [{
  366. d: irFilter.lowValue.value,
  367. u: irFilter.lowValue.value
  368. }, {
  369. d: irFilter.highValue.value,
  370. u: irFilter.highValue.value
  371. }];
  372. // filter.excludedValues = [] ; //TODO
  373. if (irFilter.filterAggregation) {
  374. filter.aggregationType = irFilter.filterAggregation.aggregationType;
  375. filter.preOrPost = FILTER_PREPOST_MAP[irFilter.filterAggregation.preOrPostAggregation];
  376. } else if (widgetSpec) {
  377. var localFilter = widgetSpec.localFilters.find(function (filter) {
  378. return filter.id === irFilter.filterId;
  379. });
  380. filter.aggregationType = localFilter.aggregationType;
  381. filter.preOrPost = localFilter.preOrPost;
  382. }
  383. } else if (irFilter.type === 'COMPOSITE') {
  384. //Not supported for now, will revisit this once dashboard filtering issues are resolved
  385. // const firstCompositeIrFilter = irFilter.filter1;
  386. //
  387. // const isInvert = irFilter.filter1.invertFlag && irFilter.filter1.invertFlag === irFilter.filter2.invertFlag;
  388. // // filter.operator = (isInvert ? 'notin' : 'in');
  389. // filter.operator = 'in';
  390. //
  391. // let valuesToUse, excludedValuesToUse;
  392. // if(!isInvert) {
  393. // valuesToUse = firstCompositeIrFilter.inclusionValues;
  394. // excludedValuesToUse = firstCompositeIrFilter.exclusionValues;
  395. // } else {
  396. // valuesToUse = firstCompositeIrFilter.exclusionValues;
  397. // excludedValuesToUse = firstCompositeIrFilter.inclusionValues;
  398. // }
  399. // filter.values = (valuesToUse || [])
  400. // .map(value => {
  401. // return {
  402. // u: value.uniqueValue,
  403. // d: value.displayValue
  404. // };
  405. // });
  406. //
  407. // filter.excludedValues = (excludedValuesToUse || [] )
  408. // .map(value => {
  409. // return {
  410. // u: value.uniqueValue,
  411. // d: value.displayValue
  412. // };
  413. // });
  414. // filter.binsLabel = firstCompositeIrFilter.label;
  415. // filter.columnId = firstCompositeIrFilter.columnId;
  416. // filter.id = irFilter.filterId;
  417. //
  418. //
  419. // const conditionOperator = irFilter.operator === 'OR' ? 'or': 'and';
  420. // filter.conditions = {};
  421. // filter.conditions[conditionOperator] = [];
  422. //
  423. // const irFiltersToProcess = [ irFilter.filter1, irFilter.filter2 ];
  424. // irFiltersToProcess.forEach( (irSubFilter) => {
  425. // const condition = this._fromIRCompositeFilterToCondition( irSubFilter );
  426. // if( condition ) {
  427. // if( irSubFilter.invertFlag ) {
  428. // filter.conditions[conditionOperator].push( { not: condition } );
  429. // } else {
  430. // filter.conditions[conditionOperator].push(condition);
  431. // }
  432. // }
  433. // } );
  434. } else if (irFilter.type === 'INCLUSION_EXCLUSION' && !irFilter.filterCondition) {
  435. filter.columnId = irFilter.columnId;
  436. filter.id = irFilter.filterId;
  437. filter.operator = irFilter.invertFlag ? 'notin' : 'in';
  438. filter.values = (irFilter.inclusionValues || irFilter.values || []).map(function (value) {
  439. return {
  440. u: value.uniqueValue,
  441. d: value.displayValue
  442. };
  443. });
  444. //TODO support for conditions will be added later
  445. // if( irFilter.filterCondition ) {
  446. // filter.conditions = this._fromIRCompositeFilterToCondition( irFilter );
  447. // }
  448. filter.binsLabel = irFilter.label;
  449. } else if (irFilter.type === 'GENERIC') {
  450. filter.columnId = irFilter.columnId;
  451. filter.id = irFilter.filterId;
  452. }
  453. return filter;
  454. };
  455. //not used for current release, will revisit this in a later change
  456. // _toIRCondition : function (conditions, index) {
  457. // if( !conditions ) {
  458. // return undefined;
  459. // }
  460. // let isInvert = false;
  461. // const op = conditions.or ? 'or' : conditions.and ? 'and': conditions.not ? 'not' : undefined;
  462. //
  463. // let condition = conditions;
  464. // if( op === 'not') {
  465. // isInvert = true;
  466. // condition = conditions.not;
  467. // } else if (op && index !== undefined) {
  468. // condition = conditions[op][index]; //and, or
  469. // if( condition.not) {
  470. // isInvert = true;
  471. // condition = condition.not;
  472. // }
  473. // } else {
  474. // condition = conditions; //simple condition
  475. // }
  476. //
  477. // const conditionMap = {
  478. // 'in': 'EQUALS',
  479. // 'containsignorecase': 'CONTAINS',
  480. // 'beginswith': 'BEGINS_WITH',
  481. // 'endswith': 'ENDS_WITH'
  482. // };
  483. //
  484. // return {
  485. // condition: conditionMap[condition.operator],
  486. // isInclude: !isInvert,
  487. // values: condition.values
  488. // };
  489. // },
  490. //
  491. // _fromIRCompositeFilterToCondition : function (irSubFilter) {
  492. // if( !irSubFilter || irSubFilter && !irSubFilter.filterCondition ) {
  493. // return undefined;
  494. // }
  495. // const conditionMap = {
  496. // 'EQUALS': 'in',
  497. // 'CONTAINS': 'containsignorecase',
  498. // 'BEGINS_WITH': 'beginswith',
  499. // 'ENDS_WITH': 'endswith'
  500. // };
  501. //
  502. // const condition = {
  503. // operator: conditionMap[irSubFilter.filterCondition.condition],
  504. // itemId: irSubFilter.columnId,
  505. // ignoreCase: true,
  506. // values: irSubFilter.filterCondition.values,
  507. // valueType: 'display'
  508. // };
  509. //
  510. // if( irSubFilter.filterCondition.isInclude === false ) {
  511. // return {
  512. // not: condition
  513. // };
  514. // }
  515. // return condition;
  516. // }
  517. return IRUtils;
  518. }();
  519. return IRUtils;
  520. });
  521. //# sourceMappingURL=IRUtils.js.map