From b89a7ee8b956c96a1dcee995ea840feddc5d4b27 Mon Sep 17 00:00:00 2001 From: Pierre Frisch Date: Thu, 22 Dec 2011 07:25:50 -0800 Subject: First commit of Ninja to ninja-internal Signed-off-by: Valerio Virgillito --- node_modules/montage/data/context.js | 374 +++++++++++++++++++++++++++++++++++ 1 file changed, 374 insertions(+) create mode 100755 node_modules/montage/data/context.js (limited to 'node_modules/montage/data/context.js') diff --git a/node_modules/montage/data/context.js b/node_modules/montage/data/context.js new file mode 100755 index 00000000..694198e3 --- /dev/null +++ b/node_modules/montage/data/context.js @@ -0,0 +1,374 @@ +/* + This file contains proprietary software owned by Motorola Mobility, Inc.
+ No rights, expressed or implied, whatsoever to this software are provided by Motorola Mobility, Inc. hereunder.
+ (c) Copyright 2011 Motorola Mobility, Inc. All Rights Reserved. +
*/ +/** + @module montage/data/context + @requires montage/core/core + @requires montage/data/store + @requires montage/data/blueprint + @requires montage/data/objectproperty + @requires montage/core/shim/weak-map + @requires montage/core/shim/structures + @requires montage/core/exception + @requires montage/core/promise + @requires montage/core/logger + */ +var Montage = require("montage").Montage; +var Store = require("data/store").Store; +var Blueprint = require("data/blueprint").Blueprint; +var ObjectProperty = require("data/objectproperty").ObjectProperty; +// TODO [June 5 2011 PJYF] This s temporary implementation of WeakMap to let the browser catch up. +var WeakMap = require("core/shim/weak-map").WeakMap; +var Set = require("core/shim/structures").Set; +var Exception = require("core/exception").Exception; +var Promise = require("core/promise").Promise; +var logger = require("core/logger").logger("context"); +/** + @class module:montage/data/context.Context + @extends module:montage/data/store.Store + */ +var Context = exports.Context = Montage.create(Store, /** @lends module:montage/data/context.Context# */ { + /** + Collection of object inserted in this context since the last save. + @private + */ + _inserted: { + value: new Set(50), + serializable: true, + distinct: true, + enumerable: false, + writable: false + }, + /** + Collection of object deleted in this context since the last save. + @private + */ + _deleted: { + value: new Set(50), + serializable: true, + distinct: true, + enumerable: false, + writable: false + }, + /** + Collection of object modified in this context since the last save. + @private + */ + _modified: { + value: new Set(50), + serializable: true, + distinct: true, + enumerable: false, + writable: false + }, + + /** + Table of fetched objects for uniquing. The key is the object ID the value the actual object or the pledge representing it.
+ Note: This is a weak map so that the context does not hold on the objects and they can be garbage collected if no one else hold on them. + @private + */ + _objectMap: { + value: new WeakMap(), + serializable: true, + enumerable: false, + writable: false + }, + + /** + Collection of object inserted in this context since the last save. + @function + @returns this._inserted + @default empty set + */ + inserted: { + get: function() { + return this._inserted; + } + }, + + /** + Collection of object deleted in this context since the last save. + @function + @returns this._deleted + @default empty set + */ + deleted: { + get: function() { + return this._deleted; + } + }, + + /** + Collection of object modified in this context since the last save. + @function + @returns this._modified + @default empty set + */ + modified: { + get: function() { + return this._modified; + } + }, + + /** + Description TODO + @function + @param {String} id objectmap + @returns this._objectMap.get(id) | null + */ + objectForId: { + value: function(id) { + if (this._objectMap.has(id)) { + return this._objectMap.get(id); + } + return null; + } + }, + + /** + Inserts a newly created object in the context. + @function + @param {Object} instance TODO + @returns initialized object + */ + insert: { + value: function(instance) { + if (instance !== null) { + if (typeof instance.context === "undefined") { + var metadata = Montage.getInfoForObject(instance); + var blueprint = this.blueprintForPrototype(metadata.objectName, metadata.moduleId); + if (blueprint !== null) { + ObjectProperty.manager.apply(Object.getPrototypeOf(instance), blueprint); + } else { + throw Exception.create().initWithMessageTargetAndMethod("Cannot find blueprint for: " + metadata.objectName + " " + metadata.moduleId, this, "insert"); + } + } + if (instance.context === null) { + instance.context = this; + this._inserted.add(instance); + return this.initializeObject(instance, this).then(function(instance) { + this._objectMap.set(instance.objectId, instance); + return Promise.ref(instance); + }.bind(this)); + } else if (instance.context !== this) { + throw Exception.initWithMessageTargetAndMethod("This instance is already inserted in another context.", this, "insert"); + } + } else { + throw Exception.initWithMessageTargetAndMethod("Cannot insert a null object.", this, "insert"); + } + } + }, + + /** + Delete an object.
+ A deleted object will be deleted from the backing store on the next save. + @function + @param {Object} instance TODO + @returns Promise.ref(instance) + */ + 'delete': { + value: function(instance) { + if (instance !== null) { + if ((typeof instance.context === "undefined") || (instance.context === null)) { + return Promise.ref(instance); + } + if (instance.context !== this) { + throw Exception.initWithMessageTargetAndMethod("This instance is belongs to another context.", this, "delete"); + } + if (this._inserted.has(instance)) { + // We are forgetting a newly inserted object + this._inserted.delete(instance); + if (typeof instance.context !== "undefined") { + instance.context = null; + } + } else { + if (this._modified.has(instance)) { + // the object was modified before teh delete forget those. + this._modified.delete(instance); + instance = this._revertValues(instance); + } + this._deleted.add(instance); + } + this._objectMap.delete(instance.objectId); + } else { + throw Exception.initWithMessageTargetAndMethod("Cannot delete a null object.", this, "delete"); + } + return Promise.ref(instance); + } + }, + + /** + Revert an object to its saved values. + @function + @param {Object} instance TODO + @returns Promise.ref(instance) + */ + revert: { + value: function(instance) { + if (instance !== null) { + if (typeof instance.context === "undefined") { + return Promise.ref(instance); + } + if (instance.context !== null) { + if (instance.context !== this) { + throw Exception.initWithMessageTargetAndMethod("This instance is belongs to another context.", this, "revert"); + } + if (this._inserted.has(instance)) { + // This is a newly inserted object, there is no value to revert to, so do nothing. + } else if (this._modified.has(instance)) { + this._modified.delete(instance); + instance = this._revertValues(instance); + } + } else { + // Maybe that object was deleted let retrieve it? + if (this._deleted.has(instance)) { + this._deleted.delete(instance); + instance.context = this; + instance = this._revertValues(instance); + } + } + } else { + throw Exception.initWithMessageTargetAndMethod("Cannot revert a null object.", this, "revert"); + } + return Promise.ref(instance); + } + }, + + /** + Description TODO + @private + */ + _revertValues: { + value: function(instance) { + // TODO [PJYF May 24 2011] We should restore the saved values + return Promise.ref(instance); + } + }, + + /** + Saves all current changes and deletion to the backing store. + @function + */ + save: { + value: function() { + // TODO [PJYF Sept 4 2011] This is probably incomplete - we need to handle the callback + if (this.hasChanges()) { + this.parent.saveChangesInContext(this); + } + } + }, + + /** + This method from the parent store is overwritten to handle the save from the child context. + @function + @param {Property} context The child context + @param {String} transactionID The transaction id + */ + saveChangesInContext$Implementation: { + value: function(context, transactionID) { + if (context === this) { + // If called on it-self then save the context + Store.saveChangesInContext$Implementation.call(this, context, transactionID); + } + // The context has all the changes and we need to merge them with our own. + var inserted = context.inserted; + var deleted = context.deleted; + var modified = context.modified; + + var newUpdated = null; + var removedInserted = null; + + // First create and insert all new objects + inserted.forEach(function(object) { + var gid = object.objectId; + var localObject = this.objectForId(gid); + + if (localObject == null) { + // Insert a copy in our context. + ; + } else { + // Inserting an object already registered in my context? Pretty bogus! Treat it as an update. + ; + // Remove from the inserted list and add it to the updated one. + ; + } + + }); + + // Initialize the property values in these new objects. + + // Copy the values for all updated objects. + + // Delete removed Objects. + + // TODO [PJYF Sept 4 2011] This needs to be reimplemented + + } + }, + + /** + Description TODO + @function + @param {String} attribute TODO + @param {Object} instance TODO + */ + fulfillPropertyForInstance: { + value: function(attribute, instance) { + + } + }, + + /** + Description TODO + @function + @param {String} attribute TODO + @param {Object} instance TODO + */ + willModifyPropertyForInstance: { + value: function(attribute, instance) { + // TODO [PJYF Sep 30 2011] We should probably be smarter. + this._modified.add(instance); + } + }, + + /** + Fetch objects from the backing store. + @function + @param {String} query TODO + @returns Promise.ref(this.parent.queryInContext(query, this)) + */ + query: { + value: function(query) { + // TODO [PJYF Sept 23 2011] This is probably incomplete - we need to handle the refresh + return Promise.ref(this.parent.queryInContext(query, this)); + } + }, + + /** + Reload all objects from the backing store and merges changes in the context with the new values.
+ If the target passed is an Array each object will be refreshed. + @function + @param {Object} target The target to be refreshed. + @returns Promise.ref(this.repledgeObject(target, this)) + */ + refresh: { + value: function(target) { + // TODO [PJYF May 10 2011] This is incorrect we need to merge the changes in the refaulted objects + return Promise.ref(this.repledgeObject(target, this)); + } + }, + + /** + Check if there are unsaved changes in the context. + @function + @returns this._inserted.length > 0 or this._modified.length > 0 or this._deleted.length > 0 + */ + hasChanges: { + value: function() { + return this._inserted.length > 0 || this._modified.length > 0 || this._deleted.length > 0; + } + } + +}); -- cgit v1.2.3