@thermopylae/lib.cache
Version:
91 lines (90 loc) • 2.58 kB
JavaScript
import { EventEmitter } from 'events';
import { NOT_FOUND_VALUE } from "../constants.js";
class PolicyBasedCache extends EventEmitter {
backend;
policies;
constructor(backend, policies) {
super();
this.backend = backend;
this.policies = policies || [];
for (const policy of this.policies) {
policy.setDeleter(this.internalDelete);
}
}
get size() {
return this.backend.size;
}
get(key) {
const entry = this.backend.get(key);
if (entry === NOT_FOUND_VALUE) {
for (const policy of this.policies) {
policy.onMiss(key);
}
return entry;
}
for (const policy of this.policies) {
if (policy.onHit(entry) === 0 ) {
return NOT_FOUND_VALUE;
}
}
return entry.value;
}
has(key) {
return this.backend.has(key);
}
set(key, value, argsBundle) {
let entry = this.backend.get(key);
if (entry === NOT_FOUND_VALUE) {
entry = this.backend.set(key, value);
let policyIndex = 0;
try {
for (; policyIndex < this.policies.length; policyIndex++) {
this.policies[policyIndex].onSet(entry, argsBundle);
}
this.emit("insert" , key, value);
return;
}
catch (e) {
for (let i = 0; i < policyIndex; i++) {
this.policies[i].onDelete(entry);
}
this.backend.del(entry);
throw e;
}
}
entry.value = value;
for (const policy of this.policies) {
policy.onUpdate(entry, argsBundle);
}
this.emit("update" , key, value);
}
del(key) {
const entry = this.backend.get(key);
if (!entry) {
return false;
}
this.internalDelete(entry);
return true;
}
keys() {
return Array.from(this.backend.keys());
}
clear() {
for (const policy of this.policies) {
policy.onClear();
}
this.backend.clear();
this.emit("flush" );
}
on(event, listener) {
return super.on(event, listener);
}
internalDelete = (entry) => {
for (const policy of this.policies) {
policy.onDelete(entry);
}
this.emit("delete" , entry.key, entry.value);
this.backend.del(entry);
};
}
export { PolicyBasedCache };