Repository: sequelize/sequelize
File: packages/core/src/model.js (JavaScript)

Code before:
      // TODO: v5 make setters return new value instead of changing internal store
      const newValue = this.dataValues[key];
      if (!isEqual(newValue, originalValue)) {
        this._previousDataValues[key] = originalValue;
        this.changed(key, true);
      }
    } else {
      // Check if we have included models, and if this key matches the include model names/aliases
      if (this._options && this._options.include && this._options.includeNames.includes(key)) {
        // Pass it on to the include handler
        this._setInclude(key, value, options);

        return this;
      }

      // Bunch of stuff we won't do when it's raw
      if (!options.raw) {
        // If the attribute is not in model definition, return
        if (!attributeDefinition) {
          const jsonAttributeNames = modelDefinition.jsonAttributeNames;

          if (key.includes('.') && jsonAttributeNames.has(key.split('.')[0])) {
            const previousNestedValue = getByPathArray(this.dataValues, tokenizePath(key));
            if (!isEqual(previousNestedValue, value)) {
              setByPathArray(this.dataValues, tokenizePath(key), value);
              this.changed(key.split('.')[0], true);
            }
          }

          return this;
        }

        // If attempting to set primary key and primary key is already defined, return
        const primaryKeyNames = modelDefinition.primaryKeysAttributeNames;
        if (originalValue && primaryKeyNames.has(key)) {
          return this;
        }

        // TODO: throw an error when trying to set a read only attribute with to a different value
        // If attempting to set read only attributes, return
        const readOnlyAttributeNames = modelDefinition.readOnlyAttributeNames;
        if (!this.isNewRecord && readOnlyAttributeNames.has(key)) {
          return this;
        }
      }

      // If there's a data type sanitizer
      const attributeType = attributeDefinition?.type;
      if (
        !options.comesFromDatabase &&
        value != null &&

Review comment (performance):
`tokenizePath(key)` is called twice (once for `getByPathArray` and once for `setByPathArray`), which re-parses the same string. Consider tokenizing once (e.g., store the path in a local variable) and reusing it to avoid duplicate work in this hot path.

Code after:
      // TODO: v5 make setters return new value instead of changing internal store
      const newValue = this.dataValues[key];
      if (!isEqual(newValue, originalValue)) {
        this._previousDataValues[key] = originalValue;
        this.changed(key, true);
      }
    } else {
      // Check if we have included models, and if this key matches the include model names/aliases
      if (this._options && this._options.include && this._options.includeNames.includes(key)) {
        // Pass it on to the include handler
        this._setInclude(key, value, options);

        return this;
      }

      // Bunch of stuff we won't do when it's raw
      if (!options.raw) {
        // If the attribute is not in model definition, return
        if (!attributeDefinition) {
          const jsonAttributeNames = modelDefinition.jsonAttributeNames;

          if (key.includes('.') && jsonAttributeNames.has(key.split('.')[0])) {
            const path = tokenizePath(key);
            const previousNestedValue = getByPathArray(this.dataValues, path);
            if (!isEqual(previousNestedValue, value)) {
              setByPathArray(this.dataValues, path, value);
              this.changed(key.split('.')[0], true);
            }
          }

          return this;
        }

        // If attempting to set primary key and primary key is already defined, return
        const primaryKeyNames = modelDefinition.primaryKeysAttributeNames;
        if (originalValue && primaryKeyNames.has(key)) {
          return this;
        }

        // TODO: throw an error when trying to set a read only attribute with to a different value
        // If attempting to set read only attributes, return
        const readOnlyAttributeNames = modelDefinition.readOnlyAttributeNames;
        if (!this.isNewRecord && readOnlyAttributeNames.has(key)) {
          return this;
        }
      }

      // If there's a data type sanitizer
      const attributeType = attributeDefinition?.type;
      if (
        !options.comesFromDatabase &&