QueryDefinition.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. 'use strict';
  2. /**
  3. * Licensed Materials - Property of IBM
  4. * IBM Cognos Products: Dashboard
  5. * (C) Copyright IBM Corp. 2017, 2019
  6. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  7. *
  8. * @module /dashboard/data/QueryDefinition
  9. * @see QueryDefinition
  10. */
  11. define(['underscore', '../../../../filters/Filters', '../QueryFilterSpec', '../../../../lib/@waca/dashboard-common/dist/core/Model', '../CommonQueryBuilder'], function (_, Filters, QueryFilterSpec, Model, CommonQueryBuilder) {
  12. 'use strict';
  13. /**
  14. * The QueryDefinition object is responsible for providing an interface between how a caller sees data
  15. * and the query engine needs data (in dimensions-first order).
  16. *
  17. * In general, it allows a caller to define an arbitrary 'field order'. In the case of widgets, this
  18. * order would correspond to slot/slot mapping order depending on the application and type of slot.
  19. *
  20. * That same order is available through the QueryResults object.
  21. */
  22. // Declare the class
  23. var PROP_ID_SUPPRESSION = 'suppression';
  24. var SUPPRESSION_NONE = 'none';
  25. var QueryDefinition = null;
  26. QueryDefinition = Model.extend({
  27. filters: null,
  28. localFilters: null,
  29. //If not specified in query options, the query row limit is this value.
  30. DEFAULT_QUERY_ROW_LIMIT: 3000,
  31. DEFAULT_QUERY_HINT_REALTIME_REFRESH: false,
  32. init: function init(options) {
  33. QueryDefinition.inherited('init', this, arguments);
  34. this.dashboardAPI = options.dashboardAPI;
  35. this.logger = options.logger;
  36. this._topBottomQueryPageScope = null; //If not set, top bottom queries will be scoped to all pages.
  37. this._queryDataItems = [];
  38. this._queryProjections = [];
  39. },
  40. /**
  41. * @param {Array} QueryDataItems
  42. **/
  43. setQueryDataItems: function setQueryDataItems(queryDataItems) {
  44. this._queryDataItems = queryDataItems;
  45. },
  46. getQueryDataItems: function getQueryDataItems() {
  47. return this._queryDataItems;
  48. },
  49. setQueryProjections: function setQueryProjections(projections) {
  50. this._queryProjections = projections;
  51. },
  52. getQueryProjections: function getQueryProjections() {
  53. return this._queryProjections;
  54. },
  55. /**
  56. * because widget-to-widget filters only affect values of widgets on a particular page (tab),
  57. * topBottom queries need to be 'scoped' to collect items on this widget's page only.
  58. * @param topBottomQueryPageScope - the id of a parent object that must match when collecting items (set to null if no scope is needed).
  59. */
  60. setTopBottomQueryPageScope: function setTopBottomQueryPageScope(topBottomQueryPageScope) {
  61. this._topBottomQueryPageScope = topBottomQueryPageScope;
  62. },
  63. _canQuery: function _canQuery(slotAPI) {
  64. return !(slotAPI.isMultiMeasuresSeries() && !slotAPI.isStacked());
  65. },
  66. _LayersHaveCategoricalSlots: function _LayersHaveCategoricalSlots(visAPI) {
  67. var _this = this;
  68. var aSlotGroups = visAPI.getSlotInfoForEachView();
  69. _.each(aSlotGroups, function (entry) {
  70. var oCategorySlots = _.find(entry.slotAPIs, function (slotAPI) {
  71. return slotAPI.getFinalSlotType() === 'category' && _this._canQuery(slotAPI);
  72. });
  73. entry.hasCategoricalSlots = oCategorySlots !== undefined;
  74. });
  75. return aSlotGroups;
  76. },
  77. /**
  78. * Construct the query specs needed for the current visualization.
  79. * @param queryOptions - options on the query (shouldAxisScalesBeFixed, dataRowLimit etc.)
  80. * @param visApi - visApi
  81. * @returns querySpec - the query spec to retrieve the needed data set, topBottomQuery -
  82. * query to get the top and bottom values for each ordinal field if needed.
  83. * TODO: Should move this to a more central place.
  84. */
  85. build: function build(queryOptions, visAPI) {
  86. // build the query
  87. queryOptions = queryOptions || {}; //QueryOptions should always be defined even if members are not.
  88. var queryDescriptor = this._buildEndorQuerySpec();
  89. var topBottomQuery = void 0;
  90. var containsCategorySlots = this._LayersHaveCategoricalSlots(visAPI);
  91. /* If we do not have any dimensions (a summary view for instance) we do
  92. * not need to do top and bottom queries (shouldAxisScaleBeFixed will be false).
  93. */
  94. if (queryOptions.shouldAxisScaleBeFixed && containsCategorySlots) {
  95. var aItemsToExclude = [];
  96. _.each(visAPI.getDataSlots(), function (slot) {
  97. //By definition, items in certain slots should not be added to top bottom queries
  98. if (slot.getDefinition().useInTopBottomQueries === false) {
  99. aItemsToExclude = aItemsToExclude.concat(slot.getDataItemRefs());
  100. } else if (slot.isStacked()) {
  101. // If the slot is stacked and has multiple data items then we can not add it to the min max query
  102. // In this scenario the slot is shown as a nested set of data items and we need to remove using the id.
  103. aItemsToExclude = aItemsToExclude.concat(slot.getId());
  104. }
  105. });
  106. // Make one query to get min and max only with the fields from the current widget, plus the global filters and slicers (filters from other widgets).
  107. topBottomQuery = CommonQueryBuilder.buildMinMaxQueryFromDataItems(queryDescriptor.querySpec, {
  108. 'itemsToExclude': aItemsToExclude
  109. }, this.logger);
  110. }
  111. this._setSuppresion(queryDescriptor, visAPI);
  112. return {
  113. querySpec: queryDescriptor.querySpec,
  114. endPoint: 'data',
  115. topBottomQuery: topBottomQuery
  116. };
  117. },
  118. _setSuppresion: function _setSuppresion(queryDescriptor, visAPI) {
  119. if (queryDescriptor && queryDescriptor.querySpec) {
  120. var contentAPI = visAPI.ownerWidget.content;
  121. var suppression = contentAPI && contentAPI.getPropertyValue(PROP_ID_SUPPRESSION);
  122. if (suppression === SUPPRESSION_NONE) {
  123. queryDescriptor.querySpec.suppress = [SUPPRESSION_NONE];
  124. if (!queryDescriptor.querySpec.queryHints) {
  125. queryDescriptor.querySpec.queryHints = {};
  126. }
  127. queryDescriptor.querySpec.queryHints.suppress = SUPPRESSION_NONE;
  128. }
  129. }
  130. },
  131. //TODO: Merge this API for Endor release
  132. _buildEndorQuerySpec: function _buildEndorQuerySpec() {
  133. var oQuerySpec = {};
  134. oQuerySpec.version = '1';
  135. oQuerySpec.dataItems = this._queryDataItems;
  136. oQuerySpec.projections = this._queryProjections;
  137. oQuerySpec.limit = 3000; //TODO: Capped as 3000 as limited as of Pre-Endor
  138. return {
  139. querySpec: oQuerySpec
  140. };
  141. },
  142. /**
  143. * @returns the query URL string that is equivalent to the output of build.
  144. */
  145. buildURL: function buildURL() {
  146. var queryDescriptor = this._buildEndorQuerySpec();
  147. return JSON.stringify(queryDescriptor.querySpec);
  148. }
  149. });
  150. return QueryDefinition;
  151. });
  152. //# sourceMappingURL=QueryDefinition.js.map