///
///
class RelationHandlerStrictOneToMany extends RelationHandler {
public setRelation (relation : Relation, left : any, right : any, value? : any) : boolean {
// a LEFT must not circle in on itself
// Is right any of the left's parents?
let parents = this.getAllLeft(left);
if (parents.indexOf(right) != -1) {
console.warn("[Relation] Attempt to create a circular relation:", this, left, right);
return false; // Allowing this would create a circular relation
}
// from this point on we'll guarantee that the new relation can be made.
// Changes will occur, so "return false" is no longer acceptable.
// a RIGHT can only point to a single LEFT
this.unsetRight(right);
return true;
}
public unset (thing : any) {
this.unsetLeft(thing);
this.unsetRight(thing);
}
public unsetLeft (left: any) {
this.relations.forEach(relation => {
relation.unsetLeft(left);
});
}
public unsetRight (right : any) {
this.relations.forEach(relation => {
relation.unsetRight(right);
});
}
// A many can only have one one
public getLeft (right : any) {
let result;
for (let i = 0; i < this.relations.length; i++) {
result = this.relations[i].getLeft(right);
if (result != undefined) {
return result;
}
}
}
/**
* This returns all ones that are relevant.
* So in a relationship like A -> B -> C and asking for C, this will return
* B because it's related to C and then A because that's related to B.
* @param right
* @returns {Array}
*/
public getAllLeft (right : any) {
let newParent = this.getLeft(right);
let parents = [];
while (newParent != undefined ) {
parents.push(newParent);
newParent = this.getLeft(newParent);
}
return parents;
}
public getAllLeftType (right : any, type : any) {
return this.getAllLeft(right).filter(left => {
return left instanceof type;
});
}
/**
* Returns the highest One that can be found.
* for A -> B -> C and asking for C, this would return A
* as that's the one "originating" the other relations.
* @param right
* @returns {any}
*/
public getLastLeft (right : any) {
let parent = this.getLeft(right);
let newParent = this.getLeft(parent);
while (newParent != undefined) {
parent = newParent;
newParent = this.getLeft(parent);
}
return parent;
}
public getAllRight (left : any) {
let rights = [];
this.relations.forEach(relation => {
rights.push(...relation.getRight(left));
});
arrayUnique(rights);
return rights;
}
public getAllRightTypes (left : any, rightType : any) {
return this.getAllRight(left).filter(right => {
return right instanceof rightType;
});
}
}
class RelationOneToMany extends Relation {
private valuesHash : {[idid : string] : any} = {};
private oneMap = new Map>();
private manyMap = new Map();
public getValue (left : any, right : any) {
return this.valuesHash[Relation.createString(left, right)];
}
/**
* Only relationships between Objets can have values
* @param left
* @param right
* @param value
*/
public setValue (left : any, right : any, value : any) {
if (this.manyMap.get(right) == left) {
let string = Relation.createString(left, right);
if (string != undefined) {
this.valuesHash[string] = value;
}
}
}
public setRelation (left : any, right : any, value? : any) {
let proceed;
if (this.handler != undefined) {
proceed = this.handler.setRelation(this, left, right, value);
}
if (proceed) {
// something on the left can't be on the right
this.unsetRight(left);
// something on the right can't be on the left
this.unsetLeft(right);
// something on the right can only have one left
this.unsetRight(right);
let string = Relation.createString(left, right);
if (string != undefined) {
this.valuesHash[string] = value;
}
this.manyMap.set(right, left);
if (this.oneMap.get(left) == undefined) {
this.oneMap.set(left, [right]);
} else {
this.oneMap.get(left).push(right);
}
}
}
public getLeft (right : any) {
return this.manyMap.get(right);
}
public getAnyLeft () {
let left = [];
this.oneMap.forEach((value, key) => {
left.push(key);
});
arrayUnique(left);
return left;
}
public getAnyRight () {
let rights = [];
this.oneMap.forEach((value) => {
rights.push(...value);
});
arrayUnique(rights);
return rights;
}
public getAnyRightType (type : any) {
return this.getAnyRight().filter(value => {
return value instanceof type;
});
}
public isRight (left : any, needle : any) {
let right = this.oneMap.get(left);
if (right != undefined) {
return right.indexOf(needle) != -1;
}
return false;
}
public getRight (left : any) {
let right = this.oneMap.get(left);
if (right != undefined) {
return [].concat(...right);
}
return [];
}
public getRightType (left : any, type : any) {
return this.getRight(left).filter(right => {
return right instanceof type;
});
}
public getRightTypeOne (left : any, type : any) {
let rights = this.getRightType(left, type);
if (rights.length > 0) {
return rights[0];
}
}
public getRelationValue (left : any, right : any) {
return this.valuesHash[Relation.createString(left, right)];
}
public unsetRight (right : any) {
let left = this.manyMap.get(right);
if (left != undefined) {
let allRight = this.oneMap.get(left);
allRight.splice(allRight.indexOf(right), 1);
this.manyMap.delete(right);
if (allRight.length == 0) {
this.oneMap.delete(left);
}
let string = Relation.createString(left, right);
if (string != undefined) {
delete(this.valuesHash[string]);
}
}
}
public unsetLeft (left : any) {
let allRight = this.oneMap.get(left);
if (allRight != undefined) {
allRight.forEach((right : any) => {
this.manyMap.delete(right);
let string = Relation.createString(left, right);
if (string != undefined) {
delete(this.valuesHash[string]);
}
});
this.oneMap.delete(left);
}
}
}