Skip to content

Instantly share code, notes, and snippets.

@peteromano
Last active January 14, 2018 16:45
Show Gist options
  • Save peteromano/d9cd9082e5d53385f6f6e0e50285f599 to your computer and use it in GitHub Desktop.
Save peteromano/d9cd9082e5d53385f6f6e0e50285f599 to your computer and use it in GitHub Desktop.
Sequelize Model Class Definitions
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);
)();
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
};
}
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;
}
}
@peteromano
Copy link
Author

peteromano commented Jan 14, 2018

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 a models subdirectory.)

To retrieve all models by CommonJS requires (Node), an index.js file can be added in the models subdirectory, as follows:

// models/index.js

import {getModels} from '../lib/Sequelize';
export default getModels(''./');

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment