diff --git a/platform/persistence/overwrite/README.md b/platform/persistence/overwrite/README.md new file mode 100644 index 0000000000..ffd8db4d3e --- /dev/null +++ b/platform/persistence/overwrite/README.md @@ -0,0 +1,5 @@ +This bundle provides an Overwrite/Cancel dialog when persisting +domain objects, if persistence fails. It is meant to be paired +with a persistence adapter which performs revision-checking +on update calls, in order to provide the user interface for +choosing between Overwrite and Cancel in that situation. \ No newline at end of file diff --git a/platform/persistence/overwrite/src/PersistenceQueue.js b/platform/persistence/overwrite/src/PersistenceQueue.js new file mode 100644 index 0000000000..26e3e7d606 --- /dev/null +++ b/platform/persistence/overwrite/src/PersistenceQueue.js @@ -0,0 +1,94 @@ +/*global define*/ + +define( + ['./QueuedPersistenceHandler'], + function (QueuedPersistenceHandler) { + "use strict"; + + /** + * The PersistenceQueue is used by the QueuingPersistenceCapability + * to aggregrate calls for object persistence. These are then issued + * in a group, such that if some or all are rejected, this result can + * be shown to the user (again, in a group.) + * + * @param $q Angular's $q + * @param $timeout Angular's $timeout + * @param {number} [DELAY] optional; delay in milliseconds between + * attempts to flush the queue + */ + function PersistenceQueue($q, $timeout, DELAY) { + var queue = {}, + lastObservedSize = 0, + handler = new QueuedPersistenceHandler($q), + pendingTimeout, + flushPromise; + + // Check if the queue's size has stopped increasing) + function quiescent() { + return Object.keys(queue).length === lastObservedSize; + } + + // Look up a queued persistence capability + function lookup(id) { + return queue[id]; + } + + // Persist all queued objects + function flush() { + // Convert to array of persistence capabilities + var toFlush = Object.keys(queue).map(lookup); + + // Persist them + flushPromise = handler.persist(toFlush); + + // When persisted, clear the active promise + flushPromise.then(function () { + flushPromise = undefined; + }); + + // Reset queue, etc. + queue = {}; + lastObservedSize = 0; + pendingTimeout = undefined; + } + + // Schedule a flushing of the queue (that is, plan to flush + // all objects in the queue) + function scheduleFlush() { + function maybeFlush() { + // Only flush when we've stopped receiving updates + (quiescent() ? flush : scheduleFlush)(); + } + + // If we are already flushing the queue... + if (flushPromise) { + // Wait until that's over before considering a flush + flushPromise.then(maybeFlush); + } else { + // Otherwise, schedule a flush on a timeout (to give + // a window for other updates to get aggregated) + pendingTimeout = pendingTimeout || + $timeout(maybeFlush, DELAY, false); + } + } + + + // If no delay is provided, use a default + DELAY = DELAY || 0; + + return { + /** + * Queue persistence of a domain object. + * @param {string} id the domain object's identifier + * @param {PersistenceCapability} persistence the object's + * undecorated persistence capability + */ + put: function (id, persistence) { + queue[id] = persistence; + } + }; + } + + return PersistenceQueue; + } +); \ No newline at end of file diff --git a/platform/persistence/overwrite/src/QueuedPersistenceHandler.js b/platform/persistence/overwrite/src/QueuedPersistenceHandler.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/platform/persistence/overwrite/src/QueuingPersistenceCapability.js b/platform/persistence/overwrite/src/QueuingPersistenceCapability.js new file mode 100644 index 0000000000..abbc94c171 --- /dev/null +++ b/platform/persistence/overwrite/src/QueuingPersistenceCapability.js @@ -0,0 +1,31 @@ +/*global define*/ + +define( + [], + function () { + "use strict"; + + /** + * The QueuingPersistenceCapability places `persist` calls in a queue + * to be handled in batches. + * @param {PersistenceQueue} queue of persistence calls + * @param {PersistenceCapability} persistence the wrapped persistence + * capability + * @param {DomainObject} domainObject the domain object which exposes + * the capability + */ + function QueuingPersistenceCapability(queue, persistence, domainObject) { + var queuingPersistence = Object.create(persistence), + id = domainObject.getId(); + + // Override persist calls to queue them instead + queuingPersistence.persist = function () { + queue.put(id, persistence); + }; + + return queuingPersistence; + } + + return QueuingPersistenceCapability; + } +); \ No newline at end of file