UNPKG

typeorm

Version:

Data-Mapper ORM for TypeScript, ES7, ES6, ES5. Supports MySQL, PostgreSQL, MariaDB, SQLite, MS SQL Server, Oracle, MongoDB databases.

203 lines (201 loc) • 10.5 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SubjectChangedColumnsComputer = void 0; const DateUtils_1 = require("../util/DateUtils"); const OrmUtils_1 = require("../util/OrmUtils"); const ApplyValueTransformers_1 = require("../util/ApplyValueTransformers"); const ObjectUtils_1 = require("../util/ObjectUtils"); /** * Finds what columns are changed in the subject entities. */ class SubjectChangedColumnsComputer { // ------------------------------------------------------------------------- // Public Methods // ------------------------------------------------------------------------- /** * Finds what columns are changed in the subject entities. */ compute(subjects) { subjects.forEach((subject) => { this.computeDiffColumns(subject); this.computeDiffRelationalColumns(subjects, subject); }); } // ------------------------------------------------------------------------- // Protected Methods // ------------------------------------------------------------------------- /** * Differentiate columns from the updated entity and entity stored in the database. */ computeDiffColumns(subject) { // if there is no persisted entity then nothing to compute changed in it if (!subject.entity) return; subject.metadata.columns.forEach((column) => { // ignore special columns if (column.isVirtual || column.isDiscriminator // || // column.isUpdateDate || // column.isVersion || // column.isCreateDate ) return; const changeMap = subject.changeMaps.find((changeMap) => changeMap.column === column); if (changeMap) { subject.changeMaps.splice(subject.changeMaps.indexOf(changeMap), 1); } // get user provided value - column value from the user provided persisted entity const entityValue = column.getEntityValue(subject.entity); // we don't perform operation over undefined properties (but we DO need null properties!) if (entityValue === undefined) return; // if there is no database entity then all columns are treated as new, e.g. changed if (subject.databaseEntity) { // skip transform database value for json / jsonb for comparison later on const shouldTransformDatabaseEntity = column.type !== "json" && column.type !== "jsonb"; // get database value of the column let databaseValue = column.getEntityValue(subject.databaseEntity, shouldTransformDatabaseEntity); // filter out "relational columns" only in the case if there is a relation object in entity if (column.relationMetadata) { const value = column.relationMetadata.getEntityValue(subject.entity); if (value !== null && value !== undefined) return; } let normalizedValue = entityValue; // normalize special values to make proper comparision if (entityValue !== null) { switch (column.type) { case "date": normalizedValue = DateUtils_1.DateUtils.mixedDateToDateString(entityValue); break; case "time": case "time with time zone": case "time without time zone": case "timetz": normalizedValue = DateUtils_1.DateUtils.mixedDateToTimeString(entityValue); break; case "datetime": case "datetime2": case Date: case "timestamp": case "timestamp without time zone": case "timestamp with time zone": case "timestamp with local time zone": case "timestamptz": normalizedValue = DateUtils_1.DateUtils.mixedDateToUtcDatetimeString(entityValue); databaseValue = DateUtils_1.DateUtils.mixedDateToUtcDatetimeString(databaseValue); break; case "json": case "jsonb": // JSON.stringify doesn't work because postgresql sorts jsonb before save. // If you try to save json '[{"messages": "", "attribute Key": "", "level":""}] ' as jsonb, // then postgresql will save it as '[{"level": "", "message":"", "attributeKey": ""}]' if (OrmUtils_1.OrmUtils.deepCompare(entityValue, databaseValue)) return; break; case "simple-array": normalizedValue = DateUtils_1.DateUtils.simpleArrayToString(entityValue); databaseValue = DateUtils_1.DateUtils.simpleArrayToString(databaseValue); break; case "simple-enum": normalizedValue = DateUtils_1.DateUtils.simpleEnumToString(entityValue); databaseValue = DateUtils_1.DateUtils.simpleEnumToString(databaseValue); break; case "simple-json": normalizedValue = DateUtils_1.DateUtils.simpleJsonToString(entityValue); databaseValue = DateUtils_1.DateUtils.simpleJsonToString(databaseValue); break; } if (column.transformer) { normalizedValue = ApplyValueTransformers_1.ApplyValueTransformers.transformTo(column.transformer, entityValue); } } // if value is not changed - then do nothing if (Buffer.isBuffer(normalizedValue) && Buffer.isBuffer(databaseValue)) { if (normalizedValue.equals(databaseValue)) { return; } } else { if (normalizedValue === databaseValue) return; } } if (!subject.diffColumns.includes(column)) subject.diffColumns.push(column); subject.changeMaps.push({ column: column, value: entityValue, }); }); } /** * Difference columns of the owning one-to-one and many-to-one columns. */ computeDiffRelationalColumns(allSubjects, subject) { // if there is no persisted entity then nothing to compute changed in it if (!subject.entity) return; subject.metadata.relationsWithJoinColumns.forEach((relation) => { // get the related entity from the persisted entity let relatedEntity = relation.getEntityValue(subject.entity); // we don't perform operation over undefined properties (but we DO need null properties!) if (relatedEntity === undefined) return; // if there is no database entity then all relational columns are treated as new, e.g. changed if (subject.databaseEntity) { // here we cover two scenarios: // 1. related entity can be another entity which is natural way // 2. related entity can be just an entity id // if relation entity is just a relation id set (for example post.tag = 1) // then we create an id map from it to make a proper comparision let relatedEntityRelationIdMap = relatedEntity; if (relatedEntityRelationIdMap !== null && ObjectUtils_1.ObjectUtils.isObject(relatedEntityRelationIdMap)) relatedEntityRelationIdMap = relation.getRelationIdMap(relatedEntityRelationIdMap); // get database related entity. Since loadRelationIds are used on databaseEntity // related entity will contain only its relation ids const databaseRelatedEntityRelationIdMap = relation.getEntityValue(subject.databaseEntity); // if relation ids are equal then we don't need to update anything const areRelatedIdsEqual = OrmUtils_1.OrmUtils.compareIds(relatedEntityRelationIdMap, databaseRelatedEntityRelationIdMap); if (areRelatedIdsEqual) { return; } else { subject.diffRelations.push(relation); } } // if there is an inserted subject for the related entity of the persisted entity then use it as related entity // this code is used for related entities without ids to be properly inserted (and then updated if needed) const valueSubject = allSubjects.find((subject) => subject.mustBeInserted && subject.entity === relatedEntity); if (valueSubject) relatedEntity = valueSubject; // find if there is already a relation to be changed const changeMap = subject.changeMaps.find((changeMap) => changeMap.relation === relation); if (changeMap) { // and update its value if it was found changeMap.value = relatedEntity; } else { // if it wasn't found add a new relation for change subject.changeMaps.push({ relation: relation, value: relatedEntity, }); } }); } } exports.SubjectChangedColumnsComputer = SubjectChangedColumnsComputer; //# sourceMappingURL=SubjectChangedColumnsComputer.js.map