I'm trying to build a reusable object cache for Angular.  The goal is to:Cache objects by typePrevent collisions and conflictsFind objects by like propertyEnsure caches are separated by the logged in userI am using Satellizer to determine if the user is logged in.  Each object's service will act as a wrapper to this service and pass in its typeName property (probably set as a constant in the calling service).(function () {    'use strict';    angular        .module('blocks.object-cache');    objectCache.$inject = ['CacheFactory', '$auth'];    function objectCache(CacheFactory, $auth) {        var _options = {            maxAge : (60 * 60 * 1000),            deleteOnExpire : 'passive',            storageMode : 'localStorage'        };        var service = {            setOptions          : setOptions,            getCache            : getCache,            clear               : clear,            getAll              : getAll,            getItem             : getItem,            getItems            : getItems,            putItem             : putItem,            putItems            : putItems,            getItemsByKey       : getItemsByKey,            getItemByKeyFirst   : getItemByKeyFirst,            getItemByKeySingle  : getItemByKeySingle,            removeItemsByKey    : removeItemsByKey,            removeItemByKey     : removeItemByKey,            putItemsByKey       : putItemsByKey,            putItemByKey        : putItemByKey        };        return service;        ////////////////////////////////////////////////////////////////////////////////        function setOptions (options) {            options = options || {};            options.maxAge = options.maxAge = _options.maxAge;            options.deleteOnExpire = options.deleteOnExpire = _options.deleteOnExpire;            options.storageMode = options.storageMode = _options.storageMode;            _options = options;        }        function getCache(typeName) {            var cacheName = [getUserId(), normalizeTypeName(typeName || 'objects')].join('_');            var cache = CacheFactory(cacheName);            if (cache) { return cache; }            cache = CacheFactory(cacheName, _options);            return cache;        }        function clear (typeName) {            var cache = getCache(typeName);            cache.removeAll();            return (!cache.keys() || (cache.keys().length < 1));        }        function getAll (typeName) {            var cache = getCache(typeName);            var result = [];            (cache.keys() || []).forEach(function(key){                result.push(cache(key));            });            return result;        }        function getItem(typeName, id) {            if (typeof id == 'undefined' || !id.trim) { return null; }            var cache = getCache(typeName);            return cache.get(id);        }        function getItems(typeName, ids) {            var cache = getCache(typeName),                result = [],                _ids   = [];            (ids || []).forEach(function(id){                if (_ids.indexOf(id) < 0) {                    _ids.push(id);                    var item = cache.get(id);                    if (item) { result.push(item); }                }            });            return result;        }        function putItem(typeName, item, id, refresh) {            if (typeof item == 'undefined') { return false; }            if (typeof id == 'undefined' || !id.trim) { return false; }            var cache = getCache(typeName);            var existing = cache.get(id);            if (existing && !refresh) { return true; }            if (existing) { cache.remove(id); }            cache.put(item, id);            return (!!cache.get(id));        }        function putItems(typeName, items, idField, refresh) {            var cache = getCache(typeName);            (items || []).forEach(function(item){                var id = item[idField];                if (typeof id != 'undefined') {                    var existing = cache.get(id);                    if (existing && !!refresh) { cache.remove(id); }                    if (!existing || !!refresh) { cache.put(item, id); }                    if (!cache.get(id)) { return false; }                }            });            return true;        }        function getItemsByKey(typeName, key, value, isCaseSensitive) {            var result = [];            (getAll(typeName) || []).forEach(function(item){                var itemValue = item[key];                if (typeof itemValue != 'undefined') {                    if ((typeof value == 'string') && (typeof itemValue == 'string') && (!isCaseSensitive || value.toLowerCase() == itemValue.toLowerCase())) {                        result.push(item);                    } else if (((typeof value) == (typeof itemValue)) && (value == itemValue)) {                        result.push(item);                    } else {                        // Other scenarios?                    }                }            });            return result;        }        function getItemByKeyFirst(typeName, key, value, isCaseSensitive) {            var items = getItemsByKey(typeName, key, value, isCaseSensitive) || [];            return (items.length > 0) ? items[0] : null;        }        function getItemByKeySingle(typeName, key, value, isCaseSensitive) {            var items = getItemsByKey(typeName, key, value, isCaseSensitive) || [];            return (items.length === 0) ? items[0] : null;        }        function removeItemsByKey (typeName, keyField, values, isCaseSensitive) {            var cache = getCache(typeName),                keysToRemove = [];            (cache.keys() || []).forEach(function(key){                var item        = cache.get[key],                    itemValue   = item[keyField];                if (typeof itemValue != 'undefined') {                    for (var v = 0; v < (values || []).length; v += 1) {                        if ((typeof values[v] == 'string') && (typeof itemValue == 'string') && (!isCaseSensitive || values[v].toLowerCase() == itemValue.toLowerCase())) {                            keysToRemove.push(key);                            break;                        } else if (((typeof values[v]) == (typeof itemValue)) && (values[v] == itemValue)) {                            keysToRemove.push(key);                            break;                        } else {                            // Other scenarios?                        }                    }                }            });            var success = true;            keysToRemove.forEach(function(key){                cache.remove(key);                if (cache.get(key)) { success = false; }            });            return success;        }        function removeItemByKey (typeName, keyField, value, isCaseSensitive) {            return removeItemsByKey(typeName, keyField, [value], isCaseSensitive);        }        function putItemsByKey(typeName, items, keyField, refresh, isCaseSensitive) {            if (!!refresh) {                var values  = _.map((items || []), keyField);                if (!removeItemsByKey(typeName, keyField, values, isCaseSensitive)) { return false; }            }            var cache = getCache(typeName);            (items || []).forEach(function(item){                var id = item[keyField];                if (typeof value != 'undefined') { cache.put(item, id); }                if (!cache.get(id)) { return false; }            });            return true;        }        function putItemByKey(typeName, item, keyField, refresh, isCaseSensitive) {            return putItemsByKey(typeName, [item], keyField, refresh, isCaseSensitive);        }        function getUserId () {            return $auth.isAuthenticated() ? ($auth.getPayload().sub || 'unknown') : 'public';        }        function normalizeTypeName (typeName) {            return typeName.split('.').join('-');        }    }})();
Member-specific object cache for Angular
javascript;angular.js