/// /// 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); } } }