1 /* ---------------------------------------------------------------------------
2 * Copyright (C) 2008 Equinox Software, Inc
3 * Mike Rylander <miker@esilibrary.com>
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.
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 * ---------------------------------------------------------------------------
17 if(!dojo._hasResource["openils.PermaCrud"]) {
19 dojo._hasResource["openils.PermaCrud"] = true;
20 dojo.provide("openils.PermaCrud");
21 dojo.require("fieldmapper.Fieldmapper");
22 dojo.require("openils.User");
24 dojo.declare('openils.PermaCrud', null, {
30 constructor : function ( kwargs ) {
31 kwargs = kwargs || {};
33 this.authtoken = kwargs.authtoken;
37 new OpenSRF.ClientSession('open-ils.pcrud');
41 this.session.state == OSRF_APP_SESSION_CONNECTED
42 ) this.connected = true;
45 auth : function (token) {
46 if (token) this.authtoken = token;
47 return this.authtoken || openils.User.authtoken;
50 connect : function ( onerror ) {
51 if (!this.connected && !this.session.connect()) {
52 this.connected = false;
53 if (onerror) onerror(this.session);
56 this.connected = true;
60 disconnect : function ( onerror ) {
61 this.connected = false;
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);
71 retrieve : function ( fm_class /* Fieldmapper class hint */, id /* Fieldmapper object primary key value */, opts /* Option hash */) {
73 var req_hash = dojo.mixin(
75 { method : 'open-ils.pcrud.retrieve.' + fm_class,
76 params : [ this.auth(), id ]
80 if (!opts.async && !opts.timeout) req_hash.timeout = 10;
83 var req = this.session.request( req_hash );
86 req.onerror = function (r) { throw js2JSON(r); };
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()){}; };
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();
105 retrieveAll : function ( fm_class /* Fieldmapper class hint */, opts /* Option hash */) {
106 var pkey = fieldmapper[fm_class].Identifier;
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 if (opts.join) order_by.join = opts.join;
116 var method = 'open-ils.pcrud.search.' + fm_class;
117 if(!opts.streaming) method += '.atomic';
120 search[pkey] = { '!=' : null };
122 var req_hash = dojo.mixin(
125 params : [ this.auth(), search, order_by ]
129 if (!opts.async && !opts.timeout) req_hash.timeout = 10;
132 var req = this.session.request( req_hash );
135 req.onerror = function (r) { throw js2JSON(r); };
137 // if it's an async call and the user does not care about
138 // the responses, pull them off the network and discard them
139 if (!req_hash.timeout && !req.oncomplete)
140 req.oncomplete = function (r) { while(r.recv()){}; };
144 // for synchronous calls with no handlers, return the first received value
145 if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
146 var resp = req.recv();
147 if(resp) return resp.content();
154 search : function ( fm_class /* Fieldmapper class hint */, search /* Fieldmapper query object */, opts /* Option hash */) {
155 var return_type = 'search';
158 if (opts.order_by) order_by.order_by = opts.order_by;
159 if (opts.select) order_by.select = opts.select;
160 if (opts.limit) order_by.limit = opts.limit;
161 if (opts.offset) order_by.offset = opts.offset;
162 if (opts.join) order_by.join = opts.join;
163 if (opts.id_list) return_type = 'id_list';
165 var method = 'open-ils.pcrud.' + return_type + '.' + fm_class;
166 if(!opts.streaming) method += '.atomic';
168 var req_hash = dojo.mixin(
171 params : [ this.auth(), search, order_by ]
175 if (!opts.async && !opts.timeout) req_hash.timeout = 10;
178 var req = this.session.request( req_hash );
181 req.onerror = function (r) { throw js2JSON(r); };
183 // if it's an async call and the user does not care about
184 // the responses, pull them off the network and discard them
185 if (!req_hash.timeout && !req.oncomplete)
186 req.oncomplete = function (r) { while(r.recv()){}; };
190 // for synchronous calls with no handlers, return the first received value
191 if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
192 var resp = req.recv();
193 if(resp) return resp.content();
200 _CUD : function ( method /* 'create' or 'update' or 'delete' */, list /* Fieldmapper object */, opts /* Option hash */) {
203 if (dojo.isArray(list)) {
204 if (list.classname) list = [ list ];
209 if (!this.connected) this.connect();
212 var _return_list = [];
214 function _CUD_recursive ( obj_list, pos, final_complete, final_error ) {
215 var obj = obj_list[pos];
217 method : 'open-ils.pcrud.' + method + '.' + obj.classname,
218 params : [ _pcrud.auth(), obj ],
219 onerror : final_error || function (r) { _pcrud.disconnect(); throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj); }
222 var req = _pcrud.session.request( req_hash );
223 req._final_complete = final_complete;
224 req._final_error = final_error;
226 if (++pos == obj_list.length) {
227 req.oncomplete = function (r) {
230 if ( res && res.content() ) {
231 _return_list.push( res.content() );
232 _pcrud.session.request({
233 method : 'open-ils.pcrud.transaction.commit',
235 params : [ _pcrud.auth() ],
236 onerror : function (r) {
238 throw 'Transaction commit error';
240 oncomplete : function (r) {
242 if ( res && res.content() ) {
243 if(req._final_complete)
244 req._final_complete(req, _return_list);
248 throw 'Transaction commit error';
254 throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
258 req.onerror = function (r) {
259 if (r._final_error) r._final_error(r);
261 throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
266 req._obj_list = obj_list;
267 req.oncomplete = function (r) {
269 if ( res && res.content() ) {
270 _return_list.push( res.content() );
271 _CUD_recursive( r._obj_list, r._pos, r._final_complete );
274 throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
277 req.onerror = function (r) {
278 if (r._final_error) r._final_error(r);
280 throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
287 var f_complete = opts.oncomplete;
288 var f_error = opts.onerror;
290 this.session.request({
291 method : 'open-ils.pcrud.transaction.begin',
293 params : [ _pcrud.auth() ],
294 onerror : function (r) {
296 throw 'Transaction begin error';
298 oncomplete : function (r) {
300 if ( res && res.content() ) {
301 _CUD_recursive( list, 0, f_complete, f_error );
304 throw 'Transaction begin error';
313 create : function ( list, opts ) {
314 return this._CUD( 'create', list, opts );
317 update : function ( list, opts ) {
318 var id_list = this._CUD( 'update', list, opts );
321 for (var idx = 0; idx < id_list.length; idx++) {
323 this.retrieve( list[idx].classname, id_list[idx] )
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 * NOTE: delete() is now removed -- use eliminate instead
335 delete : function ( list, opts ) {
336 return this._CUD( 'delete', list, opts );
340 eliminate: function ( list, opts ) {
341 return this._CUD( 'delete', list, opts );
344 apply : function ( list, opts ) {
345 this._auto_CUD( list, opts );
348 _auto_CUD : function ( list /* Fieldmapper object */, opts /* Option hash */) {
352 if (dojo.isArray(list)) {
353 if (list.classname) list = [ list ];
358 if (!this.connected) this.connect();
362 function _auto_CUD_recursive ( obj_list, pos, final_complete, final_error ) {
363 var obj = obj_list[pos];
366 if (obj.ischanged()) method = 'update';
367 if (obj.isnew()) method = 'create';
368 if (obj.isdeleted()) method = 'delete';
369 if (!method) throw 'No action detected';
372 method : 'open-ils.pcrud.' + method + '.' + obj.classname,
374 params : [ _pcrud.auth(), obj ],
375 onerror : final_error || function (r) { _pcrud.disconnect(); throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj); }
378 var req = _pcrud.session.request( req_hash );
379 req._final_complete = final_complete;
380 req._final_error = final_error;
382 if (++pos == obj_list.length) {
383 req.oncomplete = function (r) {
385 _pcrud.session.request({
386 method : 'open-ils.pcrud.transaction.commit',
388 params : [ _pcrud.auth() ],
389 onerror : function (r) {
391 throw 'Transaction commit error';
393 oncomplete : function (r) {
395 if ( res && res.content() ) {
396 _auto_CUD_recursive( list, 0 );
399 throw 'Transaction commit error';
404 if (r._final_complete) r._final_complete(r);
408 req.onerror = function (r) {
409 if (r._final_error) r._final_error(r);
415 req._obj_list = obj_list;
416 req.oncomplete = function (r) {
418 if ( res && res.content() ) {
419 _auto_CUD_recursive( r._obj_list, r._pos, r._final_complete, r._final_error );
422 throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj);
430 var f_complete = opts.oncomplete;
431 var f_error = opts.onerror;
433 this.session.request({
434 method : 'open-ils.pcrud.transaction.begin',
436 params : [ _pcrud.auth() ],
437 onerror : function (r) {
439 throw 'Transaction begin error';
441 oncomplete : function (r) {
443 if ( res && res.content() ) {
444 _auto_CUD_recursive( list, 0, f_complete, f_error );
447 throw 'Transaction begin error';