Skip to content

Instantly share code, notes, and snippets.

@toboqus
Created December 18, 2015 08:32
Show Gist options
  • Save toboqus/82309fbd8356ff8eada4 to your computer and use it in GitHub Desktop.
Save toboqus/82309fbd8356ff8eada4 to your computer and use it in GitHub Desktop.
Cache for angularjs
/**
* Created by Alex on 20/10/2014.
*/
describe("Service: Cache", function () {
var $interval,
cacheService,
scope,
lo;
beforeEach(function () {
module("storage.Cache", function ($provide) {
$provide.value('lo', _);
});
});
beforeEach(inject(function ($rootScope, _$interval_, _Cache_, _lo_) {
scope = $rootScope.$new();
$interval = _$interval_;
cacheService = _Cache_;
lo = _lo_;
scope.$digest();
}));
describe("initial setup", function () {
it('CacheService should exist', function () {
expect(cacheService).toBeDefined();
});
it('cacheService.items should be empty', function () {
expect(cacheService.items).toEqual([]);
});
it('cacheService.MAX_LENGTH should default to 10', function () {
expect(cacheService.MAX_LENGTH).toEqual(10);
});
it('cacheService.MAX_TIME should default to 10 minutes', function () {
expect(cacheService.MAX_TIME).toEqual(1000 * 60 * 10);
});
it('cacheService.INTERVAL should default to 30 seconds', function () {
expect(cacheService.INTERVAL).toEqual(1000 * 30);
});
});
describe('cache.add function', function () {
it('cacheService.add should exist', function () {
expect(cacheService.add).toBeDefined();
});
it('should add a new object to cache', function () {
expect(cacheService.items.length).toEqual(0);
var obj = {
key: 'riskScores',
value: [
{riskID: 1},
{riskID: 2},
{riskID: 3}
]
};
cacheService.add(obj);
expect(cacheService.items.length).toEqual(1);
});
it('should decorate the object with a key and time for new objects', function () {
var obj = {
key: 'riskScores',
value: [
{riskID: 1},
{riskID: 2},
{riskID: 3}
]
};
cacheService.add(obj);
expect(cacheService.items[0].time).toBeDefined();
expect(cacheService.items[0].key).toEqual('riskScores');
});
it('should decorate the object with a key and time for updating objects', function () {
var obj = {
key: 'riskScores',
value: [
{riskID: 1},
{riskID: 2},
{riskID: 3}
]
};
var obj2 = {
key: 'riskScores',
value: [
{riskID: 1}
]
};
cacheService.add(obj);
cacheService.add(obj2);
expect(cacheService.items[0].time).toBeDefined();
expect(cacheService.items[0].key).toEqual('riskScores');
});
it('should call removeOldItem when adding new objects', function (){
cacheService.removeOldItem = jasmine.createSpy("removeOldItem spy");
cacheService.add({key: 'test', value: 'this is dummy data'});
expect(cacheService.removeOldItem).toHaveBeenCalled();
});
it('should update an object if the key already exists', function () {
var obj1 = {key: 'inspections', value: [
{guidInspection: '123456789', siteName: 'Alex test site'},
{guidInspection: '987654321', siteName: 'test site 2'}
]};
var obj2 = {key: 'inspections', value: []};
cacheService.add(obj1);
expect(cacheService.items.length).toEqual(1);
expect(cacheService.get('inspections').value).toEqual(obj1);
cacheService.add(obj2);
expect(cacheService.items.length).toEqual(1);
expect(cacheService.get('inspections').value).toEqual(obj2);
});
});
describe('cache.get function', function () {
it('cacheService.get should exist', function () {
expect(cacheService.get).toBeDefined();
});
it('should return object with the requested key', function () {
cacheService.items = [
{key: 'inspections', value: 'this is some data', time: new Date()},
{key: 1, value: {key: 'sites', value: 'sites data'}, time: new Date()}
];
expect(cacheService.get('inspections').key).toEqual('inspections');
expect(cacheService.get('inspections').value).toEqual('this is some data');
expect(cacheService.get(1).key).toEqual(1);
expect(cacheService.get(1).value.key).toEqual('sites');
});
it('should be falsy when cached item does not exist', function () {
cacheService.items = [
{key: 'inspections', value: 'this is some data', time: new Date()},
{key: 1, value: {key: 'sites', value: 'sites data'}, time: new Date()}
];
expect(cacheService.get('sd')).toBeFalsy();
expect(cacheService.get(434)).toBeFalsy();
});
});
describe('cache.exists function', function () {
it('cacheService.exists should exist', function () {
expect(cacheService.exists).toBeDefined();
});
it('should return true when an object exists with a key', function () {
cacheService.items = [
{key: 'inspections', value: 'this is some data', time: new Date()},
{key: 1, value: 'this is some data', time: new Date()}
];
expect(cacheService.exists('inspections')).toEqual(true);
expect(cacheService.exists(1)).toEqual(true);
});
it('should return false when an object does not exist', function () {
cacheService.items = [
{key: 'inspections', value: 'this is some data', time: new Date()},
{key: 999, value: 'this is some data', time: new Date()}
];
expect(cacheService.exists('inspectors')).toEqual(false);
expect(cacheService.exists(5)).toEqual(false);
});
it('should return false when the cache is empty', function () {
cacheService.items = [];
expect(cacheService.exists('inspectors')).toEqual(false);
expect(cacheService.exists(5)).toEqual(false);
});
});
describe('cache.removeExpiredItem function', function () {
it('cacheService.removeExpiredItem should exist', function () {
expect(cacheService.removeExpiredItem).toBeDefined();
});
it('should remove an object if it is over the cache.MAX_TIME threshold', function () {
var time =( new Date() - (cacheService.MAX_TIME+10));
cacheService.items[0] = {key:'inspections', value:'', time:time};
expect(cacheService.items.length).toEqual(1);
cacheService.removeExpiredItem();
expect(cacheService.items.length).toEqual(0);
});
it('should not remove an object if it is within the cache.MAX_TIME threshold', function () {
var time =( new Date() - (cacheService.MAX_TIME - 100));
cacheService.items[0] = {key:'inspections', value:'', time:time};
expect(cacheService.items.length).toEqual(1);
cacheService.removeExpiredItem();
expect(cacheService.items.length).toEqual(1);
});
});
describe('cache.removeOldItem function', function () {
it('cacheService.removeOldItem should exist', function () {
expect(cacheService.removeOldItem).toBeDefined();
});
it('should remove the oldest item in the array if its at its maximum defined length', function (){
for (var i = 0; i < 10; i++) {
cacheService.add({key: 'test' + [i], value: 'this is dummy data'});
}
expect(cacheService.items.length).toEqual(10);
expect(cacheService.items[0].key).toEqual('test0');
cacheService.add({key: 'test10', value: 'this is dummy data'});
cacheService.add({key: 'test11', value: 'this is dummy data'});
cacheService.removeOldItem();
expect(cacheService.items[0].key).toEqual('test2');
});
it('should not delete an item if the cache.items.length is below the threshold', function (){
for (var i = 0; i < 5; i++) {
cacheService.add({key: 'test' + [i], value: 'this is dummy data'});
}
expect(cacheService.items.length).toEqual(5);
cacheService.removeOldItem();
expect(cacheService.items.length).toEqual(5);
});
});
describe('cache.autoRemove', function () {
it('cacheService.autoRemove should exist', function () {
expect(cacheService.autoRemove).toBeDefined();
});
it('should call removeOldItem and removeExpiredItem if there are items in the cache', function (){
cacheService.removeOldItem = jasmine.createSpy("removeOldItem spy");
cacheService.removeExpiredItem = jasmine.createSpy("removeExpiredItem spy");
cacheService.add({key: 'test', value: 'this is dummy data'});
cacheService.autoRemove();
expect(cacheService.removeOldItem).toHaveBeenCalled();
expect(cacheService.removeExpiredItem).toHaveBeenCalled();
});
it('should not call removeOldItem and removeExpiredItem if there are no items in the cache', function (){
cacheService.removeOldItem = jasmine.createSpy("removeOldItem spy");
cacheService.removeExpiredItem = jasmine.createSpy("removeExpiredItem spy");
expect(cacheService.items.length).toEqual(0);
cacheService.autoRemove();
expect(cacheService.removeOldItem).not.toHaveBeenCalled();
expect(cacheService.removeExpiredItem).not.toHaveBeenCalled();
});
});
describe('$interval for autoRemove', function (){
it('intervalRef should be defined', function (){
expect(cacheService.intervalRef).toBeDefined();
});
});
});
/**
* Created by Alex on 20/10/2014.
* Must have LoDash installed (http://lodash.com)
*/
(function () {
"use strict";
angular.module('storage.Cache', []);
var Cache = function Cache($interval, lo) {
var obj = {};
/**
* @description array to store cached items
* @type {Array}
*/
obj.items = [];
/**
* @description Static var, max number of items cache can store, in this case 10.
* @type {number}
*/
obj.MAX_LENGTH = 10;
/**
* @description Static var, max time to store cache items for: 10 minutes: 1000 x 60 x 10
* @type {number}
*/
obj.MAX_TIME = 600000;
/**
* @description Static var, interval time to fire autoDelete: 30 seconds.
* @type {number}
*/
obj.INTERVAL = 1000 * 30;
/**
* @name add
* @param {Object} data
* @description Add method to decorate the data with a key and timestamp
* it will then push the data into the cache array or update existing record.
* data must have 'key' defined in the object to work.
*/
obj.add = function add(data) {
var toAdd = {
key: data.key,
value: data,
time: new Date()
};
if (obj.exists(data.key)) {
obj.items = lo.map(obj.items, function (item) {
return (item.key === toAdd.key) ? toAdd : item;
})
} else {
obj.items.push(toAdd);
obj.removeOldItem();
}
toAdd = null;
};
/**
* @name cache.get
* @param {String} key
* @description Get method to return data stored in the cache.
* @returns {object}
*/
obj.get = function get(key) {
return lo(obj.items).find({key: key});
};
/**
* @name cache.exists
* @param {String} key
* @description Exists method to check if data for that key is stored in cache.
* @returns {Boolean}
*/
obj.exists = function exists(key) {
return lo(obj.items).some({key: key});
};
/**
* @name removeExpiredItem
* @description checks to see if a cached item has expired
* and if it has then remove it from the cache
*/
obj.removeExpiredItem = function removeExpiredItem() {
lo.remove(obj.items, function (item) {
return ((new Date() - item.time) > obj.MAX_TIME);
})
};
/**
* @name removeOldItem
* @description checks to see if the cache has too many items,
* it will remove the oldest if its over the MAX_LENGTH
*/
obj.removeOldItem = function removeOldItem() {
if (obj.items.length > obj.MAX_LENGTH) {
obj.items.splice(0, 1);
obj.removeOldItem();
}
};
/**
* @name autoRemove
* @description Method to fire both removeExpiredItem
* and removeOldItem if there are items in the array.
* this will be fired each minute.
*/
obj.autoRemove = function autoRemove() {
if (obj.items.length) {
obj.removeExpiredItem();
obj.removeOldItem();
}
};
obj.intervalRef = $interval(obj.autoRemove, obj.INTERVAL);
return obj;
};
angular.module('storage.Cache').factory('Cache', ['$interval', 'lo', Cache])
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment