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, {
29 authoritative : false,
31 constructor : function ( kwargs ) {
32 kwargs = kwargs || {};
34 this.authtoken = kwargs.authtoken;
35 this.authoritative = kwargs.authoritative;
39 new OpenSRF.ClientSession('open-ils.pcrud');
43 this.session.state == OSRF_APP_SESSION_CONNECTED
44 ) this.connected = true;
47 auth : function (token) {
48 if (token) this.authtoken = token;
49 return this.authtoken || openils.User.authtoken;
52 connect : function ( onerror ) {
53 if (!this.connected && !this.session.connect()) {
54 this.connected = false;
55 if (onerror) onerror(this.session);
58 this.connected = true;
62 disconnect : function ( onerror ) {
63 this.connected = false;
65 // disconnect returns nothing, which is null, which is not true, cause the following to always run ... arg.
66 if (!this.session.disconnect()) {
67 if (onerror) onerror(this.session);
72 _session_request : function ( args /* hash */, commitOnComplete /* set to true, else no */ ) {
75 var endstyle = 'rollback';
76 var aopts = dojo.mixin({}, args);
78 if (commitOnComplete) endstyle = 'commit';
80 if (me.authoritative) {
81 if (!me.connected) me.connect();
82 if (args.timeout && !args.oncomplete && !args.onresponse) { // pure sync call
83 args.oncomplete = function (r) {
84 me.session.request('open-ils.pcrud.transaction.' + endstyle, me.auth());
85 me.session.disconnect();
88 } else if (args.oncomplete) { // there's an oncomplete, fire that, and then end the transaction
89 var orig_oncomplete = args.oncomplete;
90 args.oncomplete = function (r) {
93 ret = orig_oncomplete(r);
95 me.session.request('open-ils.pcrud.transaction.' + endstyle, me.auth());
96 me.session.disconnect();
102 me.session.request('open-ils.pcrud.transaction.begin', me.auth());
104 return me.session.request( args );
107 retrieve : function ( fm_class /* Fieldmapper class hint */, id /* Fieldmapper object primary key value */, opts /* Option hash */) {
110 if (opts.join) ffj.join = opts.join;
111 if (opts.flesh) ffj.flesh = opts.flesh;
112 if (opts.flesh_fields) ffj.flesh_fields = opts.flesh_fields;
113 var req_hash = dojo.mixin(
115 { method : 'open-ils.pcrud.retrieve.' + fm_class,
116 params : [ this.auth(), id, ffj ]
120 if (!opts.async && !opts.timeout) req_hash.timeout = 10;
123 var req = this._session_request( req_hash );
126 req.onerror = function (r) { throw js2JSON(r); };
128 // if it's an async call and the user does not care about
129 // the responses, pull them off the network and discard them
130 if (!req_hash.timeout && !req.oncomplete)
131 req.oncomplete = function (r) { while(r.recv()){}; };
135 // for synchronous calls with no handlers, return the first received value
136 if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
137 var resp = req.recv();
138 if(resp) return resp.content();
145 retrieveAll : function ( fm_class /* Fieldmapper class hint */, opts /* Option hash */) {
146 var pkey = fieldmapper[fm_class].Identifier;
150 if (opts.order_by) order_by.order_by = opts.order_by;
151 if (opts.select) order_by.select = opts.select;
152 if (opts.limit) order_by.limit = opts.limit;
153 if (opts.offset) order_by.offset = opts.offset;
154 if (opts.join) order_by.join = opts.join;
155 if (opts.flesh) order_by.flesh = opts.flesh;
156 if (opts.flesh_fields) order_by.flesh_fields = opts.flesh_fields;
158 var method = 'open-ils.pcrud.search.' + fm_class;
159 if(!opts.streaming) method += '.atomic';
162 search[pkey] = { '!=' : null };
164 var req_hash = dojo.mixin(
167 params : [ this.auth(), search, order_by ]
171 if (!opts.async && !opts.timeout) req_hash.timeout = 10;
174 var req = this._session_request( req_hash );
177 req.onerror = function (r) { throw js2JSON(r); };
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()){}; };
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();
196 search : function ( fm_class /* Fieldmapper class hint */, search /* Fieldmapper query object */, opts /* Option hash */) {
197 var return_type = 'search';
200 if (opts.order_by) order_by.order_by = opts.order_by;
201 if (opts.select) order_by.select = opts.select;
202 if (opts.limit) order_by.limit = opts.limit;
203 if (opts.offset) order_by.offset = opts.offset;
204 if (opts.join) order_by.join = opts.join;
205 if (opts.flesh) order_by.flesh = opts.flesh;
206 if (opts.flesh_fields) order_by.flesh_fields = opts.flesh_fields;
207 if (opts.id_list) return_type = 'id_list';
209 var method = 'open-ils.pcrud.' + return_type + '.' + fm_class;
210 if(!opts.streaming) method += '.atomic';
212 var req_hash = dojo.mixin(
215 params : [ this.auth(), search, order_by ]
219 if (!opts.async && !opts.timeout) req_hash.timeout = 10;
222 var req = this._session_request( req_hash );
225 req.onerror = function (r) { throw js2JSON(r); };
227 // if it's an async call and the user does not care about
228 // the responses, pull them off the network and discard them
229 if (!req_hash.timeout && !req.oncomplete)
230 req.oncomplete = function (r) { while(r.recv()){}; };
234 // for synchronous calls with no handlers, return the first received value
235 if (req_hash.timeout && !opts.oncomplete && !opts.onresponse) {
236 var resp = req.recv();
237 if(resp) return resp.content();
244 _CUD : function ( method /* 'create' or 'update' or 'delete' */, list /* Fieldmapper object */, opts /* Option hash */) {
247 if (dojo.isArray(list)) {
248 if (list.classname) list = [ list ];
253 if (!this.connected) this.connect();
256 var _return_list = [];
258 function _CUD_recursive ( obj_list, pos, final_complete, final_error ) {
259 var obj = obj_list[pos];
261 method : 'open-ils.pcrud.' + method + '.' + obj.classname,
262 params : [ _pcrud.auth(), obj ],
263 onerror : final_error || function (r) { _pcrud.disconnect(); throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj); }
266 var req = _pcrud.session.request( req_hash );
267 req._final_complete = final_complete;
268 req._final_error = final_error;
270 if (++pos == obj_list.length) {
271 req.oncomplete = function (r) {
274 if ( res && res.content() ) {
275 _return_list.push( res.content() );
276 _pcrud.session.request({
277 method : 'open-ils.pcrud.transaction.commit',
279 params : [ _pcrud.auth() ],
280 onerror : function (r) {
282 if (req._final_error) req._final_error(r)
283 else throw 'Transaction commit error';
285 oncomplete : function (r) {
287 if ( res && res.content() ) {
288 if(req._final_complete)
289 req._final_complete(req, _return_list);
293 if (req._final_error) req._final_error(r)
294 else throw 'Transaction commit error';
300 if (req._final_error) req._final_error(r)
301 else throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
305 req.onerror = function (r) {
307 if (req._final_error) req._final_error(r);
308 else throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
313 req._obj_list = obj_list;
314 req.oncomplete = function (r) {
316 if ( res && res.content() ) {
317 _return_list.push( res.content() );
318 _CUD_recursive( r._obj_list, r._pos, req._final_complete, req._final_error );
321 if (req._final_error) req._final_error(r);
322 else throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
325 req.onerror = function (r) {
327 if (req._final_error) req._final_error(r);
328 throw '_CUD: Error creating, deleting or updating ' + js2JSON(obj);
335 var f_complete = opts.oncomplete;
336 var f_error = opts.onerror;
338 this.session.request({
339 method : 'open-ils.pcrud.transaction.begin',
341 params : [ _pcrud.auth() ],
342 onerror : function (r) {
344 throw 'Transaction begin error';
346 oncomplete : function (r) {
348 if ( res && res.content() ) {
349 _CUD_recursive( list, 0, f_complete, f_error );
352 throw 'Transaction begin error';
361 create : function ( list, opts ) {
362 return this._CUD( 'create', list, opts );
365 update : function ( list, opts ) {
366 var id_list = this._CUD( 'update', list, opts );
369 for (var idx = 0; idx < id_list.length; idx++) {
371 this.retrieve( list[idx].classname, id_list[idx] )
379 * 'delete' is a reserved keyword in JavaScript and can't be used
380 * in browsers like IE or Chrome, so we define a safe synonym
381 * NOTE: delete() is now removed -- use eliminate instead
383 delete : function ( list, opts ) {
384 return this._CUD( 'delete', list, opts );
388 eliminate: function ( list, opts ) {
389 return this._CUD( 'delete', list, opts );
392 apply : function ( list, opts ) {
393 this._auto_CUD( list, opts );
396 _auto_CUD : function ( list /* Fieldmapper object */, opts /* Option hash */) {
400 if (dojo.isArray(list)) {
401 if (list.classname) list = [ list ];
406 if (!this.connected) this.connect();
409 var _return_list = [];
411 function _auto_CUD_recursive ( obj_list, pos, final_complete, final_error ) {
412 var obj = obj_list[pos];
415 if (obj.ischanged()) method = 'update';
416 if (obj.isnew()) method = 'create';
417 if (obj.isdeleted()) method = 'delete';
419 return _auto_CUD_recursive(obj_list, pos+1, final_complete, final_error);
423 method : 'open-ils.pcrud.' + method + '.' + obj.classname,
425 params : [ _pcrud.auth(), obj ],
426 onerror : final_error || function (r) { _pcrud.disconnect(); throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj); }
429 var req = _pcrud.session.request( req_hash );
430 req._final_complete = final_complete;
431 req._final_error = final_error;
433 if (++pos == obj_list.length) {
434 req.oncomplete = function (r) {
437 if ( res && res.content() ) {
438 _return_list.push( res.content() );
439 _pcrud.session.request({
440 method : 'open-ils.pcrud.transaction.commit',
442 params : [ _pcrud.auth() ],
443 onerror : function (r) {
445 throw 'Transaction commit error';
447 oncomplete : function (r) {
449 if ( res && res.content() ) {
450 if (req._final_complete)
451 req._final_complete(req, _return_list);
455 if (req._final_error) req._final_error(r);
456 else throw 'Transaction commit error';
462 if (req._final_error) req._final_error(r)
463 else throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj);
467 req.onerror = function (r) {
469 if (req._final_error) req._final_error(r);
474 req._obj_list = obj_list;
475 req.oncomplete = function (r) {
477 if ( res && res.content() ) {
478 _return_list.push( res.content() );
479 _auto_CUD_recursive( r._obj_list, r._pos, req._final_complete, req._final_error );
482 if (req._final_error) req._final_error(r);
483 else throw '_auto_CUD: Error creating, deleting or updating ' + js2JSON(obj);
491 var f_complete = opts.oncomplete;
492 var f_error = opts.onerror;
494 this.session.request({
495 method : 'open-ils.pcrud.transaction.begin',
497 params : [ _pcrud.auth() ],
498 onerror : function (r) {
500 throw 'Transaction begin error';
502 oncomplete : function (r) {
504 if ( res && res.content() ) {
505 _auto_CUD_recursive( list, 0, f_complete, f_error );
508 throw 'Transaction begin error';