{"version":3,"sources":["../browser/src/persistence/SubjectChangedColumnsComputer.ts"],"names":[],"mappings":"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","file":"SubjectChangedColumnsComputer.js","sourcesContent":["import { Subject } from \"./Subject\"\nimport { DateUtils } from \"../util/DateUtils\"\nimport { ObjectLiteral } from \"../common/ObjectLiteral\"\nimport { OrmUtils } from \"../util/OrmUtils\"\nimport { ApplyValueTransformers } from \"../util/ApplyValueTransformers\"\nimport { ObjectUtils } from \"../util/ObjectUtils\"\n\n/**\n * Finds what columns are changed in the subject entities.\n */\nexport class SubjectChangedColumnsComputer {\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 // if there is no persisted entity then nothing to compute changed in it\n if (!subject.entity) return\n\n subject.metadata.columns.forEach((column) => {\n // ignore special columns\n if (\n column.isVirtual ||\n column.isDiscriminator // ||\n // column.isUpdateDate ||\n // column.isVersion ||\n // column.isCreateDate\n )\n return\n\n const changeMap = subject.changeMaps.find(\n (changeMap) => changeMap.column === column,\n )\n if (changeMap) {\n subject.changeMaps.splice(\n subject.changeMaps.indexOf(changeMap),\n 1,\n )\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) return\n\n // if there is no database entity then all columns are treated as new, e.g. changed\n if (subject.databaseEntity) {\n // skip transform database value for json / jsonb for comparison later on\n const shouldTransformDatabaseEntity =\n column.type !== \"json\" && column.type !== \"jsonb\"\n\n // get database value of the column\n let databaseValue = column.getEntityValue(\n subject.databaseEntity,\n shouldTransformDatabaseEntity,\n )\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(\n subject.entity!,\n )\n if (value !== null && value !== undefined) return\n }\n let normalizedValue = entityValue\n // normalize special values to make proper comparision\n if (entityValue !== null) {\n switch (column.type) {\n case \"date\":\n normalizedValue =\n DateUtils.mixedDateToDateString(entityValue)\n break\n\n case \"time\":\n case \"time with time zone\":\n case \"time without time zone\":\n case \"timetz\":\n normalizedValue =\n DateUtils.mixedDateToTimeString(entityValue)\n break\n\n case \"datetime\":\n case \"datetime2\":\n case Date:\n case \"timestamp\":\n case \"timestamp without time zone\":\n case \"timestamp with time zone\":\n case \"timestamp with local time zone\":\n case \"timestamptz\":\n normalizedValue =\n DateUtils.mixedDateToUtcDatetimeString(\n entityValue,\n )\n databaseValue =\n DateUtils.mixedDateToUtcDatetimeString(\n databaseValue,\n )\n break\n\n case \"json\":\n case \"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 (\n OrmUtils.deepCompare(entityValue, databaseValue)\n )\n return\n break\n\n case \"simple-array\":\n normalizedValue =\n DateUtils.simpleArrayToString(entityValue)\n databaseValue =\n DateUtils.simpleArrayToString(databaseValue)\n break\n case \"simple-enum\":\n normalizedValue =\n DateUtils.simpleEnumToString(entityValue)\n databaseValue =\n DateUtils.simpleEnumToString(databaseValue)\n break\n case \"simple-json\":\n normalizedValue =\n DateUtils.simpleJsonToString(entityValue)\n databaseValue =\n DateUtils.simpleJsonToString(databaseValue)\n break\n }\n\n if (column.transformer) {\n normalizedValue = ApplyValueTransformers.transformTo(\n column.transformer,\n entityValue,\n )\n }\n }\n\n // if value is not changed - then do nothing\n if (\n Buffer.isBuffer(normalizedValue) &&\n Buffer.isBuffer(databaseValue)\n ) {\n if (normalizedValue.equals(databaseValue)) {\n return\n }\n } else {\n if (normalizedValue === databaseValue) return\n }\n }\n\n if (!subject.diffColumns.includes(column))\n subject.diffColumns.push(column)\n\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(\n allSubjects: Subject[],\n subject: Subject,\n ): void {\n // if there is no persisted entity then nothing to compute changed in it\n if (!subject.entity) return\n\n subject.metadata.relationsWithJoinColumns.forEach((relation) => {\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) 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 // 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 (\n relatedEntityRelationIdMap !== null &&\n ObjectUtils.isObject(relatedEntityRelationIdMap)\n )\n relatedEntityRelationIdMap = relation.getRelationIdMap(\n relatedEntityRelationIdMap,\n )!\n\n // get database related entity. Since loadRelationIds are used on databaseEntity\n // related entity will contain only its relation ids\n const databaseRelatedEntityRelationIdMap =\n relation.getEntityValue(subject.databaseEntity)\n\n // if relation ids are equal then we don't need to update anything\n const areRelatedIdsEqual = OrmUtils.compareIds(\n relatedEntityRelationIdMap,\n databaseRelatedEntityRelationIdMap,\n )\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(\n (subject) =>\n subject.mustBeInserted && subject.entity === relatedEntity,\n )\n if (valueSubject) relatedEntity = valueSubject\n\n // find if there is already a relation to be changed\n const changeMap = subject.changeMaps.find(\n (changeMap) => changeMap.relation === relation,\n )\n if (changeMap) {\n // and update its value if it was found\n changeMap.value = relatedEntity\n } else {\n // 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"],"sourceRoot":".."}