// Copyright 2011 The Closure Library Authors. All Rights Reserved. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS-IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /** * @fileoverview Provides a convenient API for data with attached metadata * persistence. You probably don't want to use this class directly as it * does not save any metadata by itself. It only provides the necessary * infrastructure for subclasses that need to save metadata along with * values stored. * */ goog.provide('goog.storage.RichStorage'); goog.provide('goog.storage.RichStorage.Wrapper'); goog.require('goog.storage.ErrorCode'); goog.require('goog.storage.Storage'); /** * Provides a storage for data with attached metadata. * * @param {!goog.storage.mechanism.Mechanism} mechanism The underlying * storage mechanism. * @constructor * @struct * @extends {goog.storage.Storage} */ goog.storage.RichStorage = function(mechanism) { goog.storage.RichStorage.base(this, 'constructor', mechanism); }; goog.inherits(goog.storage.RichStorage, goog.storage.Storage); /** * Metadata key under which the actual data is stored. * * @type {string} * @protected */ goog.storage.RichStorage.DATA_KEY = 'data'; /** * Wraps a value so metadata can be associated with it. You probably want * to use goog.storage.RichStorage.Wrapper.wrapIfNecessary to avoid multiple * embeddings. * * @param {*} value The value to wrap. * @constructor * @final */ goog.storage.RichStorage.Wrapper = function(value) { this[goog.storage.RichStorage.DATA_KEY] = value; }; /** * Convenience method for wrapping a value so metadata can be associated with * it. No-op if the value is already wrapped or is undefined. * * @param {*} value The value to wrap. * @return {(!goog.storage.RichStorage.Wrapper|undefined)} The wrapper. */ goog.storage.RichStorage.Wrapper.wrapIfNecessary = function(value) { if (!goog.isDef(value) || value instanceof goog.storage.RichStorage.Wrapper) { return /** @type {(!goog.storage.RichStorage.Wrapper|undefined)} */ (value); } return new goog.storage.RichStorage.Wrapper(value); }; /** * Unwraps a value, any metadata is discarded (not returned). You might want to * use goog.storage.RichStorage.Wrapper.unwrapIfPossible to handle cases where * the wrapper is missing. * * @param {!Object} wrapper The wrapper. * @return {*} The wrapped value. */ goog.storage.RichStorage.Wrapper.unwrap = function(wrapper) { var value = wrapper[goog.storage.RichStorage.DATA_KEY]; if (!goog.isDef(value)) { throw goog.storage.ErrorCode.INVALID_VALUE; } return value; }; /** * Convenience method for unwrapping a value. Returns undefined if the * wrapper is missing. * * @param {(!Object|undefined)} wrapper The wrapper. * @return {*} The wrapped value or undefined. */ goog.storage.RichStorage.Wrapper.unwrapIfPossible = function(wrapper) { if (!wrapper) { return undefined; } return goog.storage.RichStorage.Wrapper.unwrap(wrapper); }; /** @override */ goog.storage.RichStorage.prototype.set = function(key, value) { goog.storage.RichStorage.base( this, 'set', key, goog.storage.RichStorage.Wrapper.wrapIfNecessary(value)); }; /** * Get an item wrapper (the item and its metadata) from the storage. * * WARNING: This returns an Object, which once used to be * goog.storage.RichStorage.Wrapper. This is due to the fact * that deserialized objects lose type information and it * is hard to do proper typecasting in JavaScript. Be sure * you know what you are doing when using the returned value. * * @param {string} key The key to get. * @return {(!Object|undefined)} The wrapper, or undefined if not found. */ goog.storage.RichStorage.prototype.getWrapper = function(key) { var wrapper = goog.storage.RichStorage.superClass_.get.call(this, key); if (!goog.isDef(wrapper) || wrapper instanceof Object) { return /** @type {(!Object|undefined)} */ (wrapper); } throw goog.storage.ErrorCode.INVALID_VALUE; }; /** @override */ goog.storage.RichStorage.prototype.get = function(key) { return goog.storage.RichStorage.Wrapper.unwrapIfPossible( this.getWrapper(key)); };