]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/dojo/openils/PermaCrud.js
prevent case where .recv() is called more than once on a single response. on sync...
[working/Evergreen.git] / Open-ILS / web / js / dojo / openils / PermaCrud.js
1 /* ---------------------------------------------------------------------------
2  * Copyright (C) 2008  Equinox Software, Inc
3  * Mike Rylander <miker@esilibrary.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  * ---------------------------------------------------------------------------
15  */
16
17 if(!dojo._hasResource["openils.PermaCrud"]) {
18
19     dojo._hasResource["openils.PermaCrud"] = true;
20     dojo.provide("openils.PermaCrud");
21     dojo.require("fieldmapper.Fieldmapper");
22     dojo.require("openils.User");
23
24     dojo.declare('openils.PermaCrud', null, {
25
26         session : null,
27         authtoken : null,
28         connnected : false,
29
30         constructor : function ( kwargs ) {
31             kwargs = kwargs || {};
32
33             this.authtoken = kwargs.authtoken;
34
35             this.session =
36                 kwargs.session ||
37                 new OpenSRF.ClientSession('open-ils.pcrud');
38
39             if (
40                 this.session &&
41                 this.session.state == OSRF_APP_SESSION_CONNECTED
42             ) this.connected = true;
43         },
44
45         auth : function (token) {
46             if (token) this.authtoken = token;
47             return this.authtoken || openils.User.authtoken;
48         },
49
50         connect : function ( onerror ) {
51             if (!this.connected && !this.session.connect()) {
52                 this.connected = false;
53                 if (onerror) onerror(this.session);
54                 return false;
55             }
56             this.connected = true;
57             return true;
58         },
59
60         disconnect : function ( onerror ) {
61             if (!this.session.disconnect()) {
62                 if (onerror) onerror(this.session);
63                 return false;
64             }
65             return true;
66         },
67         
68
69         retrieve : function ( fm_class /* Fieldmapper class hint */, id /* Fieldmapper object primary key value */,  opts /* Option hash */) {
70             if(!opts) opts = {};
71             var req_hash = dojo.mixin(
72                 opts, 
73                 { method : 'open-ils.pcrud.retrieve.' + fm_class,
74                   params : [ this.auth(), id ]
75                 }
76             );
77
78             if (!opts.async && !opts.timeout) req_hash.timeout = 10;
79
80             var _pcrud = this;
81             var req = this.session.request( req_hash );
82
83             if (!req.onerror)
84                 req.onerror = function (r) { throw js2JSON(r); };
85
86             // if it's an async call and the user does not care about 
87             // the responses, pull them off the network and discard them
88             if (!req_hash.timeout && !req.oncomplete)
89                 req.oncomplete = function (r) { while(r.recv()){}; };
90
91             req.send();
92
93             // for synchronous calls with no handlers, return the first received value
94             if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
95                 var resp = req.recv();
96                 if(resp) return resp.content();
97                 return null;
98             }
99
100             return req;
101         },
102
103         retrieveAll : function ( fm_class /* Fieldmapper class hint */, opts /* Option hash */) {
104             var pkey = fieldmapper[fm_class].Identifier;
105
106             if(!opts) opts = {};
107             var order_by = {};
108             if (opts.order_by) order_by.order_by = opts.order_by;
109             if (opts.select) order_by.select = opts.select;
110             
111             var method = 'open-ils.pcrud.search.' + fm_class;
112             if(!opts.streaming) method += '.atomic';
113
114             var search = {};
115             search[pkey] = { '!=' : null };
116
117             var req_hash = dojo.mixin(
118                 opts, 
119                 { method : method,
120                   params : [ this.auth(), search, order_by ]
121                 }
122             );
123
124             if (!opts.async && !opts.timeout) req_hash.timeout = 10;
125
126             var _pcrud = this;
127             var req = this.session.request( req_hash );
128
129             if (!req.onerror)
130                 req.onerror = function (r) { throw js2JSON(r); };
131             
132             // if it's an async call and the user does not care about 
133             // the responses, pull them off the network and discard them
134             if (!req_hash.timeout && !req.oncomplete)
135                 req.oncomplete = function (r) { while(r.recv()){}; };
136
137             req.send();
138
139             // for synchronous calls with no handlers, return the first received value
140             if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
141                 var resp = req.recv();
142                 if(resp) return resp.content();
143                 return null;
144             }
145
146             return req;
147         },
148
149         search : function ( fm_class /* Fieldmapper class hint */, search /* Fieldmapper query object */, opts /* Option hash */) {
150             if(!opts) opts = {};
151             var order_by = {};
152             if (opts.order_by) order_by.order_by = opts.order_by;
153             if (opts.select) order_by.select = opts.select;
154
155             var method = 'open-ils.pcrud.search.' + fm_class;
156             if(!opts.streaming) method += '.atomic';
157
158             var req_hash = dojo.mixin(
159                 opts, 
160                 { method : method,
161                   params : [ this.auth(), search, order_by ]
162                 }
163             );
164
165             if (!opts.async && !opts.timeout) req_hash.timeout = 10;
166
167             var _pcrud = this;
168             var req = this.session.request( req_hash );
169
170             if (!req.onerror)
171                 req.onerror = function (r) { throw js2JSON(r); };
172
173             // if it's an async call and the user does not care about 
174             // the responses, pull them off the network and discard them
175             if (!req_hash.timeout && !req.oncomplete)
176                 req.oncomplete = function (r) { while(r.recv()){}; };
177
178             req.send();
179
180             // for synchronous calls with no handlers, return the first received value
181             if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
182                 var resp = req.recv();
183                 if(resp) return resp.content();
184                 return null;
185             }
186
187             return req;
188         },
189
190         _CUD : function ( method /* 'create' or 'update' or 'delete' */, list /* Fieldmapper object */, opts /* Option hash */) {
191             if(!opts) opts = {};
192
193             if (dojo.isArray(list)) {
194                 if (list.classname) list = [ list ];
195             } else {
196                 list = [ list ];
197             }
198
199             if (!this.connected) this.connect();
200
201             var _pcrud = this;
202
203             function _CUD_recursive ( obj_list, pos, final_complete, final_error ) {
204                 var obj = obj_list[pos];
205                 var req_hash = {
206                     method : 'open-ils.pcrud.' + method + '.' + obj.classname,
207                     params : [ _pcrud.auth(), obj ],
208                     onerror : final_error || function (r) { _pcrud.disconnect(); throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj); }
209                 };
210
211                 var req = _pcrud.session.request( req_hash );
212                 req._final_complete = final_complete;
213                 req._final_error = final_error;
214
215                 if (++pos == obj_list.length) {
216                     req.oncomplete = function (r) {
217
218                         _pcrud.session.request({
219                             method : 'open-ils.pcrud.transaction.commit',
220                             timeout : 10,
221                             params : [ _pcrud.auth() ],
222                             onerror : function (r) {
223                                 _pcrud.disconnect();
224                                 throw 'Transaction commit error';
225                             },      
226                             oncomplete : function (r) {
227                                 var res = r.recv();
228                                 if ( res && res.content() ) {
229                                     if(req._final_complete)
230                                         req._final_complete(req);
231                                     _pcrud.disconnect();
232                                 } else {
233                                     _pcrud.disconnect();
234                                     throw 'Transaction commit error';
235                                 }
236                             },
237                         }).send();
238                     };
239
240                     req.onerror = function (r) {
241                         if (r._final_error) r._final_error(r);
242                         _pcrud.disconnect();
243                     };
244
245                 } else {
246                     req._pos = pos;
247                     req._obj_list = obj_list;
248                     req.oncomplete = function (r) {
249                         var res = r.recv();
250                         if ( res && res.content() ) {
251                             _CUD_recursive( r._obj_list, r._pos, r._final_complete );
252                         } else {
253                             _pcrud.disconnect();
254                             throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
255                         }
256                     };
257                 }
258
259                 req.send();
260             }
261
262             var f_complete = opts.oncomplete;
263             var f_error = opts.onerror;
264
265             this.session.request({
266                 method : 'open-ils.pcrud.transaction.begin',
267                 timeout : 10,
268                 params : [ _pcrud.auth() ],
269                 onerror : function (r) {
270                     _pcrud.disconnect();
271                     throw 'Transaction begin error';
272                 },      
273                 oncomplete : function (r) {
274                     var res = r.recv();
275                     if ( res && res.content() ) {
276                         _CUD_recursive( list, 0, f_complete, f_error );
277                     } else {
278                         _pcrud.disconnect();
279                         throw 'Transaction begin error';
280                     }
281                 },
282             }).send();
283         },
284
285         create : function ( list, opts ) {
286             this._CUD( 'create', list, opts );
287         },
288
289         update : function ( list, opts ) {
290             this._CUD( 'update', list, opts );
291         },
292
293         delete : function ( list, opts ) {
294             this._CUD( 'delete', list, opts );
295         },
296
297         apply : function ( list, opts ) {
298             this._auto_CUD( list, opts );
299         },
300
301         _auto_CUD : function ( list /* Fieldmapper object */, opts /* Option hash */) {
302
303             if(!opts) opts = {};
304
305             if (dojo.isArray(list)) {
306                 if (list.classname) list = [ list ];
307             } else {
308                 list = [ list ];
309             }
310
311             if (!this.connected) this.connect();
312
313             var _pcrud = this;
314
315             function _auto_CUD_recursive ( obj_list, pos, final_complete, final_error ) {
316                 var obj = obj_list[pos];
317
318                 var method;
319                 if (obj.ischanged()) method = 'update';
320                 if (obj.isnew())     method = 'create';
321                 if (obj.isdeleted()) method = 'delete';
322                 if (!method) throw 'No action detected';
323
324                 var req_hash = {
325                     method : 'open-ils.pcrud.' + method + '.' + obj.classname,
326                     timeout : 10,
327                     params : [ _pcrud.auth(), obj ],
328                     onerror : final_error || function (r) { _pcrud.disconnect(); throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj); }
329                 };
330
331                 var req = _pcrud.session.request( req_hash );
332                 req._final_complete = final_complete;
333                 req._final_error = final_error;
334
335                 if (++pos == obj_list.length) {
336                     req.oncomplete = function (r) {
337
338                         _pcrud.session.request({
339                             method : 'open-ils.pcrud.transaction.commit',
340                             timeout : 10,
341                             params : [ _pcrud.auth() ],
342                             onerror : function (r) {
343                                 _pcrud.disconnect();
344                                 throw 'Transaction commit error';
345                             },      
346                             oncomplete : function (r) {
347                                 var res = r.recv();
348                                 if ( res && res.content() ) {
349                                     _auto_CUD_recursive( list, 0 );
350                                 } else {
351                                     _pcrud.disconnect();
352                                     throw 'Transaction commit error';
353                                 }
354                             },
355                         }).send();
356
357                         if (r._final_complete) r._final_complete(r);
358                         _pcrud.disconnect();
359                     };
360
361                     req.onerror = function (r) {
362                         if (r._final_error) r._final_error(r);
363                         _pcrud.disconnect();
364                     };
365
366                 } else {
367                     req._pos = pos;
368                     req._obj_list = obj_list;
369                     req.oncomplete = function (r) {
370                         var res = r.recv();
371                         if ( res && res.content() ) {
372                             _auto_CUD_recursive( r._obj_list, r._pos, r._final_complete, r._final_error );
373                         } else {
374                             _pcrud.disconnect();
375                             throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj);
376                         }
377                     };
378                 }
379
380                 req.send();
381             }
382
383             var f_complete = opts.oncomplete;
384             var f_error = opts.onerror;
385
386             this.session.request({
387                 method : 'open-ils.pcrud.transaction.begin',
388                 timeout : 10,
389                 params : [ _pcrud.auth() ],
390                 onerror : function (r) {
391                     _pcrud.disconnect();
392                     throw 'Transaction begin error';
393                 },      
394                 oncomplete : function (r) {
395                     var res = r.recv();
396                     if ( res && res.content() ) {
397                         _auto_CUD_recursive( list, 0, f_complete, f_error );
398                     } else {
399                         _pcrud.disconnect();
400                         throw 'Transaction begin error';
401                     }
402                 },
403             }).send();
404         }
405
406     });
407 }
408
409