memory-cache-node
Advanced tools
Comparing version 1.2.0 to 1.3.0
@@ -1,4 +0,4 @@ | ||
export declare type ItemValueWrapper<V> = { | ||
itemValue: V; | ||
expirationTimestampInMillisSinceEpoch: number | undefined; | ||
export declare type ValueWrapper<V> = { | ||
readonly value: V; | ||
readonly expirationTimestampInMillis: number | undefined; | ||
}; | ||
@@ -9,10 +9,12 @@ export default class MemoryCache<K, V> { | ||
private static readonly EXPIRATION_PROCESSING_ITEM_BATCH_SIZE; | ||
private readonly itemKeyToItemValueWrapperMap; | ||
private readonly itemKeyToValueWrapperMap; | ||
private timer; | ||
private itemCount; | ||
constructor(itemsExpirationCheckIntervalInSecs: number, maxItemCount: number); | ||
storePermanentItem(itemKey: K, itemValue: V): void; | ||
storeExpiringItem(itemKey: K, itemValue: V, timeToLiveInSecs: number): void; | ||
storePermanentItem(key: K, value: V): void; | ||
storeExpiringItem(key: K, value: V, timeToLiveInSecs: number): void; | ||
getItemCount(): number; | ||
hasItem(itemKey: K): boolean; | ||
getValues(): V[]; | ||
getItems(): [K, V][]; | ||
retrieveItemValue(itemKey: K): V | undefined; | ||
@@ -23,4 +25,7 @@ getItemExpirationTimestampInMillisSinceEpoch(itemKey: K): number | undefined; | ||
destroy(): void; | ||
exportItemsToJson(): string; | ||
importPermanentItemsFrom(json: string): void; | ||
importExpiringItemsFrom(json: string, timeToLiveInSecs: number): void; | ||
private readonly deleteExpiredItems; | ||
private deleteExpiredItemsFromBatch; | ||
} |
@@ -7,7 +7,7 @@ "use strict"; | ||
this.maxItemCount = maxItemCount; | ||
this.itemKeyToItemValueWrapperMap = new Map(); | ||
this.itemKeyToValueWrapperMap = new Map(); | ||
this.itemCount = 0; | ||
this.deleteExpiredItems = () => { | ||
const currentTimestampInMillisSinceEpoch = Date.now(); | ||
const iterator = this.itemKeyToItemValueWrapperMap.entries(); | ||
const iterator = this.itemKeyToValueWrapperMap.entries(); | ||
this.deleteExpiredItemsFromBatch(iterator, currentTimestampInMillisSinceEpoch); | ||
@@ -17,6 +17,6 @@ }; | ||
} | ||
storePermanentItem(itemKey, itemValue) { | ||
this.storeExpiringItem(itemKey, itemValue, 0); | ||
storePermanentItem(key, value) { | ||
this.storeExpiringItem(key, value, 0); | ||
} | ||
storeExpiringItem(itemKey, itemValue, timeToLiveInSecs) { | ||
storeExpiringItem(key, value, timeToLiveInSecs) { | ||
if (this.timer === null) { | ||
@@ -26,7 +26,5 @@ throw new Error('Cache is destroyed. Cannot store items anymore.'); | ||
if (this.itemCount < this.maxItemCount) { | ||
this.itemKeyToItemValueWrapperMap.set(itemKey, { | ||
itemValue, | ||
expirationTimestampInMillisSinceEpoch: timeToLiveInSecs | ||
? Date.now() + timeToLiveInSecs * 1000 | ||
: undefined, | ||
this.itemKeyToValueWrapperMap.set(key, { | ||
value, | ||
expirationTimestampInMillis: timeToLiveInSecs ? Date.now() + timeToLiveInSecs * 1000 : undefined, | ||
}); | ||
@@ -40,15 +38,24 @@ this.itemCount++; | ||
hasItem(itemKey) { | ||
return this.itemKeyToItemValueWrapperMap.has(itemKey); | ||
return this.itemKeyToValueWrapperMap.has(itemKey); | ||
} | ||
getValues() { | ||
return Array.from(this.itemKeyToValueWrapperMap.values()).map((valueWrapper) => valueWrapper.value); | ||
} | ||
getItems() { | ||
return Array.from(this.itemKeyToValueWrapperMap.entries()).map(([key, valueWrapper]) => [ | ||
key, | ||
valueWrapper.value, | ||
]); | ||
} | ||
retrieveItemValue(itemKey) { | ||
var _a; | ||
return (_a = this.itemKeyToItemValueWrapperMap.get(itemKey)) === null || _a === void 0 ? void 0 : _a.itemValue; | ||
return (_a = this.itemKeyToValueWrapperMap.get(itemKey)) === null || _a === void 0 ? void 0 : _a.value; | ||
} | ||
getItemExpirationTimestampInMillisSinceEpoch(itemKey) { | ||
var _a; | ||
return (_a = this.itemKeyToItemValueWrapperMap.get(itemKey)) === null || _a === void 0 ? void 0 : _a.expirationTimestampInMillisSinceEpoch; | ||
return (_a = this.itemKeyToValueWrapperMap.get(itemKey)) === null || _a === void 0 ? void 0 : _a.expirationTimestampInMillis; | ||
} | ||
removeItem(itemKey) { | ||
if (this.hasItem(itemKey)) { | ||
this.itemKeyToItemValueWrapperMap.delete(itemKey); | ||
this.itemKeyToValueWrapperMap.delete(itemKey); | ||
this.itemCount--; | ||
@@ -58,3 +65,3 @@ } | ||
clear() { | ||
this.itemKeyToItemValueWrapperMap.clear(); | ||
this.itemKeyToValueWrapperMap.clear(); | ||
this.itemCount = 0; | ||
@@ -69,2 +76,19 @@ } | ||
} | ||
exportItemsToJson() { | ||
const itemsObject = Array.from(this.itemKeyToValueWrapperMap.entries()).reduce((object, [key, { value }]) => ({ | ||
...object, | ||
[key]: value, | ||
}), {}); | ||
return JSON.stringify(itemsObject); | ||
} | ||
importPermanentItemsFrom(json) { | ||
Object.entries(JSON.parse(json)).forEach(([key, value]) => { | ||
this.storePermanentItem(key, value); | ||
}); | ||
} | ||
importExpiringItemsFrom(json, timeToLiveInSecs) { | ||
Object.entries(JSON.parse(json)).forEach(([key, value]) => { | ||
this.storeExpiringItem(key, value, timeToLiveInSecs); | ||
}); | ||
} | ||
deleteExpiredItemsFromBatch(iterator, currentTimestampInMillisSinceEpoch) { | ||
@@ -77,5 +101,5 @@ for (let i = 0; i < MemoryCache.EXPIRATION_PROCESSING_ITEM_BATCH_SIZE; i++) { | ||
const [itemKey, valueWrapper] = iteratorResult.value; | ||
if (valueWrapper.expirationTimestampInMillisSinceEpoch && | ||
valueWrapper.expirationTimestampInMillisSinceEpoch < currentTimestampInMillisSinceEpoch) { | ||
this.itemKeyToItemValueWrapperMap.delete(itemKey); | ||
if (valueWrapper.expirationTimestampInMillis && | ||
valueWrapper.expirationTimestampInMillis < currentTimestampInMillisSinceEpoch) { | ||
this.itemKeyToValueWrapperMap.delete(itemKey); | ||
this.itemCount--; | ||
@@ -82,0 +106,0 @@ } |
@@ -16,3 +16,3 @@ "use strict"; | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(0); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(0); | ||
}); | ||
@@ -33,3 +33,3 @@ }); | ||
expect(memoryCache.hasItem('key')).toBe(true); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(1); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(1); | ||
}); | ||
@@ -40,3 +40,3 @@ it('should not store item in the cache if cache is full', () => { | ||
memoryCache.storeExpiringItem('key', 2, 10); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(1); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(1); | ||
}); | ||
@@ -82,2 +82,28 @@ it('should replace an existing item in the cache', () => { | ||
}); | ||
describe('getValues', () => { | ||
it('should return an empty array if cache is empty', () => { | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
expect(memoryCache.getValues()).toEqual([]); | ||
}); | ||
it('should return an array of values in cache', () => { | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
memoryCache.storePermanentItem('key', 1); | ||
memoryCache.storePermanentItem('key2', 2); | ||
memoryCache.removeItem('key2'); | ||
expect(memoryCache.getValues()).toEqual([1]); | ||
}); | ||
}); | ||
describe('getItems', () => { | ||
it('should return an empty array if cache is empty', () => { | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
expect(memoryCache.getItems()).toEqual([]); | ||
}); | ||
it('should return an array of items in cache', () => { | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
memoryCache.storePermanentItem('key', 1); | ||
memoryCache.storePermanentItem('key2', 2); | ||
memoryCache.removeItem('key2'); | ||
expect(memoryCache.getItems()).toEqual([['key', 1]]); | ||
}); | ||
}); | ||
describe('retrieveItemValue', () => { | ||
@@ -98,4 +124,3 @@ it('should return the item value if cache contains item with given key', () => { | ||
memoryCache.storeExpiringItem('key', 2, 60); | ||
expect(memoryCache.getItemExpirationTimestampInMillisSinceEpoch('key')) | ||
.toBeGreaterThan(Date.now()); | ||
expect(memoryCache.getItemExpirationTimestampInMillisSinceEpoch('key')).toBeGreaterThan(Date.now()); | ||
}); | ||
@@ -112,3 +137,3 @@ it('should return undefined if cache does not contain item with given key', () => { | ||
memoryCache.removeItem('key'); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(0); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(0); | ||
}); | ||
@@ -119,5 +144,40 @@ it('should not decrement item count if cache does not contain item with given key', () => { | ||
memoryCache.removeItem('key2'); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(1); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(1); | ||
}); | ||
}); | ||
describe('exportItemsToJson', () => { | ||
it('should return an empty JSON object if cache is empty', () => { | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
expect(memoryCache.exportItemsToJson()).toEqual('{}'); | ||
}); | ||
it('should return a JSON object with cache items', () => { | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
expect(memoryCache.exportItemsToJson()).toEqual('{}'); | ||
memoryCache.storePermanentItem('key', 1); | ||
memoryCache.storePermanentItem('key2', 2); | ||
expect(JSON.parse(memoryCache.exportItemsToJson())).toEqual({ key: 1, key2: 2 }); | ||
}); | ||
}); | ||
describe('importPermanentItemsFrom', () => { | ||
it('should add items from JSON to the cache', () => { | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
memoryCache.importPermanentItemsFrom('{ "key": 1, "key2": 2 }'); | ||
expect(memoryCache.getItemCount()).toBe(2); | ||
expect(memoryCache.retrieveItemValue('key')).toEqual(1); | ||
expect(memoryCache.retrieveItemValue('key2')).toEqual(2); | ||
expect(memoryCache.getItemExpirationTimestampInMillisSinceEpoch('key')).toBeUndefined(); | ||
expect(memoryCache.getItemExpirationTimestampInMillisSinceEpoch('key2')).toBeUndefined(); | ||
}); | ||
}); | ||
describe('importExpiringItemsFrom', () => { | ||
it('should add items from JSON to the cache', () => { | ||
memoryCache = new MemoryCache_1.default(1, 10); | ||
memoryCache.importExpiringItemsFrom('{ "key": 1, "key2": 2 }', 10); | ||
expect(memoryCache.getItemCount()).toBe(2); | ||
expect(memoryCache.retrieveItemValue('key')).toEqual(1); | ||
expect(memoryCache.retrieveItemValue('key2')).toEqual(2); | ||
expect(memoryCache.getItemExpirationTimestampInMillisSinceEpoch('key')).toBeDefined(); | ||
expect(memoryCache.getItemExpirationTimestampInMillisSinceEpoch('key2')).toBeDefined(); | ||
}); | ||
}); | ||
describe('clear', () => { | ||
@@ -128,3 +188,3 @@ it('it should clear the cache', () => { | ||
memoryCache.clear(); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(0); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(0); | ||
}); | ||
@@ -171,3 +231,3 @@ it('it should set the item count to zero', () => { | ||
expect(memoryCache.getItemCount()).toBe(1); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(1); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(1); | ||
done(); | ||
@@ -181,3 +241,3 @@ }, 3000); | ||
expect(memoryCache.getItemCount()).toBe(1); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(1); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(1); | ||
done(); | ||
@@ -196,3 +256,3 @@ }, 3000); | ||
expect(memoryCache.getItemCount()).toBe(0); | ||
expect(memoryCache.itemKeyToItemValueWrapperMap.size).toBe(0); | ||
expect(memoryCache.itemKeyToValueWrapperMap.size).toBe(0); | ||
done(); | ||
@@ -199,0 +259,0 @@ }, 5000); |
{ | ||
"name": "memory-cache-node", | ||
"version": "1.2.0", | ||
"version": "1.3.0", | ||
"description": "Fast, modern and event loop non-blocking memory cache for Node.js and browse", | ||
@@ -5,0 +5,0 @@ "author": { |
@@ -150,5 +150,13 @@ # memory-cache-node | ||
hasItem(itemKey: K): boolean; | ||
getValues(): V[]; | ||
getItems(): [K, V][]; | ||
retrieveItemValue(itemKey: K): V | undefined; | ||
getItemExpirationTimestampInMillisSinceEpoch(itemKey: K): number | undefined; | ||
removeItem(itemKey: K): void; | ||
exportItemsToJson(): string; | ||
// Use below two functions only with JSON output from exportItemsToJson method | ||
importPermanentItemsFrom(json: string): void; // Can throw if JSON is invalid | ||
importExpiringItemsFrom(json: string, timeToLiveInSecs: number): void; // Can throw if JSON is invalid | ||
clear(): void; | ||
@@ -155,0 +163,0 @@ destroy(): void; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
61694
395
178