Skip to content

Instantly share code, notes, and snippets.

@paulmowat
Last active December 21, 2018 07:12
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save paulmowat/1999c07a10f068d11d8bc7614d214c4e to your computer and use it in GitHub Desktop.
Save paulmowat/1999c07a10f068d11d8bc7614d214c4e to your computer and use it in GitHub Desktop.
Sequelize Migration Generator from Models
// ////////////////////////////////
// How to use?
// 1. Make sure you've ran the `sequelize init` before (It should create `config`,`seeders`,`migrations` folders).
// 2. Run it with `node sequelize-schema-file-generator.js`
// 3. Review the generated migrations inside of the `migrations` folder.
// ////////////////////////////////
/* jscs:disable */
/* jshint ignore:start */
var path = require('path')
var models = require(path.join(__dirname, '/models')).sequelize.models
var Sequelize = require('sequelize')
var fs = require('fs')
// Logger
var logger = require(path.join(__dirname, '../', 'lib/log/logger'))
delete models.default
var env = require(path.join(__dirname, '/../config/config')).env
var config = require(path.join(__dirname, '/../config/dbconfig'))[env]
var sequelize = {}
if (config.use_env_variable) {
sequelize = new Sequelize(process.env[config.use_env_variable])
} else {
sequelize = new Sequelize(config.database, config.username, config.password, config)
}
// fix date for all files
const d = new Date(2017, 8, 16, 22, 18, 57)
// The priority is to create first tables that others by restriction to create an association first, before the table is created.
// is write in name of file migration. example : 201703291645-01-user.js this file run first that 201703291645-02-user-grant.js
for (const model in models) { // jshint ignore:line
if (models.hasOwnProperty(model)) {
process.stdout.write(models[model].name + 'Singular=' + models[model].options.name.singular + ' Plural=' + models[model].options.name.plural)
var priority = '00'
const attributes = models[model].attributes
priority = setPriority(attributes, model)
process.stdout.write(' Priority=' + priority)
var processedattributes = processAttributes(attributes)
var schema = JSON.stringify(processedattributes, null, 2)
schema = schema.replace(/"([^"]+)":/g, '$1:')
schema = schema.replace(/"Sequelize([^"]+)"/g, 'Sequelize$1')
schema = schema.replace(/["]+/g, '\'')
const tableName = models[model].tableName
var indexes = buildIndexes(models, model, tableName)
schema = schema.split('\n').map((line) => ' ' + line).join('\n')
// with respect original file remove return queryInterface.sequelize.query('SET FOREIGN_KEY_CHECKS = 0')
// and return queryInterface.sequelize.query('SET FOREIGN_KEY_CHECKS = 1') because postgres dont work only for mysql
const template = `'use strict'
module.exports = {
up: function (queryInterface, Sequelize) {
return queryInterface.createTable('${tableName}',
${schema})${indexes.join('\n')}
},
down: function (queryInterface, Sequelize) {
return queryInterface.dropTable('${tableName}')
}
}
`
const filename = [d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds()]
.map((num) => (num <= 60 && (num + 100).toString().substring(1)) || num)
.join('') + `-` + priority + `-${models[model].tableName}`
fs.writeFileSync(path.join(__dirname, `/migrations/${filename}.js`), template)
process.stdout.write(' Migration=' + filename + '.js\n')
}
}
logger.debug('Completed')
process.exit(0)
function processAttributes (attributes) {
for (const column in attributes) {
if (attributes.hasOwnProperty(column)) {
delete attributes[column].Model
delete attributes[column].fieldName
delete attributes[column].field
attributes = processAttributesColumnProperty(attributes, column)
if (typeof attributes[column]['type'] !== 'undefined') {
attributes = processAttributesColumnTypeOptions(attributes, column)
attributes = processAttributesColumnType(attributes, column)
}
if (typeof attributes[column]['defaultValue'] !== 'undefined') {
attributes = processAttributesDefaultValue(attributes, column)
}
}
}
return attributes
}
function processAttributesColumnProperty (attributes, column) {
for (const property in attributes[column]) {
if (property.startsWith('_')) {
delete attributes[column][property]
}
}
return attributes
}
function processAttributesColumnTypeOptions (attributes, column) {
if (typeof attributes[column]['type']['options'] !== 'undefined' && typeof attributes[column]['type']['options'].toString === 'function') {
attributes[column]['type']['options'] = attributes[column]['type']['options'].toString(sequelize)
}
return attributes
}
function processAttributesColumnType (attributes, column) {
if (typeof attributes[column]['type'].toString === 'function') {
if (attributes[column].type.key === 'DOUBLE PRECISION') {
attributes[column]['type'] = 'Sequelize.DOUBLE'
} else {
attributes[column]['type'] = 'Sequelize.' + attributes[column].type.key
}
}
return attributes
}
function processAttributesDefaultValue (attributes, column) {
if (attributes[column].defaultValue !== null) {
if (attributes[column].defaultValue.key === 'UUIDV4') {
attributes[column]['defaultValue'] = 'Sequelize.UUIDV4'
}
}
return attributes
}
function setPriority (attributes, model) {
var priority = '00'
// put all tables with reference 2nd
for (const column in attributes) {
if ((attributes.hasOwnProperty(column)) && (models[model].attributes[column].references !== undefined)) {
priority = '01'
break
}
}
// handle tables that need to be defined later
if (['authaccesstoken', 'authrefreshtoken', 'passwordemailtoken', 'userpasswordhistory', 'bankaccount', 'dsconfig', 'fmsagreementtype', 'fmsbudgetaccount', 'fmscommitmenttype', 'fmsdocument', 'layout',
'userdataversion'].includes(models[model].options.name.singular)) {
priority = '02'
} else if (['databankbalance', 'datasummary', 'dsconfigstat', 'datatransaction', 'dsagreementtype', 'dsbudgetmodel', 'dsbudgetaccount', 'dsbudgetparameter', 'dscommitmenttype',
'dscompany', 'dsdocument', 'dsledger', 'dstransactiontype', 'layoutdetail', 'userdatarevision', 'pendingimport'
].includes(models[model].options.name.singular)) {
priority = '03'
} else if (['userdatastate', 'userdatasummary'
].includes(models[model].options.name.singular)) {
priority = '04'
}
return priority
}
function buildIndexes (models, model, tableName) {
const indexes = []
// any indexes?
if (models[model].options.indexes.length) {
indexes.push('\n')
for (var index = 0; index <= models[model].options.indexes.length - 1; index++) {
var obj = models[model].options.indexes[index]
indexes.push(' .then(() => {')
indexes.push(' return queryInterface.addIndex(')
indexes.push(` '${tableName}',`)
const opts = {}
if (obj.name) {
opts.indexName = obj.name
}
if (obj.unique === true) {
opts.indicesType = 'UNIQUE'
}
if (obj.method === true) {
opts.indexType = obj.method
}
if (Object.keys(opts).length) {
indexes.push(` ['${obj.fields.join("', '")}'],`)
// Deals with using single quotes to match our standards
var indexString = JSON.stringify(opts)
indexString = indexString.replace(/"/g, '\'')
indexString = indexString.replace(/:/g, ': ')
indexes.push(` ${indexString}`)
} else {
indexes.push(` ['${obj.fields.join("', '")}']`)
}
indexes.push(' )')
if (index === (models[model].options.indexes.length - 1)) {
indexes.push(' })')
} else {
indexes.push(' })')
}
}
} else {
indexes.push('')
}
return indexes
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment