Skip to content

Instantly share code, notes, and snippets.

@igorvolnyi
Last active February 23, 2021 22:18
Show Gist options
  • Save igorvolnyi/f7989fc64006941a7d7a1a9d5e61be47 to your computer and use it in GitHub Desktop.
Save igorvolnyi/f7989fc64006941a7d7a1a9d5e61be47 to your computer and use it in GitHub Desktop.
DRY solution for Sequelize.js models vs migrations problem
/**
* src/helpers/common-sequelize-datatypes.js
* Some common data types
*/
const DataTypes = require('sequelize')
module.exports = {
PrimaryKeyID: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
Name: {
type: DataTypes.STRING(255),
allowNull: false,
unique: true,
},
Email(unique) {
let uq = unique || true;
return {
type: DataTypes.STRING(255),
allowNull: false,
unique: uq
}
},
TimeStamp(allowNull) {
let beNull = allowNull || true;
return {
type: DataTypes.INTEGER(11),
allowNull: beNull,
}
},
Description(length) {
let len = length || 255;
return {
type: DataTypes.STRING(len),
allowNull: true
}
}
}
// src/db/migrate/20190314144703-create-user-table.js
'use strict';
const userData = require('../data-definitions/user')
module.exports = {
up: (queryInterface, Sequelize) => {
return queryInterface.createTable('user', userData);
},
down: (queryInterface, Sequelize) => {
return queryInterface.dropTable('user');
},
};
// src/db/data-definitions/user.js
'use strict';
const Sequelize = require('sequelize')
const {
PrimaryKeyID,
Name,
Email,
TimeStamp
} = require('../../helpers/common-sequelize-datatypes');
/**
* Data definition common for both model and migration.
*/
module.exports = {
id: PrimaryKeyID,
username: Name,
auth_key: {
type: Sequelize.STRING(32),
allowNull: false,
},
password_hash: {
type: Sequelize.STRING(255),
allowNull: false,
},
email: Email(),
created_at: TimeStamp(),
updated_at: TimeStamp()
}
// src/db/models/user.js
'use strict';
const bcrypt = require('bcryptjs');
const { isId, isUserName } = require('../../helpers/validators');
let userData = require('../data-definitions/user');
module.exports = function(sequelize, DataTypes) {
userData.id['validate'] = isId;
userData.username['validate'] = isUserName;
userData['password'] = {
type: DataTypes.VIRTUAL,
set(pass) {
this.setDataValue('password', pass); // Trigger validation
const salt = bcrypt.genSaltSync(10);
this.setDataValue('password_hash', bcrypt.hashSync(pass, salt));
},
validate: {
len: {
args: [ 8, 40 ],
msg: 'Password must be 8 to 40 symbols long',
},
is: {
args: /^[a-zA-Z0-9_\-=+!@#$%^&*()[\]]{8,40}$/,
msg: 'Password must contain only lowercase and uppercase letters, numbers and symbols _-=+!@#$%^&*()[]{}',
},
matchConfirm() {
return this.password === this.password_confirm;
},
},
};
userData['password_confirm'] = {
type: DataTypes.VIRTUAL
},
userData.email['validate'] = { isEmail: true };
return sequelize.define('user', userData, { tableName: 'user' });
};
/**
* src/helpers/validators.js
* Validators for some common data types
*/
module.exports = {
isId: {
notNull: true,
isInt: true,
min: 1,
max: 0x80000000 - 1
},
isShort(notNull) {
return {
notNull: !!notNull,
isInt: true,
min: 1,
max: 0xffff
}
},
isDescription(length) {
let len = length || 255;
return {
notNull: false,
notEmpty: true,
len: [1, len]
}
},
isName: {
notNull: true,
notEmpty: true,
len: [1, 255]
},
isUserName: {
isAlphanumeric: true,
len: [2, 255]
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment