@inversifyjs/core
Version:
InversifyJs core package
156 lines • 6.22 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OneToManyMapStar = void 0;
const NOT_FOUND_INDEX = -1;
/**
* Data structure able to efficiently manage a set of models related to a set of properties in a one to many relation.
*/
class OneToManyMapStar {
#modelToRelationMap;
#relationToModelsMaps;
#spec;
constructor(spec) {
this.#modelToRelationMap = new Map();
this.#relationToModelsMaps = {};
for (const specProperty of Reflect.ownKeys(spec)) {
this.#relationToModelsMaps[specProperty] = new Map();
}
this.#spec = spec;
}
add(model, relation) {
this.#buildOrGetModelArray(model).push(relation);
for (const relationKey of Reflect.ownKeys(relation)) {
this.#buildOrGetRelationModels(relationKey, relation[relationKey]).push(model);
}
}
clone() {
const modelToCloneModelMap = this.#buildModelToCloneModelMap();
const relationToCloneRelationMap = this.#buildRelationToRelationModelMap();
const properties = Reflect.ownKeys(this.#spec);
const clone = this._buildNewInstance(this.#spec);
this.#pushRelationEntriesIntoRelationMap(this.#modelToRelationMap, clone.#modelToRelationMap, modelToCloneModelMap, relationToCloneRelationMap);
for (const property of properties) {
this.#pushModelEntriesIntoModelMap(this.#relationToModelsMaps[property], clone.#relationToModelsMaps[property], modelToCloneModelMap);
}
return clone;
}
get(key, value) {
return this.#relationToModelsMaps[key].get(value);
}
getAllKeys(key) {
return this.#relationToModelsMaps[key].keys();
}
removeByRelation(key, value) {
const models = this.get(key, value);
if (models === undefined) {
return;
}
const uniqueModelsSet = new Set(models);
for (const model of uniqueModelsSet) {
const relations = this.#modelToRelationMap.get(model);
if (relations === undefined) {
throw new Error('Expecting model relation, none found');
}
for (const relation of relations) {
if (relation[key] === value) {
this.#removeModelFromRelationMaps(model, relation);
}
}
this.#modelToRelationMap.delete(model);
}
}
_buildNewInstance(spec) {
return new OneToManyMapStar(spec);
}
_cloneModel(model) {
return model;
}
_cloneRelation(relation) {
return relation;
}
#buildModelToCloneModelMap() {
const modelToCloneModelMap = new Map();
for (const model of this.#modelToRelationMap.keys()) {
const clonedModel = this._cloneModel(model);
modelToCloneModelMap.set(model, clonedModel);
}
return modelToCloneModelMap;
}
#buildRelationToRelationModelMap() {
const relationToCloneRelationMap = new Map();
for (const relations of this.#modelToRelationMap.values()) {
for (const relation of relations) {
const clonedRelation = this._cloneRelation(relation);
relationToCloneRelationMap.set(relation, clonedRelation);
}
}
return relationToCloneRelationMap;
}
#buildOrGetModelArray(model) {
let relations = this.#modelToRelationMap.get(model);
if (relations === undefined) {
relations = [];
this.#modelToRelationMap.set(model, relations);
}
return relations;
}
#buildOrGetRelationModels(relationKey, relationValue) {
let models = this.#relationToModelsMaps[relationKey].get(relationValue);
if (models === undefined) {
models = [];
this.#relationToModelsMaps[relationKey].set(relationValue, models);
}
return models;
}
#getCloneModel(model, modelToCloneModelMap) {
const clonedModel = modelToCloneModelMap.get(model);
if (clonedModel === undefined) {
throw new Error('Expecting model to be cloned, none found');
}
return clonedModel;
}
#getCloneRelation(relation, relationToCloneRelationMap) {
const clonedRelation = relationToCloneRelationMap.get(relation);
if (clonedRelation === undefined) {
throw new Error('Expecting relation to be cloned, none found');
}
return clonedRelation;
}
#pushModelEntriesIntoModelMap(source, target, modelToCloneModelMap) {
for (const [relationValue, models] of source) {
const modelsClone = new Array();
for (const model of models) {
modelsClone.push(this.#getCloneModel(model, modelToCloneModelMap));
}
target.set(relationValue, modelsClone);
}
}
#pushRelationEntriesIntoRelationMap(source, target, modelToCloneModelMap, relationToCloneRelationMap) {
for (const [model, relations] of source) {
const relationsClone = new Array();
for (const relation of relations) {
relationsClone.push(this.#getCloneRelation(relation, relationToCloneRelationMap));
}
target.set(this.#getCloneModel(model, modelToCloneModelMap), relationsClone);
}
}
#removeModelFromRelationMaps(model, relation) {
for (const relationKey of Reflect.ownKeys(relation)) {
this.#removeModelFromRelationMap(model, relationKey, relation[relationKey]);
}
}
#removeModelFromRelationMap(model, relationKey, relationValue) {
const relationModels = this.#relationToModelsMaps[relationKey].get(relationValue);
if (relationModels !== undefined) {
const index = relationModels.indexOf(model);
if (index !== NOT_FOUND_INDEX) {
relationModels.splice(index, 1);
}
if (relationModels.length === 0) {
this.#relationToModelsMaps[relationKey].delete(relationValue);
}
}
}
}
exports.OneToManyMapStar = OneToManyMapStar;
//# sourceMappingURL=OneToManyMapStar.js.map