rsDatasetService.js 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367
  1. /**
  2. * Licensed Materials - Property of IBM
  3. * IBM Cognos Products: rs
  4. * (C) Copyright IBM Corp. 2020
  5. * US Government Users Restricted Rights - Use, duplication or disclosure restricted by GSA ADP Schedule Contract with IBM Corp.
  6. *
  7. */
  8. define([
  9. 'baglass/core-client/js/core-client/ui/core/Class',
  10. 'bi/authoring/utils/pat/rsLaunchParameters',
  11. 'q'
  12. ], function(Class, rsLaunchParameters, Q) {
  13. 'use strict';
  14. /**
  15. * Utility class that does the real work of creating a dataset
  16. */
  17. function C_DatasetCreator( glassContext )
  18. {
  19. this._glassContext = glassContext;
  20. this._deferred = Q.defer();
  21. };
  22. C_DatasetCreator._serializer = new XMLSerializer();
  23. /**
  24. * Perform XML parsing of a string
  25. */
  26. C_DatasetCreator.prototype.parseString = function( v_sXML )
  27. {
  28. var doc = null;
  29. try
  30. {
  31. doc = ( new DOMParser() ).parseFromString( v_sXML, "text/xml" );
  32. }
  33. catch ( e )
  34. {
  35. // IE throws an error
  36. return null;
  37. }
  38. if (doc.documentElement.querySelector("parsererror") || doc.documentElement.nodeName == "parsererror") {
  39. // Chrome injects parsererror in the document where the error occurred, others set the root as parsererror with a namespace
  40. return null;
  41. }
  42. return doc;
  43. };
  44. C_DatasetCreator.prototype.addDataItem = function( v_nSelection, v_oItem )
  45. {
  46. var v_nDataItem = v_nSelection.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "dataItem"));
  47. v_nDataItem.setAttribute("name", v_oItem.name);
  48. if (v_oItem.aggregate) {
  49. v_nDataItem.setAttribute("aggregate", v_oItem.aggregate);
  50. }
  51. if (v_oItem.rollupAggregate) {
  52. v_nDataItem.setAttribute("rollupAggregate", v_oItem.rollupAggregate);
  53. }
  54. var expression = v_nDataItem.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "expression"));
  55. expression.appendChild(this.v_nDoc.createTextNode(v_oItem.expression));
  56. };
  57. C_DatasetCreator.prototype.addStyle = function( v_nParent, v_sRefStyle )
  58. {
  59. var v_nStyle = v_nParent.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "style"));
  60. var v_nDefaultStyles = v_nStyle.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "defaultStyles"));
  61. var v_nDefaultStyle = v_nDefaultStyles.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "defaultStyle"));
  62. v_nDefaultStyle.setAttribute("refStyle", v_sRefStyle);
  63. };
  64. C_DatasetCreator.prototype.addDataSource = function( v_nParent, v_sDataItemName, v_sName )
  65. {
  66. var v_nContents = v_nParent.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "contents"));
  67. var v_nTextItem = v_nContents.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "textItem"));
  68. var v_nDataSource = v_nTextItem.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "dataSource"));
  69. var v_nDataItem = v_nDataSource.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, v_sDataItemName));
  70. v_nDataItem.setAttribute("refDataItem", v_sName);
  71. };
  72. C_DatasetCreator.prototype.addTitle = function( v_nListColumn, v_sName )
  73. {
  74. var v_nListColumnTitle = v_nListColumn.appendChild( this.v_nDoc.createElementNS(this.m_sNamespace, "listColumnTitle"));
  75. this.addStyle(v_nListColumnTitle, "lt");
  76. this.addDataSource(v_nListColumnTitle, "dataItemLabel", v_sName);
  77. };
  78. C_DatasetCreator.prototype.addBody = function( v_nListColumn, v_oItem )
  79. {
  80. var v_nListColumnBody = v_nListColumn.appendChild( this.v_nDoc.createElementNS(this.m_sNamespace, "listColumnBody"));
  81. this.addStyle(v_nListColumnBody, v_oItem.measure ? "lm" : "lc");
  82. this.addDataSource(v_nListColumnBody, "dataItemValue", v_oItem.name);
  83. };
  84. C_DatasetCreator.prototype.addColumn = function( v_nListColumns, v_oItem )
  85. {
  86. var v_nListColumn = v_nListColumns.appendChild( this.v_nDoc.createElementNS(this.m_sNamespace, "listColumn"));
  87. this.addTitle(v_nListColumn, v_oItem.name);
  88. this.addBody(v_nListColumn, v_oItem);
  89. };
  90. C_DatasetCreator.prototype.getSpecVersion = function()
  91. {
  92. return this._glassContext.services.ajax.ajax({
  93. type : 'GET',
  94. url : '../schemas/rspec/version.json'
  95. }).then(function(v_oResponse){
  96. return v_oResponse.version;
  97. });
  98. };
  99. C_DatasetCreator.prototype.getCMInfo = function( v_sID )
  100. {
  101. return this._glassContext.services.ajax.ajax({
  102. type : 'GET',
  103. url : "v1/objects/" + v_sID + "?fields=searchPath,type"
  104. }).then( function(v_oResponse) {
  105. return v_oResponse.data[0];
  106. });
  107. };
  108. C_DatasetCreator.prototype.raiseError = function( v_sMsg )
  109. {
  110. console.log("rsDatasetService.createDataset: " + v_sMsg);
  111. this._deferred.reject( new Error(v_sMsg) );
  112. };
  113. C_DatasetCreator.prototype.setUpdateAction = function( v_sUpdateAction )
  114. {
  115. switch (v_sUpdateAction) {
  116. case 'fail':
  117. case 'replace':
  118. case 'update':
  119. case null:
  120. case undefined:
  121. this.m_sUpdateAction = v_sUpdateAction;
  122. break;
  123. default:
  124. delete this.m_sUpdateAction;
  125. }
  126. };
  127. C_DatasetCreator.prototype.setNames = function( v_sName, v_sQueryName )
  128. {
  129. this.m_sName = v_sName;
  130. this.m_sQueryName = v_sQueryName || v_sName || 'Query1';
  131. };
  132. C_DatasetCreator.prototype.loadItems = function( v_aItems )
  133. {
  134. // Create a map of existing names
  135. var v_oSpecifiedNames = {};
  136. v_aItems.forEach( function(v_oItem) {
  137. if (v_oItem.name) {
  138. if (v_oSpecifiedNames[v_oItem.name]) {
  139. // Duplicate name
  140. this.raiseError( "Duplicate item name " + v_oItem.name);
  141. return this._deferred.promise;
  142. }
  143. v_oSpecifiedNames[v_oItem.name] = true;
  144. }
  145. }.bind(this));
  146. // Assign unique name if none specified
  147. var i = 0;
  148. v_aItems.forEach( function(v_oItem) {
  149. if (!v_oItem.name) {
  150. var v_sName = 'Data Item' + (++i);
  151. while (v_oSpecifiedNames[v_sName]) {
  152. v_sName = 'Data Item' + (++i);
  153. }
  154. v_oItem.name = v_sName;
  155. }
  156. });
  157. this.m_aItems = v_aItems;
  158. return null;
  159. };
  160. C_DatasetCreator.prototype.generateSpecification = function(v_oMetadata, v_bExclude, v_bSummarize)
  161. {
  162. // Remove top level comments (template copyright)
  163. for (var v_nNode = this.v_nDoc.firstChild; v_nNode != null; ) {
  164. var v_nNext = v_nNode.nextSibling;
  165. if (v_nNode.nodeType == Node.COMMENT_NODE) {
  166. this.v_nDoc.removeChild(v_nNode);
  167. }
  168. v_nNode = v_nNext;
  169. }
  170. var v_nReport = this.v_nDoc.documentElement;
  171. if (this.m_sName) {
  172. var v_nReportName = v_nReport.appendChild(this.v_nDoc.createElementNS(this.m_sNamespace, "reportName"));
  173. v_nReportName.appendChild(this.v_nDoc.createTextNode(this.m_sName));
  174. }
  175. // set refQuery in list
  176. var v_nList = v_nReport.querySelector("list");
  177. v_nList.setAttribute("refQuery", this.m_sQueryName);
  178. v_nList.setAttribute("name", "List1");
  179. // rename query
  180. var v_nQuery = v_nReport.querySelector("query");
  181. v_nQuery.setAttribute("name", this.m_sQueryName);
  182. // set modelPath
  183. var v_nModelPath = v_nReport.querySelector("modelPath");
  184. var v_sSearchPath = v_oMetadata.searchPath;
  185. switch (v_oMetadata.type) {
  186. case "module":
  187. v_nModelPath.setAttribute("type", "module");
  188. break;
  189. case "package":
  190. v_sSearchPath += "/model[last()]";
  191. break;
  192. case "model":
  193. break;
  194. default:
  195. this.raiseError( 'Metadata ID references invalid object of type ' + v_oMetadata.type );
  196. return;
  197. }
  198. v_nModelPath.appendChild(this.v_nDoc.createTextNode(v_oMetadata.searchPath));
  199. // set autoSummary=false on query/selection
  200. var v_nSelection = v_nQuery.querySelector("selection");
  201. if (!v_bSummarize) {
  202. v_nSelection.setAttribute("autoSummary", "false");
  203. }
  204. // iterate over items
  205. var v_nListColumns = v_nList.appendChild( this.v_nDoc.createElementNS(this.m_sNamespace, "listColumns"));
  206. this.m_aItems.forEach( function(v_oItem) {
  207. this.addColumn(v_nListColumns, v_oItem);
  208. this.addDataItem(v_nSelection, v_oItem);
  209. }.bind(this));
  210. // set listSupress
  211. if (v_bExclude) {
  212. v_nList.appendChild( this.v_nDoc.createElementNS(this.m_sNamespace, "listSuppress"));
  213. }
  214. };
  215. C_DatasetCreator.prototype.create = function( v_sParentId, v_sMetadataId, v_bExclude, v_bSummarize, v_aParameters )
  216. {
  217. this.getSpecVersion().then(function(v_sVersion){
  218. this.m_sNamespace = 'http://developer.cognos.com/schemas/report/' + v_sVersion + '/';
  219. this.getCMInfo(v_sMetadataId).then( function(v_oMetadata) {
  220. // Retrieve dataset list template and parse
  221. var v_sTemplate = rsLaunchParameters.GetTemplate( 'DatasetList' );
  222. // Inject namespace attribute into template
  223. v_sTemplate = v_sTemplate.replace( /<report /, '<report xmlns="' + this.m_sNamespace + '" ');
  224. this.v_nDoc = this.parseString( v_sTemplate );
  225. if (!this.v_nDoc) {
  226. this.raiseError( "Failed to parse template" );
  227. return;
  228. }
  229. this.generateSpecification(v_oMetadata, v_bExclude, v_bSummarize);
  230. var v_sSpecification = C_DatasetCreator._serializer.serializeToString( this.v_nDoc );
  231. // POST to report service to create the dataset object
  232. var v_oDataset = {
  233. type: 'dataSet2',
  234. defaultName: this.m_sName || undefined,
  235. specification: v_sSpecification,
  236. parameters: v_aParameters || undefined,
  237. runInAdvancedViewer: true
  238. };
  239. var v_aUrl = ['v1/reports/', v_sParentId];
  240. if (this.m_sUpdateAction) {
  241. v_aUrl.push('?updateAction=');
  242. v_aUrl.push(this.m_sUpdateAction);
  243. }
  244. var v_oRequest = {
  245. type : 'POST',
  246. url : v_aUrl.join(''),
  247. contentType: "application/json",
  248. data : JSON.stringify(v_oDataset)
  249. };
  250. this._glassContext.services.ajax.ajax(v_oRequest).then(function(v_oResponse){
  251. this._deferred.resolve(v_oResponse);
  252. }.bind(this))
  253. .fail(function(x, http, y){
  254. this.raiseError( 'Server request to create dataset failed. ' + http.status + " " + http.statusText );
  255. }.bind(this));
  256. }.bind(this))
  257. .fail(function(v_oErr) {
  258. this.raiseError( "Invalid metadata ID" );
  259. }.bind(this));
  260. }.bind(this));
  261. return this._deferred.promise;
  262. };
  263. var rsDatasetService = Class.extend({
  264. init: function(attributes) {
  265. this._glassContext = attributes.glassContext;
  266. rsDatasetService.inherited('init', this, arguments);
  267. },
  268. /**
  269. * Create a dataset object.
  270. * @param v_sName (optional) The name of the dataset. If unspecified, a unique name will be generated by the system.
  271. * @param v_sQueryName (optional) The name of the query in the dataset. If unspecified, use v_sName or "Query1".
  272. * @param v_sParentId The ID of the object under which the dataset will be created
  273. * @param v_sMetadataId The ID of the metadata source (module/package/model)
  274. * @param v_bExclude Whether or not to exclude
  275. * @param v_bSummarize Whether or not auto summarization should be used
  276. * @param v_aParameters The parameter values to be stored with the dataset
  277. * @param v_aItems Array of data item names and corresponding expressions as in
  278. * [
  279. * {
  280. * name: "ProductLine", - (optional) a unique name of the form "Data Item#" will be generated if none provided
  281. * expression: "[Inventory (query)].[Products].[Product line]" - a V5 query expression
  282. * aggregate: (optional) aggregation mode from V5 spec
  283. * rollupAggregate: (optional) aggregation mode from V5 spec
  284. * measure: (optional) true/false- used to determine styling of list
  285. * }
  286. * ...
  287. * ]
  288. * @param v_sUpdateAction How object name collisions are resolved. Values other than the following are ignored: fail, replace, update
  289. * The default is fail.
  290. *
  291. * @return A promise that will resolve with the new datatastore object e.g.
  292. * {
  293. * searchPath: "/content/folder[@name='Data Sets']/dataSet2[@name='myDataset']"
  294. * _meta: {links: {…}}
  295. * id: "i96D7B925A62746988FD5ACD4814B266C"
  296. * type: "dataSet2"
  297. * defaultName: "myDataset"
  298. * }
  299. *
  300. * The aggregation values from the V5 specification are currently:
  301. * none, automatic, summarize, total, minimum, maximum, average, count, calculated,
  302. * countDistinct, standardDeviation, variance, median, notApplicable
  303. *
  304. * Parameter values are specified as an array of parameter objects using the JSON representation of CA parameter values
  305. * as per the soap-bridge or content-service.
  306. * [
  307. * {
  308. * name: "parameterName",
  309. * value: [...]
  310. * }
  311. * ...
  312. * ]
  313. * where the value objects for simple values are
  314. * {
  315. * type: "simpleParmValueItem",
  316. * use: "use value",
  317. * display: "display value" (optional)
  318. * inclusive: true
  319. * }
  320. */
  321. createDataset: function( v_sName, v_sQueryName, v_sParentId, v_sMetadataId, v_bExclude, v_bSummarize, v_aParameters, v_aItems, v_sUpdateAction ) {
  322. var creator = new C_DatasetCreator( this._glassContext );
  323. creator.setNames( v_sName, v_sQueryName );
  324. creator.setUpdateAction( v_sUpdateAction );
  325. var v_oError = creator.loadItems(v_aItems);
  326. return v_oError || creator.create( v_sParentId, v_sMetadataId, v_bExclude, v_bSummarize, v_aParameters );
  327. }
  328. });
  329. return rsDatasetService;
  330. });