We need to implement data validation for a Colors table with specific requirements for the name field:
We'll be working with both database-level constraints and model-level validations to achieve this.
// Migration file (20211011170805-create-color.js)
module.exports = {
up: async (queryInterface, Sequelize) => {
await queryInterface.createTable('Colors', {
id: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: Sequelize.INTEGER
},
name: {
type: Sequelize.STRING(20),
allowNull: false, // Database constraint: No NULL values
unique: true // Database constraint: No duplicates
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal("CURRENT_TIMESTAMP")
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
defaultValue: Sequelize.literal("CURRENT_TIMESTAMP")
}
});
},
down: async (queryInterface, Sequelize) => {
await queryInterface.dropTable('Colors');
}
};
// Model file (color.js)
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Color extends Model {
static associate(models) {
// Define associations here if needed
}
}
Color.init({
name: {
type: DataTypes.STRING,
allowNull: false,
validate: {
// Basic type validation
isString(value) {
if (typeof value !== 'string') {
throw new Error('name must be a string');
}
},
// Length validation
len: {
args: [2, 20],
msg: 'name must be between 2 and 20 characters'
},
// Custom validation for 'y' ending
noEndingInY(value) {
if (value.slice(-1) === 'y') {
throw new Error('name must not end in y');
}
}
}
}
}, {
sequelize,
modelName: 'Color',
});
return Color;
};
Think of database constraints like the security guards at a building's entrance, while model validations are like the receptionist who checks your appointment before you even leave home.
// Example test cases and their outcomes:
await Color.create({}) // Fails: name cannot be null
await Color.create({name: []}) // Fails: name must be a string
await Color.create({name: 'a'}) // Fails: name too short
await Color.create({name: 'orangey'})// Fails: ends in 'y'
await Color.create({name: 'orange'}) // Succeeds!
This pattern is commonly used in many real-world scenarios:
To deepen your understanding, try: