QueryResultDataPoints.v2.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  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: BI Dashboard
  7. *| (C) Copyright IBM Corp. 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([], function () {
  14. 'use strict';
  15. /**
  16. * This object hides the implementation of the pt array and allows a caller to have keyed access to point information.
  17. * The initial use is as a postProcessor helper.
  18. * The hope longer term is for DataQueryResultV2 to use this class rather than the pt array.
  19. *
  20. * For any key, all measure/calculation values can be accessed
  21. * AND, if a point does not exist, a null point will be returned.
  22. **/
  23. return function () {
  24. /**
  25. *
  26. * @param {integer} edgeCount - the count of the number of edges in the result.
  27. * @param {integer} measureCount - the count of the number of measures (and calcs) in the result.
  28. * @param {integer} measureEdgeIdx - the edge where the measure is
  29. * @param {*} suppressionEnabled - true if suppression is enabled (used to determine the null value string)
  30. */
  31. function QueryResultDataPointsV2(edgeCount, measureCount) {
  32. var measureEdgeIdx = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : -1;
  33. var suppressionEnabled = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : true;
  34. _classCallCheck(this, QueryResultDataPointsV2);
  35. this._edgeCount = edgeCount;
  36. this._measureCount = measureCount;
  37. this._measureEdgeIdx = measureEdgeIdx; //If we extend to support single edge, this will be -1.
  38. this.missingValue = suppressionEnabled ? '' : null;
  39. this._measureMap = {};
  40. this._createNullValueTemplate();
  41. this._nullMeasureArray = this._createNullMeasureArray();
  42. }
  43. /**
  44. * Return a point that corresponds to one or two edgeIds in '{ pt: [] }' form.
  45. * NOTE: This API is not called getPoint() because in future, we should have getPoint()
  46. * return a QueryResultDataPointAPI.
  47. * @param {integer} edge1Id
  48. * @param {integer=null} [edge2Id]
  49. * @returns a dataPoint in "pt form" - { pt: [] }
  50. */
  51. QueryResultDataPointsV2.prototype.getPtByEdgeIds = function getPtByEdgeIds(edge1Id) {
  52. var edge2Id = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  53. var currentCell = this._measureMap[this._getPointKey(edge1Id, edge2Id)];
  54. //If a pt exists at this coordinate, 'consume it', otherwise, fill with a null.
  55. if (currentCell && currentCell[0] === edge1Id && (edge2Id === null || currentCell[1] === edge2Id)) {
  56. return { pt: currentCell };
  57. }
  58. return this._newNullValue(edge1Id, edge2Id);
  59. };
  60. /**
  61. * Load points into an internal structure that can be accessed with get methods.
  62. * This api expects an input value list in the form that is returned in the dss response.
  63. * (internally, it stores a map of arrays similar to the pt array but this is not necessay longer term)
  64. * @param {*} valueList - the pt array as returned in the DSS response.
  65. */
  66. QueryResultDataPointsV2.prototype.loadPoints = function loadPoints(valueList) {
  67. //Read the data and fill values in based on the measure being processed
  68. var measureMap = {};
  69. for (var pointIdx = 0; pointIdx < valueList.length; ++pointIdx) {
  70. var point = valueList[pointIdx];
  71. if (point.pt) {
  72. var currentMeasureNum = point.pt[this._measureEdgeIdx]; //Read the measureNum out of the point.
  73. //To merge measures into 1 pt entry, get the "pointKey"
  74. //(entries in the point excluding measure. eg 0,1 for col 0, row 1)
  75. var pointKey = this._buildPointKey(point.pt, this._measureEdgeIdx);
  76. var valueIndex = point.pt.length - 1;
  77. var pointValue = point.pt[valueIndex];
  78. if (measureMap[pointKey]) {
  79. //This case will occur when there are multiple measures and we need to augment the entry
  80. //with a new measure value. Set the value for the nth measure into the existing map.
  81. var mapEntry = measureMap[pointKey];
  82. mapEntry[valueIndex + currentMeasureNum] = pointValue;
  83. } else if (this._measureCount === 1) {
  84. //1 measure optimization: (and no calculations) case...
  85. //Since the internal form of a map entry is identical to the content of the pt array
  86. //and we aren't modifying it, we can simply use the original pt array for this point.
  87. //NOTE: This optimization would be invalid if the internal map entry format is changed.
  88. measureMap[pointKey] = point.pt;
  89. } else {
  90. //multi-measure case: create an array with measureCount 'null value' object references,
  91. //Replace the n'th measure with the non-null value.
  92. //NOTE: the result can be any combination of nulls and non-nulls depending on which measures have values.
  93. //[edge#,edge#,measureEdge,{ v:null}, { v:null } ... ]
  94. var newValue = this._nullMeasureArray.slice(0);
  95. newValue[currentMeasureNum] = pointValue;
  96. var newPt = point.pt.slice(0, valueIndex);
  97. newPt = newPt.concat(newValue);
  98. measureMap[pointKey] = newPt;
  99. }
  100. }
  101. }
  102. this._measureMap = measureMap;
  103. };
  104. /**
  105. * @returns a count of the number of measures as passed in the constructor.
  106. */
  107. QueryResultDataPointsV2.prototype.getMeasureCount = function getMeasureCount() {
  108. return this._measureCount;
  109. };
  110. /**
  111. * @returns the edge where the measure is defined (or -1 if there is no measure edge)
  112. */
  113. QueryResultDataPointsV2.prototype.getMeasureEdgeIndex = function getMeasureEdgeIndex() {
  114. return this._measureEdgeIndex;
  115. };
  116. /**
  117. * @returns the size of the first categorical edge
  118. */
  119. QueryResultDataPointsV2.prototype.getFirstEdgeSize = function getFirstEdgeSize(edges) {
  120. return this._getEdgeSize(edges, this._getFirstEdgeIndex());
  121. };
  122. /**
  123. * @returns the size of the second categorical edge (or null)
  124. */
  125. QueryResultDataPointsV2.prototype.getSecondEdgeSize = function getSecondEdgeSize(edges) {
  126. var secondEdgeIndex = this._getSecondEdgeIndex();
  127. return secondEdgeIndex !== null ? this._getEdgeSize(edges, secondEdgeIndex) : null;
  128. };
  129. //Build a "point key" which is the value of a data row minus the measure index and measure value.
  130. //EXAMPLES: 2-edge crosstab point: [1, 0, { v:x }] ... key = 1
  131. // 3-edge crosstab point: [1, 3, 0, { v: x }] ... key = 1,3
  132. QueryResultDataPointsV2.prototype._buildPointKey = function _buildPointKey(pt, measureEdgeIdx) {
  133. var pointKey = [];
  134. pt.forEach(function (part, partIdx) {
  135. //In v2, a pt has a single cell value { v:x } as the last entry in the array. Exclude it from the key.
  136. if (partIdx !== measureEdgeIdx && partIdx < pt.length - 1) {
  137. pointKey.push(pt[partIdx]);
  138. }
  139. });
  140. return pointKey.join(',');
  141. };
  142. QueryResultDataPointsV2.prototype._getPointKey = function _getPointKey(edge1Id) {
  143. var edge2Id = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  144. return edge1Id + (edge2Id !== null ? ',' + edge2Id : '');
  145. };
  146. //Generate a "null value entry" which is { pt: [ <ptFirstEdgeId>, <ptSecondEdgeId>, 0, { v: null} ]
  147. QueryResultDataPointsV2.prototype._newNullValue = function _newNullValue(ptFirstEdgeId) {
  148. var ptSecondEdgeId = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
  149. var nullPt = this._nullValueTemplate.slice(0);
  150. //Set firstEdge as specified.
  151. nullPt[this._getFirstEdgeIndex()] = ptFirstEdgeId;
  152. if (ptSecondEdgeId !== null) {
  153. //Set edge1 as specified.
  154. nullPt[this._getSecondEdgeIndex()] = ptSecondEdgeId;
  155. }
  156. return { pt: nullPt };
  157. };
  158. //a null value template is a pt entry with 2 edge or 3 edge form and n { v:null } entries...1 per measure.
  159. //eg: [0, 0, 0, { v: null}, { v: null }] for a 3 edge, 2 measure crosstab.
  160. //It is used whenever we need to add a null as a starting point (then edgeId's are filled in.)
  161. QueryResultDataPointsV2.prototype._createNullValueTemplate = function _createNullValueTemplate() {
  162. this._nullValueTemplate = [];
  163. for (var i = 0; i < this._edgeCount; ++i) {
  164. this._nullValueTemplate.push(0);
  165. }
  166. this._nullValueTemplate = this._nullValueTemplate.concat(this._createNullMeasureArray());
  167. };
  168. QueryResultDataPointsV2.prototype._createNullMeasureArray = function _createNullMeasureArray() {
  169. var nullMeasureArray = [];
  170. for (var i = 0; i < this._measureCount; ++i) {
  171. nullMeasureArray.push({ v: this.missingValue });
  172. }
  173. return nullMeasureArray;
  174. };
  175. //The edge size is the number of items in the item array for an edge (minus the hasNext item)
  176. QueryResultDataPointsV2.prototype._getEdgeSize = function _getEdgeSize(edges, edgeIndex) {
  177. var edgeItems = edges[edgeIndex] && edges[edgeIndex].items;
  178. var edgeSize = edgeItems && edgeItems.length;
  179. if (edgeSize && edgeItems[edgeSize - 1].hasNext) {
  180. edgeSize--;
  181. }
  182. return edgeSize;
  183. };
  184. QueryResultDataPointsV2.prototype._getFirstEdgeIndex = function _getFirstEdgeIndex() {
  185. return this.getMeasureEdgeIndex() === 0 ? 1 : 0;
  186. };
  187. QueryResultDataPointsV2.prototype._getSecondEdgeIndex = function _getSecondEdgeIndex() {
  188. return this._edgeCount === 3 ? this._getFirstEdgeIndex() + 1 : null;
  189. };
  190. return QueryResultDataPointsV2;
  191. }();
  192. });
  193. //# sourceMappingURL=QueryResultDataPoints.v2.js.map