156 lines
6.1 KiB
Plaintext
156 lines
6.1 KiB
Plaintext
"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 |