- Modify & run
dump-sequelize-schema.js
.- It currently uses a few
lodash
methods, so be sure to temporarily install them—or if you feel up to it you can rewrite the script so they're not needed. npm i lodash.sortby lodash.pick lodash.omit lodash.mapvalues
- It currently uses a few
- Inspect
sequelize-schema.json
and make sure it appears represent all of your tables, attributes, indexes, constraints, references, etc... - When you are satisfied, copy and rename
sequelize-schema.json
file into amigration-extras/
directory that is next to yourmigrations/
. Name itinitial-sequelize-schema.json
.migration-extras/
- ->
initial-sequelize-schema.json
- ->
migrations/
- (this folder should probably be empty)
- Run
sequelize migration:create
and then copy the contents of2018XXXXXXXXXX-initial-migration.js
into the newly generated migration script. No additional modifications are required if yourinitial-sequelize-schema.json
is in the right place relative to your new migration script. - Run your migration using
sequelize db:migrate
. You should see it synchronize all of your model definitions to your DB. - ???
- Congratulations, your project's first migration script was a snap!
- Go ahead and inspect in a DB explorer to verify everything is as you intended; It should be exactly the same as if you had called
sequelize.sync()
in your project.
- Go ahead and inspect in a DB explorer to verify everything is as you intended; It should be exactly the same as if you had called
Last active
October 24, 2019 01:52
-
-
Save scryptonite/3bee4b3d55485230db113af639a0601f to your computer and use it in GitHub Desktop.
Dumps all Sequelize models to JSON to help with creating the first migration script.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
module.exports = { | |
up: (queryInterface, Sequelize) => { | |
const {sequelize} = queryInterface; | |
// Setup all models: | |
const models = require("../migration-extras/initial-sequelize-schema.json") | |
// First, restore the sequelize attribute type property so sequelize recognizes it: | |
.map(def => Object.assign(def, { | |
attributes: Object.entries(def.attributes) | |
.map(([field, attribute]) => { | |
let type = Object.assign({}, attribute.type); | |
if(type && "_constructor" in type && type._constructor) { | |
try { | |
type = Object.assign(Object.create(Sequelize.DataTypes[type._constructor].prototype), type); | |
delete type._constructor; | |
} catch(err){ | |
throw new TypeError(`Failed type def creation for ${def.name}.${field}, ${err}`); | |
} | |
} else { | |
console.error(type); | |
throw new TypeError(`Unexpected attribute type for ${def.name}.${field}, ${type}`); | |
} | |
return { | |
[field]: Object.assign({}, attribute, { | |
type | |
}) | |
}; | |
}) | |
.reduce((_, b) => Object.assign(_, b), {}), | |
})) | |
// Second, define the model using the model definition: | |
.map(def => ({ | |
[def.name]: sequelize.define(def.name, def.attributes, def.options) | |
})) | |
// Third, merge all { [modelName]: model } objects into one object | |
// (It will be exactly like the `sequelize.models` property): | |
.reduce((_, b) => Object.assign(_, b), {}); | |
// Fourth, create a promise chain of synchronizing the models to the DB: | |
return Object.values(models) | |
.reduce((sync, model) => | |
sync.then(() => { | |
console.log(`Synchronizing ${model.name} (table: ${model.options.tableName})...`); | |
return model.sync(); | |
}) | |
, Promise.resolve()); | |
}, | |
down: (queryInterface, Sequelize) => { | |
const tables = require("../migration-extras/initial-sequelize-schema.json") | |
.map(({ options: {tableName} }) => tableName); | |
// Create a promise chain of dropping the model tables from the DB: | |
return tables.reduce((dropOperation, tableName) => { | |
return dropOperation.then(() => { | |
console.log(`Dropping table "${tableName}"...`); | |
return queryInterface.dropTable(tableName); | |
}); | |
}, Promise.resolve(undefined)); | |
} | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const _ = { | |
sortBy: require("lodash.sortby"), | |
pick: require("lodash.pick"), | |
mapValues: require("lodash.mapvalues"), | |
omit: require("lodash.omit"), | |
}; | |
const fs = require("fs"); | |
const sequelize = ...; // [TODO] point to your sequelize instance | |
// Make sure you have all of your models defined already, | |
// as well as their associations have been setup too | |
// (e.g. using an associate() method or similar pattern). | |
const models = _.sortBy(Object.values(sequelize.models).map( | |
(model) => | |
_.mapValues(_.pick(model, [ | |
// keep only the model name, the provided options, and the defined attributes. | |
"name", | |
"options", | |
"attributes" | |
]), (value, key) => { | |
switch(key){ | |
case "options": { | |
// Omit the sequelize instance reference from the options property to | |
// avoid a circular reference error when we JSON.stringify: | |
return _.omit(value, [ | |
"sequelize" | |
]); | |
} | |
case "attributes": { | |
// Preserve sequelize column type (as a string in a _constructor property): | |
return _.mapValues(value, (attribute, column) => { | |
return Object.assign( | |
{}, | |
attribute, | |
{ | |
type: Object.assign({ | |
_constructor: attribute.type.key | |
}, attribute.type) | |
} | |
); | |
}); | |
} | |
case "tableName": | |
case "name": | |
default: { | |
return value; | |
} | |
} | |
}) | |
), ["name"]); | |
// Save the schema to a file: | |
fs.writeFileSync("./sequelize-schema.json", JSON.stringify(models, null, 4)); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hey I just tried out your script thanks for providing it!
Unfortunately the result of dump-sequelize-schema.js doesn't look too promising (without the schema) what am i doing wrong?
By the way I used the model definition described here: https://github.com/sequelize/express-example/blob/master/models/index.js
as an example.
[ { "name": "Task", "options": { "timestamps": true, "validate": {}, "freezeTableName": false, "underscored": false, "paranoid": false, "rejectOnEmpty": false, "whereCollection": null, "schema": null, "schemaDelimiter": "", "defaultScope": {}, "scopes": {}, "indexes": [], "name": { "plural": "Tasks", "singular": "Task" }, "omitNull": false, "hooks": {} } }, { "name": "User", "options": { "timestamps": true, "validate": {}, "freezeTableName": false, "underscored": false, "paranoid": false, "rejectOnEmpty": false, "whereCollection": null, "schema": null, "schemaDelimiter": "", "defaultScope": {}, "scopes": {}, "indexes": [], "name": { "plural": "Users", "singular": "User" }, "omitNull": false, "hooks": {} } } ]