schangxiang@126.com
2025-09-19 0821aa23eabe557c0d9ef5dbe6989c68be35d1fe
1
{"version":3,"sources":["../../src/persistence/SubjectChangedColumnsComputer.ts"],"names":[],"mappings":";;AACA,+CAA4C;AAE5C,6DAA0D;AAC1D,6CAA0C;AAE1C;;GAEG;AACH;IAAA;IAsKA,CAAC;IApKG,4EAA4E;IAC5E,iBAAiB;IACjB,4EAA4E;IAE5E;;OAEG;IACH,+CAAO,GAAP,UAAQ,QAAmB;QAA3B,iBAKC;QAJG,QAAQ,CAAC,OAAO,CAAC,UAAA,OAAO;YACpB,KAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC;YACjC,KAAI,CAAC,4BAA4B,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACzD,CAAC,CAAC,CAAC;IACP,CAAC;IAED,4EAA4E;IAC5E,oBAAoB;IACpB,4EAA4E;IAE5E;;OAEG;IACO,0DAAkB,GAA5B,UAA6B,OAAgB;QAEzC,wEAAwE;QACxE,IAAI,CAAC,OAAO,CAAC,MAAM;YACf,OAAO;QAEX,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,UAAA,MAAM;YAEnC,yBAAyB;YACzB,IAAI,MAAM,CAAC,SAAS;gBAChB,MAAM,CAAC,eAAe;gBACtB,MAAM,CAAC,YAAY;gBACnB,MAAM,CAAC,SAAS;gBAChB,MAAM,CAAC,YAAY;gBACnB,OAAO;YAEX,IAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAA,SAAS,IAAI,OAAA,SAAS,CAAC,MAAM,KAAK,MAAM,EAA3B,CAA2B,CAAC,CAAC;YACpF,IAAI,SAAS,EAAE;gBACX,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC;aACvE;YAED,iFAAiF;YACjF,IAAM,WAAW,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,MAAO,CAAC,CAAC;YAE3D,yFAAyF;YACzF,IAAI,WAAW,KAAK,SAAS;gBACzB,OAAO;YAEX,mFAAmF;YACnF,IAAI,OAAO,CAAC,cAAc,EAAE;gBAExB,mCAAmC;gBACnC,IAAI,aAAa,GAAG,MAAM,CAAC,cAAc,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;gBAElE,2FAA2F;gBAC3F,IAAI,MAAM,CAAC,gBAAgB,EAAE;oBACzB,IAAM,KAAK,GAAG,MAAM,CAAC,gBAAgB,CAAC,cAAc,CAAC,OAAO,CAAC,MAAO,CAAC,CAAC;oBACtE,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;wBACrC,OAAO;iBACd;gBACD,IAAI,eAAe,GAAG,WAAW,CAAC;gBAClC,sDAAsD;gBACtD,IAAI,WAAW,KAAK,IAAI,EAAE;oBACtB,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE;wBACxB,eAAe,GAAG,qBAAS,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;qBAElE;yBAAM,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,EAAE;wBAC/B,eAAe,GAAG,qBAAS,CAAC,qBAAqB,CAAC,WAAW,CAAC,CAAC;qBAElE;yBAAM,IAAI,MAAM,CAAC,IAAI,KAAK,UAAU,IAAI,MAAM,CAAC,IAAI,KAAK,IAAI,EAAE;wBAC3D,eAAe,GAAG,qBAAS,CAAC,4BAA4B,CAAC,WAAW,CAAC,CAAC;wBACtE,aAAa,GAAG,qBAAS,CAAC,4BAA4B,CAAC,aAAa,CAAC,CAAC;qBAEzE;yBAAM,IAAI,MAAM,CAAC,IAAI,KAAK,MAAM,IAAI,MAAM,CAAC,IAAI,KAAK,OAAO,EAAE;wBAC1D,0EAA0E;wBAC1E,2FAA2F;wBAC3F,sFAAsF;wBACtF,IAAI,mBAAQ,CAAC,WAAW,CAAC,WAAW,EAAE,aAAa,CAAC;4BAAE,OAAO;qBAEhE;yBAAM,IAAI,MAAM,CAAC,IAAI,KAAK,cAAc,EAAE;wBACvC,eAAe,GAAG,qBAAS,CAAC,mBAAmB,CAAC,WAAW,CAAC,CAAC;wBAC7D,aAAa,GAAG,qBAAS,CAAC,mBAAmB,CAAC,aAAa,CAAC,CAAC;qBAChE;yBAAM,IAAI,MAAM,CAAC,IAAI,KAAK,aAAa,EAAE;wBACtC,eAAe,GAAG,qBAAS,CAAC,kBAAkB,CAAC,WAAW,CAAC,CAAC;wBAC5D,aAAa,GAAG,qBAAS,CAAC,kBAAkB,CAAC,aAAa,CAAC,CAAC;qBAC/D;iBACJ;gBAED,4CAA4C;gBAC5C,IAAI,eAAe,KAAK,aAAa;oBACjC,OAAO;aACd;YACD,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACjC,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;gBACpB,MAAM,EAAE,MAAM;gBACd,KAAK,EAAE,WAAW;aACrB,CAAC,CAAC;QACP,CAAC,CAAC,CAAC;IACP,CAAC;IAED;;OAEG;IACO,oEAA4B,GAAtC,UAAuC,WAAsB,EAAE,OAAgB;QAE3E,wEAAwE;QACxE,IAAI,CAAC,OAAO,CAAC,MAAM;YACf,OAAO;QAEX,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,OAAO,CAAC,UAAA,QAAQ;YAEtD,mDAAmD;YACnD,IAAI,aAAa,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,MAAO,CAAC,CAAC;YAE7D,yFAAyF;YACzF,IAAI,aAAa,KAAK,SAAS;gBAC3B,OAAO;YAEX,8FAA8F;YAC9F,IAAI,OAAO,CAAC,cAAc,EAAE;gBAExB,+BAA+B;gBAC/B,+DAA+D;gBAC/D,6CAA6C;gBAC7C,0EAA0E;gBAC1E,gEAAgE;gBAChE,IAAI,0BAA0B,GAAkB,aAAa,CAAC;gBAC9D,IAAI,0BAA0B,KAAK,IAAI,IAAI,0BAA0B,YAAY,MAAM;oBACnF,0BAA0B,GAAG,QAAQ,CAAC,gBAAgB,CAAC,0BAA0B,CAAE,CAAC;gBAExF,gFAAgF;gBAChF,oDAAoD;gBACpD,IAAM,kCAAkC,GAAG,QAAQ,CAAC,cAAc,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;gBAE3F,kEAAkE;gBAClE,IAAM,kBAAkB,GAAG,+BAAc,CAAC,UAAU,CAAC,0BAA0B,EAAE,kCAAkC,CAAC,CAAC;gBACrH,IAAI,kBAAkB,EAAE;oBACpB,OAAO;iBACV;qBAAM;oBACH,OAAO,CAAC,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;iBACxC;aACJ;YAED,+GAA+G;YAC/G,0GAA0G;YAC1G,IAAM,YAAY,GAAG,WAAW,CAAC,IAAI,CAAC,UAAA,OAAO,IAAI,OAAA,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,MAAM,KAAK,aAAa,EAA1D,CAA0D,CAAC,CAAC;YAC7G,IAAI,YAAY;gBACZ,aAAa,GAAG,YAAY,CAAC;YAEjC,oDAAoD;YACpD,IAAM,SAAS,GAAG,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC,UAAA,SAAS,IAAI,OAAA,SAAS,CAAC,QAAQ,KAAK,QAAQ,EAA/B,CAA+B,CAAC,CAAC;YACxF,IAAI,SAAS,EAAE,EAAE,uCAAuC;gBACpD,SAAS,CAAC,KAAK,GAAG,aAAa,CAAC;aAEnC;iBAAM,EAAE,mDAAmD;gBACxD,OAAO,CAAC,UAAU,CAAC,IAAI,CAAC;oBACpB,QAAQ,EAAE,QAAQ;oBAClB,KAAK,EAAE,aAAa;iBACvB,CAAC,CAAC;aACN;QACL,CAAC,CAAC,CAAC;IACP,CAAC;IAEL,oCAAC;AAAD,CAtKA,AAsKC,IAAA;AAtKY,sEAA6B","file":"SubjectChangedColumnsComputer.js","sourcesContent":["import {Subject} from \"./Subject\";\nimport {DateUtils} from \"../util/DateUtils\";\nimport {ObjectLiteral} from \"../common/ObjectLiteral\";\nimport {EntityMetadata} from \"../metadata/EntityMetadata\";\nimport {OrmUtils} from \"../util/OrmUtils\";\n\n/**\n * Finds what columns are changed in the subject entities.\n */\nexport class SubjectChangedColumnsComputer {\n\n    // -------------------------------------------------------------------------\n    // Public Methods\n    // -------------------------------------------------------------------------\n\n    /**\n     * Finds what columns are changed in the subject entities.\n     */\n    compute(subjects: Subject[]) {\n        subjects.forEach(subject => {\n            this.computeDiffColumns(subject);\n            this.computeDiffRelationalColumns(subjects, subject);\n        });\n    }\n\n    // -------------------------------------------------------------------------\n    // Protected Methods\n    // -------------------------------------------------------------------------\n\n    /**\n     * Differentiate columns from the updated entity and entity stored in the database.\n     */\n    protected computeDiffColumns(subject: Subject): void {\n\n        // if there is no persisted entity then nothing to compute changed in it\n        if (!subject.entity)\n            return;\n\n        subject.metadata.columns.forEach(column => {\n\n            // ignore special columns\n            if (column.isVirtual ||\n                column.isDiscriminator ||\n                column.isUpdateDate ||\n                column.isVersion ||\n                column.isCreateDate)\n                return;\n\n            const changeMap = subject.changeMaps.find(changeMap => changeMap.column === column);\n            if (changeMap) {\n                subject.changeMaps.splice(subject.changeMaps.indexOf(changeMap), 1);\n            }\n\n            // get user provided value - column value from the user provided persisted entity\n            const entityValue = column.getEntityValue(subject.entity!);\n\n            // we don't perform operation over undefined properties (but we DO need null properties!)\n            if (entityValue === undefined)\n                return;\n\n            // if there is no database entity then all columns are treated as new, e.g. changed\n            if (subject.databaseEntity) {\n\n                // get database value of the column\n                let databaseValue = column.getEntityValue(subject.databaseEntity);\n\n                // filter out \"relational columns\" only in the case if there is a relation object in entity\n                if (column.relationMetadata) {\n                    const value = column.relationMetadata.getEntityValue(subject.entity!);\n                    if (value !== null && value !== undefined)\n                        return;\n                }\n                let normalizedValue = entityValue;\n                // normalize special values to make proper comparision\n                if (entityValue !== null) {\n                    if (column.type === \"date\") {\n                        normalizedValue = DateUtils.mixedDateToDateString(entityValue);\n\n                    } else if (column.type === \"time\") {\n                        normalizedValue = DateUtils.mixedDateToTimeString(entityValue);\n\n                    } else if (column.type === \"datetime\" || column.type === Date) {\n                        normalizedValue = DateUtils.mixedDateToUtcDatetimeString(entityValue);\n                        databaseValue = DateUtils.mixedDateToUtcDatetimeString(databaseValue);\n\n                    } else if (column.type === \"json\" || column.type === \"jsonb\") {\n                        // JSON.stringify doesn't work because postgresql sorts jsonb before save.\n                        // If you try to save json '[{\"messages\": \"\", \"attribute Key\": \"\", \"level\":\"\"}] ' as jsonb,\n                        // then postgresql will save it as '[{\"level\": \"\", \"message\":\"\", \"attributeKey\": \"\"}]'\n                        if (OrmUtils.deepCompare(entityValue, databaseValue)) return;\n\n                    } else if (column.type === \"simple-array\") {\n                        normalizedValue = DateUtils.simpleArrayToString(entityValue);\n                        databaseValue = DateUtils.simpleArrayToString(databaseValue);\n                    } else if (column.type === \"simple-enum\") {\n                        normalizedValue = DateUtils.simpleEnumToString(entityValue);\n                        databaseValue = DateUtils.simpleEnumToString(databaseValue);\n                    }\n                }\n\n                // if value is not changed - then do nothing\n                if (normalizedValue === databaseValue)\n                    return;\n            }\n            subject.diffColumns.push(column);\n            subject.changeMaps.push({\n                column: column,\n                value: entityValue\n            });\n        });\n    }\n\n    /**\n     * Difference columns of the owning one-to-one and many-to-one columns.\n     */\n    protected computeDiffRelationalColumns(allSubjects: Subject[], subject: Subject): void {\n\n        // if there is no persisted entity then nothing to compute changed in it\n        if (!subject.entity)\n            return;\n\n        subject.metadata.relationsWithJoinColumns.forEach(relation => {\n\n            // get the related entity from the persisted entity\n            let relatedEntity = relation.getEntityValue(subject.entity!);\n\n            // we don't perform operation over undefined properties (but we DO need null properties!)\n            if (relatedEntity === undefined)\n                return;\n\n            // if there is no database entity then all relational columns are treated as new, e.g. changed\n            if (subject.databaseEntity) {\n\n                // here we cover two scenarios:\n                // 1. related entity can be another entity which is natural way\n                // 2. related entity can be just an entity id\n                // if relation entity is just a relation id set (for example post.tag = 1)\n                // then we create an id map from it to make a proper comparision\n                let relatedEntityRelationIdMap: ObjectLiteral = relatedEntity;\n                if (relatedEntityRelationIdMap !== null && relatedEntityRelationIdMap instanceof Object)\n                    relatedEntityRelationIdMap = relation.getRelationIdMap(relatedEntityRelationIdMap)!;\n\n                // get database related entity. Since loadRelationIds are used on databaseEntity\n                // related entity will contain only its relation ids\n                const databaseRelatedEntityRelationIdMap = relation.getEntityValue(subject.databaseEntity);\n\n                // if relation ids are equal then we don't need to update anything\n                const areRelatedIdsEqual = EntityMetadata.compareIds(relatedEntityRelationIdMap, databaseRelatedEntityRelationIdMap);\n                if (areRelatedIdsEqual) {\n                    return;\n                } else {\n                    subject.diffRelations.push(relation);\n                }\n            }\n\n            // if there is an inserted subject for the related entity of the persisted entity then use it as related entity\n            // this code is used for related entities without ids to be properly inserted (and then updated if needed)\n            const valueSubject = allSubjects.find(subject => subject.mustBeInserted && subject.entity === relatedEntity);\n            if (valueSubject)\n                relatedEntity = valueSubject;\n\n            // find if there is already a relation to be changed\n            const changeMap = subject.changeMaps.find(changeMap => changeMap.relation === relation);\n            if (changeMap) { // and update its value if it was found\n                changeMap.value = relatedEntity;\n\n            } else { // if it wasn't found add a new relation for change\n                subject.changeMaps.push({\n                    relation: relation,\n                    value: relatedEntity\n                });\n            }\n        });\n    }\n\n}\n"],"sourceRoot":".."}