text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  exports.EntityComparator = void 0;
  const enums_1 = require("../enums");
  const Utils_1 = require("./Utils");
  class EntityComparator {
      constructor(metadata, platform) {
          this.metadata = metadata;
          this.platform = platform;
      }
      /**
       * Computes difference between two entities. First calls `prepareEntity` on both, then uses the `diff` method.
       */
      diffEntities(a, b) {
          return Utils_1.Utils.diff(this.prepareEntity(a), this.prepareEntity(b));
      }
      /**
       * Removes ORM specific code from entities and prepares it for serializing. Used before change set computation.
       * References will be mapped to primary keys, collections to arrays of primary keys.
       */
      prepareEntity(entity) {
          if (entity.__prepared) {
              return entity;
          }
          const meta = this.metadata.get(entity.constructor.name);
          const root = Utils_1.Utils.getRootEntity(this.metadata, meta);
          const ret = {};
          if (meta.discriminatorValue) {
              ret[root.discriminatorColumn] = meta.discriminatorValue;
          }
          // copy all props, ignore collections and references, process custom types
          Object.values(meta.properties).forEach(prop => {
              if (this.shouldIgnoreProperty(entity, prop, root)) {
                  return;
              }
              if (prop.reference === enums_1.ReferenceType.EMBEDDED) {
                  return Object.values(meta.properties).filter(p => { var _a; return ((_a = p.embedded) === null || _a === void 0 ? void 0 : _a[0]) === prop.name; }).forEach(childProp => {
                      ret[childProp.name] = entity[prop.name][childProp.embedded[1]];
                  });
              }
              if (Utils_1.Utils.isEntity(entity[prop.name], true)) {
                  ret[prop.name] = Utils_1.Utils.getPrimaryKeyValues(entity[prop.name], this.metadata.find(prop.type).primaryKeys, true);
                  if (prop.customType) {
                      return ret[prop.name] = prop.customType.convertToDatabaseValue(ret[prop.name], this.platform);
                  }
                  return;
              }
              if (prop.customType) {
                  return ret[prop.name] = prop.customType.convertToDatabaseValue(entity[prop.name], this.platform);
              }
              if (Array.isArray(entity[prop.name]) || Utils_1.Utils.isObject(entity[prop.name])) {
                  return ret[prop.name] = Utils_1.Utils.copy(entity[prop.name]);
              }
              ret[prop.name] = entity[prop.name];
          });
          Object.defineProperty(ret, '__prepared', { value: true });
          return ret;
      }
      shouldIgnoreProperty(entity, prop, root) {
          if (!(prop.name in entity) || prop.persist === false) {
              return true;
          }
          const value = entity[prop.name];
          const collection = Utils_1.Utils.isCollection(value);
          const noPkRef = Utils_1.Utils.isEntity(value, true) && !value.__helper.__primaryKeys.every(pk => Utils_1.Utils.isDefined(pk, true));
          const noPkProp = prop.primary && !Utils_1.Utils.isDefined(value, true);
          const inverse = prop.reference === enums_1.ReferenceType.ONE_TO_ONE && !prop.owner;
          const discriminator = prop.name === root.discriminatorColumn;
          // bidirectional 1:1 and m:1 fields are defined as setters, we need to check for `undefined` explicitly
          const isSetter = [enums_1.ReferenceType.ONE_TO_ONE, enums_1.ReferenceType.MANY_TO_ONE].includes(prop.reference) && (prop.inversedBy || prop.mappedBy);
          const emptyRef = isSetter && value === undefined;
          return collection || noPkProp || noPkRef || inverse || discriminator || emptyRef;
      }
  }
  exports.EntityComparator = EntityComparator;
  