Location: A review of cardiac cellular electrophysiology models @ c47db6b2fedb / dojo-presentation / js / dojo / dojox / data / JsonRestStore.js

Author:
David Nickerson <david.nickerson@gmail.com>
Date:
2021-09-17 15:39:51+12:00
Desc:
tweak html formatting
Permanent Source URI:
https://models.fieldml.org/workspace/a1/rawfile/c47db6b2fedb368422c7f4d5191aeb9f319ad684/dojo-presentation/js/dojo/dojox/data/JsonRestStore.js

dojo.provide("dojox.data.JsonRestStore");

dojo.require("dojox.data.ServiceStore");
dojo.require("dojox.rpc.JsonRest");


dojo.declare("dojox.data.JsonRestStore",
	dojox.data.ServiceStore,
	{
		constructor: function(options){
			//summary:
			//		JsonRestStore is a Dojo Data store interface to JSON HTTP/REST web
			//		storage services that support read and write through GET, PUT, POST, and DELETE. 
			// options: 
			// 		Keyword arguments
			//	
			// The *schema* parameter
			//		This is a schema object for this store. This should be JSON Schema format.
			//
			// The *service* parameter
			// 		This is the service object that is used to retrieve lazy data and save results
			// 		The function should be directly callable with a single parameter of an object id to be loaded
			// 		The function should also have the following methods:
			// 			put(id,value) - puts the value at the given id
			// 			post(id,value) - posts (appends) the value at the given id
			// 			delete(id) - deletes the value corresponding to the given id
			//
			// The *target* parameter
			// 		This is the target URL for this Service store. This may be used in place
			// 		of a service parameter to connect directly to RESTful URL without
			// 		using a dojox.rpc.Service object.
			//
			// The *idAttribute* parameter
			//		Defaults to 'id'. The name of the attribute that holds an objects id.
			//		This can be a preexisting id provided by the server.
			//		If an ID isn't already provided when an object
			//		is fetched or added to the store, the autoIdentity system
			//		will generate an id for it and add it to the index.
			//
			// The *syncMode* parameter
			//		Setting this to true will set the store to using synchronous calls by default.
			//		Sync calls return their data immediately from the calling function, so
			//		callbacks are unnecessary
			//
			//	description:
			//		The JsonRestStore will then cause all saved modifications to be server using Rest commands (PUT, POST, or DELETE).
			// 		When using a Rest store on a public network, it is important to implement proper security measures to
			//		control access to resources
			//	example:
			// 		A JsonRestStore takes a REST service or a URL and uses it the remote communication for a
			// 		read/write dojo.data implementation. A JsonRestStore can be created with a simple URL like:
			// 	|	new JsonRestStore({target:"/MyData/"});
			//	example:
			// 		To use a JsonRestStore with a service, you should create a
			// 		service with a REST transport. This can be configured with an SMD:
			//	|	{
			//	|		services: {
			//	|			jsonRestStore: {
			//	|				transport: "REST",
			//	|				envelope: "URL",
			//	|				target: "store.php",
			//	|				contentType:"application/json",
			//	|				parameters: [
			//	|					{name: "location", type: "string", optional: true}
			//	|				]
			//	|			}
			//	|		}
			//	|	}
			// 		The SMD can then be used to create service, and the service can be passed to a JsonRestStore. For example:
			//	|	var myServices = new dojox.rpc.Service(dojo.moduleUrl("dojox.rpc.tests.resources", "test.smd"));
			//	|	var jsonStore = new dojox.data.JsonRestStore({service:myServices.jsonRestStore});
			//	example:
			//		The JsonRestStore also supports lazy loading. References can be made to objects that have not been loaded.
			//		For example if a service returned:
			//	|	{"name":"Example","lazyLoadedObject":{"$ref":"obj2"}}
			// 		And this object has accessed using the dojo.data API:
			//	|	var obj = jsonStore.getValue(myObject,"lazyLoadedObject");
			//		The object would automatically be requested from the server (with an object id of "obj2").

			dojo.connect(dojox.rpc.Rest._index,"onUpdate",this,function(obj,attrName,oldValue,newValue){
				var prefix = this.service.servicePath;
				if(!obj.__id){
					console.log("no id on updated object ", obj);
				}else if(obj.__id.substring(0,prefix.length) == prefix){
					this.onSet(obj,attrName,oldValue,newValue);
				}
			});
			this.idAttribute = this.idAttribute || 'id';// no options about it, we have to have identity
			//setup a byId alias to the api call
			if(typeof this.target == 'string' && !this.service){
				this.service = dojox.rpc.Rest(this.target,true); // create a default Rest service
			}
			dojox.rpc.JsonRest.registerService(this.service, this.target, this.schema);
			this.schema = this.service._schema = this.schema || this.service._schema || {};
			// wrap the service with so it goes through JsonRest manager 
			this.service._store = this;
			this.schema._idAttr = this.idAttribute;
			this._constructor = dojox.rpc.JsonRest.getConstructor(this.service);
			//given a url, load json data from as the store
		},
		//Write API Support
		newItem: function(data, parentInfo){
			// summary:
			//		adds a new item to the store at the specified point.
			//		Takes two parameters, data, and options.
			//
			//	data: /* object */
			//		The data to be added in as an item.
			data = new this._constructor(data);
			if(parentInfo){
				// get the previous value or any empty array
				var values = this.getValue(parentInfo.parent,parentInfo.attribute,[]);
				// set the new value
				this.setValue(parentInfo.parent,parentInfo.attribute,values.concat([data]));
			}
			this.onNew(data); // should this go before the set?
			return data;
		},
		deleteItem: function(item){
			// summary:
			//		deletes item any references to that item from the store.
			//
			//	item:
			//  	item to delete
			//

			//	If the desire is to delete only one reference, unsetAttribute or
			//	setValue is the way to go.
			dojox.rpc.JsonRest.deleteObject(item);
			var store = dojox.data._getStoreForItem(item);
			store._doDelete(item);
		},
		_doDelete : function(item){
			this.onDelete(item);
		},
		changing: function(item,_deleting){
			// summary:
			//		adds an item to the list of dirty items.  This item
			//		contains a reference to the item itself as well as a
			//		cloned and trimmed version of old item for use with
			//		revert.
			dojox.rpc.JsonRest.changing(item,_deleting);
		},

		setValue: function(item, attribute, value){
			// summary:
			//		sets 'attribute' on 'item' to 'value'

			var old = item[attribute];
			var store = dojox.data._getStoreForItem(item);
			if(dojox.json.schema && store.schema && store.schema.properties){
				// if we have a schema and schema validator available we will validate the property change
				var result = dojox.json.schema.checkPropertyChange(value,store.schema.properties[attribute]);
				if(!result.valid){
					throw new Error(dojo.map(result.errors,function(error){return error.message;}).join(","));
				}
			}
			if(old != value){
				store.changing(item);
				item[attribute]=value;
				store.onSet(item,attribute,old,value);
			}
		},
		setValues: function(item, attribute, values){
			// summary:
			//	sets 'attribute' on 'item' to 'value' value
			//	must be an array.


			if(!dojo.isArray(values)){
				throw new Error("setValues expects to be passed an Array object as its value");
			}
			this.setValue(item,attribute,values);
		},

		unsetAttribute: function(item, attribute){
			// summary:
			//		unsets 'attribute' on 'item'

			this.changing(item);
			var old = item[attribute];
			delete item[attribute];
			this.onSet(item,attribute,old,undefined);
		},
		save: function(kwArgs){
			// summary:
			//		Saves the dirty data using REST Ajax methods
			
			var actions = dojox.rpc.JsonRest.commit(kwArgs);
			this.serverVersion = this._updates && this._updates.length;
			return actions;
		},

		revert: function(){
			// summary
			//		returns any modified data to its original state prior to a save();
			var dirtyObjects = dojox.rpc.JsonRest.getDirtyObjects().concat([]);
			while (dirtyObjects.length>0){
				var d = dirtyObjects.pop();
				//TODO: Find the correct store for each one
				if(!d.object){
					// was a deletion, we will add it back
					this.onNew(d.old);
				}else if(!d.old){
					// was an addition, remove it
					this.onDelete(d.object);
				}else{
					//TODO: onSet
				}
			}
			dojox.rpc.JsonRest.revert();
		},

		isDirty: function(item){
			// summary
			//		returns true if the item is marked as dirty.
			return dojox.rpc.JsonRest.isDirty(item);
		},
		isItem: function(item){
			// summary:
			//	Checks to see if a passed 'item'
			//	is really belongs to this JsonRestStore.
			//
			//	item: /* object */
			//	attribute: /* string */
			return item && item.__id && this.service == dojox.rpc.JsonRest.getServiceAndId(item.__id).service;
		},
		_doQuery: function(args){
			var query= typeof args.queryStr == 'string' ? args.queryStr : args.query;
			return dojox.rpc.JsonRest.get(this.service,query, args);
		},
		_processResults: function(results, deferred){
			// index the results
			var count = results.length;
			return {totalCount:deferred.fullLength || (deferred.request.count == count ? count * 2 : count), items: results};
		},

		fetchItemByIdentity: function(args){
			// summary:
			//		fetch an item by its identity. fetch and fetchItemByIdentity work the same

			// convert the different spellings
			args.query = args.identity;
			args.onComplete = args.onItem;
			args.useIndexCache = true;
			delete args.onItem;
			// we can rely on the Rest service to provide the index/cache
			return this.fetch(args).results;
		},
		getConstructor: function(){
			// summary:
			// 		Gets the constructor for objects from this store
			return this._constructor;
		},
		//Notifcation Support

		onSet: function(){},
		onNew: function(){},
		onDelete: 	function(){},

		getFeatures: function(){
			// summary:
			// 		return the store feature set
			var features = dojox.data.ServiceStore.prototype.getFeatures();
			features["dojo.data.api.Write"] = true;
			features["dojo.data.api.Notification"] = true;
			return features;
		}


	}
);
dojox.data._getStoreForItem = function(item){
	return dojox.rpc.JsonRest.services[item.__id.match(/.*\//)[0]]._store;
};