DatasourceUtil.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337
  1. 'use strict';
  2. function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
  3. /*
  4. * +------------------------------------------------------------------------+
  5. * | Licensed Materials - Property of IBM
  6. * | IBM Cognos Products: Dashboard
  7. * | (C) Copyright IBM Corp. 2018, 2020
  8. * |
  9. * | US Government Users Restricted Rights - Use, duplication or disclosure
  10. * | restricted by GSA ADP Schedule Contract with IBM Corp.
  11. * +------------------------------------------------------------------------+
  12. */
  13. define(['underscore', 'bi/moser/moser.min', '../../apiHelpers/SlotAPIHelper'], function (_, MoserJS, SlotAPIHelper) {
  14. var _class, _temp;
  15. var SOURCE_TYPES_TO_VERIFY_JOIN = [MoserJS.default.UseSpecType.FILE.value(), MoserJS.default.UseSpecType.DATASET.value()];
  16. var DatasourceUtil = (_temp = _class = function () {
  17. function DatasourceUtil() {
  18. _classCallCheck(this, DatasourceUtil);
  19. }
  20. /**
  21. * We agreed only do client level join for uploaded files and data sets (dataset2),
  22. * or a module created from uploaded files or data sets (dataset2).
  23. * @returns true if items are from source types in SOURCE_TYPES_TO_VERIFY_JOIN
  24. */
  25. DatasourceUtil._shouldVerifyJoin = function _shouldVerifyJoin(module) {
  26. var items = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  27. var moserDataSources = arguments[2];
  28. var newAPI = !!(module.getInterfaceType && module.getImplType);
  29. if (newAPI) {
  30. var dataSourceId = module.getId();
  31. var verifyJoin = true;
  32. for (var i = 0; i < items.length && verifyJoin; i++) {
  33. var columnId = items[i];
  34. var metadataColumn = module.getMetadataColumn(columnId);
  35. var table = metadataColumn ? metadataColumn.getTableName() : null;
  36. if (!metadataColumn || !table) {
  37. // Skip if not a metadata column or metadata column is not from a table, e.g. stand alone model calculations.
  38. verifyJoin = false;
  39. break;
  40. }
  41. var originalType = moserDataSources.getOriginalSourceType(dataSourceId, columnId);
  42. if (originalType && SOURCE_TYPES_TO_VERIFY_JOIN.indexOf(originalType) === -1) {
  43. verifyJoin = false;
  44. break;
  45. }
  46. }
  47. return verifyJoin;
  48. } else {
  49. var theMoserJS = DatasourceUtil.MoserJS_Inst || MoserJS;
  50. var tables = [];
  51. return _.find(items, function (columnId) {
  52. if (!DatasourceUtil.isMultiMeasuresSeriesOrValue(columnId)) {
  53. var _metadataColumn = module.getMetadataColumn(columnId);
  54. var _table = _metadataColumn ? _metadataColumn.getTable() : null;
  55. if (!_metadataColumn || !_table) {
  56. return true;
  57. }
  58. // Do not check again if already checked
  59. if (tables.indexOf(_table.idForExpression) === -1) {
  60. tables.push(_table.idForExpression);
  61. var useSpec = theMoserJS.default.ModuleUtils.getObjectUseSpec(_table);
  62. if (useSpec) {
  63. // Return if there is a source type not belongs to the local join
  64. return SOURCE_TYPES_TO_VERIFY_JOIN.indexOf(useSpec.getType().value()) === -1;
  65. }
  66. }
  67. }
  68. }) === undefined;
  69. }
  70. };
  71. DatasourceUtil.isMultiMeasuresSeriesOrValue = function isMultiMeasuresSeriesOrValue(itemId) {
  72. return itemId.indexOf(SlotAPIHelper.MULTI_MEASURES_SERIES) === 0 || itemId.indexOf(SlotAPIHelper.MULTI_MEASURES_VALUE) === 0;
  73. };
  74. DatasourceUtil.getTableRef = function getTableRef(dataSource, itemIds) {
  75. var names = [];
  76. if (dataSource) {
  77. itemIds.forEach(function (item) {
  78. var metadataColumn = dataSource.getMetadataColumn(item);
  79. var tableName = metadataColumn && metadataColumn.getTableName();
  80. if (tableName && names.indexOf(tableName) === -1) {
  81. names.push(tableName);
  82. }
  83. });
  84. }
  85. return names;
  86. };
  87. /**
  88. *
  89. * @param {object} module - the data source module, either an uploaded file, a dataset, a package, a module, or a model built from an uploaded file, a dataset, a package, or a module
  90. * @param {object[]} projectedItems - An array of projected items ids
  91. * @param return true if metadata columns referenced by pageContextItemSpec and dataSlots are from:
  92. * 1) uploaded files
  93. * 2) data sets
  94. * 3) the combination of 1) and 2).
  95. */
  96. DatasourceUtil.isSupportedNonJoinTableDatascourceType = function isSupportedNonJoinTableDatascourceType(module) {
  97. var itemIds = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  98. if (!module || module.getSourceType() === 'package' || itemIds.length === 0) {
  99. return false;
  100. }
  101. return DatasourceUtil._shouldVerifyJoin(module, itemIds);
  102. };
  103. /**
  104. * A dashboard works against one MUI module created on the fly each time a dashboard is created.
  105. * A package is a metadata model that have not the necessary table joins applied at the database level.
  106. * Therefore dashboards need not worry about these joins.
  107. * A dashboard only handle join relationships at the data module level.
  108. * MUI creates a module which can be one of:
  109. * 1) contain one single package, this is the simplest case
  110. * 2) uploaded file containing more than one table where there are no joins between tables. In Endor, all tables within an uploaded xlsx are not joined
  111. * 3) a data module containing any combination of packgages, other modules, uploaded files and data sets. This is the complex case.
  112. *
  113. * For Endor release, decision is made to only verify table joins for uploaded files and data sets since currently there is no API to get accurate
  114. * join relationships for case3).
  115. *
  116. * @param return true if metadata columns referenced by pageContextItemSpec and dataSlots are from:
  117. * 1) uploaded files
  118. * 2) data sets
  119. * 3) the combination of 1) and 2).
  120. */
  121. DatasourceUtil.mustVerifyJoinTablesInSameDataSource = function mustVerifyJoinTablesInSameDataSource(dataSource, pageContextItemSpec) {
  122. var itemIds = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : [];
  123. var moserDataSources = arguments[3];
  124. //A module can be a package in which case return false (this is the simples case) OR when pageContextItem has no hierarchy context to work on
  125. var dataSourceType = dataSource.getType && dataSource.getType() || dataSource.getSourceType && dataSource.getSourceType();
  126. if (dataSourceType === 'package') {
  127. return false;
  128. }
  129. var pageContextColumnIds = pageContextItemSpec && pageContextItemSpec.hierarchies && pageContextItemSpec.hierarchies.map(function (h) {
  130. return h.hierarchyUniqueName;
  131. }) || pageContextItemSpec && pageContextItemSpec.getItemIds && pageContextItemSpec.getItemIds();
  132. if (!_.isArray(pageContextColumnIds) || !pageContextColumnIds.length) {
  133. return false;
  134. }
  135. itemIds.push.apply(itemIds, pageContextColumnIds);
  136. return DatasourceUtil._shouldVerifyJoin(dataSource, itemIds, moserDataSources);
  137. };
  138. DatasourceUtil.haveTableJoinsInSameDataSource = function haveTableJoinsInSameDataSource(module, tableNames, otherTableNames) {
  139. // TODO Clean internal function names in other classes.
  140. var tablesHaveJoinRelationship = module.hasJoinedTables ? module.hasJoinedTables.bind(module) : module.tablesHaveJointRelationship.bind(module);
  141. var result = _.find(otherTableNames, function (otherTableName) {
  142. return _.find(tableNames, function (tableName) {
  143. return tablesHaveJoinRelationship(tableName, otherTableName);
  144. });
  145. });
  146. return result ? true : false;
  147. };
  148. /**
  149. * Returns a boolean indicating whether there is a least the same table referenced in both tables
  150. *
  151. * @param {array} tableRef1 - table 1 to check
  152. * @param {array} tableRef2 - the table to check against tableRef1
  153. *
  154. * @return {boolean} return true if there is at least one table name matched in both tables, else return false
  155. */
  156. DatasourceUtil.haveATableReference = function haveATableReference() {
  157. var tableRef1 = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : [];
  158. var tableRef2 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  159. var exactMatch = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
  160. if (exactMatch && tableRef1.length !== tableRef2.length || tableRef1.length === 0 && tableRef2.length === 0) {
  161. return false;
  162. }
  163. return _.find(tableRef1, function (ref1) {
  164. return tableRef2.indexOf(ref1) !== -1;
  165. }) ? true : false;
  166. };
  167. /**
  168. * Dynamically calculates and returns the list of table references for the specified page context entry
  169. *
  170. * @param {object} module - the module to retrieve the table names
  171. * @param {object} pageContextEntry - the page context entry
  172. *
  173. * @return {array} List of retrieved table names
  174. */
  175. /**
  176. * Determine whether the slot and dataItem are ordinal and attribute
  177. *
  178. * @param {object} slot - The slot item that the function will compare
  179. * @param {object} dataItem - The dataItem that the function will compare to the slot
  180. *
  181. * @return {boolean} A boolean to represent whether or not it is Ordinal vs. Attribute
  182. **/
  183. /**
  184. * Process and return a merged filter page context
  185. *
  186. * @param {array} netFilterPageContext - array filter net page context
  187. * @param {array} synchronizedFilters - array of synchronized filters
  188. *
  189. * @return {array} merged synchronized and filter net page context array
  190. */
  191. DatasourceUtil.mergeSynchronizePageContextFilter = function mergeSynchronizePageContextFilter(netFilterPageContext, synchronizedFilters) {
  192. if (!synchronizedFilters || synchronizedFilters.length === 0) {
  193. return netFilterPageContext;
  194. }
  195. var hasFilterByName = function hasFilterByName(filtersToCheck, filterName) {
  196. var exist = _.find(filtersToCheck, function (filter) {
  197. return filter.getItemName().toLowerCase() === filterName;
  198. });
  199. return exist ? true : false;
  200. };
  201. //Populate this vis Filters
  202. var thisVisFilters = {};
  203. var getFiltersByScope = function getFiltersByScope(scope) {
  204. var array = thisVisFilters[scope] = thisVisFilters[scope] || [];
  205. return array;
  206. };
  207. netFilterPageContext.forEach(function (entry) {
  208. var filters = getFiltersByScope(entry.getScope());
  209. filters.push(entry);
  210. });
  211. //Process synch local filters first because they have precedence over global filters
  212. var localSynchFilters = synchronizedFilters.filter(function (entry) {
  213. return entry.scope !== 'global';
  214. });
  215. localSynchFilters.forEach(function (entry) {
  216. var nameToCheck = entry.filterName.toLowerCase();
  217. var thisTableFilters = getFiltersByScope(entry.scope);
  218. if (!hasFilterByName(thisTableFilters, nameToCheck)) {
  219. thisTableFilters.push(entry.getAPI());
  220. }
  221. //Remove the same one in the global if it exists since the thisTab one takes precedence since these ones may have been already defined in this vis so remove them
  222. thisVisFilters.global = _.filter(thisVisFilters.global, function (filter) {
  223. return filter.getItemName().toLowerCase() !== nameToCheck;
  224. });
  225. });
  226. //Now process synch global filters
  227. var globalSynchFilters = synchronizedFilters.filter(function (entry) {
  228. return entry.scope === 'global';
  229. });
  230. globalSynchFilters.forEach(function (entry) {
  231. var nameToCheck = entry.filterName.toLowerCase();
  232. var toAdd = true;
  233. //Loop through set of thisTab filters and only add the global filter if it is not defined in the thisTab scope
  234. for (var property in thisVisFilters) {
  235. if (property !== 'global' && hasFilterByName(thisVisFilters[property], nameToCheck)) {
  236. toAdd = false;
  237. break;
  238. }
  239. }
  240. if (toAdd) {
  241. var globalFilters = getFiltersByScope('global');
  242. globalFilters.push(entry.getAPI());
  243. }
  244. });
  245. //Now concat all results and return as a single array
  246. var result = void 0;
  247. for (var prop in thisVisFilters) {
  248. if (thisVisFilters[prop] && thisVisFilters[prop].length > 0) {
  249. if (!result) {
  250. result = thisVisFilters[prop];
  251. } else {
  252. result = result.concat(thisVisFilters[prop]);
  253. }
  254. }
  255. }
  256. return result || [];
  257. };
  258. DatasourceUtil.metadataColumnSupportsFiltering = function metadataColumnSupportsFiltering(column) {
  259. if (!column) {
  260. return false;
  261. }
  262. // getAggregateMode is from the old object MetadaColumn
  263. // getAggregationMode is the new API function
  264. // the column passed in can be either the old MetadaColumn or the new API Column
  265. var getAggregationMode = (column.getAggregateMode || column.getAggregationMode).bind(column);
  266. return !(column.getType() === 'fact' && (getAggregationMode() === 'static' || column.getDefaultAggregation() === 'calculated'));
  267. };
  268. return DatasourceUtil;
  269. }(), _class.getPageContextItemTableRef = function (dataSource, pageContextEntry) {
  270. var tableRef = [];
  271. var itemIds = pageContextEntry.getItemIds ? pageContextEntry.getItemIds() : _.pluck(pageContextEntry.hierarchies, 'hierarchyUniqueName');
  272. itemIds.forEach(function (itemId) {
  273. var column = dataSource.getMetadataColumn(itemId);
  274. if (column) {
  275. var name = column.getTableName();
  276. if (tableRef.indexOf(name) === -1) {
  277. tableRef.push(name);
  278. }
  279. }
  280. });
  281. return tableRef;
  282. }, _class.isOrdinalAttribute = function (slot, dataItem) {
  283. var slotType = slot.getDefinition().getType();
  284. var dataType = dataItem.getMetadataColumn().getType();
  285. return slotType === 'ordinal' && dataType === 'attribute';
  286. }, _temp);
  287. return DatasourceUtil;
  288. });
  289. //# sourceMappingURL=DatasourceUtil.js.map