UNPKG

key-file-storage

Version:

Simple key-value storage directly on file system, maps each key to a separate file.

187 lines (186 loc) 8.05 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); function createCache(cacheConfig) { if (cacheConfig === true || typeof cacheConfig === 'undefined') { // Unlimited cache by default return createCache_Unlimited(cacheConfig); } else if (cacheConfig === false) { // No cache return createCache_NoCache(cacheConfig); } else if (typeof cacheConfig === 'number' && cacheConfig > 0) { // Limited cache by the number of keys return createCache_LimitedByKeyCount(cacheConfig); } else { throw new Error('Invalid cache config.'); } function createCache_Unlimited(cacheConfig) { var collectionCache = {}; return new Proxy({ /*CACHE*/ }, { set: function (target, property, value, receiver) { var propertyName = String(property); if (propertyName.endsWith('/')) { collectionCache[propertyName] = value; return true; } target[propertyName] = value; Object.keys(collectionCache) .filter(function (collection) { return keyInCollection(propertyName, collection); }) .forEach(function (collection) { return collectionCache[collection].includes(propertyName) || collectionCache[collection].push(propertyName); }); return true; }, get: function (target, property, receiver) { var propertyName = String(property); if (propertyName.endsWith('/')) return collectionCache[propertyName]; return target[propertyName]; }, deleteProperty: function (target, property) { var propertyName = String(property); if (propertyName === '*') { collectionCache = {}; Object.keys(target).forEach(function (key) { return delete target[key]; }); return true; } if (propertyName.endsWith('/')) return delete collectionCache[propertyName]; Object.keys(collectionCache) .filter(function (collection) { return keyInCollection(propertyName, collection); }) .forEach(function (collection) { return collectionCache[collection].includes(propertyName) && collectionCache[collection].splice(collectionCache[collection].indexOf(propertyName), 1); }); return delete target[propertyName]; }, has: function (target, property) { var propertyName = String(property); if (propertyName.endsWith('/')) return propertyName in collectionCache; return property in target; }, }); } function createCache_NoCache(cacheConfig) { return new Proxy({ /*CACHE*/ }, { set: function (target, property, value, receiver) { return true; }, get: function (target, property, receiver) { return undefined; }, deleteProperty: function (target, property) { return true; }, has: function (target, property) { return false; }, }); } function createCache_LimitedByKeyCount(cacheConfig) { var collectionCache = {}; var keyNumber = Math.ceil(cacheConfig), keys = Array(keyNumber), nextKeyIndex = 0, keyIndex; return new Proxy({ /*CACHE*/ }, { set: function (target, property, value, receiver) { var propertyName = String(property); if (propertyName.endsWith('/')) { collectionCache[propertyName] = value; return true; } updateKeys(target, propertyName, 'SET'); target[propertyName] = value; Object.keys(collectionCache) .filter(function (collection) { return keyInCollection(propertyName, collection); }) .forEach(function (collection) { return collectionCache[collection].includes(propertyName) || collectionCache[collection].push(propertyName); }); return true; }, get: function (target, property, receiver) { var propertyName = String(property); if (propertyName.endsWith('/')) return collectionCache[propertyName]; updateKeys(target, propertyName, 'GET'); return target[propertyName]; }, deleteProperty: function (target, property) { var propertyName = String(property); if (propertyName === '*') { collectionCache = {}; keys = Array(keyNumber); nextKeyIndex = 0; return true; } if (propertyName.endsWith('/')) return delete collectionCache[propertyName]; Object.keys(collectionCache) .filter(function (collection) { return keyInCollection(propertyName, collection); }) .forEach(function (collection) { return collectionCache[collection].includes(propertyName) && collectionCache[collection].splice(collectionCache[collection].indexOf(propertyName), 1); }); updateKeys(target, propertyName, 'DELETE'); return delete target[propertyName]; }, has: function (target, property) { var propertyName = String(property); if (propertyName.endsWith('/')) return propertyName in collectionCache; return keys.indexOf(property) >= 0; }, }); function realIndex(i) { return (i + keyNumber) % keyNumber; } function updateKeys(target, property, mode) { keyIndex = keys.indexOf(property); if (keyIndex < 0) { // Does not exist mode === 'SET' && addKey(); } else if (keyIndex === realIndex(nextKeyIndex - 1)) { // The latest key mode === 'DELETE' && removeKey(); } else { // Otherwise removeKey(); mode === 'DELETE' || addKey(); } function removeKey() { while (keyIndex !== nextKeyIndex && keys[keyIndex]) { keys[keyIndex] = keys[realIndex(keyIndex - 1)]; keyIndex = realIndex(keyIndex - 1); } keys[nextKeyIndex] = undefined; } function addKey() { if (keys[nextKeyIndex] !== property) { if (keys[nextKeyIndex] !== undefined) delete target[keys[nextKeyIndex]]; keys[nextKeyIndex] = property; } nextKeyIndex = realIndex(nextKeyIndex + 1); } } } function keyInCollection(key, collection) { collection = collection.startsWith('./') ? collection.slice(1) : collection.startsWith('/') ? collection : '/' + collection; key = key.startsWith('./') ? key.slice(1) : key.startsWith('/') ? key : '/' + key; return key.startsWith(collection); } } exports.default = createCache;