10

I'm facing the problem with implementation model in Sequalize with primary key as uuid. I follow step by step all instruction, but still I cannot solve it.

This is how my model looks like:

'use strict';
module.exports = (sequelize, DataTypes) => {
  var Todo = sequelize.define('Todo', {
    title: DataTypes.STRING,
    description: DataTypes.STRING,
    test: DataTypes.UUID
  }, {});
  Todo.associate = function(models) {
    // associations can be defined here
  };
  return Todo;
};

And migration file:

'use strict';
module.exports = {
  up: (queryInterface, Sequelize) => {
    return queryInterface.createTable('Todos', {
      id: {
        primaryKey: true,
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV1
      },
      title: {
        type: Sequelize.STRING
      },
      description: {
        type: Sequelize.STRING
      },
      test: {
        type: Sequelize.UUID,
        defaultValue: Sequelize.UUIDV4
      },
      createdAt: {
        allowNull: false,
        type: Sequelize.DATE
      },
      updatedAt: {
        allowNull: false,
        type: Sequelize.DATE
      }
    });
  },
  down: (queryInterface, Sequelize) => {
    return queryInterface.dropTable('Todos');
  }
};

After calling post method to create element, I habe got an empty value in ID column, and NULL in test column...

The Datebase is MySql.

Is there any other way to do it?

agims7
  • 216
  • 2
  • 6
  • 16

3 Answers3

14

1) Setting Custom Keys in Sequelize

I'm facing the problem with implementation model in Sequalize with primary key as uuid.

By default, if your model does not contain a key with primaryKey: true, then sequelize assumes a PK of type INTEGER named id.

In your case, it seems like you wish to make your own custom PK.

Use the following in your model:

var Todo = sequelize.define('Todo', {
    id: {
      primaryKey: true,
      type: DataTypes.UUID
    }
    // rest of properties
 });

2) Validations

After calling post method to create element, I habe got an empty value in ID column, and NULL in test column...

Without much information regarding not only your query, but how you seeded the database, it's hard to answer specifically.

However, it doesn't surprise me that test column was null, because you have not listed any validations. Thus if you seed/create rows that do not set a test value, it will be null.

To create validations do the following

model:

var Todo = sequelize.define('Todo', {
    // rest of properties
    test: {
      allowNull: false
      type: DataTypes.UUID,
      validate: {
        notNull: true
      }
    }
});

migration:

queryInterface.createTable('Todos', {
    // rest of properties
    test: {
      allowNull: false,
      type: Sequelize.UUID,
      defaultValue: Sequelize.UUIDV4
    }
});

3) Keeping Models and Migrations Synchronized

(see: https://stackoverflow.com/a/49796801/8954866) In sequelize, models and migrations are not automatically in-sync with one another, except when initially generated using sequelize-cli model:generate. I'm unsure if you ran your migrations or if you were running your query in a unit test against the model. But you have to make sure they are synchronized. A primary example is that in the above case, your migration says id is of type UUID, but your model will think it's of type INTEGER.

References

vapurrmaid
  • 2,287
  • 2
  • 14
  • 30
  • I have this in my code. The problem with this is that it doesn't translate to an ID column with a default value for UUID in the database. By default, it leaves it at null if I insert a row directly (using a database client). Sequelize should set a default value at the dabase level, in case a user is not using the API. – Lucio Mollinedo Jun 15 '21 at 17:00
2

Make sure your package.json has updated uuid module, this was the problem in my case.

accessSecret: {
      type: DataTypes.UUID,
      defaultValue: Sequelize.UUIDV4,
      allowNull: false,
      unique: true,
    },

This works fine, just make sure package.json has

"uuid": "^8.2.0",
Sanket Berde
  • 6,555
  • 4
  • 35
  • 39
0

Looks like this issue is the same for both MySQL and Postgres: Sequelize needs to use the defaultValue setting of the model to point to its uuid dependency.

For example, for an entity called Product, create your migration like this:

"use strict";
module.exports = {
  up: async (queryInterface, Sequelize) => {
    await queryInterface.createTable("Products", {
      id: {
        type: Sequelize.UUID,
        primaryKey: true,
        defaultValue: Sequelize.UUIDV4,
      },
      productName: {
        type: Sequelize.STRING,
      },
    });
  },
  down: async (queryInterface, Sequelize) => {
    await queryInterface.dropTable("Products");
  },
};

Then, create your model like this:

"use strict";
const { Model } = require("sequelize");
module.exports = (sequelize, DataTypes) => {
  class Product extends Model {
    static associate(models) {
      // associations
    }
  }
  Product.init(
    {
      id: {
        type: DataTypes.UUID,
        defaultValue: DataTypes.UUIDV4,
        primaryKey: true,
      },
      productName: DataTypes.STRING,
    },
    {
      sequelize,
      modelName: "Product",
    }
  );
  return Product;
};

Note that in your model, you're defining defaultValue: DataTypes.UUIDV4.

When you create a new instance of Product, you only need the name field. The UUID is auto-generated by the Sequelize model.

const {
    Product
  } = require("./models");

const createProduct = async (name) => {
  const newProductData = { productName: "First product" };
  const creationResult = await Product.create(newProductData);
};

The id field in the model will trace the defaultValue setting back to the v4() function of the uuid package that Sequelize relies on to auto-generate the UUID as part of the model operation, not as part of native Postgres.

lauri108
  • 1,381
  • 1
  • 13
  • 22