]> git.evergreen-ils.org Git - working/Evergreen.git/blob - Open-ILS/web/js/dojo/openils/PermaCrud.js
permacrud CUD actions support an oncomplete handler, but the request object passed...
[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             this.connected = false;
62             return true;
63             // disconnect returns nothing, which is null, which is not true, cause the following to always run ... arg.
64             if (!this.session.disconnect()) {
65                 if (onerror) onerror(this.session);
66                 return false;
67             }
68         },
69         
70
71         retrieve : function ( fm_class /* Fieldmapper class hint */, id /* Fieldmapper object primary key value */,  opts /* Option hash */) {
72             if(!opts) opts = {};
73             var req_hash = dojo.mixin(
74                 opts, 
75                 { method : 'open-ils.pcrud.retrieve.' + fm_class,
76                   params : [ this.auth(), id ]
77                 }
78             );
79
80             if (!opts.async && !opts.timeout) req_hash.timeout = 10;
81
82             var _pcrud = this;
83             var req = this.session.request( req_hash );
84
85             if (!req.onerror)
86                 req.onerror = function (r) { throw js2JSON(r); };
87
88             // if it's an async call and the user does not care about 
89             // the responses, pull them off the network and discard them
90             if (!req_hash.timeout && !req.oncomplete)
91                 req.oncomplete = function (r) { while(r.recv()){}; };
92
93             req.send();
94
95             // for synchronous calls with no handlers, return the first received value
96             if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
97                 var resp = req.recv();
98                 if(resp) return resp.content();
99                 return null;
100             }
101
102             return req;
103         },
104
105         retrieveAll : function ( fm_class /* Fieldmapper class hint */, opts /* Option hash */) {
106             var pkey = fieldmapper[fm_class].Identifier;
107
108             if(!opts) opts = {};
109             var order_by = {};
110             if (opts.order_by) order_by.order_by = opts.order_by;
111             if (opts.select) order_by.select = opts.select;
112             if (opts.limit) order_by.limit = opts.limit;
113             if (opts.offset) order_by.offset = opts.offset;
114             
115             var method = 'open-ils.pcrud.search.' + fm_class;
116             if(!opts.streaming) method += '.atomic';
117
118             var search = {};
119             search[pkey] = { '!=' : null };
120
121             var req_hash = dojo.mixin(
122                 opts, 
123                 { method : method,
124                   params : [ this.auth(), search, order_by ]
125                 }
126             );
127
128             if (!opts.async && !opts.timeout) req_hash.timeout = 10;
129
130             var _pcrud = this;
131             var req = this.session.request( req_hash );
132
133             if (!req.onerror)
134                 req.onerror = function (r) { throw js2JSON(r); };
135             
136             // if it's an async call and the user does not care about 
137             // the responses, pull them off the network and discard them
138             if (!req_hash.timeout && !req.oncomplete)
139                 req.oncomplete = function (r) { while(r.recv()){}; };
140
141             req.send();
142
143             // for synchronous calls with no handlers, return the first received value
144             if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
145                 var resp = req.recv();
146                 if(resp) return resp.content();
147                 return null;
148             }
149
150             return req;
151         },
152
153         search : function ( fm_class /* Fieldmapper class hint */, search /* Fieldmapper query object */, opts /* Option hash */) {
154             if(!opts) opts = {};
155             var order_by = {};
156             if (opts.order_by) order_by.order_by = opts.order_by;
157             if (opts.select) order_by.select = opts.select;
158             if (opts.limit) order_by.limit = opts.limit;
159             if (opts.offset) order_by.offset = opts.offset;
160
161             var method = 'open-ils.pcrud.search.' + fm_class;
162             if(!opts.streaming) method += '.atomic';
163
164             var req_hash = dojo.mixin(
165                 opts, 
166                 { method : method,
167                   params : [ this.auth(), search, order_by ]
168                 }
169             );
170
171             if (!opts.async && !opts.timeout) req_hash.timeout = 10;
172
173             var _pcrud = this;
174             var req = this.session.request( req_hash );
175
176             if (!req.onerror)
177                 req.onerror = function (r) { throw js2JSON(r); };
178
179             // if it's an async call and the user does not care about 
180             // the responses, pull them off the network and discard them
181             if (!req_hash.timeout && !req.oncomplete)
182                 req.oncomplete = function (r) { while(r.recv()){}; };
183
184             req.send();
185
186             // for synchronous calls with no handlers, return the first received value
187             if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
188                 var resp = req.recv();
189                 if(resp) return resp.content();
190                 return null;
191             }
192
193             return req;
194         },
195
196         _CUD : function ( method /* 'create' or 'update' or 'delete' */, list /* Fieldmapper object */, opts /* Option hash */) {
197             if(!opts) opts = {};
198
199             if (dojo.isArray(list)) {
200                 if (list.classname) list = [ list ];
201             } else {
202                 list = [ list ];
203             }
204
205             if (!this.connected) this.connect();
206
207             var _pcrud = this;
208             var _return_list = [];
209
210             function _CUD_recursive ( obj_list, pos, final_complete, final_error ) {
211                 var obj = obj_list[pos];
212                 var req_hash = {
213                     method : 'open-ils.pcrud.' + method + '.' + obj.classname,
214                     params : [ _pcrud.auth(), obj ],
215                     onerror : final_error || function (r) { _pcrud.disconnect(); throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj); }
216                 };
217
218                 var req = _pcrud.session.request( req_hash );
219                 req._final_complete = final_complete;
220                 req._final_error = final_error;
221
222                 if (++pos == obj_list.length) {
223                     req.oncomplete = function (r) {
224                         var res = r.recv();
225
226                         if ( res && res.content() ) {
227                             _return_list.push( res.content() );
228                             _pcrud.session.request({
229                                 method : 'open-ils.pcrud.transaction.commit',
230                                 timeout : 10,
231                                 params : [ _pcrud.auth() ],
232                                 onerror : function (r) {
233                                     _pcrud.disconnect();
234                                     throw 'Transaction commit error';
235                                 },      
236                                 oncomplete : function (r) {
237                                     var res = r.recv();
238                                     if ( res && res.content() ) {
239                                         if(req._final_complete)
240                                             req._final_complete(req, _return_list);
241                                         _pcrud.disconnect();
242                                     } else {
243                                         _pcrud.disconnect();
244                                         throw 'Transaction commit error';
245                                     }
246                                 },
247                             }).send();
248                         } else {
249                             _pcrud.disconnect();
250                             throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
251                         }
252                     };
253
254                     req.onerror = function (r) {
255                         if (r._final_error) r._final_error(r);
256                         _pcrud.disconnect();
257                         throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
258                     };
259
260                 } else {
261                     req._pos = pos;
262                     req._obj_list = obj_list;
263                     req.oncomplete = function (r) {
264                         var res = r.recv();
265                         if ( res && res.content() ) {
266                             _return_list.push( res.content() );
267                             _CUD_recursive( r._obj_list, r._pos, r._final_complete );
268                         } else {
269                             _pcrud.disconnect();
270                             throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
271                         }
272                     };
273                     req.onerror = function (r) {
274                         if (r._final_error) r._final_error(r);
275                         _pcrud.disconnect();
276                         throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
277                     };
278                 }
279
280                 req.send();
281             }
282
283             var f_complete = opts.oncomplete;
284             var f_error = opts.onerror;
285
286             this.session.request({
287                 method : 'open-ils.pcrud.transaction.begin',
288                 timeout : 10,
289                 params : [ _pcrud.auth() ],
290                 onerror : function (r) {
291                     _pcrud.disconnect();
292                     throw 'Transaction begin error';
293                 },      
294                 oncomplete : function (r) {
295                     var res = r.recv();
296                     if ( res && res.content() ) {
297                         _CUD_recursive( list, 0, f_complete, f_error );
298                     } else {
299                         _pcrud.disconnect();
300                         throw 'Transaction begin error';
301                     }
302                 },
303             }).send();
304
305             return _return_list;
306
307         },
308
309         create : function ( list, opts ) {
310             return this._CUD( 'create', list, opts );
311         },
312
313         update : function ( list, opts ) {
314             var id_list = this._CUD( 'update', list, opts );
315             var obj_list = [];
316
317             for (var idx = 0; idx < id_list.length; idx++) {
318                 obj_list.push(
319                     this.retrieve( list[idx].classname, id_list[idx] )
320                 );
321             }
322
323             return obj_list;
324         },
325
326         delete : function ( list, opts ) {
327             return this._CUD( 'delete', list, opts );
328         },
329
330         /* 
331          * 'delete' is a reserved keyword in JavaScript and can't be used
332          * in browsers like IE or Chrome, so we define a safe synonym
333          */
334         eliminate: function ( list, opts ) {
335             return this._CUD( 'delete', list, opts );
336         },
337
338         apply : function ( list, opts ) {
339             this._auto_CUD( list, opts );
340         },
341
342         _auto_CUD : function ( list /* Fieldmapper object */, opts /* Option hash */) {
343
344             if(!opts) opts = {};
345
346             if (dojo.isArray(list)) {
347                 if (list.classname) list = [ list ];
348             } else {
349                 list = [ list ];
350             }
351
352             if (!this.connected) this.connect();
353
354             var _pcrud = this;
355
356             function _auto_CUD_recursive ( obj_list, pos, final_complete, final_error ) {
357                 var obj = obj_list[pos];
358
359                 var method;
360                 if (obj.ischanged()) method = 'update';
361                 if (obj.isnew())     method = 'create';
362                 if (obj.isdeleted()) method = 'delete';
363                 if (!method) throw 'No action detected';
364
365                 var req_hash = {
366                     method : 'open-ils.pcrud.' + method + '.' + obj.classname,
367                     timeout : 10,
368                     params : [ _pcrud.auth(), obj ],
369                     onerror : final_error || function (r) { _pcrud.disconnect(); throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj); }
370                 };
371
372                 var req = _pcrud.session.request( req_hash );
373                 req._final_complete = final_complete;
374                 req._final_error = final_error;
375
376                 if (++pos == obj_list.length) {
377                     req.oncomplete = function (r) {
378
379                         _pcrud.session.request({
380                             method : 'open-ils.pcrud.transaction.commit',
381                             timeout : 10,
382                             params : [ _pcrud.auth() ],
383                             onerror : function (r) {
384                                 _pcrud.disconnect();
385                                 throw 'Transaction commit error';
386                             },      
387                             oncomplete : function (r) {
388                                 var res = r.recv();
389                                 if ( res && res.content() ) {
390                                     _auto_CUD_recursive( list, 0 );
391                                 } else {
392                                     _pcrud.disconnect();
393                                     throw 'Transaction commit error';
394                                 }
395                             },
396                         }).send();
397
398                         if (r._final_complete) r._final_complete(r);
399                         _pcrud.disconnect();
400                     };
401
402                     req.onerror = function (r) {
403                         if (r._final_error) r._final_error(r);
404                         _pcrud.disconnect();
405                     };
406
407                 } else {
408                     req._pos = pos;
409                     req._obj_list = obj_list;
410                     req.oncomplete = function (r) {
411                         var res = r.recv();
412                         if ( res && res.content() ) {
413                             _auto_CUD_recursive( r._obj_list, r._pos, r._final_complete, r._final_error );
414                         } else {
415                             _pcrud.disconnect();
416                             throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj);
417                         }
418                     };
419                 }
420
421                 req.send();
422             }
423
424             var f_complete = opts.oncomplete;
425             var f_error = opts.onerror;
426
427             this.session.request({
428                 method : 'open-ils.pcrud.transaction.begin',
429                 timeout : 10,
430                 params : [ _pcrud.auth() ],
431                 onerror : function (r) {
432                     _pcrud.disconnect();
433                     throw 'Transaction begin error';
434                 },      
435                 oncomplete : function (r) {
436                     var res = r.recv();
437                     if ( res && res.content() ) {
438                         _auto_CUD_recursive( list, 0, f_complete, f_error );
439                     } else {
440                         _pcrud.disconnect();
441                         throw 'Transaction begin error';
442                     }
443                 },
444             }).send();
445         }
446
447     });
448 }
449
450