CommonQueryBuilder.js 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814
  1. 'use strict';
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. /**
  4. * Licensed Materials - Property of IBM
  5. * IBM Cognos Products: Dashboard
  6. * (C) Copyright IBM Corp. 2017, 2020
  7. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  8. */
  9. define(['underscore', '../../../lib/@waca/dashboard-common/dist/core/UniqueHashIdBuilder', '../../../features/content/dataQueryExecution/DataQueryUtils'], function (_, UniqueHashIdBuilder, DataQueryUtils) {
  10. var QUERY_RESULTS_SIZE_LIMIT = 1000;
  11. // Filter operators constant
  12. var OR = 'or';
  13. var IN = 'in';
  14. var GT = 'gt';
  15. var LT = 'lt';
  16. var BETWEEN = 'between';
  17. var NOTBETWEEN = 'notbetween';
  18. var CONTAINSIGNORECASE = 'containsignorecase';
  19. var ISNULL = 'isnull';
  20. // Filter aggregation type
  21. var PRE = 'pre';
  22. /**
  23. * The singleton class to build the common queryspec shared by visualizations, filters, prompts or other components.
  24. */
  25. var CommonQueryBuilder = function () {
  26. function CommonQueryBuilder() {
  27. _classCallCheck(this, CommonQueryBuilder);
  28. }
  29. /**
  30. * Build single item query spec.
  31. * @param {Object} queryDefinition.column - optional: the column used to build the item query. column is mandatory if dataItems is not provided.
  32. * @param {Object} queryDefinition.dataItems - optional: if the queryDefinition doesn't have column it must provide dataItems.
  33. * @param {Object} queryDefinition.filters - optional: The caller can provide an optional set of filters in querySpec form (as generated by filterEntry.toQuerySpec())
  34. * @param {String} queryContext.searchTerm - optional: the search string used to refine the query result.
  35. */
  36. CommonQueryBuilder.buildSingleItemQuery = function buildSingleItemQuery(queryDefinition, queryContext, logger) {
  37. var oQuerySpec = {};
  38. var aDataItems = CommonQueryBuilder._buildDataItems(queryDefinition, logger, queryContext);
  39. var aProjections = CommonQueryBuilder.buildProjections(queryDefinition, logger);
  40. if (!aDataItems.length || !aProjections.length) {
  41. logger.warn('Could not build singleItemQuery', this);
  42. return oQuerySpec;
  43. }
  44. oQuerySpec.version = '1';
  45. oQuerySpec.dataItems = aDataItems;
  46. oQuerySpec.projections = aProjections;
  47. oQuerySpec.limit = queryDefinition.limit || CommonQueryBuilder.getQueryResultsSizeLimit();
  48. if (queryDefinition.queryHints) {
  49. oQuerySpec.queryHints = queryDefinition.queryHints;
  50. }
  51. if (queryDefinition.parameterValues) {
  52. oQuerySpec.parameterValues = queryDefinition.parameterValues;
  53. }
  54. //Allow the caller to optionally pass in filters in the query Definition.
  55. var filters = queryDefinition.filters || [];
  56. if (!queryContext) {
  57. oQuerySpec.filters = filters;
  58. return oQuerySpec;
  59. }
  60. if (queryContext.pageContext) {
  61. filters = filters.concat(CommonQueryBuilder.buildFilterFromPageContext(queryContext.pageContext));
  62. }
  63. if (queryContext.searchTerm) {
  64. filters = filters.concat(CommonQueryBuilder._buildFilterFromSearchTerm(queryDefinition, queryContext.searchTerm));
  65. }
  66. if (queryContext.filter) {
  67. filters.push(queryContext.filter);
  68. }
  69. oQuerySpec.filters = filters;
  70. return oQuerySpec;
  71. };
  72. /**
  73. * Build minmax query spec from a column.
  74. * @param {Object} queryDefinition.column - mandatory: the column to get the minmax values.
  75. * @example of querySpec returned by this function:
  76. * {
  77. * 'version': '1',
  78. * 'dataItems': [
  79. * {
  80. * 'id': 'Sheet1.Revenue_Min',
  81. * 'itemId': 'Sheet1.Revenue',
  82. * 'aggregate': 'min'
  83. * },
  84. * {
  85. * 'id': 'Sheet1.Revenue_Max',
  86. * 'itemId': 'Sheet1.Revenue',
  87. * 'aggregate': 'max'
  88. * }
  89. * ],
  90. * 'projections': [
  91. * 'Sheet1.Revenue_Min',
  92. * 'Sheet1.Revenue_Max'
  93. * ],
  94. * 'limit': 1000
  95. * }
  96. *
  97. */
  98. CommonQueryBuilder.buildMinMaxQueryFromColumns = function buildMinMaxQueryFromColumns(queryDefinition, queryContext, logger) {
  99. var oQuerySpec = {};
  100. var maxDataItemId = queryDefinition.column.columnId + '_Max';
  101. var minDataItemId = queryDefinition.column.columnId + '_Min';
  102. var maxDataItem = CommonQueryBuilder._buildDataItems({
  103. 'column': {
  104. 'id': maxDataItemId,
  105. 'columnId': queryDefinition.column.columnId,
  106. 'getAggregation': function getAggregation() {
  107. return 'max';
  108. }
  109. }
  110. }, logger);
  111. var minDataItem = CommonQueryBuilder._buildDataItems({
  112. 'column': {
  113. 'id': minDataItemId,
  114. 'columnId': queryDefinition.column.columnId,
  115. 'getAggregation': function getAggregation() {
  116. return 'min';
  117. }
  118. }
  119. }, logger);
  120. var aDataItems = minDataItem.concat(maxDataItem);
  121. if (!aDataItems.length) {
  122. logger.warn('Could not build minMax Query', this);
  123. return oQuerySpec;
  124. }
  125. oQuerySpec.version = '1';
  126. oQuerySpec.dataItems = aDataItems;
  127. oQuerySpec.projections = [minDataItemId, maxDataItemId];
  128. oQuerySpec.limit = queryDefinition.limit || CommonQueryBuilder.getQueryResultsSizeLimit();
  129. if (!queryContext) {
  130. return oQuerySpec;
  131. }
  132. var filters = [];
  133. if (queryContext.pageContext) {
  134. filters = CommonQueryBuilder.buildFilterFromPageContext(queryContext.pageContext);
  135. }
  136. oQuerySpec.filters = filters;
  137. return oQuerySpec;
  138. };
  139. /**
  140. * Build minmax query spec.
  141. * @param {Object} queryDefinition object that could include dataItems and Projections list etc
  142. * @param {Object} queryContext, object that could include pageContent or other query options
  143. * @see CommonQueryHelper.whenDataItemsMinMaxQueryReady
  144. */
  145. CommonQueryBuilder.buildMinMaxQueryFromDataItems = function buildMinMaxQueryFromDataItems(queryDefinition, queryContext, logger) {
  146. var oQuerySpec = {};
  147. if (!queryDefinition.dataItems.length || !queryDefinition.projections.length) {
  148. logger.warn('Could not build minMax Query', this);
  149. return oQuerySpec;
  150. }
  151. var oResult = CommonQueryBuilder._getNormalizedItems(queryDefinition, queryContext);
  152. // check if any items left after exclusions filtered in _getNormalizedItems
  153. if (!oResult.dataItems.length || !oResult.projections.length) {
  154. logger.warn('Could not build minMax Query', this);
  155. return oQuerySpec;
  156. }
  157. oQuerySpec.version = '1';
  158. oQuerySpec.dataItems = oResult.dataItems;
  159. oQuerySpec.projections = oResult.projections;
  160. oQuerySpec.limit = queryDefinition.limit || CommonQueryBuilder.getQueryResultsSizeLimit();
  161. oQuerySpec.type = 'minmax';
  162. if (!queryContext) {
  163. logger.warn('Could not build minMax Query with filters', this);
  164. return oQuerySpec;
  165. }
  166. var filters = [];
  167. if (queryContext.pageContext) {
  168. filters = CommonQueryBuilder.buildFilterFromPageContext(queryContext.pageContext);
  169. }
  170. oQuerySpec.filters = filters;
  171. return oQuerySpec;
  172. };
  173. /**
  174. * We do not want data items or projections of calculations (from smart annotations)
  175. * for min max queries. This method allows us to filter them out.
  176. * @param {Array} items objects that may or may not have calculations.
  177. * @returns {Array} items that do not have calculations.
  178. */
  179. CommonQueryBuilder._getNonCalculationItems = function _getNonCalculationItems(items) {
  180. return _.filter(items, function (item) {
  181. return item.hasOwnProperty('calculation') === false;
  182. });
  183. };
  184. CommonQueryBuilder._getNormalizedItems = function _getNormalizedItems(queryDef, options) {
  185. var aDataItemsClone = [];
  186. var oDataItemClone;
  187. var dataItemsToNormalize = CommonQueryBuilder._getNonCalculationItems(queryDef.dataItems);
  188. _.each(dataItemsToNormalize, function (dataItem) {
  189. oDataItemClone = _.clone(dataItem);
  190. //Remove selection to be consistent R6
  191. delete oDataItemClone.selection;
  192. aDataItemsClone.push(oDataItemClone);
  193. });
  194. if (!options || !options.itemsToExclude || options.itemsToExclude.length === 0) {
  195. return {
  196. 'dataItems': aDataItemsClone,
  197. 'projections': CommonQueryBuilder._getNonCalculationItems(queryDef.projections)
  198. };
  199. }
  200. //Continue to normalize query items based on options
  201. var aProjectionsClone = _.clone(queryDef.projections);
  202. var aItemsToExclude = options.itemsToExclude;
  203. aDataItemsClone = _.filter(aDataItemsClone, function (entry) {
  204. return aItemsToExclude.indexOf(entry.id) === -1;
  205. });
  206. aProjectionsClone = _.filter(aProjectionsClone, function (entry) {
  207. return aItemsToExclude.indexOf(entry) === -1;
  208. });
  209. return {
  210. 'dataItems': aDataItemsClone,
  211. 'projections': aProjectionsClone
  212. };
  213. };
  214. CommonQueryBuilder._buildBinnedDataItem = function _buildBinnedDataItem(column) {
  215. var oDataitem = {
  216. 'itemId': column.binningItemId,
  217. 'id': column.binningId,
  218. 'binning': column.binning
  219. };
  220. return oDataitem;
  221. };
  222. CommonQueryBuilder._buildDataItems = function _buildDataItems(queryDefinition, logger, queryContext) {
  223. var aDataItems = queryDefinition.dataItems || [];
  224. if (!aDataItems || !aDataItems.length) {
  225. var columns = [];
  226. if (queryDefinition.column) {
  227. columns.push(queryDefinition.column);
  228. } else {
  229. logger.warn('No columns or dataItems in the queryDefinition', CommonQueryBuilder);
  230. return aDataItems;
  231. }
  232. _.each(columns, function (column) {
  233. var oDataitem;
  234. if (column.binning) {
  235. oDataitem = CommonQueryBuilder._buildBinnedDataItem(column);
  236. } else {
  237. oDataitem = {
  238. 'id': column.id || column.columnId,
  239. 'itemId': column.columnId
  240. };
  241. }
  242. if (queryDefinition.column.getAggregation && column.columnId === queryDefinition.column.columnId) {
  243. oDataitem.aggregate = queryDefinition.column.getAggregation(column);
  244. }
  245. // If we have a hierarchy with a drill selection,
  246. // We need to maintain the drill selection in the column queryContext
  247. // This is the case when we show the non numeric filter for hierarchies with drill selections
  248. if (queryContext && queryContext.drillSelection) {
  249. oDataitem.selection = [queryContext.drillSelection.toJSON()];
  250. }
  251. if (queryDefinition.sort) {
  252. if (!oDataitem.selection) {
  253. oDataitem.selection = [];
  254. }
  255. oDataitem.selection.push({
  256. 'operation': 'order',
  257. 'sort': {
  258. 'type': queryDefinition.sort,
  259. 'priority': 1
  260. }
  261. });
  262. }
  263. aDataItems.push(oDataitem);
  264. });
  265. }
  266. return aDataItems;
  267. };
  268. /**
  269. * Build function query data items based on functionDefinitions.
  270. * @param {Object} queryDefinition - mandatory: the query definitions to build the query spec.
  271. * @param {Object} functionDefinitions - mandatory: the function definitions to build the query spec.
  272. */
  273. CommonQueryBuilder.buildFunctionQueryDataItems = function buildFunctionQueryDataItems(queryDefinition, functionDefinitions) {
  274. var oDataitem = {
  275. id: queryDefinition.column.columnId,
  276. itemId: queryDefinition.column.columnId
  277. };
  278. // Add the function definition
  279. var selection = [];
  280. var addOperation = {
  281. operation: 'add'
  282. };
  283. addOperation[functionDefinitions.functionName] = functionDefinitions.functionParameter;
  284. selection.push(addOperation);
  285. // Add the limit if there is any.
  286. if (queryDefinition.limit) {
  287. selection.push({
  288. 'operation': 'keep',
  289. 'head': queryDefinition.limit
  290. });
  291. }
  292. oDataitem.selection = selection;
  293. return [oDataitem];
  294. };
  295. CommonQueryBuilder.buildProjections = function buildProjections(queryDefinition, logger) {
  296. var aProjections = queryDefinition.projections || [];
  297. var columns = [];
  298. if (!aProjections || !aProjections.length) {
  299. if (queryDefinition.column) {
  300. columns.push(queryDefinition.column);
  301. }
  302. if (columns.length === 0 && (!queryDefinition.dataItems || queryDefinition.dataItems.length === 0)) {
  303. logger.warn('No columns or projections in the queryDefinition', CommonQueryBuilder);
  304. return aProjections;
  305. }
  306. if (queryDefinition.dataItems) {
  307. aProjections.push(queryDefinition.dataItems[0].id);
  308. } else {
  309. _.each(columns, function (column) {
  310. if (column.binning) {
  311. aProjections.push(column.binningId);
  312. } else {
  313. aProjections.push(column.columnId);
  314. }
  315. });
  316. }
  317. }
  318. return aProjections;
  319. };
  320. CommonQueryBuilder.buildFilterFromPageContext = function buildFilterFromPageContext(pageContext, queryContext, outBinningInfos) {
  321. var filters = [];
  322. if (_.isEmpty(pageContext)) {
  323. return filters;
  324. }
  325. queryContext = queryContext || {};
  326. _.each(pageContext, function (pageContextItem) {
  327. if (!CommonQueryBuilder._processVisiblePageContextItem(pageContextItem, queryContext.visibleItemsMap)) {
  328. var filterEntry = CommonQueryBuilder._buildFilterEntryFromPageContext(pageContextItem, queryContext, outBinningInfos);
  329. if (filterEntry) {
  330. filterEntry = DataQueryUtils.removeForecastFilters(filterEntry);
  331. filters.push(filterEntry);
  332. }
  333. }
  334. });
  335. return filters;
  336. };
  337. CommonQueryBuilder._processVisiblePageContextItem = function _processVisiblePageContextItem(pageContextEntry, visibleItemsMap) {
  338. if (pageContextEntry.origin === 'visualization' && visibleItemsMap) {
  339. var nonProjectedHierarchyFound = _.find(pageContextEntry.hierarchies, function (hierarchy) {
  340. return visibleItemsMap[hierarchy.hierarchyUniqueName] === undefined;
  341. });
  342. //Return true if all items in this visualization entry are projected.
  343. return nonProjectedHierarchyFound ? false : true;
  344. }
  345. return false;
  346. };
  347. CommonQueryBuilder._buildFilterEntryFromPageContext = function _buildFilterEntryFromPageContext(contextEntry, queryContext, outBinningInfos) {
  348. var filterEntry = void 0;
  349. if (contextEntry.exclude && contextEntry.tupleSet && contextEntry.tupleSet.length === 0 && contextEntry.origin === 'filter') {
  350. // Convert exclude empty filter to include all filter
  351. var hierarchy = contextEntry.hierarchies && contextEntry.hierarchies[0]; // Should always only have one hierarchy in filter dock filters.
  352. var newExtraQueryDataItem = queryContext && queryContext.queryOptions && queryContext.queryOptions.addExtraQueryDataItem && queryContext.queryOptions.addExtraQueryDataItem(hierarchy.hierarchyUniqueName);
  353. if (newExtraQueryDataItem) {
  354. filterEntry = {
  355. type: PRE,
  356. expression: {
  357. operator: IN,
  358. itemId: newExtraQueryDataItem.itemId,
  359. valueDataItem: newExtraQueryDataItem.id
  360. }
  361. };
  362. }
  363. } else {
  364. var filterExpression = CommonQueryBuilder._buildFilterExpressionFromContextEntry(contextEntry, queryContext, outBinningInfos);
  365. if (filterExpression && !_.isEmpty(filterExpression)) {
  366. filterEntry = {};
  367. filterEntry.type = PRE; // For pageContext, the aggregation type is always preaggregation.
  368. filterEntry.expression = contextEntry.exclude ? { 'not': filterExpression } : filterExpression;
  369. }
  370. }
  371. return filterEntry;
  372. };
  373. /**
  374. // Build filter expression based on each contextEntry.
  375. // example of contextEntry with 2 hierarchies:
  376. // {
  377. // 'origin': 'visualization',
  378. // 'table': '',
  379. // 'alias': '0',
  380. // 'filterName': '',
  381. // 'assetId': 'id:/0059b99d-9692-4607-99a5-d682d5858ce8',
  382. // 'exclude': false,
  383. // 'hierarchies': [
  384. // {
  385. // 'hierarchyUniqueName': 'Sheet1.Year_'
  386. // },
  387. // {
  388. // 'hierarchyUniqueName': 'Sheet1.Order_method_type'
  389. // }
  390. // ],
  391. // 'error': null,
  392. // 'tupleSet': [
  393. // [
  394. // {
  395. // 'u': '2013'
  396. // },
  397. // {
  398. // 'u': 'Sales visit'
  399. // }
  400. // ],
  401. // [
  402. // {
  403. // 'u': '2012'
  404. // },
  405. // {
  406. // 'u': 'Fax'
  407. // }
  408. // ],
  409. // [
  410. // {
  411. // 'u': '2011'
  412. // },
  413. // {
  414. // 'u': 'E-mail'
  415. // }
  416. // ]
  417. // ]
  418. // }
  419. //
  420. // The filter expression produced:
  421. // [{
  422. // 'type': 'pre',
  423. // 'expression': {
  424. // 'or': [
  425. // {
  426. // 'and': [
  427. // {
  428. // 'operator': 'in',
  429. // 'itemId': 'Sheet1.Year_',
  430. // 'values': [
  431. // '2013'
  432. // ]
  433. // },
  434. // {
  435. // 'operator': 'in',
  436. // 'itemId': 'Sheet1.Order_method_type',
  437. // 'values': [
  438. // 'Sales visit'
  439. // ]
  440. // }
  441. // ]
  442. // },
  443. // {
  444. // 'and': [
  445. // {
  446. // 'operator': 'in',
  447. // 'itemId': 'Sheet1.Year_',
  448. // 'values': [
  449. // '2012'
  450. // ]
  451. // },
  452. // {
  453. // 'operator': 'in',
  454. // 'itemId': 'Sheet1.Order_method_type',
  455. // 'values': [
  456. // 'Fax'
  457. // ]
  458. // }
  459. // ]
  460. // },
  461. // {
  462. // 'and': [
  463. // {
  464. // 'operator': 'in',
  465. // 'itemId': 'Sheet1.Year_',
  466. // 'values': [
  467. // '2011'
  468. // ]
  469. // },
  470. // {
  471. // 'operator': 'in',
  472. // 'itemId': 'Sheet1.Order_method_type',
  473. // 'values': [
  474. // 'E-mail'
  475. // ]
  476. // }
  477. // ]
  478. // }
  479. // ]
  480. // }
  481. // }]
  482. */
  483. CommonQueryBuilder._buildFilterExpressionFromContextEntry = function _buildFilterExpressionFromContextEntry(contextEntry, queryContext, outBinningInfos) {
  484. var filterExpression = {};
  485. var hierarchies = contextEntry.hierarchies;
  486. var tupleSet = contextEntry.tupleSet;
  487. // Single hierarchy case
  488. if (hierarchies.length === 1) {
  489. if (contextEntry.isModeledFilter) {
  490. //Model filter always has only one hierarchy
  491. return { filterId: contextEntry.hierarchies[0].hierarchyUniqueName };
  492. }
  493. if (tupleSet && tupleSet.length) {
  494. filterExpression = CommonQueryBuilder._buildFilterExpressionFromSingleHierarchy(contextEntry, queryContext, outBinningInfos);
  495. } else if (contextEntry.conditions && contextEntry.conditions[0]) {
  496. var itemId = contextEntry.hierarchies[0].hierarchyUniqueName;
  497. if (this._filterIsOnDisplayValue(contextEntry, queryContext, itemId)) {
  498. filterExpression.valueType = 'display';
  499. }
  500. // page context can contain 1 or 2 values.
  501. // depending on which value is missing we generate:
  502. // a) between from and to
  503. // b) before to
  504. // c) after from
  505. // unless it's inverted. Then we do the reverse.
  506. CommonQueryBuilder.setFilterExpressionId(contextEntry.binningAPIs, contextEntry.hierarchies[0].hierarchyUniqueName, filterExpression, outBinningInfos);
  507. var from = contextEntry.conditions[0].from ? contextEntry.conditions[0].from[0] : '';
  508. var to = contextEntry.conditions[0].to ? contextEntry.conditions[0].to[0] : '';
  509. var invert = contextEntry.conditions[0].invert;
  510. if (to !== '' && from !== '') {
  511. filterExpression.operator = invert ? NOTBETWEEN : BETWEEN;
  512. filterExpression.values = [contextEntry.conditions[0].from[0], contextEntry.conditions[0].to[0]];
  513. } else if (from !== '') {
  514. filterExpression.operator = invert ? LT : GT;
  515. filterExpression.values = [from];
  516. } else if (to !== '') {
  517. filterExpression.operator = invert ? GT : LT;
  518. filterExpression.values = [to];
  519. }
  520. } else {
  521. var binningInfo = CommonQueryBuilder.getBinningInfoForDataItem(contextEntry.binningAPIs, hierarchies[0].hierarchyUniqueName);
  522. if (!binningInfo) {
  523. CommonQueryBuilder.setFilterExpressionId(contextEntry.binningAPIs, hierarchies[0].hierarchyUniqueName, filterExpression, outBinningInfos);
  524. CommonQueryBuilder._buildFilterExpressionFromSingleHierarchyNoTupleSet(filterExpression);
  525. }
  526. }
  527. return filterExpression;
  528. }
  529. // Multiple hierarchies case.
  530. var aFilterExpressions = [];
  531. _.each(tupleSet, function (tuple) {
  532. var filterExpression = CommonQueryBuilder._buildFilterExpressionFromSingleTuple(hierarchies, tuple, contextEntry.binningAPIs, outBinningInfos);
  533. if (filterExpression && !_.isEmpty(filterExpression)) {
  534. aFilterExpressions.push(filterExpression);
  535. }
  536. });
  537. // If there are multiple tuples, need to add OR operator.
  538. if (aFilterExpressions.length) {
  539. filterExpression = tupleSet.length > 1 ? { 'or': aFilterExpressions } : aFilterExpressions[0];
  540. }
  541. return filterExpression;
  542. };
  543. CommonQueryBuilder._buildFilterExpressionFromSingleHierarchy = function _buildFilterExpressionFromSingleHierarchy(pageContextEntry, queryContext, binningInfos) {
  544. var itemId = pageContextEntry.hierarchies[0].hierarchyUniqueName;
  545. var filterExpression = void 0;
  546. var binningInfo = CommonQueryBuilder.getBinningInfoForDataItem(pageContextEntry.binningAPIs, itemId);
  547. if (!binningInfo) {
  548. // determine the filter type....
  549. var useDisplayValue = CommonQueryBuilder._filterIsOnDisplayValue(pageContextEntry, queryContext, itemId);
  550. var tupleValues = [];
  551. _.each(pageContextEntry.tupleSet, function (tuple) {
  552. tupleValues.push(useDisplayValue ? tuple[0].d : tuple[0].u);
  553. });
  554. // Get rid of the explicit null entries in the values
  555. var valuesExcludingNull = _.without(tupleValues, null, 'null');
  556. if (valuesExcludingNull.length > 0) {
  557. filterExpression = {
  558. operator: IN,
  559. values: valuesExcludingNull
  560. };
  561. CommonQueryBuilder.setFilterExpressionId(pageContextEntry.binningAPIs, itemId, filterExpression, binningInfos);
  562. }
  563. if (valuesExcludingNull.length < pageContextEntry.tupleSet.length) {
  564. var filterExpressionWithNull = {
  565. operator: ISNULL
  566. };
  567. CommonQueryBuilder.setFilterExpressionId(pageContextEntry.binningAPIs, itemId, filterExpressionWithNull, binningInfos);
  568. if (valuesExcludingNull.length > 0) {
  569. var combiningOperator = OR;
  570. var combiningExpression = {};
  571. combiningExpression[combiningOperator] = [filterExpressionWithNull, filterExpression];
  572. filterExpression = combiningExpression;
  573. } else {
  574. filterExpression = filterExpressionWithNull;
  575. }
  576. }
  577. if (filterExpression && useDisplayValue) {
  578. filterExpression.valueType = 'display';
  579. }
  580. }
  581. return filterExpression;
  582. };
  583. CommonQueryBuilder.getBinningInfoForDataItem = function getBinningInfoForDataItem(binningAPIs, itemId) {
  584. var binningInfo;
  585. if (binningAPIs && binningAPIs.length) {
  586. binningInfo = binningAPIs.find(function (binningInfo) {
  587. return binningInfo.itemId === itemId;
  588. });
  589. }
  590. return binningInfo;
  591. };
  592. CommonQueryBuilder.setFilterExpressionId = function setFilterExpressionId(binningAPIs, itemId, filterExpression, binningInfos) {
  593. var binningInfo = CommonQueryBuilder.getBinningInfoForDataItem(binningAPIs, itemId);
  594. if (binningInfo) {
  595. filterExpression.dataItem = binningInfo.binningAPI.getId();
  596. if (binningInfos) {
  597. binningInfos.push(binningInfo);
  598. }
  599. } else {
  600. filterExpression.itemId = itemId;
  601. }
  602. };
  603. /* add binning dataItem from pagecontext to query */
  604. CommonQueryBuilder.addBinningDataItemIfNeedit = function addBinningDataItemIfNeedit(dataItems, binningInfos) {
  605. binningInfos.forEach(function (binningInfo) {
  606. var dataItem = dataItems.find(function (dataItem) {
  607. return binningInfo.binningAPI.getId() === dataItem.id && binningInfo.itemId === dataItem.itemId;
  608. });
  609. if (!dataItem) {
  610. var binningSpec = binningInfo.binningAPI.toQueryJSON();
  611. // binningAPI has Binned DataItem label that must not be included in querySpec
  612. delete binningSpec.label;
  613. binningSpec.itemId = binningInfo.itemId;
  614. dataItems.push(binningSpec);
  615. }
  616. });
  617. };
  618. CommonQueryBuilder._isOlapProperty = function _isOlapProperty(queryContext, itemId) {
  619. var mdColumn = queryContext && queryContext.metadataAPI && queryContext.metadataAPI.getMetadataColumn && queryContext.metadataAPI.getMetadataColumn(itemId);
  620. return mdColumn && mdColumn.getSourceCategory && mdColumn.getSourceCategory() === 'property' ? true : false;
  621. };
  622. CommonQueryBuilder._filterIsOnDisplayValue = function _filterIsOnDisplayValue(pageContextEntry, queryContext, itemId) {
  623. return pageContextEntry && pageContextEntry.isSynchronizedEntry || this._isOlapProperty(queryContext, itemId);
  624. };
  625. CommonQueryBuilder._buildFilterExpressionFromSingleTuple = function _buildFilterExpressionFromSingleTuple(hierarchies, tuple, binningAPIs, binningInfos) {
  626. var aFilterExpressions = [];
  627. //Normally, we pass the use values, however; if the tuple is a number (ie: tuplePart.d is a number not a string)
  628. //we can't include members.
  629. var tupleContainsNumber = _.find(tuple, function (tuplePart) {
  630. return _.isNumber(tuplePart.d);
  631. });
  632. for (var i = 0; i < hierarchies.length; i++) {
  633. var binningInfo = CommonQueryBuilder.getBinningInfoForDataItem(binningAPIs, hierarchies[i].hierarchyUniqueName);
  634. if (!binningInfo) {
  635. var filterExpression = {};
  636. CommonQueryBuilder.setFilterExpressionId(binningAPIs, hierarchies[i].hierarchyUniqueName, filterExpression, binningInfos);
  637. var filterValue = tupleContainsNumber ? tuple[i].d : tuple[i].u;
  638. if (filterValue === null) {
  639. filterExpression.operator = ISNULL;
  640. } else {
  641. filterExpression.operator = IN;
  642. filterExpression.values = [filterValue];
  643. if (tupleContainsNumber) {
  644. filterExpression.valueType = 'display';
  645. }
  646. }
  647. aFilterExpressions.push(filterExpression);
  648. }
  649. }
  650. return aFilterExpressions.length ? { 'and': aFilterExpressions } : null;
  651. };
  652. /**
  653. *
  654. * @param {Object} filterExpression Filter expression of a full set or a data item.
  655. * e.g.
  656. * {
  657. * "type": "pre",
  658. * "expression": {
  659. * "operator": "in",
  660. * "itemId": "[Automobile_C01].[RGB Colors]",
  661. * "valueDataItem": "[Automobile_C01].[RGB Colors]"
  662. * }
  663. * }
  664. */
  665. CommonQueryBuilder._buildFilterExpressionFromSingleHierarchyNoTupleSet = function _buildFilterExpressionFromSingleHierarchyNoTupleSet(filterExpression) {
  666. filterExpression.operator = IN;
  667. filterExpression.valueDataItem = filterExpression.itemId ? filterExpression.itemId : filterExpression.dataItem;
  668. };
  669. CommonQueryBuilder._buildFilterFromSearchTerm = function _buildFilterFromSearchTerm(specOption, searchTerm) {
  670. if (!_.isArray(searchTerm) && !_.isString(searchTerm)) {
  671. throw new Error('Invalid searchTerm');
  672. }
  673. var isArray = _.isArray(searchTerm);
  674. var values = isArray ? searchTerm : [searchTerm];
  675. var filter = {
  676. 'type': PRE,
  677. 'expression': {
  678. 'itemId': specOption.column.columnId,
  679. 'values': values
  680. }
  681. };
  682. if (isArray) {
  683. filter.expression.operator = IN;
  684. filter.expression.ignoreCase = true;
  685. filter.expression.valueType = 'display';
  686. } else {
  687. filter.expression.operator = CONTAINSIGNORECASE;
  688. }
  689. return [filter];
  690. };
  691. CommonQueryBuilder.getQueryResultsSizeLimit = function getQueryResultsSizeLimit() {
  692. return QUERY_RESULTS_SIZE_LIMIT;
  693. };
  694. CommonQueryBuilder.addExtraQueryDataItem = function addExtraQueryDataItem(uniqueDataItemIdsMap, queryOptions, itemId) {
  695. var extraDataItems = queryOptions.extraDataItems || [];
  696. if (_.pluck(extraDataItems, 'itemId').indexOf(itemId) === -1) {
  697. var uniqueId = UniqueHashIdBuilder.createUniqueHashId(itemId, uniqueDataItemIdsMap);
  698. var random = 0;
  699. var extraDataItemIds = _.pluck(extraDataItems, 'id');
  700. while (extraDataItemIds.indexOf(uniqueId) !== -1) {
  701. uniqueId = UniqueHashIdBuilder.createUniqueHashId(itemId + random++, uniqueDataItemIdsMap);
  702. }
  703. var extraQueryDataItem = {
  704. id: uniqueId,
  705. itemId: itemId
  706. };
  707. extraDataItems.push(extraQueryDataItem);
  708. queryOptions.extraDataItems = extraDataItems;
  709. return extraQueryDataItem;
  710. }
  711. };
  712. return CommonQueryBuilder;
  713. }();
  714. return CommonQueryBuilder;
  715. });
  716. //# sourceMappingURL=CommonQueryBuilder.js.map