{"version":3,"sources":["../browser/src/persistence/subject-builder/OneToOneInverseSideSubjectBuilder.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,OAAO,EAAC,MAAM,YAAY,CAAC;AACnC,OAAO,EAAC,QAAQ,EAAC,MAAM,qBAAqB,CAAC;AAI7C;;;;;;;;;;GAUG;AACH;IAEI,wEAAwE;IACxE,cAAc;IACd,wEAAwE;IAExE,2CAAsB,QAAmB;QAAnB,aAAQ,GAAR,QAAQ,CAAW;IACzC,CAAC;IAED,wEAAwE;IACxE,iBAAiB;IACjB,wEAAwE;IAExE;;OAEG;IACH,iDAAK,GAAL;QAAA,iBAYC;QAXG,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC,UAAA,OAAO;YACzB,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAA,QAAQ;gBAE/C,kGAAkG;gBAClG,mDAAmD;gBACnD,IAAI,QAAQ,CAAC,QAAQ,IAAI,QAAQ,CAAC,kBAAkB,KAAK,KAAK;oBAC1D,OAAO;gBAEX,KAAI,CAAC,uBAAuB,CAAC,OAAO,EAAE,QAAQ,CAAC,CAAC;YACpD,CAAC,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;IAED,wEAAwE;IACxE,oBAAoB;IACpB,wEAAwE;IAExE;;;;OAIG;IACO,mEAAuB,GAAjC,UAAkC,OAAgB,EAAE,QAA0B;QAE1E,4DAA4D;QAC5D,uFAAuF;QACvF,2GAA2G;QAC3G,oFAAoF;QACpF,IAAI,+BAA+B,GAA4B,SAAS,CAAC;QACzE,IAAI,OAAO,CAAC,cAAc,EAAE,+EAA+E;YACvG,+BAA+B,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;QAEtF,2CAA2C;QAC3C,kEAAkE;QAClE,IAAI,aAAa,GAAuB,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,MAAO,CAAC,CAAC,CAAC,+CAA+C;QACjI,IAAI,aAAa,KAAK,SAAS,EAAE,kDAAkD;YAC/E,OAAO;QAEX,+FAA+F;QAC/F,sEAAsE;QACtE,kGAAkG;QAClG,IAAI,aAAa,KAAK,IAAI,EAAE;YAExB,yFAAyF;YACzF,IAAI,+BAA+B,EAAE;gBACjC,+FAA+F;gBAC/F,iHAAiH;gBACjH,0FAA0F;gBAE1F,IAAM,2BAA2B,GAAG,IAAI,OAAO,CAAC;oBAC5C,QAAQ,EAAE,QAAQ,CAAC,qBAAqB;oBACxC,aAAa,EAAE,OAAO;oBACtB,YAAY,EAAE,IAAI;oBAClB,UAAU,EAAE,+BAA+B;oBAC3C,UAAU,EAAE,CAAC;4BACT,QAAQ,EAAE,QAAQ,CAAC,eAAgB;4BACnC,KAAK,EAAE,IAAI;yBACd,CAAC;iBACL,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,2BAA2B,CAAC,CAAC;aACnD;YAED,OAAO;SACV,CAAC,4CAA4C;QAE9C,4FAA4F;QAC5F,+HAA+H;QAC/H,IAAI,aAAa,GAAG,QAAQ,CAAC,qBAAsB,CAAC,cAAc,CAAC,aAAa,CAAC,CAAC,CAAC,sEAAsE;QAEzJ,kGAAkG;QAClG,IAAI,oBAAoB,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,UAAA,cAAc;YACxD,OAAO,CAAC,CAAC,cAAc,CAAC,MAAM,IAAI,cAAc,CAAC,MAAM,KAAK,aAAa,CAAC;QAC9E,CAAC,CAAC,CAAC;QAEH,6HAA6H;QAC7H,IAAI,oBAAoB;YACpB,aAAa,GAAG,oBAAoB,CAAC,UAAU,CAAC;QAEpD,uGAAuG;QACvG,mGAAmG;QACnG,6GAA6G;QAC7G,4GAA4G;QAC5G,IAAI,CAAC,aAAa,EAAE;YAEhB,6GAA6G;YAC7G,uGAAuG;YACvG,6FAA6F;YAC7F,+GAA+G;YAC/G,6BAA6B;YAC7B,2HAA2H;YAC3H,qGAAqG;YACrG,+EAA+E;YAC/E,IAAI,CAAC,oBAAoB;gBACrB,OAAO;YAEX,yFAAyF;YACzF,oGAAoG;YACpG,qEAAqE;YACrE,kFAAkF;YAClF,iEAAiE;YACjE,oBAAoB,CAAC,UAAU,CAAC,IAAI,CAAC;gBACjC,QAAQ,EAAE,QAAQ,CAAC,eAAgB;gBACnC,KAAK,EAAE,OAAO;aACjB,CAAC,CAAC;SACN;QAED,qDAAqD;QACrD,wHAAwH;QACxH,IAAM,6BAA6B,GAAG,+BAA+B,IAAI,QAAQ,CAAC,WAAW,CAAC,aAAa,EAAE,+BAA+B,CAAC,CAAC;QAE9I,8EAA8E;QAC9E,oGAAoG;QACpG,qEAAqE;QACrE,6EAA6E;QAC7E,iEAAiE;QACjE,IAAI,CAAC,6BAA6B,EAAE;YAEhC,iFAAiF;YACjF,4GAA4G;YAC5G,gCAAgC;YAChC,IAAI,CAAC,oBAAoB,EAAE;gBACvB,oBAAoB,GAAG,IAAI,OAAO,CAAC;oBAC/B,QAAQ,EAAE,QAAQ,CAAC,qBAAqB;oBACxC,YAAY,EAAE,IAAI;oBAClB,UAAU,EAAE,aAAa;iBAC5B,CAAC,CAAC;gBACH,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;aAC5C;YAED,oBAAoB,CAAC,UAAU,CAAC,IAAI,CAAC;gBACjC,QAAQ,EAAE,QAAQ,CAAC,eAAgB;gBACnC,KAAK,EAAE,OAAO;aACjB,CAAC,CAAC;SACN;IACL,CAAC;IAEL,wCAAC;AAAD,CAzJA,AAyJC,IAAA","file":"OneToOneInverseSideSubjectBuilder.js","sourcesContent":["import {Subject} from \"../Subject\";\nimport {OrmUtils} from \"../../util/OrmUtils\";\nimport {ObjectLiteral} from \"../../common/ObjectLiteral\";\nimport {RelationMetadata} from \"../../metadata/RelationMetadata\";\n\n/**\n * Builds operations needs to be executed for one-to-one non-owner relations of the given subjects.\n *\n * by example: post contains one-to-one non-owner relation with category in the property called \"category\", e.g.\n * @OneToOne(type => Category, category => category.post) category: Category\n * If user sets a category into the post and saves post we need to bind them.\n * This operation requires updation of category table since its owner of the relation and contains a join column.\n *\n * note: this class shares lot of things with OneToManyUpdateBuilder, so when you change this class\n * make sure to reflect changes there as well.\n */\nexport class OneToOneInverseSideSubjectBuilder {\n\n // ---------------------------------------------------------------------\n // Constructor\n // ---------------------------------------------------------------------\n\n constructor(protected subjects: Subject[]) {\n }\n\n // ---------------------------------------------------------------------\n // Public Methods\n // ---------------------------------------------------------------------\n\n /**\n * Builds all required operations.\n */\n build(): void {\n this.subjects.forEach(subject => {\n subject.metadata.oneToOneRelations.forEach(relation => {\n\n // we don't need owning relations, this operation is only for inverse side of one-to-one relations\n // skip relations for which persistence is disabled\n if (relation.isOwning || relation.persistenceEnabled === false)\n return;\n\n this.buildForSubjectRelation(subject, relation);\n });\n });\n }\n\n // ---------------------------------------------------------------------\n // Protected Methods\n // ---------------------------------------------------------------------\n\n /**\n * Builds operations for a given subject and relation.\n *\n * by example: subject is \"post\" entity we are saving here and relation is \"category\" inside it here.\n */\n protected buildForSubjectRelation(subject: Subject, relation: RelationMetadata) {\n\n // prepare objects (relation id map) for the database entity\n // note: subject.databaseEntity contains relation with loaded relation id only (id map)\n // by example: since subject is a post, we are expecting to get post's category saved in the database here,\n // particularly its relation id, e.g. category id stored in the database\n let relatedEntityDatabaseRelationId: ObjectLiteral|undefined = undefined;\n if (subject.databaseEntity) // related entity in the database can exist only if this entity (post) is saved\n relatedEntityDatabaseRelationId = relation.getEntityValue(subject.databaseEntity);\n\n // get related entities of persisted entity\n // by example: get category from the passed to persist post entity\n let relatedEntity: ObjectLiteral|null = relation.getEntityValue(subject.entity!); // by example: relatedEntity is a category here\n if (relatedEntity === undefined) // if relation is undefined then nothing to update\n return;\n\n // if related entity is null then we need to check if there a bind in the database and unset it\n // if there is no bind in the entity then we don't need to do anything\n // by example: if post.category = null and category has this post in the database then we unset it\n if (relatedEntity === null) {\n\n // it makes sense to update database only there is a previously set value in the database\n if (relatedEntityDatabaseRelationId) {\n // todo: probably we can improve this in the future by finding entity with column those values,\n // todo: maybe it was already in persistence process. This is possible due to unique requirements of join columns\n // we create a new subject which operations will be executed in subject operation executor\n\n const removedRelatedEntitySubject = new Subject({\n metadata: relation.inverseEntityMetadata,\n parentSubject: subject,\n canBeUpdated: true,\n identifier: relatedEntityDatabaseRelationId,\n changeMaps: [{\n relation: relation.inverseRelation!,\n value: null\n }]\n });\n this.subjects.push(removedRelatedEntitySubject);\n }\n\n return;\n } // else means entity is bind in the database\n\n // extract only relation id from the related entities, since we only need it for comparision\n // by example: extract from category only relation id (category id, or let's say category title, depend on join column options)\n let relationIdMap = relation.inverseEntityMetadata!.getEntityIdMap(relatedEntity); // by example: relationIdMap is category.id map here, e.g. { id: ... }\n\n // try to find a subject of this related entity, maybe it was loaded or was marked for persistence\n let relatedEntitySubject = this.subjects.find(operateSubject => {\n return !!operateSubject.entity && operateSubject.entity === relatedEntity;\n });\n\n // if subject with entity was found take subject identifier as relation id map since it may contain extra properties resolved\n if (relatedEntitySubject)\n relationIdMap = relatedEntitySubject.identifier;\n\n // if relationIdMap is undefined then it means user binds object which is not saved in the database yet\n // by example: if post contains category which does not have id(s) yet (because its a new category)\n // it means its always newly inserted and relation update operation always must be created for it\n // it does not make sense to perform difference operation for it for both add and remove actions\n if (!relationIdMap) {\n\n // we decided to remove this error because it brings complications when saving object with non-saved entities\n // if related entity does not have a subject then it means user tries to bind entity which wasn't saved\n // in this persistence because he didn't pass this entity for save or he did not set cascades\n // but without entity being inserted we cannot bind it in the relation operation, so we throw an exception here\n // if (!relatedEntitySubject)\n // throw new Error(`One-to-one inverse relation \"${relation.entityMetadata.name}.${relation.propertyPath}\" contains ` +\n // `entity which does not exist in the database yet, thus cannot be bind in the database. ` +\n // `Please setup cascade insertion or save entity before binding it.`);\n if (!relatedEntitySubject)\n return;\n\n // okay, so related subject exist and its marked for insertion, then add a new change map\n // by example: this will tell category to insert into its post relation our post we are working with\n // relatedEntitySubject is newly inserted CategorySubject\n // relation.inverseRelation is OneToOne owner relation inside Category\n // subject is Post needs to be inserted into Category\n relatedEntitySubject.changeMaps.push({\n relation: relation.inverseRelation!,\n value: subject\n });\n }\n\n // check if this binding really exist in the database\n // by example: find our post if its already bind to category in the database and its not equal to what user tries to set\n const areRelatedIdEqualWithDatabase = relatedEntityDatabaseRelationId && OrmUtils.deepCompare(relationIdMap, relatedEntityDatabaseRelationId);\n\n // if they aren't equal it means its a new relation and we need to \"bind\" them\n // by example: this will tell category to insert into its post relation our post we are working with\n // relatedEntitySubject is newly inserted CategorySubject\n // relation.inverseRelation is ManyToOne relation inside Category\n // subject is Post needs to be inserted into Category\n if (!areRelatedIdEqualWithDatabase) {\n\n // if there is no relatedEntitySubject then it means \"category\" wasn't persisted,\n // but since we are going to update \"category\" table (since its an owning side of relation with join column)\n // we create a new subject here:\n if (!relatedEntitySubject) {\n relatedEntitySubject = new Subject({\n metadata: relation.inverseEntityMetadata,\n canBeUpdated: true,\n identifier: relationIdMap\n });\n this.subjects.push(relatedEntitySubject);\n }\n\n relatedEntitySubject.changeMaps.push({\n relation: relation.inverseRelation!,\n value: subject\n });\n }\n }\n\n}"],"sourceRoot":"../.."}
|