From fad83bb6a63e4d2c63a31cb611c2c4537629ca24 Mon Sep 17 00:00:00 2001 From: Jason Dobry Date: Wed, 20 Nov 2013 08:18:39 -0700 Subject: [PATCH] Accept numbers as keys, but stringify them. #76 --- dist/angular-cache.js | 21 ++++++++++++++++++++- dist/angular-cache.min.js | 2 +- src/angular-cache.js | 19 +++++++++++++++++++ test/angularCache.get-test.js | 8 ++++---- test/angularCache.put-test.js | 8 ++++---- test/karma.start.js | 2 ++ 6 files changed, 50 insertions(+), 10 deletions(-) diff --git a/dist/angular-cache.js b/dist/angular-cache.js index ca09966..b12c47f 100644 --- a/dist/angular-cache.js +++ b/dist/angular-cache.js @@ -325,6 +325,19 @@ this.$get = ['$window', 'BinaryHeap', function ($window, BinaryHeap) { var caches = {}; + /** + * Stringify a number. + * @param {number|*} number The number to be stringified. + * @returns {*} number or a string. + * @private + */ + function _stringifyNumber(number) { + if (number && angular.isNumber(number)) { + return number.toString(); + } + return number; + } + /** * @method _keySet * @desc Returns an object of the keys of the given collection. @@ -631,7 +644,7 @@ storage.removeItem(prefix + '.keys'); if (keys && keys.length) { for (var i = 0; i < keys.length; i++) { - var data = angular.fromJson(storage.getItem(prefix + '.data.' + keys[i])), + var data = angular.fromJson(storage.getItem(prefix + '.data.' + keys[i])) || {}, maxAge = data.maxAge || config.maxAge, deleteOnExpire = data.deleteOnExpire || config.deleteOnExpire; if (maxAge && ((new Date().getTime() - data.created) > maxAge) && deleteOnExpire === 'aggressive') { @@ -718,6 +731,9 @@ */ this.put = function (key, value, options) { options = options || {}; + + key = _stringifyNumber(key); + if (!angular.isString(key)) { throw new Error('AngularCache.put(key, value, options): key: must be a string!'); } else if (options && !angular.isObject(options)) { @@ -791,6 +807,7 @@ * @returns {*} The value of the item in the cache with the specified key. */ this.get = function (key, options) { + if (angular.isArray(key)) { var keys = key, values = []; @@ -803,6 +820,8 @@ }); return values; + } else { + key = _stringifyNumber(key); } options = options || {}; diff --git a/dist/angular-cache.min.js b/dist/angular-cache.min.js index 68dd9c1..444756c 100644 --- a/dist/angular-cache.min.js +++ b/dist/angular-cache.min.js @@ -7,4 +7,4 @@ * * @overview angular-cache is a very useful replacement for Angular's $cacheFactory. */ -!function(a,b,c){"use strict";function d(){this.$get=function(){function a(a,b,c){for(var d=a[c],e=b(d);c>0;){var f=Math.floor((c+1)/2)-1,g=a[f];if(e>=b(g))break;a[f]=d,a[c]=g,c=f}}function c(a,b,c){for(var d=a.length,e=a[c],f=b(e);;){var g=2*(c+1),h=g-1,i=null;if(d>h){var j=a[h],k=b(j);f>k&&(i=h)}if(d>g){var l=a[g],m=b(l);m<(null===i?f:b(a[h]))&&(i=g)}if(null===i)break;a[c]=a[i],a[i]=e,c=i}}function d(a){if(a&&!b.isFunction(a))throw new Error("BinaryHeap(weightFunc): weightFunc: must be a function!");a=a||function(a){return a},this.weightFunc=a,this.heap=[]}return d.prototype.push=function(b){this.heap.push(b),a(this.heap,this.weightFunc,this.heap.length-1)},d.prototype.peek=function(){return this.heap[0]},d.prototype.pop=function(){var a=this.heap[0],b=this.heap.pop();return this.heap.length>0&&(this.heap[0]=b,c(this.heap,this.weightFunc,0)),a},d.prototype.remove=function(d){for(var e=this.heap.length,f=0;e>f;f++)if(b.equals(this.heap[f],d)){var g=this.heap[f],h=this.heap.pop();return f!==e-1&&(this.heap[f]=h,a(this.heap,this.weightFunc,f),c(this.heap,this.weightFunc,f)),g}return null},d.prototype.removeAll=function(){this.heap=[]},d.prototype.size=function(){return this.heap.length},d}}function e(){function a(a,c){b.isNumber(a)?0>a?c("must be greater than zero!"):c(null):c("must be a number!")}var d,e=function(){return{capacity:Number.MAX_VALUE,maxAge:null,deleteOnExpire:"none",onExpire:null,cacheFlushInterval:null,recycleFreq:1e3,storageMode:"none",storageImpl:null,verifyIntegrity:!0}};this.setCacheDefaults=function(c){var f="$angularCacheFactoryProvider.setCacheDefaults(options): ";if(c=c||{},!b.isObject(c))throw new Error(f+"options: must be an object!");if("capacity"in c&&a(c.capacity,function(a){if(a)throw new Error(f+"capacity: "+a)}),"deleteOnExpire"in c){if(!b.isString(c.deleteOnExpire))throw new Error(f+"deleteOnExpire: must be a string!");if("none"!==c.deleteOnExpire&&"passive"!==c.deleteOnExpire&&"aggressive"!==c.deleteOnExpire)throw new Error(f+'deleteOnExpire: accepted values are "none", "passive" or "aggressive"!')}if("maxAge"in c&&a(c.maxAge,function(a){if(a)throw new Error(f+"maxAge: "+a)}),"recycleFreq"in c&&a(c.recycleFreq,function(a){if(a)throw new Error(f+"recycleFreq: "+a)}),"cacheFlushInterval"in c&&a(c.cacheFlushInterval,function(a){if(a)throw new Error(f+"cacheFlushInterval: "+a)}),"storageMode"in c){if(!b.isString(c.storageMode))throw new Error(f+"storageMode: must be a string!");if("none"!==c.storageMode&&"localStorage"!==c.storageMode&&"sessionStorage"!==c.storageMode)throw new Error(f+'storageMode: accepted values are "none", "localStorage" or "sessionStorage"!');if("storageImpl"in c){if(!b.isObject(c.storageImpl))throw new Error(f+"storageImpl: must be an object!");if(!("setItem"in c.storageImpl&&"function"==typeof c.storageImpl.setItem))throw new Error(f+'storageImpl: must implement "setItem(key, value)"!');if(!("getItem"in c.storageImpl&&"function"==typeof c.storageImpl.getItem))throw new Error(f+'storageImpl: must implement "getItem(key)"!');if(!("removeItem"in c.storageImpl)||"function"!=typeof c.storageImpl.removeItem)throw new Error(f+'storageImpl: must implement "removeItem(key)"!')}}if("onExpire"in c&&"function"!=typeof c.onExpire)throw new Error(f+"onExpire: must be a function!");d=b.extend({},e(),c)},this.setCacheDefaults({}),this.$get=["$window","BinaryHeap",function(e,f){function g(a){var b,c={};for(b in a)a.hasOwnProperty(b)&&(c[b]=b);return c}function h(a){var b,c=[];for(b in a)a.hasOwnProperty(b)&&c.push(b);return c}function i(i,j){function l(b){a(b,function(a){if(a)throw new Error("capacity: "+a);for(y.capacity=b;B.size()>y.capacity;)E.remove(B.peek().key,{verifyIntegrity:!1})})}function m(a){if(!b.isString(a))throw new Error("deleteOnExpire: must be a string!");if("none"!==a&&"passive"!==a&&"aggressive"!==a)throw new Error('deleteOnExpire: accepted values are "none", "passive" or "aggressive"!');y.deleteOnExpire=a}function n(b){var c=h(z);if(null===b){if(y.maxAge)for(var d=0;de&&"aggressive"===f)F.removeItem(C+".data."+a[c]);else{var g={created:d.created};d.expires&&(g.expires=d.expires),d.accessed&&(g.accessed=d.accessed),d.maxAge&&(g.maxAge=d.maxAge),d.deleteOnExpire&&(g.deleteOnExpire=d.deleteOnExpire),E.put(a[c],d.value,g)}}t(null)}}function t(a){"none"!==y.storageMode&&F&&(F.setItem(C+".keys",b.toJson(h(z))),a&&F.setItem(C+".data."+a,b.toJson(z[a])))}function u(a){if((a||a!==!1&&y.verifyIntegrity)&&"none"!==y.storageMode&&F){var c=h(z);F.setItem(C+".keys",b.toJson(c));for(var d=0;dy.capacity&&this.remove(B.peek().key,{verifyIntegrity:!1}),d},this.get=function(a,d){if(b.isArray(a)){var e=a,f=[];return b.forEach(e,function(a){var c=E.get(a,d);b.isDefined(c)&&f.push(c)}),f}if(d=d||{},!b.isString(a))throw new Error("AngularCache.get(key, options): key: must be a string!");if(d&&!b.isObject(d))throw new Error("AngularCache.get(key, options): options: must be an object!");if(d.onExpire&&!b.isFunction(d.onExpire))throw new Error("AngularCache.get(key, options): onExpire: must be a function!");if(a in z){u(d.verifyIntegrity);var g=z[a],h=g.value,i=(new Date).getTime(),j=g.deleteOnExpire||y.deleteOnExpire;return B.remove(g),g.accessed=i,B.push(g),"passive"===j&&"expires"in g&&g.expiresc.maxAge),c}return z[a]}return b.extend({},y,{size:B&&B.size()||0})},this.keySet=function(){return g(z)},this.keys=function(){return h(z)},this.setOptions=r,r(j,!0,{verifyIntegrity:!1})}function j(a,c){if(a in k)throw new Error("cacheId "+a+" taken!");if(!b.isString(a))throw new Error("cacheId must be a string!");return k[a]=new i(a,c),k[a]}var k={};return j.info=function(){for(var a=h(k),c={size:a.length,caches:{}},e=0;e0;){var f=Math.floor((c+1)/2)-1,g=a[f];if(e>=b(g))break;a[f]=d,a[c]=g,c=f}}function c(a,b,c){for(var d=a.length,e=a[c],f=b(e);;){var g=2*(c+1),h=g-1,i=null;if(d>h){var j=a[h],k=b(j);f>k&&(i=h)}if(d>g){var l=a[g],m=b(l);m<(null===i?f:b(a[h]))&&(i=g)}if(null===i)break;a[c]=a[i],a[i]=e,c=i}}function d(a){if(a&&!b.isFunction(a))throw new Error("BinaryHeap(weightFunc): weightFunc: must be a function!");a=a||function(a){return a},this.weightFunc=a,this.heap=[]}return d.prototype.push=function(b){this.heap.push(b),a(this.heap,this.weightFunc,this.heap.length-1)},d.prototype.peek=function(){return this.heap[0]},d.prototype.pop=function(){var a=this.heap[0],b=this.heap.pop();return this.heap.length>0&&(this.heap[0]=b,c(this.heap,this.weightFunc,0)),a},d.prototype.remove=function(d){for(var e=this.heap.length,f=0;e>f;f++)if(b.equals(this.heap[f],d)){var g=this.heap[f],h=this.heap.pop();return f!==e-1&&(this.heap[f]=h,a(this.heap,this.weightFunc,f),c(this.heap,this.weightFunc,f)),g}return null},d.prototype.removeAll=function(){this.heap=[]},d.prototype.size=function(){return this.heap.length},d}}function e(){function a(a,c){b.isNumber(a)?0>a?c("must be greater than zero!"):c(null):c("must be a number!")}var d,e=function(){return{capacity:Number.MAX_VALUE,maxAge:null,deleteOnExpire:"none",onExpire:null,cacheFlushInterval:null,recycleFreq:1e3,storageMode:"none",storageImpl:null,verifyIntegrity:!0}};this.setCacheDefaults=function(c){var f="$angularCacheFactoryProvider.setCacheDefaults(options): ";if(c=c||{},!b.isObject(c))throw new Error(f+"options: must be an object!");if("capacity"in c&&a(c.capacity,function(a){if(a)throw new Error(f+"capacity: "+a)}),"deleteOnExpire"in c){if(!b.isString(c.deleteOnExpire))throw new Error(f+"deleteOnExpire: must be a string!");if("none"!==c.deleteOnExpire&&"passive"!==c.deleteOnExpire&&"aggressive"!==c.deleteOnExpire)throw new Error(f+'deleteOnExpire: accepted values are "none", "passive" or "aggressive"!')}if("maxAge"in c&&a(c.maxAge,function(a){if(a)throw new Error(f+"maxAge: "+a)}),"recycleFreq"in c&&a(c.recycleFreq,function(a){if(a)throw new Error(f+"recycleFreq: "+a)}),"cacheFlushInterval"in c&&a(c.cacheFlushInterval,function(a){if(a)throw new Error(f+"cacheFlushInterval: "+a)}),"storageMode"in c){if(!b.isString(c.storageMode))throw new Error(f+"storageMode: must be a string!");if("none"!==c.storageMode&&"localStorage"!==c.storageMode&&"sessionStorage"!==c.storageMode)throw new Error(f+'storageMode: accepted values are "none", "localStorage" or "sessionStorage"!');if("storageImpl"in c){if(!b.isObject(c.storageImpl))throw new Error(f+"storageImpl: must be an object!");if(!("setItem"in c.storageImpl&&"function"==typeof c.storageImpl.setItem))throw new Error(f+'storageImpl: must implement "setItem(key, value)"!');if(!("getItem"in c.storageImpl&&"function"==typeof c.storageImpl.getItem))throw new Error(f+'storageImpl: must implement "getItem(key)"!');if(!("removeItem"in c.storageImpl)||"function"!=typeof c.storageImpl.removeItem)throw new Error(f+'storageImpl: must implement "removeItem(key)"!')}}if("onExpire"in c&&"function"!=typeof c.onExpire)throw new Error(f+"onExpire: must be a function!");d=b.extend({},e(),c)},this.setCacheDefaults({}),this.$get=["$window","BinaryHeap",function(e,f){function g(a){return a&&b.isNumber(a)?a.toString():a}function h(a){var b,c={};for(b in a)a.hasOwnProperty(b)&&(c[b]=b);return c}function i(a){var b,c=[];for(b in a)a.hasOwnProperty(b)&&c.push(b);return c}function j(j,k){function m(b){a(b,function(a){if(a)throw new Error("capacity: "+a);for(z.capacity=b;C.size()>z.capacity;)F.remove(C.peek().key,{verifyIntegrity:!1})})}function n(a){if(!b.isString(a))throw new Error("deleteOnExpire: must be a string!");if("none"!==a&&"passive"!==a&&"aggressive"!==a)throw new Error('deleteOnExpire: accepted values are "none", "passive" or "aggressive"!');z.deleteOnExpire=a}function o(b){var c=i(A);if(null===b){if(z.maxAge)for(var d=0;de&&"aggressive"===f)G.removeItem(D+".data."+a[c]);else{var g={created:d.created};d.expires&&(g.expires=d.expires),d.accessed&&(g.accessed=d.accessed),d.maxAge&&(g.maxAge=d.maxAge),d.deleteOnExpire&&(g.deleteOnExpire=d.deleteOnExpire),F.put(a[c],d.value,g)}}u(null)}}function u(a){"none"!==z.storageMode&&G&&(G.setItem(D+".keys",b.toJson(i(A))),a&&G.setItem(D+".data."+a,b.toJson(A[a])))}function v(a){if((a||a!==!1&&z.verifyIntegrity)&&"none"!==z.storageMode&&G){var c=i(A);G.setItem(D+".keys",b.toJson(c));for(var d=0;dz.capacity&&this.remove(C.peek().key,{verifyIntegrity:!1}),d},this.get=function(a,d){if(b.isArray(a)){var e=a,f=[];return b.forEach(e,function(a){var c=F.get(a,d);b.isDefined(c)&&f.push(c)}),f}if(a=g(a),d=d||{},!b.isString(a))throw new Error("AngularCache.get(key, options): key: must be a string!");if(d&&!b.isObject(d))throw new Error("AngularCache.get(key, options): options: must be an object!");if(d.onExpire&&!b.isFunction(d.onExpire))throw new Error("AngularCache.get(key, options): onExpire: must be a function!");if(a in A){v(d.verifyIntegrity);var h=A[a],i=h.value,j=(new Date).getTime(),k=h.deleteOnExpire||z.deleteOnExpire;return C.remove(h),h.accessed=j,C.push(h),"passive"===k&&"expires"in h&&h.expiresc.maxAge),c}return A[a]}return b.extend({},z,{size:C&&C.size()||0})},this.keySet=function(){return h(A)},this.keys=function(){return i(A)},this.setOptions=s,s(k,!0,{verifyIntegrity:!1})}function k(a,c){if(a in l)throw new Error("cacheId "+a+" taken!");if(!b.isString(a))throw new Error("cacheId must be a string!");return l[a]=new j(a,c),l[a]}var l={};return k.info=function(){for(var a=i(l),c={size:a.length,caches:{}},e=0;e