indexable-map
Version:
Built-in JavaScript Map with secondary indexes
96 lines (95 loc) • 3.34 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.IndexableMap = void 0;
const objKeys = Object.keys.bind(Object);
class IndexableMap extends Map {
_indexes = {};
_indexFields = {};
_indexFilters = {};
_indexesEnabled = true;
constructor(entries = [], { indexes = [], indexesEnabled = true, } = { indexes: [], indexesEnabled: true }) {
super(entries);
for (const { field, filter, name } of indexes) {
this._indexes[name] = new Map();
this._indexFields[name] = field;
this._indexFilters[name] = filter;
}
if (indexesEnabled === false) {
this._indexesEnabled = false;
}
if (this._indexesEnabled) {
this.refreshIndexes();
}
}
getByIndex(name, value) {
const resp = [];
for (const key of this._indexes[name]?.get(value) ?? new Set()) {
resp.push(this.get(key));
}
return resp;
}
refreshIndexes() {
for (const indexedField of objKeys(this._indexes)) {
this._indexes[indexedField].clear();
}
for (const [key, value] of this.entries()) {
for (const indexName of objKeys(this._indexes)) {
if (this._indexFilters[indexName](value)) {
this._indexes[indexName].set(value[this._indexFields[indexName]], (this._indexes[indexName].get(value[this._indexFields[indexName]]) ?? new Set()).add(key));
}
}
}
return this;
}
enableIndexes() {
this._indexesEnabled = true;
return this;
}
disableIndexes() {
this._indexesEnabled = false;
return this;
}
vacuum() {
for (const indexedField of objKeys(this._indexes)) {
for (const [fieldValue, set] of this._indexes[indexedField].entries()) {
if (!set.size) {
this._indexes[indexedField].delete(fieldValue);
}
}
}
}
set(key, value) {
if (this._indexesEnabled) {
const oldVal = this.get(key);
for (const indexName of objKeys(this._indexes)) {
if (oldVal != null) {
this._indexes[indexName].get(oldVal[this._indexFields[indexName]])?.delete(key);
}
if (this._indexFilters[indexName](value)) {
this._indexes[indexName].set(value[this._indexFields[indexName]], (this._indexes[indexName].get(value[this._indexFields[indexName]]) ?? new Set()).add(key));
}
}
}
return super.set(key, value);
}
delete(key) {
if (this._indexesEnabled) {
const oldVal = this.get(key);
if (oldVal != null) {
for (const indexName of objKeys(this._indexes)) {
this._indexes[indexName].get(oldVal[this._indexFields[indexName]])?.delete(key);
}
}
}
return super.delete(key);
}
clear() {
if (this._indexesEnabled) {
for (const indexedField of objKeys(this._indexes)) {
this._indexes[indexedField].clear();
}
}
return super.clear();
}
}
exports.IndexableMap = IndexableMap;