Last active
January 14, 2018 16:45
-
-
Save peteromano/d9cd9082e5d53385f6f6e0e50285f599 to your computer and use it in GitHub Desktop.
Sequelize Model Class Definitions
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
import {getInstance, getModels} from './Sequelize'; | |
(async () => { | |
/** | |
* Sync models to database | |
* | |
* - Specify the directory path of models as argument. | |
* - (TIP) Never use `{ force: true }` option; use a migration, instead, for most DB operations. | |
*/ | |
await getInstance('./').sync(); | |
/** | |
* Get all models | |
* | |
* - Specify the directory path of models as argument. | |
*/ | |
const models = getModels('./'); | |
/** | |
* Find all Product descriptions | |
*/ | |
const descriptions = await models.Product.findAll() | |
.then(products => products.map(product => product.dataValues.description)); | |
console.log('Product descriptions:', descriptions); | |
)(); |
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
import {parse, define, Model, DataTypes} from './Sequelize'; | |
/** | |
* Decorator for creating Sequelize model definition | |
* | |
* - `parse(__filename)` extracts the name of the current file (without extension.) | |
* - `@define('MyProduct')` would define the model as `MyProduct`. | |
*/ | |
@define(parse(__filename)) | |
/** | |
* Table Definition | |
* | |
* @see http://docs.sequelizejs.com/manual/tutorial/models-definition.html | |
*/ | |
export default class extends Model { | |
/** | |
* Attributes | |
* | |
* @see http://docs.sequelizejs.com/manual/tutorial/models-definition.html#data-types | |
* | |
* Examples: | |
* | |
* id = { type: DataTypes.INTEGER, allowNull: false, primaryKey: true, autoIncrement: true }; | |
* name = DataTypes.STRING; | |
*/ | |
description = DataTypes.TEXT; | |
published = { type: DataTypes.BOOLEAN, defaultValue: true }; | |
/** | |
* Descriptors | |
* | |
* @see http://docs.sequelizejs.com/manual/tutorial/associations.html | |
* | |
* Examples: | |
* | |
* static associate = function(models) { | |
* this.belongsTo(models.User); // Create an `UserId` column/foreign key | |
* }; | |
* | |
* static tableName = parse(__filename); // Use filename as the literal table name | |
*/ | |
static associate = function(models) { | |
this.belongsTo(models.Category); // Create an `CategoryId` column/foreign key | |
}; | |
} |
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
import fs from 'fs'; | |
import {join, resolve} from 'path'; | |
import {env} from 'process'; | |
import Sequelize from 'sequelize'; | |
class Model { | |
static underscored = false; | |
} | |
const RE_FILENAME = /.*\/(\w+)\.model\.js$/; | |
const config = { | |
user: env.DB_USER, | |
password: env.DB_PASSWORD, | |
database: env.DB_NAME, | |
options: { | |
host: env.DB_HOST || 'localhost', | |
port: env.DB_PORT || 3306, | |
dialect: env.DB_DRIVER || 'mysql', | |
logging: process.env.NODE_ENV === 'development' && console.log | |
} | |
}; | |
const connections = {}; | |
const definition = name => Definition => sequelize => Object.assign(sequelize.define(name, new Definition, Object.assign(Definition, Model)), { | |
associate: Definition.associate || (() => {}) | |
}); | |
const connect = path => { | |
const models = {}; | |
const instance = new Sequelize( | |
config.database, | |
config.user, | |
config.password, | |
config.options | |
); | |
if (fs.existsSync(path)) { | |
fs.readdirSync(path) | |
.filter(file => file.indexOf('.model.js') > 0 && file.indexOf('.map') === -1 && file !== 'index.js') | |
.forEach(file => { | |
const definition = join(path, file); | |
const model = instance.importCache[definition] = require(definition)(instance, Sequelize); | |
models[model.name] = model; | |
}); | |
} | |
Object.keys(models).forEach(name => { | |
const model = models[name]; | |
model.associate.call(model, models); | |
}); | |
return { models, instance }; | |
}; | |
const getConnection = path => { | |
return (connections[path] = connections[path] || connect(path)); | |
}; | |
export default class { | |
static parse = path => path.replace(RE_FILENAME, '$1'); | |
static DataTypes = Sequelize; | |
static Model = Model; | |
static define(...args) { | |
return definition(...args); | |
} | |
static getInstance(...args) { | |
return getConnection(...args).instance; | |
} | |
static getModels(...args) { | |
return getConnection(...args).models; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
We use a
models
directory, without.model.js
extensions, for our models.For the purposes of this Gist (which doesn't allow subdirectory paths as filenames), example models are filtered by a
.model.js
extension.Remove all occurernces of
.model.js
as needed (we suggest using amodels
subdirectory.)To retrieve all models by CommonJS requires (Node), an
index.js
file can be added in themodels
subdirectory, as follows: