SnapLogicStore.js 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338
  1. /*
  2. Copyright (c) 2004-2012, The Dojo Foundation All Rights Reserved.
  3. Available via Academic Free License >= 2.1 OR the modified BSD license.
  4. see: http://dojotoolkit.org/license for details
  5. */
  6. if(!dojo._hasResource["dojox.data.SnapLogicStore"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
  7. dojo._hasResource["dojox.data.SnapLogicStore"] = true;
  8. dojo.provide("dojox.data.SnapLogicStore");
  9. dojo.require("dojo.io.script");
  10. dojo.require("dojo.data.util.sorter");
  11. dojo.declare("dojox.data.SnapLogicStore", null, {
  12. Parts: {
  13. DATA: "data",
  14. COUNT: "count"
  15. },
  16. url: "",
  17. constructor: function(/* Object */args){
  18. // summary:
  19. // Initialize a SnapLogicStore object.
  20. // args:
  21. // An object that contains properties for initializing the new data store object. The
  22. // following properties are understood:
  23. // url:
  24. // A URL to the SnapLogic pipeline's output routed through PipeToHttp. Typically, this
  25. // will look like "http://<server-host>:<port>/pipe/<pipeline-url>/<pipeline-output-view>".
  26. // parameters:
  27. // An object whose properties define parameters to the pipeline. The values of these
  28. // properties will be sent to the pipeline as parameters when it run.
  29. //
  30. if(args.url){
  31. this.url = args.url;
  32. }
  33. this._parameters = args.parameters;
  34. },
  35. _assertIsItem: function(/* item */item){
  36. // summary:
  37. // This function tests whether the item passed in is indeed an item in the store.
  38. // item:
  39. // The item to test for being contained by the store.
  40. if(!this.isItem(item)){
  41. throw new Error("dojox.data.SnapLogicStore: a function was passed an item argument that was not an item");
  42. }
  43. },
  44. _assertIsAttribute: function(/* attribute-name-string */ attribute){
  45. // summary:
  46. // This function tests whether the item passed in is indeed a valid 'attribute' like type for the store.
  47. // attribute:
  48. // The attribute to test for being contained by the store.
  49. if(typeof attribute !== "string"){
  50. throw new Error("dojox.data.SnapLogicStore: a function was passed an attribute argument that was not an attribute name string");
  51. }
  52. },
  53. getFeatures: function(){
  54. // summary:
  55. // See dojo.data.api.Read.getFeatures()
  56. return {
  57. 'dojo.data.api.Read': true
  58. };
  59. },
  60. getValue: function(item, attribute, defaultValue){
  61. // summary:
  62. // See dojo.data.api.Read.getValue()
  63. this._assertIsItem(item);
  64. this._assertIsAttribute(attribute);
  65. var i = dojo.indexOf(item.attributes, attribute);
  66. if(i !== -1){
  67. return item.values[i];
  68. }
  69. return defaultValue;
  70. },
  71. getAttributes: function(item){
  72. // summary:
  73. // See dojo.data.api.Read.getAttributes()
  74. this._assertIsItem(item);
  75. return item.attributes;
  76. },
  77. hasAttribute: function(item, attribute){
  78. // summary:
  79. // See dojo.data.api.Read.hasAttributes()
  80. this._assertIsItem(item);
  81. this._assertIsAttribute(attribute);
  82. for(var i = 0; i < item.attributes.length; ++i){
  83. if(attribute == item.attributes[i]){
  84. return true;
  85. }
  86. }
  87. return false;
  88. },
  89. isItemLoaded: function(item){
  90. // summary:
  91. // See dojo.data.api.Read.isItemLoaded()
  92. return this.isItem(item); // Boolean
  93. },
  94. loadItem: function(keywordArgs){
  95. // summary:
  96. // See dojo.data.api.Read.loadItem()
  97. },
  98. getLabel: function(item){
  99. // summary:
  100. // See dojo.data.api.Read.getLabel()
  101. return undefined;
  102. },
  103. getLabelAttributes: function(item){
  104. // summary:
  105. // See dojo.data.api.Read.getLabelAttributes()
  106. return null;
  107. },
  108. containsValue: function(item, attribute, value){
  109. // summary:
  110. // See dojo.data.api.Read.containsValue()
  111. return this.getValue(item, attribute) === value; // Boolean
  112. },
  113. getValues: function(item, attribute){
  114. // summary:
  115. // See dojo.data.api.Read.getValue()
  116. this._assertIsItem(item);
  117. this._assertIsAttribute(attribute);
  118. var i = dojo.indexOf(item.attributes, attribute);
  119. if(i !== -1){
  120. return [item.values[i]]; // Array
  121. }
  122. return [];
  123. },
  124. isItem: function(item){
  125. // summary:
  126. // See dojo.data.api.Read.isItem()
  127. if(item && item._store === this){
  128. return true;
  129. }
  130. return false;
  131. },
  132. close: function(request){
  133. // summary:
  134. // See dojo.data.api.Read.close()
  135. },
  136. _fetchHandler: function(/* Object */request){
  137. // summary:
  138. // Process data retrieved via fetch and send it back to requester.
  139. // response:
  140. // The data returend from the I/O transport. In the normal case, it will be an array of result rows
  141. // from the pipeline. In the special case for record count optimization, response will be an array
  142. // with a single element containing the total pipeline result row count. See fetch() for details
  143. // on this optimization.
  144. var scope = request.scope || dojo.global;
  145. if(request.onBegin){
  146. // Check for the record count optimization
  147. request.onBegin.call(scope, request._countResponse[0], request);
  148. }
  149. if(request.onItem || request.onComplete){
  150. var response = request._dataResponse;
  151. if(!response.length){
  152. request.onError.call(scope,
  153. new Error("dojox.data.SnapLogicStore: invalid response of length 0"),
  154. request);
  155. return;
  156. }else if(request.query != 'record count'){
  157. //If this was not a record count request, the first element returned will contain
  158. //the field names.
  159. var field_names = response.shift();
  160. var items = [];
  161. for(var i = 0; i < response.length; ++i){
  162. if(request._aborted){
  163. break;
  164. }
  165. items.push({attributes: field_names, values: response[i], _store: this});
  166. }
  167. if(request.sort && !request._aborted){
  168. items.sort(dojo.data.util.sorter.createSortFunction(request.sort, self));
  169. }
  170. }else{
  171. //This is a record count request, so manually set the field names.
  172. items = [({attributes: ['count'], values: response, _store: this})];
  173. }
  174. if(request.onItem){
  175. for(var i = 0; i < items.length; ++i){
  176. if(request._aborted){
  177. break;
  178. }
  179. request.onItem.call(scope, items[i], request);
  180. }
  181. items = null;
  182. }
  183. if(request.onComplete && !request._aborted){
  184. request.onComplete.call(scope, items, request);
  185. }
  186. }
  187. },
  188. _partHandler: function(/* Object */request, /* String */part, /* Object */response){
  189. // summary:
  190. // Handle the individual replies for both data and length requests.
  191. // request:
  192. // The request/handle object used with the original fetch() call.
  193. // part:
  194. // A value indicating which request this handler call is for (this.Parts).
  195. // response:
  196. // Response received from the underlying IO transport.
  197. if(response instanceof Error){
  198. if(part == this.Parts.DATA){
  199. request._dataHandle = null;
  200. }else{
  201. request._countHandle = null;
  202. }
  203. request._aborted = true;
  204. if(request.onError){
  205. request.onError.call(request.scope, response, request);
  206. }
  207. }else{
  208. if(request._aborted){
  209. return;
  210. }
  211. if(part == this.Parts.DATA){
  212. request._dataResponse = response;
  213. }else{
  214. request._countResponse = response;
  215. }
  216. if((!request._dataHandle || request._dataResponse !== null) &&
  217. (!request._countHandle || request._countResponse !== null)){
  218. this._fetchHandler(request);
  219. }
  220. }
  221. },
  222. fetch: function(/* Object */request){
  223. // summary:
  224. // See dojo.data.api.Read.close()
  225. // request:
  226. // See dojo.data.api.Read.close() for generic interface.
  227. //
  228. // In addition to the standard Read API fetch support, this store supports an optimization for
  229. // for retrieving the total count of records in the Pipeline without retrieving the data. To
  230. // use this optimization, simply provide an onBegin handler without an onItem or onComplete handler.
  231. request._countResponse = null;
  232. request._dataResponse = null;
  233. request._aborted = false;
  234. request.abort = function(){
  235. if(!request._aborted){
  236. request._aborted = true;
  237. if(request._dataHandle && request._dataHandle.cancel){
  238. request._dataHandle.cancel();
  239. }
  240. if(request._countHandle && request._countHandle.cancel){
  241. request._countHandle.cancel();
  242. }
  243. }
  244. };
  245. // Only make the call for data if onItem or onComplete is used. Otherwise, onBegin will only
  246. // require the total row count.
  247. if(request.onItem || request.onComplete){
  248. var content = this._parameters || {};
  249. if(request.start){
  250. if(request.start < 0){
  251. throw new Error("dojox.data.SnapLogicStore: request start value must be 0 or greater");
  252. }
  253. content['sn.start'] = request.start + 1;
  254. }
  255. if(request.count){
  256. if(request.count < 0){
  257. throw new Error("dojox.data.SnapLogicStore: request count value 0 or greater");
  258. }
  259. content['sn.limit'] = request.count;
  260. }
  261. content['sn.content_type'] = 'application/javascript';
  262. var store = this;
  263. var handler = function(response, ioArgs){
  264. if(response instanceof Error){
  265. store._fetchHandler(response, request);
  266. }
  267. };
  268. var getArgs = {
  269. url: this.url,
  270. content: content,
  271. // preventCache: true,
  272. timeout: 60000, //Starting a pipeline can take a long time.
  273. callbackParamName: "sn.stream_header",
  274. handle: dojo.hitch(this, "_partHandler", request, this.Parts.DATA)
  275. };
  276. request._dataHandle = dojo.io.script.get(getArgs);
  277. }
  278. if(request.onBegin){
  279. var content = {};
  280. content['sn.count'] = 'records';
  281. content['sn.content_type'] = 'application/javascript';
  282. var getArgs = {
  283. url: this.url,
  284. content: content,
  285. timeout: 60000,
  286. callbackParamName: "sn.stream_header",
  287. handle: dojo.hitch(this, "_partHandler", request, this.Parts.COUNT)
  288. };
  289. request._countHandle = dojo.io.script.get(getArgs);
  290. }
  291. return request; // Object
  292. }
  293. });
  294. }