sequelize-typescript icon indicating copy to clipboard operation
sequelize-typescript copied to clipboard

@BeforeUpdate and @BeforeCreate user instance to be modified is undefined

Open carlosamaya opened this issue 2 years ago • 0 comments

Issue

Hello everyone, I have this issue please take a look and suggest anythig cause I'm stock here, when I call @BeforeUpdate and @BeforeCreate hooks in the model, they're triggered, the coming new instance is valid but their attributtes are undefined.

Versions

  • sequelize: 6.20.0
  • sequelize-typescript: 2.1.3
  • typescript: 4.6.4

Issue type

  • [ x] bug report
  • [ ] feature request

Actual behavior

In the model when I create User definition, I am trying to catch beforeCreate and BeforeUpdate behavior in order to hash the password, so I use @BeforeUpdate and @BeforeCreate hooks to do that, they are triggered as expected, but nothig happened, then I put some console.logs there and I notice that they are triggered as expected, then I consoled the whole instance Object:

    @BeforeUpdate
    static hashPasswordBeforeUpdate(user: User, options: any) {
      let salt = bcrypt.genSaltSync(12);
      console.log("Password2:"+bcrypt.hashSync("holaPajuo", salt));
      console.log("Entered HookHashUpdate:"+JSON.stringify(user));
      console.log("PassData: "+JSON.stringify(user.password));
        if (user.password) {
            user.password = bcrypt.hashSync(user.password, salt);
        }
    }

Result:

Password2:$2a$12$LuyXzkEyQZvJNTh7fiLR0u4IxnmyJmJX4n4N3dPh9C.cjz7YMXx.2
Entered HookHashUpdate:{"id":25,"first_name":"nombre prueba2","last_name":"apellido prueba2","username":"prueba2","password":"123456","phone":null,"cell_phone":"33234343","email":"[email protected]","address":"prueba2","zip_code":"prueba2","id_location":1,"id_company":1,"status":true}
PassData: undefined

As you can notice, they are triggered, it can hash the password with an alternative string, I logged the whole incoming instance and it is there, but when I console log any of the attributes in order to modify it, like the password it says that it is undefined....crazy isn't it?

It is driving me crazy.....

Expected behavior

I expect to call user.password and modify it with an hashed string based on its actual value

Steps to reproduce

just update or create and item and watch the console

Related code

files. user.model.ts

import { 
    Table, 
    Model, 
    Column, 
    DataType,
    BeforeCreate, 
    BeforeUpdate,
    Sequelize
  } from "sequelize-typescript";
  import bcrypt from 'bcryptjs';

  /* TABLE USER */
 @Table({
    timestamps: false,
    freezeTableName: true,
    tableName: 'user'
  }) 
  class User extends Model {
    @Column({
      type: DataType.STRING(100),
      allowNull: false
    })
    first_name!: string;
  
    @Column({
      type: DataType.STRING(100),
      allowNull: false
    })
    last_name!: string;
  
    @Column({
      type: DataType.STRING(40),
      allowNull: false
    })
    username!: string;
  
    @Column({
      type: DataType.STRING(80),
      allowNull: false
    })
    password!: string;
  
    @Column({
      type: DataType.STRING(50),
      allowNull: true
    })
    phone!: string; 
  
    @Column({
      type: DataType.STRING(50),
      allowNull: false
    })
    cell_phone!: string;  
  
    @Column({
      type: DataType.STRING(60),
      allowNull: false,
      validate: { isEmail: true }
    })
    email!: string;
  
    @Column({
      type: DataType.TEXT,
      allowNull: true
    })
    address!: string;  

    @Column({
      type: DataType.STRING(20),
      allowNull: true
    })
    zip_code!: string; 

    @Column({
      type: DataType.INTEGER,
      allowNull: true
    })
    id_location!: number; 

    @Column({
      type: DataType.INTEGER,
      allowNull: true
    })
    id_company!: number; 
  
    @Column({
      type: DataType.BOOLEAN,
      allowNull: false,
      defaultValue: true
    })
    status!: boolean;

    @BeforeCreate
    static BeforeCreateHook(user: User){
      let salt = bcrypt.genSaltSync(12);
      console.log("Password2:"+bcrypt.hashSync("holaPajuo", salt));
      console.log("Entered HookHashCreate: "+JSON.stringify(user));
      //console.log("PassData: "+JSON.stringify(user));
        if (user.password) {            
            console.log("Password2:"+bcrypt.hashSync(user.password, salt));
            user.password = bcrypt.hashSync(user.password, salt);
        }
    }

    @BeforeUpdate
    static hashPasswordBeforeUpdate(user: User, options: any) {
      let salt = bcrypt.genSaltSync(12);
      console.log("Password2:"+bcrypt.hashSync("holaPajuo", salt));
      console.log("Entered HookHashUpdate:"+JSON.stringify(user));
      console.log("PassData: "+JSON.stringify(user.password));
        if (user.password) {
            user.password = bcrypt.hashSync(user.password, salt);
        }
    }
  }
  export default User;

my user.datasource.ts

user.datasource.ts

  public async userUpdate(data: User, id: number): Promise<any> { //TODO: try to don't use any
    try{
      return await UserModel.update(data, { where: {id : id}, individualHooks: true });
    }catch(err) {
      throw err;
    }
  }

public async userSave(data: User): Promise<User> {
    const userToSave = new UserModel({
      first_name: data.first_name,
      last_name: data.last_name,
      username: data.username,
      password: data.password,
      email: data.email,
      cell_phone: data.cell_phone,
      phone: data.phone,
      address: data.address,
      zip_code: data.zip_code,
      id_location: data.id_location,
      id_company: data.id_company,
      status: data.status
    });

    try{
    return await userToSave.save();
    }catch(err) {
      throw err;
    }
  }
}

tsconfig.json

{
    "compilerOptions": {
      "sourceMap": true,
      "outDir": "dist",
      "strict": true,
      "lib": [
        "esnext"
      ],
      "esModuleInterop": true,
      "experimentalDecorators": true,
      "emitDecoratorMetadata": true,
      "target": "esnext",
      "moduleResolution": "Node",
      "strictNullChecks":false 
    }
}  

database.connection.ts

import { Sequelize } from "sequelize-typescript";
import { User } from "../models";
import dotenv from "dotenv";
dotenv.config();

const connection = new Sequelize(
    process.env.DB_NAME as string,
    process.env.DB_USER as string,
    process.env.DB_PASSWORD as string
  ,
  {
    host: process.env.DB_HOST,
    dialect: 'mysql',
    models: [__dirname + '../models']
  });

connection.addModels([ User ]);
connection
  .authenticate()
  .then(() => {
    console.log('Connection has been established successfully.');
  })
  .catch(err => {
    console.error('Unable to connect to the database:', err);
  });

export default connection;

I hope you can notice what is happening. Thanks in Advance

carlosamaya avatar May 25 '22 12:05 carlosamaya