@swarmy/lru-cache
Advanced tools
Comparing version 2.0.5 to 3.0.0
@@ -1,1 +0,1 @@ | ||
module.exports=function(t){var r={};function u(e){if(r[e])return r[e].exports;var n=r[e]={i:e,l:!1,exports:{}};return t[e].call(n.exports,n,n.exports,u),n.l=!0,n.exports}return u.m=t,u.c=r,u.d=function(e,n,t){u.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},u.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},u.t=function(n,e){if(1&e&&(n=u(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var t=Object.create(null);if(u.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var r in n)u.d(t,r,function(e){return n[e]}.bind(null,r));return t},u.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return u.d(n,"a",n),n},u.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},u.p="",u(u.s=0)}([function(e,n,t){"use strict";t.r(n);var l=function(e,n){null===n.newest?(n.newest=e,n.oldest=e):((n.newest.next=e).prev=n.newest,n.newest=e)},i=function(e,n){e!==n.newest&&(null===(n.newest.next=e).prev?(e.prev=n.newest,e.next.prev=null,n.oldest=e.next):(e.prev.next=e.next,e.next.prev=e.prev,e.prev=n.newest),e.next=null,n.newest=e)},r=function(e,n,t){null===e.next?n.newest=e.prev:e.next.prev=e.prev,null===e.prev?n.oldest=e.next:e.prev.next=e.next,t.delete(e.key)},c=function(e,n,t){var r,u,o,a=[];if(null===e)return a;for(;t.size>e;)a.push((u=t,void 0,o=(r=n).oldest,u.delete(r.oldest.key),r.oldest=r.oldest.next,r.oldest.prev=null,{key:o.key,value:o.value}));return a};function f(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,n=this instanceof f?this:Object.create(f.prototype),u=e;0===u&&(u=null);var o=new Map,a={newest:null,oldest:null};return n.setMaxSize=function(e){return(u=e)<1&&(u=null),c(u,a,o)},n.getMaxSize=function(){return u},n.getSize=function(){return o.size},n.set=function(e,n){var t=o.get(e);if(void 0!==t)return t.value=n,i(t,a),null;t={key:e,value:n,next:null,prev:null},o.set(e,t),l(t,a);var r=c(u,a,o);return 1===r.length?r[0]:null},n.get=function(e){var n=o.get(e);return void 0===n?n:(i(n,a),n.value)},n.getWithoutLruChange=function(e){var n=o.get(e);return void 0===n?n:n.value},n.delete=function(e){var n=o.get(e);return void 0!==n&&(r(n,a,o),!0)},n.forEach=function(e){for(var n=a.oldest;null!==n;)e(n.value,n.key),n=n.next},n.map=function(e){for(var n=a.oldest,t=[];null!==n;)t.push(e(n.value,n.key)),n=n.next;return t},n.clear=function(){var e=n.map(function(e,n){return{key:n,value:e}});return o.clear(),a.newest=null,a.oldest=null,e},n}function d(e){return function(e){if(Array.isArray(e)){for(var n=0,t=new Array(e.length);n<e.length;n++)t[n]=e[n];return t}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function a(n){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},r=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.forEach(function(e){s(n,e,t[e])})}return n}function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}t.d(n,"registerCacheChangedHandler",function(){return w}),t.d(n,"cacheTransaction",function(){return S}),t.d(n,"getCache",function(){return L}),t.d(n,"clearAllCaches",function(){return _});var v=500,u=0,y=new Map,h=new Map,p=new Set,o=function(t,e){null===e||Array.isArray(e)&&0===e.length?p.add(t):(Array.isArray(e)?e:[e]).forEach(function(e){var n=h.get(e);void 0===n&&(n=new Set,h.set(e,n)),n.add(t)})},g=function(n,e){null===e||Array.isArray(e)&&0===e.length?p.delete(n):(Array.isArray(e)?e:[e]).forEach(function(e){h.get(e).delete(n)})},w=function(e){var n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null,t=u;u+=1;var r={changedHandler:e,valueTypes:n,isActive:!0,unregister:function(){y.delete(t),g(t,n)},activate:function(){r.isActive=!0,o(t,n)},deactivate:function(){r.isActive=!1,g(t,n)},isRegistered:function(){return y.has(t)}};return y.set(t,r),o(t,n),r},m=function(t){var e,n,r,u=(e=t.valueTypes,n="string"==typeof e?[e]:e,r=new Set,n.forEach(function(e){var n=h.get(e);void 0!==n&&n.forEach(function(e){r.add(e)})}),p.forEach(function(e){r.add(e)}),r),o=[],a=0;if(u.forEach(function(e){var n=y.get(e);try{n.changedHandler(t)}catch(e){o.push(e)}finally{a+=1}}),0<o.length){var l="handleTransactionChangeObject: "+String(o.length)+" of "+String(a)+" handlers threw an error: ";o.forEach(function(e){l+=e.message+", "});var i=new Error(l);throw i.errors=o,i}},b=null,A=0,x=0,S=function(e){if(null===b&&(b={valueTypes:new Set}),x+=1,"function"==typeof e.finally)e.finally(function(){if(0===(x-=1))try{m(b)}finally{b=null,A=0}});else try{e()}finally{if(0===(x-=1))try{m(b)}finally{b=null,A=0}}},E=function(n,e,t,r){var u=b,o=null!==u;null===u&&(u={valueTypes:new Set}),u.valueTypes.has(n)?u[n][t].push(a({},e,{order:A++})):(u.valueTypes.add(n),u[n]=s({},t,[a({},e,{order:A++})]),r.forEach(function(e){u[n][e]=[]})),o||m(u)},O=!0,j=function(e,n){O&&E(e,n,"clearRemoves",["inserts","lruRemoves","deleteRemoves"])},k=function(e,n){O&&E(e,n,"lruRemoves",["clearRemoves","inserts","deleteRemoves"])},M=function(e,n){O&&E(e,n,"deleteRemoves",["clearRemoves","lruRemoves","inserts"])},R=function(u){return function(){for(var e=arguments.length,r=new Array(e),n=0;n<e;n++)r[n]=arguments[n];return new Promise(function(n,t){setTimeout(function(){try{var e=u.apply(void 0,r);n(e)}catch(e){t(e)}},0)})}},z=function(e,n){if(function(e){if(0<p.size)return!0;var n=h.get(e);return void 0!==n&&0<n.size}(e))S(n);else try{O=!1,n()}finally{O=!0}},C=function(c,f,s,e,v){if(!Array.isArray(e))throw new Error("LruCache::setAll: keyValueAlternateKeysArray must be an array");z(c,function(){e.forEach(function(e){var n=e.key,t=e.value,r=e.alternateKeys,u=f.getWithoutLruChange(n),o=Array.isArray(r)?r:[];0===o.length&&"string"==typeof r&&(o=[r]),o.forEach(function(e){if(s.has(e)&&s.get(e)!==n)throw new Error("LruCache::setAll: alternate key '"+e+"' is given for key '"+n+"' and value type '"+c+"' but is already used for key '"+s.get(e)+"'")}),o=new Set(o),void 0===u?u={key:n,value:t,alternateKeys:o}:(u.value=t,u.alternateKeys=new Set(d(u.alternateKeys).concat(d(o))));var a,l,i=f.set(n,u);o.forEach(function(e){s.set(e,n)}),a=c,l=u,O&&E(a,l,"inserts",["clearRemoves","lruRemoves","deleteRemoves"]),null!==i&&(i.value.alternateKeys.forEach(function(e){s.delete(e)}),v&&k(c,i.value))})})},T=function(e,n,t){var r=t(e);return void 0===r&&n.has(e)&&(r=t(n.get(e))),r};function P(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:v,n=this instanceof P?this:Object.create(P.prototype),r=f(e),u=new Map,o=!1,a=!1;return n.dispatchLruRemoves=function(e){o=e},n.dispatchClearRemoves=function(e){a=e},n.setAll=function(e){C(t,r,u,e,o)},n.setAllAsync=R(n.setAll),n.set=function(e){n.setAll([e])},n.setAsync=R(n.set),n.get=function(e){var n=T(e,u,r.get);return void 0===n?n:n.value},n.getWithoutLruChange=function(e){var n=T(e,u,r.getWithoutLruChange);return void 0===n?n:n.value},n.delete=function(e){var n=T(e,u,r.getWithoutLruChange);return void 0!==n&&(r.delete(n.key),n.alternateKeys.forEach(function(e){u.delete(e)}),z(t,function(){M(t,n)}),!0)},n.forEach=r.forEach,n.getEntries=function(){return r.map(function(e){return e})},n.clear=function(){var e=r.clear();u.clear(),a&&z(t,function(){e.forEach(function(e){j(t,e.value)})})},n.getSize=r.getSize,n.getValueType=function(){return t},n.getMaxSize=r.getMaxSize,n.setMaxSize=function(e){var n=r.setMaxSize(e);z(t,function(){n.forEach(function(e){e.value.alternateKeys.forEach(function(e){u.delete(e)}),o&&k(t,e.value)})})},n}var K=new Map,L=function(e){var n=K.get(e);return void 0===n&&(n=P(e),K.set(e,n)),n},_=function(){S(function(){K.forEach(function(e){e.clear()})})}}]); | ||
module.exports=function(t){var r={};function u(e){if(r[e])return r[e].exports;var n=r[e]={i:e,l:!1,exports:{}};return t[e].call(n.exports,n,n.exports,u),n.l=!0,n.exports}return u.m=t,u.c=r,u.d=function(e,n,t){u.o(e,n)||Object.defineProperty(e,n,{enumerable:!0,get:t})},u.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},u.t=function(n,e){if(1&e&&(n=u(n)),8&e)return n;if(4&e&&"object"==typeof n&&n&&n.__esModule)return n;var t=Object.create(null);if(u.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:n}),2&e&&"string"!=typeof n)for(var r in n)u.d(t,r,function(e){return n[e]}.bind(null,r));return t},u.n=function(e){var n=e&&e.__esModule?function(){return e.default}:function(){return e};return u.d(n,"a",n),n},u.o=function(e,n){return Object.prototype.hasOwnProperty.call(e,n)},u.p="",u(u.s=0)}([function(e,n,t){"use strict";t.r(n);var l=function(e,n){null===n.newest?(n.newest=e,n.oldest=e):((n.newest.next=e).prev=n.newest,n.newest=e)},i=function(e,n){e!==n.newest&&(null===(n.newest.next=e).prev?(e.prev=n.newest,e.next.prev=null,n.oldest=e.next):(e.prev.next=e.next,e.next.prev=e.prev,e.prev=n.newest),e.next=null,n.newest=e)},r=function(e,n,t){null===e.next?n.newest=e.prev:e.next.prev=e.prev,null===e.prev?n.oldest=e.next:e.prev.next=e.next,t.delete(e.key)},c=function(e,n,t){var r,u,o,a=[];if(null===e)return a;for(;t.size>e;)a.push((u=t,void 0,o=(r=n).oldest,u.delete(r.oldest.key),r.oldest=r.oldest.next,r.oldest.prev=null,{key:o.key,value:o.value}));return a};function f(){var e=0<arguments.length&&void 0!==arguments[0]?arguments[0]:null,n=this instanceof f?this:Object.create(f.prototype),u=e;0===u&&(u=null);var o=new Map,a={newest:null,oldest:null};return n.setMaxSize=function(e){return(u=e)<1&&(u=null),c(u,a,o)},n.getMaxSize=function(){return u},n.getSize=function(){return o.size},n.set=function(e,n){var t=o.get(e);if(void 0!==t)return t.value=n,i(t,a),null;t={key:e,value:n,next:null,prev:null},o.set(e,t),l(t,a);var r=c(u,a,o);return 1===r.length?r[0]:null},n.get=function(e){var n=o.get(e);return void 0===n?n:(i(n,a),n.value)},n.getWithoutLruChange=function(e){var n=o.get(e);return void 0===n?n:n.value},n.delete=function(e){var n=o.get(e);return void 0!==n&&(r(n,a,o),!0)},n.forEach=function(e){for(var n=a.oldest;null!==n;)e(n.value,n.key),n=n.next},n.map=function(e){for(var n=a.oldest,t=[];null!==n;)t.push(e(n.value,n.key)),n=n.next;return t},n.clear=function(){var e=n.map(function(e,n){return{key:n,value:e}});return o.clear(),a.newest=null,a.oldest=null,e},n}function y(e){return function(e){if(Array.isArray(e)){for(var n=0,t=new Array(e.length);n<e.length;n++)t[n]=e[n];return t}}(e)||function(e){if(Symbol.iterator in Object(e)||"[object Arguments]"===Object.prototype.toString.call(e))return Array.from(e)}(e)||function(){throw new TypeError("Invalid attempt to spread non-iterable instance")}()}function a(n){for(var e=1;e<arguments.length;e++){var t=null!=arguments[e]?arguments[e]:{},r=Object.keys(t);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(t).filter(function(e){return Object.getOwnPropertyDescriptor(t,e).enumerable}))),r.forEach(function(e){s(n,e,t[e])})}return n}function s(e,n,t){return n in e?Object.defineProperty(e,n,{value:t,enumerable:!0,configurable:!0,writable:!0}):e[n]=t,e}t.d(n,"registerCacheChangedHandler",function(){return w}),t.d(n,"cacheTransaction",function(){return S}),t.d(n,"getCache",function(){return L}),t.d(n,"clearAllCaches",function(){return _});var v=500,u=0,d=new Map,h=new Map,p=new Set,o=function(t,e){null===e||Array.isArray(e)&&0===e.length?p.add(t):(Array.isArray(e)?e:[e]).forEach(function(e){var n=h.get(e);void 0===n&&(n=new Set,h.set(e,n)),n.add(t)})},g=function(n,e){null===e||Array.isArray(e)&&0===e.length?p.delete(n):(Array.isArray(e)?e:[e]).forEach(function(e){h.get(e).delete(n)})},w=function(e){var n=1<arguments.length&&void 0!==arguments[1]?arguments[1]:null,t=u;u+=1;var r={changedHandler:e,valueTypes:n,isActive:!0,unregister:function(){d.delete(t),g(t,n)},activate:function(){r.isActive=!0,o(t,n)},deactivate:function(){r.isActive=!1,g(t,n)},isRegistered:function(){return d.has(t)}};return d.set(t,r),o(t,n),r},m=function(t){var e,n,r,u=(e=t.valueTypes,n="string"==typeof e?[e]:e,r=new Set,n.forEach(function(e){var n=h.get(e);void 0!==n&&n.forEach(function(e){r.add(e)})}),p.forEach(function(e){r.add(e)}),r),o=[],a=0;if(u.forEach(function(e){var n=d.get(e);try{n.changedHandler(t)}catch(e){o.push(e)}finally{a+=1}}),0<o.length){var l="handleTransactionChangeObject: "+String(o.length)+" of "+String(a)+" handlers threw an error: ";o.forEach(function(e){l+=e.message+", "});var i=new Error(l);throw i.errors=o,i}},b=null,A=0,x=0,S=function(e){if(null===b&&(b={valueTypes:new Set}),x+=1,"function"==typeof e.finally)e.finally(function(){if(0===(x-=1))try{m(b)}finally{b=null,A=0}});else try{e()}finally{if(0===(x-=1))try{m(b)}finally{b=null,A=0}}},E=function(n,e,t,r){var u=b,o=null!==u;null===u&&(u={valueTypes:new Set}),u.valueTypes.has(n)?u[n][t].push(a({},e,{order:A++})):(u.valueTypes.add(n),u[n]=s({},t,[a({},e,{order:A++})]),r.forEach(function(e){u[n][e]=[]})),o||m(u)},O=!0,j=function(e,n){O&&E(e,n,"clearRemoves",["inserts","lruRemoves","deleteRemoves"])},k=function(e,n){O&&E(e,n,"lruRemoves",["clearRemoves","inserts","deleteRemoves"])},M=function(e,n){O&&E(e,n,"deleteRemoves",["clearRemoves","lruRemoves","inserts"])},R=function(u){return function(){for(var e=arguments.length,r=new Array(e),n=0;n<e;n++)r[n]=arguments[n];return new Promise(function(n,t){setTimeout(function(){try{var e=u.apply(void 0,r);n(e)}catch(e){t(e)}},0)})}},z=function(e,n){if(function(e){if(0<p.size)return!0;var n=h.get(e);return void 0!==n&&0<n.size}(e))S(n);else try{O=!1,n()}finally{O=!0}},C=function(c,f,s,e,v){if(!Array.isArray(e))throw new Error("LruCache::setAll: keyValueAlternateKeysArray must be an array");z(c,function(){e.forEach(function(e){var n=e.key,t=e.value,r=e.alternateKeys,u=f.getWithoutLruChange(n),o=Array.isArray(r)?r:[];0===o.length&&"string"==typeof r&&(o=[r]),o.forEach(function(e){if(s.has(e)&&s.get(e)!==n)throw new Error("LruCache::setAll: alternate key '"+e+"' is given for key '"+n+"' and value type '"+c+"' but is already used for key '"+s.get(e)+"'")}),o=new Set(o),void 0===u?u={key:n,value:t,alternateKeys:o}:(u.value=t,u.alternateKeys=new Set(y(u.alternateKeys).concat(y(o))));var a,l,i=f.set(n,u);o.forEach(function(e){s.set(e,n)}),a=c,l=u,O&&E(a,l,"inserts",["clearRemoves","lruRemoves","deleteRemoves"]),null!==i&&(i.value.alternateKeys.forEach(function(e){s.delete(e)}),v&&k(c,i.value))})})},T=function(e,n,t){var r=t(e);return void 0===r&&n.has(e)&&(r=t(n.get(e))),r};function P(t){var e=1<arguments.length&&void 0!==arguments[1]?arguments[1]:v,n=this instanceof P?this:Object.create(P.prototype),r=f(e),u=new Map,o=!1,a=!1;return n.dispatchLruRemoves=function(e){o=e},n.dispatchClearRemoves=function(e){a=e},n.setAll=function(e){C(t,r,u,e,o)},n.setAllAsync=R(n.setAll),n.set=function(e){n.setAll([e])},n.setAsync=R(n.set),n.get=function(e){var n=T(e,u,r.get);return void 0===n?n:n.value},n.getWithoutLruChange=function(e){var n=T(e,u,r.getWithoutLruChange);return void 0===n?n:n.value},n.delete=function(e){var n=T(e,u,r.getWithoutLruChange);return void 0===n?(z(t,function(){M(t,{key:e})}),!1):(r.delete(n.key),n.alternateKeys.forEach(function(e){u.delete(e)}),z(t,function(){M(t,{key:e})}),!0)},n.forEach=r.forEach,n.getEntries=function(){return r.map(function(e){return e})},n.clear=function(){var e=r.clear();u.clear(),a&&z(t,function(){e.forEach(function(e){j(t,e.value)})})},n.getSize=r.getSize,n.getValueType=function(){return t},n.getMaxSize=r.getMaxSize,n.setMaxSize=function(e){var n=r.setMaxSize(e);z(t,function(){n.forEach(function(e){e.value.alternateKeys.forEach(function(e){u.delete(e)}),o&&k(t,e.value)})})},n}var K=new Map,L=function(e){var n=K.get(e);return void 0===n&&(n=P(e),K.set(e,n)),n},_=function(){S(function(){K.forEach(function(e){e.clear()})})}}]); |
{ | ||
"name": "@swarmy/lru-cache", | ||
"version": "2.0.5", | ||
"version": "3.0.0", | ||
"description": "LRU cache with event registry to handle cache changes", | ||
@@ -5,0 +5,0 @@ "author": "Gerd Neudert", |
122
README.md
@@ -9,3 +9,15 @@ # lru-cache | ||
## Installation | ||
## Table of Contents | ||
1. [Installation](#section-installation) | ||
2. [Motivation](#section-motivation) | ||
3. [Basic Usage](#section-basic-usage) | ||
4. [Quality](#section-quality) | ||
5. [Develop](#section-develop) | ||
6. [Detailed Usage](#section-detailed-usage) | ||
7. [Performance](#section-performance) | ||
8. [Questions](#section-questions) | ||
9. [Roadmap](#section-roadmap) | ||
## Installation <a name="section-installation"></a> | ||
```javascript | ||
@@ -15,3 +27,3 @@ npm install --save @swarmy/lru-cache | ||
## Motivation | ||
## Motivation <a name="section-motivation"></a> | ||
There are for sure more than a handful of different LRU-cache implementations flying around on npm. | ||
@@ -25,3 +37,3 @@ | ||
## Basic Usage | ||
## Basic Usage <a name="section-basic-usage"></a> | ||
@@ -47,3 +59,3 @@ ### Caching | ||
* [Detailed Usage](#caching-detail) | ||
* [JSDoc](https://rawcdn.githack.com/gneu77/lru-cache/a03482ca34b4dd7decf6d6057e56c8a8cee7fb6e/docs/index.html) | ||
* [JSDoc](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/docs/index.html) | ||
@@ -61,10 +73,10 @@ ### Cache Events | ||
* [Detailed Usage](#cache-events-detail) | ||
* [JSDoc](https://rawcdn.githack.com/gneu77/lru-cache/a03482ca34b4dd7decf6d6057e56c8a8cee7fb6e/docs/index.html) | ||
* [JSDoc](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/docs/index.html) | ||
## Quality | ||
* [Test results](https://rawcdn.githack.com/gneu77/lru-cache/a03482ca34b4dd7decf6d6057e56c8a8cee7fb6e/test-report.html) | ||
* [Test coverage](https://rawcdn.githack.com/gneu77/lru-cache/a03482ca34b4dd7decf6d6057e56c8a8cee7fb6e/coverage/index.html) | ||
* [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/a03482ca34b4dd7decf6d6057e56c8a8cee7fb6e/performance-report.html) | ||
## Quality <a name="section-quality"></a> | ||
* [Test results](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/test-report.html) | ||
* [Test coverage](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/coverage/index.html) | ||
* [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/performance-report.html) | ||
## Develop | ||
## Develop <a name="section-develop"></a> | ||
```javascript | ||
@@ -81,20 +93,78 @@ git clone https://github.com/gneu77/lru-cache.git | ||
## Detailed Usage | ||
## Detailed Usage <a name="section-detailed-usage"></a> | ||
### Caching <a name="caching-detail"></a> | ||
WIP | ||
The following 4 functions can be imported from lru-cache: | ||
Method | Arguments | Returns | Description | ||
--- | --- | --- | --- | ||
`cacheTransaction` | callbackOrPromise: function\|Promise | undefined | All cache events (set, delete, etc.) within the callback will be combined into a single event that will be dispatched when finished. | ||
`clearAllCaches` | none | undefined | All existing cache instances will be invalidated. If dispatchClearRemoves is set true for a cache, then a single event will be dispatched for the clear. | ||
`getCache` | valueType: string | LruCache | Return LruCache for given value type. For the same value type, the same cache instance will be returned (LruCache is a per-value-type singleton. | ||
`registerCacheChangedHandler` | changedHandler: function, valueTypes: Array\|string | handlerHandle: object | changedHandler will be called with corresponding cache event. If valueTypes is not specified or null, the handler will receive all cache events. Else it will only receive cache events for the given type(s). The returned handlerHandle has the methods `unregister`, `deactivate`, `activate` and `isRegisterd`. It also has the fields `isActive` and `valueType` | ||
LruCache has the following methods: | ||
Method | Arguments | Returns | Description | ||
--- | --- | --- | --- | ||
`clear` | none | undefined | Invalidate the cache. If dispatchClearRemoves is set true for the cache, then a single event will be dispatched for the clear. | ||
`delete` | keyOrAlternateKey: string | wasInCache: boolean | Remove an entry from the cache. A corresponding cache event will be dispatched. | ||
`dispatchClearRemoves` | newValue: boolean | undefined | Set whether a cache clear should dispatch a cache event (default: false). | ||
`dispatchLruRemoves` | newValue: boolean | undefined | Set whether a LRU-remove (entry being removed due to exceeded cache size) should dispatch a cache event (default: false). | ||
`forEach` | callback: function | undefined | Iterate over the cache from olodest to newest value. Callback receives cache entry as argument, being an object with `key`, `value` and `alternateKeys`. | ||
`get` | keyOrAlternateKey: string | value | get cached value or undefined. The returned value will be made the newest value in the cache. | ||
`getEntries` | none | Array | Returns an array with all cache entries, order from oldest to newest. | ||
`getMaxSize` | none | Int | Returns the current max size of the cache. | ||
`getSize` | none | Int | Returns the number of entries in the cache. | ||
`getValueType` | none | string | Returns the value type of the cache. | ||
`getWithoutLruChange` | keyOrAlternateKey: string | value | Like `get`, but without making the entry the newest in the cache. | ||
`set` | keyValueAlternateKeys: object | undefined | Insert or update a value in the cache. The argument must be an object with `key` and `value`. Optionally it can also have `alternateKeys`, being string or array of strings. After set, the value will be the newest in the cache. Dispatches a corresponding cache event. If an insert exceeds the max cache size and dispatchLruRemoves is set true, it will be included in the event. | ||
`setAll` | Array\[keyValueAlternateKeys\] | undefined | Like `set`, but for an array of cache entries. Leading to a single cache event. | ||
`setAllAsync` | Array\[keyValueAlternateKeys\] | Promise | Like `setAll`, but performing insert and event dispatch in another event loop, resolving the returned promise afterwards. | ||
`set` | keyValueAlternateKeys: object | Promise | Like `set`, but performing insert and event dispatch in another event loop, resolving the returned promise afterwards. | ||
`setMaxSize` | newMaxSize | undefined | Change the max size of the cache (default: 500). If the new maxSize is less than the old and this leads to LRU-removes and dispatchLruRemoves is set true, then a single cache event will be dispatched. | ||
### Cache Events <a name="cache-events-detail"></a> | ||
WIP | ||
* Especially in more complex UIs, there might be multiple models holding the same type of entity. | ||
* If an entity gets updated, you need a strategy to ensure all models get updated correspondingly. | ||
* Of course the developer implementing the update should not be required to know all models of all screens that might hold an entity of this type | ||
* Even if he would know them it would be a nightmare, if he had to update all the models | ||
* Even if he would update all the models, as soon as another developer changes one of the models half a year later, or adds a new model, the application would be broken | ||
* Like always in programming there are many different approaches to this problem. The event-based approach described here is just one of them (not necessarily the best, but if you need caching anyways, then it's handy to combine this): | ||
* Whenever an updated entity is retrieved, it is put into the cache, leading to a corresponding cache event | ||
* Whenever an entity is deleted, delete is also called on the cache, leading to a corresponding cache event | ||
* Whenever a new model is implemented, it is registered for cache events for the object types it is holding | ||
* Whenever a model receives a cache event, it can check whether it must replace or remove an entity | ||
## Performance | ||
Here is the structure of the cache change event argument: | ||
```javascript | ||
{ | ||
valueTypes: Set(), | ||
<valueType>: { | ||
inserts: [{key, value, alternateKeys, order}], | ||
clearRemoves: [{key, value, alternateKeys, order}], | ||
lruRemoves: [{key, value, alternateKeys, order}], | ||
deleteRemoves: [{key}], | ||
}, | ||
... | ||
} | ||
``` | ||
* The order can be used to determine, if an insert happened before or after a remove. | ||
* Note that by default, lruRemoves and clearRemoves are empty (usually these removes are not of any interest) | ||
* In case of a cache delete, the corresponding entity might not have been in the cache (being removed in a clear or by LRU logic). | ||
* Thus, deleteRemoves only contain the key of the deleted entity. | ||
* For the same reason, the delete method cannot be used with an alternate key, because there would be no way to tell if the given argument is key or alternate key | ||
## Performance <a name="section-performance"></a> | ||
* Compared to a native Javascript Map, the LRU logic implies performance impact on get, set and delete. It's just the price to pay for having a LRU cache. | ||
* See [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/a03482ca34b4dd7decf6d6057e56c8a8cee7fb6e/performance-report.html) | ||
* However, the methods are still O(1). (Only setMaxSize has O(size-newMaxSize), if size>newMaxSize) | ||
* Compared to a LRU cache without cache events, the is additional performance impact on get, set and delete. | ||
* Again see [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/a03482ca34b4dd7decf6d6057e56c8a8cee7fb6e/performance-report.html) | ||
* Also compared to LRU maps that do not support alternate keys, there is a performance impact on get in case of cache misses. | ||
* See [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/performance-report.html) | ||
* However, get, set and delete are still O(1). (setMaxSize has O(size-newMaxSize), if size>newMaxSize) | ||
* Compared to a LRU cache without cache events, there is additional performance impact on get, set and delete. | ||
* Again see [Performance tests](https://rawcdn.githack.com/gneu77/lru-cache/6576f0a99e825cbc3736c9658036b0a6d224b027/performance-report.html) | ||
* However, if you are caching for performance, then because the fetching of values is significantly more time consuming. So whether you save 400ms or only 399ms hardly makes a difference here. | ||
* If you are not caching for performance reasons, but to have the change events, well than again it's just the price to pay for the event handling. | ||
## Questions | ||
## Questions <a name="section-questions"></a> | ||
@@ -109,1 +179,15 @@ ### Why can I not differentiate between insert and update in the change events? | ||
* However, maybe in a future version, I will make it configurable to optionally include such a list. | ||
## Roadmap <a name="section-roadmap"></a> | ||
### 3.0.x | ||
* Fix issues that might occur | ||
* Improve README | ||
* Bring test coverage two 100% | ||
* Add further performance tests | ||
### 3.1.0 | ||
* Add option to use LruMap instead of LruCache (the LruMap is a currently not exported pure LRU cache, while the LruCache is a wrapper adding the event handling) | ||
### 3.2.0 | ||
* Make shape and content of change events configurable (with the current shape being used as default). |
@@ -80,3 +80,3 @@ import {LruMap} from "./LruMap"; | ||
* lruRemoves: [{key, value, alternateKeys, order}], | ||
* deleteRemoves: [{key, value, alternateKeys, order}], | ||
* deleteRemoves: [{key}], | ||
* }, | ||
@@ -384,2 +384,3 @@ * ... | ||
* @function | ||
* @param {Array} keyValueAlternateKeysArray - array of objects with 'key', 'value' and optional 'alternateKeys' | ||
* @returns {Promise} | ||
@@ -405,2 +406,3 @@ */ | ||
* @function | ||
* @param {object} keyValueAlternateKeys - object with 'key' and 'value' and optional 'alternateKeys' | ||
* @returns {Promise} | ||
@@ -434,12 +436,16 @@ */ | ||
/** Delete entry from cache by key or alternate key. | ||
/** Delete entry from cache by key. | ||
* Here, no alternate key can be used. | ||
* A corresponding cache changed event will be dispatched. | ||
* @memberof LruCache | ||
* @function | ||
* @param {string} keyOrAlternateKey - The key or alternate key of the to be deleted value | ||
* @param {string} key - The key of the to be deleted value | ||
* @returns {boolean} true, if the key was in the cache. | ||
*/ | ||
self.delete = keyOrAlternateKey => { | ||
const entry = entryGetter(keyOrAlternateKey, alternateKeyToKey, lruMap.getWithoutLruChange); | ||
self.delete = key => { | ||
const entry = entryGetter(key, alternateKeyToKey, lruMap.getWithoutLruChange); | ||
if (typeof entry === "undefined") { | ||
wrapInTransaction(valueType, () => { | ||
handleDeleteRemove(valueType, {key}); | ||
}); | ||
return false; | ||
@@ -454,3 +460,3 @@ } | ||
wrapInTransaction(valueType, () => { | ||
handleDeleteRemove(valueType, entry); | ||
handleDeleteRemove(valueType, {key}); | ||
}); | ||
@@ -457,0 +463,0 @@ return true; |
@@ -458,4 +458,2 @@ /* eslint-disable no-magic-number, max-lines */ | ||
expect(changeObject[VALUE_TYPE_1].deleteRemoves[0].key).toEqual("key1"); | ||
expect(changeObject[VALUE_TYPE_1].deleteRemoves[0].value).toEqual("value1 of type 1"); | ||
expect(changeObject[VALUE_TYPE_1].deleteRemoves[0].alternateKeys.has("myAltKey1")).toBeTruthy(); | ||
@@ -462,0 +460,0 @@ handlerHandle.unregister(); |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
187
94416
14
2048