pip-webui
Version:
HTML5 UI for LOB applications
287 lines (243 loc) • 10.9 kB
JavaScript
/**
* @file Global application data cache
* @copyright Digital Living Software Corp. 2014-2016
*/
/* global _, angular */
(function () {
'use strict';
var thisModule = angular.module('pipDataCache', ['pipDataModel']);
thisModule.provider('pipDataCache', function () {
var
CACHE_TIMEOUT = 5 * 60000, // 5 mins or make it configurable
cache = {};
this.timeout = timeout;
this.$get = function ($q, pipDataModel) {
return {
timeout: timeout,
clear: clear,
retrieve: retrieve,
retrieveOrLoad: retrieveOrLoad,
store: store,
storePermanent: storePermanent,
remove: remove,
removeItem: removeItem,
removeDecorator: removeDecorator,
// OBSOLETE - will be removed
addDecorator: addDecorator,
updateDecorator: updateDecorator,
};
//-------------
// Converts a string value into a numeric hash code
function hash(data) {
var filteredData = {};
// Filter only the generic parameters that can be relevant to the query
if (data != null) {
filteredData.item = data.item;
filteredData.party_id = data.party_id;
filteredData.search = data.search;
filteredData.paging = data.paging;
filteredData.take = data.take;
filteredData.skip = data.skip;
}
filteredData = angular.toJson(filteredData);
var h = 0, i, chr, len;
if (filteredData == null || filteredData.length === 0) return h;
for (i = 0, len = filteredData.length; i < len; i++) {
chr = filteredData.charCodeAt(i);
h = ((h << 5) - h) + chr;
h |= 0; // Convert to 32bit integer
}
return h;
};
// Generates parameterized key
function generateKey(name, params) {
var h = hash(params);
return name + (h != 0 ? '_' + h : '');
};
// Clear the cache, globally or selectively
function clear(name) {
if (name == null) {
cache = {};
} else {
for (var key in cache) {
if (key == name || key.startsWith(name + '_')) {
delete cache[key];
}
}
}
};
// Try to retrieve collection from the cache
function retrieve(name, params) {
if (name == null) throw new Error('name cannot be null');
if (name == '') throw new Error('name cannot be empty');
var key = generateKey(name, params);
var holder = cache[key];
if (holder == null) return null;
// If expired then cleanup and return null
if (holder.expire
&& _.now() - holder.expire > CACHE_TIMEOUT) {
delete cache[key];
return null;
}
return holder.data;
};
// Store collection into the cache
function store(name, data, params) {
if (name == null) throw new Error('name cannot be null');
if (name == '') throw new Error('name cannot be empty');
cache[generateKey(name, params)] = {
expire: _.now(),
data: data
};
};
// Store collection into the cache without expiration
function storePermanent(name, data, params) {
if (name == null) throw new Error('name cannot be null');
if (name == '') throw new Error('name cannot be empty');
cache[generateKey(name, params)] = {
expire: null,
data: data
};
};
// Remove collection from the cache
function remove(name, params) {
if (name == null) throw new Error('name cannot be null');
if (name == '') throw new Error('name cannot be empty');
delete cache[generateKey(name, params)];
};
function updateItem(name, item, params) {
if (name == null) throw new Error('name cannot be null');
if (item == null) return;
var data = retrieve(name, params);
if (data != null) {
var isAdded = false;
for (var i = 0; i < data.length; i++) {
if (data[i].id == item.id) {
data[i] = item;
isAdded = true;
return;
}
}
if (!isAdded) data.push(item);
store(name, data, params);
}
};
// Tries to retrieve collection from the cache, otherwise load it from server
function retrieveOrLoad(params, successCallback, errorCallback) {
if (params == null) throw new Error('params cannot be null');
// todo add check params?
var name = (params.cache || params.resource);
// Retrieve data from cache
var filter = params.filter,
force = !!params.force,
result = !force ? retrieve(name, params) : null,
deferred = $q.defer();
// Return result if it exists
if (result) {
if (filter) {
if (result.data) {
result.data = filter(result.data);
} else {
result = filter(result);
}
}
if (successCallback) successCallback(result);
deferred.resolve(result);
return deferred.promise;
}
// Load data from server
if (params.item.paging == 1) {
pipDataModel['page'](
params,
function (data) {
// Store data in cache and return
store(name, data, params);
if (filter) data.data = filter(data.data);
deferred.resolve(data);
if (successCallback) successCallback(data);
},
function (err) {
// Return error
deferred.reject(err);
if (errorCallback) errorCallback(err);
}
);
} else {
pipDataModel[params.singleResult ? 'readOne' : 'read'](
params,
function (data) {
// Store data in cache and return
params.singleResult ?
updateItem(name, data, params) :
store(name, data, params);
if (filter) data = filter(data);
deferred.resolve(data);
if (successCallback) successCallback(data);
},
function (err) {
// Return error
deferred.reject(err);
if (errorCallback) errorCallback(err);
}
);
}
// Return deferred object
return deferred.promise;
};
function removeItem(name, item) {
if (name == null) throw new Error('name cannot be null');
if (item == null) return;
for (var key in cache) {
if (key == name || key.startsWith(name + '_')) {
var data = cache[key].data;
if (angular.isArray(data)) {
for (var i = 0; i < data.length; i++) {
if (data[i].id == item.id) {
data.splice(i, 1);
i--;
}
}
}
}
}
};
function removeDecorator(resource, params, successCallback) {
return function (item) {
removeItem(resource, params);
if (successCallback) successCallback(item);
};
};
function updateDecorator(resource, params, successCallback) {
return function (item) {
for (var key in cache) {
if (key == resource || key.startsWith(resource + '_')) {
var data = cache[key].data;
if (angular.isArray(data)) {
for (var i = 0; i < data.length; i++) {
if (data[i].id == item.id) {
data[i] = item;
}
}
}
}
}
if (successCallback) successCallback(item);
};
};
// OBSOLETE - WILL BE REMOVED ONCE CODE IS REFACTORED
function addDecorator(resource, params, successCallback) {
return function (item) {
if (!params || !params.notClearedCache) clear(resource);
if (successCallback) successCallback(item);
};
};
};
//-----------------------
function timeout(newTimeout) {
if (newTimeout) {
CACHE_TIMEOUT = newTimeout;
}
return CACHE_TIMEOUT;
};
});
})();