npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

sequelize-markup

v1.0.5

Published

Babel plugin to transpile markup into sequelize models

Downloads

9

Readme

sequelize-markup

This is a Babel plugin that transpiles indent aware markup into a Sequelize configuration and model definition.

Features:

  • Markup syntax for declaring models
  • Declare models in a single file or in multiple files
  • Connection configuration stored in a file or in code
  • Multiple database environments
  • Conditional declarations

Model in single file, with configuration in code:

src/index.js:
// configure sequelize
var db = SQLZINIT>
  // sequelize configuration options
  (config)
    // "development" db environment
    (development(dialect="sqlite"))
      (storage="./db.development.sqlite")
    // "test" db environment
    (test)
      (dialect="sqlite")
  // execution environment
  (environment="development")

// configure models
SQLZ>
  (User)
    (name(type=DataTypes.STRING(60)))
    (...associations)
      (Tasks=hasMany.Task)

  (Task)
    (title(type=DataTypes.STRING(255)))

// configure associations
SQLZINIT(db)

// create database and insert a record
db.sequelize.sync({ force: true }).then(() => {
  db.User.findOrCreate({ 
    where: { name: 'testuser' }, 
    defaults: { other: 'ok' } } )
    .spread( (user, wasCreated) => {
      console.log(user.get( { plain: true } ));
    });
});
Transpiles to:
src/index.js:
var db = {};

var Sequelize = require("sequelize"),
  DataTypes = Sequelize.DataTypes,
  env = "development",
  cfg = {
    development: {
      dialect: "sqlite",
      storage: "./db.development.sqlite"
    },
    test: {
      dialect: "sqlite"
    }
  }[env],
  sequelize = new Sequelize(cfg);

db.sequelize = sequelize;
db.Sequelize = Sequelize;
const User = sequelize.define("User", {
  name: {
    type: DataTypes.STRING(60)
  }
});

User.associate = sequelize => {
  User.Tasks = User.hasMany(sequelize.models.Task, {});
};

const Task = sequelize.define("Task", {
  title: {
    type: DataTypes.STRING(255)
  }
});

for (let mdl in sequelize.models) {
  let model = sequelize.models[mdl];
  db[mdl] = model;
  if (model.associate) model.associate(sequelize);
}

db.sequelize.sync({ force: true }).then(() => {
  db.User.findOrCreate({
    where: { name: 'testuser' },
    defaults: { other: 'ok' } }).spread((user, wasCreated) => {
      console.log(user.get({ plain: true }));
    });
});

Models in multiple files with configuration in external file:

src/db/index.js:
var path = require("path");

// configure sequelize and import models
var db = SQLZINIT>
  // path to configuration file
  (config=path.join(__dirname, "..", "..", "config", "config.json"))
  // execution environment
  (environment=process.env.NODE_ENV || "development")
  // optional database URL
  (url=process.env.DATABASE_URL)
  // model files glob
  (models=path.join(__dirname, "**/!(index).js"))

// configure associations
SQLZINIT(db);

module.exports = db;
src/db/user.js:
export default function(sequelize, DataTypes) {
  SQLZ>
    (User)
      (name(type=DataTypes.STRING(60)))
      (...associations)
        (Tasks=hasMany.Task)
}
src/db/task.js:
export default function(sequelize, DataTypes) {
  SQLZ>
    (Task)
      (title(type=DataTypes.STRING(255)))
}
src/index.js:
var path = require('path');
var db = require(path.join(__dirname, 'db'));

db.sequelize.sync({ force: true }).then(() => {
  db.User.findOrCreate({ 
    where: { name: 'testuser' }, 
    defaults: { other: 'ok' } } )
    .spread( (user, wasCreated) => {
      console.log(user.get( { plain: true } ));
    });
});
config/config.json
{
  "development": {
    "dialect": "sqlite",
    "storage": "./db.development.sqlite"
  },
  "test": {
    "dialect": "sqlite",
    "storage": ":memory:"
  },
  "production": {
    "username": null,
    "password": null,
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "logging": false
  }
}
Transpiles to:
src/db/index.js:
var path = require("path");

var db = {};

var Sequelize = require("sequelize"),
  DataTypes = Sequelize.DataTypes,
  env = process.env.NODE_ENV || "development",
  dbUrl = process.env.DATABASE_URL,
  cfgFile = path.join(__dirname, "..", "..", "config", "config.json"),
  cfg = require(cfgFile)[env],
  sequelize = dbUrl ? new Sequelize(dbUrl, cfg) : new Sequelize(cfg),
  glob = require("glob"),
  modelGlob = path.join(__dirname, "**/!(index).js"),
  files = glob.sync(modelGlob);

for (let i = 0; i < files.length; i++) sequelize.import(files[i]);

db.sequelize = sequelize;
db.Sequelize = Sequelize;

for (let mdl in sequelize.models) {
  let model = sequelize.models[mdl];
  db[mdl] = model;
  if (model.associate) model.associate(sequelize);
}

module.exports = db;
src/db/user.js:
export default function (sequelize, DataTypes) {
  const User = sequelize.define("User", {
    name: {
      type: DataTypes.STRING(60)
    }
  });

  User.associate = sequelize => {
    User.Tasks = User.hasMany(sequelize.models.Task, {});
  };
}
src/db/task.js:
export default function (sequelize, DataTypes) {
  const Task = sequelize.define("Task", {
    title: {
      type: DataTypes.STRING(255)
    }
  });
}

Syntax

SQLZINIT>

The SQLZINIT> directive is used to declare a Sequelize configuration. Indented child elements that follow this directive are used to create the configuration.

Example:
var db = SQLZINIT>
  // path to configuration file
  (config=path.join(__dirname, "..", "..", "config", "config.json"))
  // execution environment
  (environment=process.env.NODE_ENV || "development")
  // optional database URL
  (url=process.env.DATABASE_URL)
  // optional model files glob
  (models=path.join(__dirname, "**/!(index).js"))
Transpiles to:
var db = {}; 
var Sequelize = require("sequelize"),
  DataTypes = Sequelize.DataTypes,
  env = process.env.NODE_ENV || "development",
  dbUrl = process.env.DATABASE_URL,
  cfgFile = path.join(__dirname, "..", "..", "config", "config.json"),
  cfg = require(cfgFile)[env],
  sequelize = dbUrl ? new Sequelize(dbUrl, cfg) : new Sequelize(cfg),
  glob = require("glob"),
  modelGlob = path.join(__dirname, "**/!(index).js"),
  files = glob.sync(modelGlob);

for (let i = 0; i < files.length; i++) sequelize.import(files[i]);

db.sequelize = sequelize;
db.Sequelize = Sequelize;

(environment="name")

The (environment="name") element specifies which database environment Sequelize should use. The value is used to select which configuration Sequelize uses.

  (environment=process.env.NODE_ENV || "development")

(config="config.json")

The (config="config.json") element specifies a JSON file to load as the Sequelize configuration. Each root key specifies a database environment.

Sample config.json file:

{
  "development": {
    "dialect": "sqlite",
    "storage": "./db.development.sqlite"
  },
  "test": {
    "dialect": "sqlite",
    "storage": ":memory:"
  },
  "production": {
    "username": "user",
    "password": "pass",
    "database": "database_production",
    "host": "127.0.0.1",
    "dialect": "mysql",
    "logging": false
  }
}

(config)

To specify the Sequelize configuration inside a source file, use the (config) element:

Example:
var db = SQLZINIT>
  // path to configuration file
  (config)
      (development)
          (dialect="sqlite")
          (storage="./db.development.sqlite")
        (test(dialect="sqlite", storage=":memory:"))
            (logging=false)
  // execution environment
  (environment=process.env.NODE_ENV || "development")
Transpiles to:
var db = {};

var Sequelize = require("sequelize"),
  DataTypes = Sequelize.DataTypes,
  env = process.env.NODE_ENV || "development",
  cfg = {
    development: {
      dialect: "sqlite",
      storage: "./db.development.sqlite"
    },
    test: {
      dialect: "sqlite",
      storage: ":memory:",
      logging: false
    }
  }[env],
  sequelize = new Sequelize(cfg);

db.sequelize = sequelize;
db.Sequelize = Sequelize;

Note that you can specify keys and values as element attributes or child elements.

(url="database URL")

Use the optional (url="database URL") element to declare a URL to use when connecting to the database. This allows for an environment variable to decide which database connection is used.

(url=process.env.DATABASE_URL)

(models="glob")

The optional (models="glob") element uses the glob package to import models contained in files that recursively match the wildcard pattern.

// model files glob (all but index.js)
(models=path.join(__dirname, "**/!(index).js"))

SQLZINIT(db)

After models have been defined and/or imported, use SQLZINIT(db) to initialize all model assocations.

Example:
SQLZINIT(db) // use the variable that SQLZINIT> assigns to.
Transpiles to:
for (var mdl in sequelize.models) {
  var model = sequelize.models[mdl];
  db[mdl] = model;
  if (model.associate) model.associate(sequelize);
}

SQLZ>

One or more tables are defined using SQLZ>. This will transpile the child elements that follow into Sequelize calls.

Root nodes map to database tables. Child nodes map to either columns or table options. Table options are declared using one of the following elements: (...options), (...name), (...columns), (...getters), (...setters), (...validate), (...indexes), (...associations)

Example:
SQLZ>
    (Table1)
      (Column1(type=DataTypes.STRING))
      (Column2(type=DataTypes.STRING))
      (...columns) // can also specify columns here
        (AnotherColumn1(type=DataTypes.STRING))
      (...name)
        (singular='tableone')
        (plural='tableones')
    (Table2) // multiple tables are allowed
      (test(type=DataTypes.STRING))
Transpiles to:
const Table1 = sequelize.define('Table1', {
  Column1: {
    type: DataTypes.STRING
  },
  Column2: {
    type: DataTypes.STRING
  },
  AnotherColumn1: {
    type: DataTypes.STRING
  }
}, {
  name: {
    singular: 'tableone',
    plural: 'tableones'
  }
});
const Table2 = sequelize.define('Table2', {
  test: {
    type: DataTypes.STRING
  }
});

(...options)

The (...options) element is used to specify table options. Table options specified using dot notation are set to true. Table options can also be specified as an attribute of the table element.

Example:
SQLZ>
  (User.timestamps.createdAt.updatedAt.deletedAt(comment='The user table'))
    (column1.unique(type=DataTypes.BOOLEAN))
      (onUpdate='CASCADE')
    (...options)
      (defaultScope)
        (where(active=true))
      (omitNull=false)
      (paranoid=false)
      (underscored=false)
      (underscoredAll=false)
      (freezeTableName=false)
      (tableName='users')
      (schema='public')
      (engine='MYISAM')
      (initialAutoIncrement='1')
Transpiles to:
const User = sequelize.define('User', {
  column1: {
    unique: true,
    type: DataTypes.BOOLEAN,
    onUpdate: 'CASCADE'
  }
}, {
  timestamps: true,
  createdAt: true,
  updatedAt: true,
  deletedAt: true,
  comment: 'The user table',
  defaultScope: {
    where: {
      active: true
    }
  },
  omitNull: false,
  paranoid: false,
  underscored: false,
  underscoredAll: false,
  freezeTableName: false,
  tableName: 'users',
  schema: 'public',
  engine: 'MYISAM',
  initialAutoIncrement: '1'
});

(...name)

The (...name) element is used to explicitly configure table names.

Example:
SQLZ>
  (User)
    (name(type=DataTypes.STRING))
    (...name)
      (singular='loginuser')
      (plural='loginusers')
Transpiles to:
const User = sequelize.define('User', {
  name: {
    type: DataTypes.STRING
  }
}, {
  name: {
    singular: 'loginuser',
    plural: 'loginusers'
  }
});

(...columns)

The (...columns) element allows columns to be declared. This is mainly for organization as columns can also be declared as a direct child element of a table.

Example:
SQLZ>
  (User)
    (...columns)
      (name.unique(type=DataTypes.STRING(60)))
        (get=() => { return this.getDataValue('name'); })
        (set=(val) => { this.setDataValue('name', val); })
        (validate.isAlphanumeric)
          (notNull(msg='name can\'t be null'))
          (isEven=(val) => { throw new Error('Bad validation'); })
          (isNotNull=true)
Transpiles to:
const User = sequelize.define('User', {
  name: {
    unique: true,
    type: DataTypes.STRING(60),
    function get() {
      return this.getDataValue('id');
    },
    function set(val) {
      this.setDataValue('id', val);
    },
    validate: {
      isAlphanumeric: true,
      isInt: true,
      notNull: {
        msg: 'name can\'t be null'
      },
      function isEven(val) {
        throw new Error('Bad validation');
      },
      isNotNull: true
    }
  }
});

(...getters)

The (...getters) element is where custom getters are declared.

Example:
SQLZ>
  (User)
    (name(type=DataTypes.STRING(60)))
    (...getters)
      (getTwoName=() => { 
        return this.getDataValue('name') + " " + this.getDataValue('name'); 
      })
Transpiles to:
const User = sequelize.define('User', {
  name: {
    type: DataTypes.STRING(60)
  }
}, {
  getters: {
    function getTwoName() {
      return 
        this.getDataValue('name') + " " +
        this.getDataValue('name');
    }

  }
});

(...setters)

The (...setters) element is where custom setters are declared.

Example:
SQLZ>
  (User)
    (name(type=DataTypes.STRING(60)))
    (...setters)
      (setFunName=(val) => { 
        this.setDataValue('name', 'Fun' + val);
      })
Transpiles to:
const User = sequelize.define('User', {
  name: {
    type: DataTypes.STRING(60)
  }
}, {
  setters: {
    function setFunName(val) {
      this.setDataValue('name', 'Fun' + val);
    }
  }
});

(...validate)

The (...validate) element is where custom validations are declared.

Example:
SQLZ>
  (User)
    (name(type=DataTypes.STRING(60)))
    (...validate)
      (namesAreOk=() => { 
        if (this.name == "Sam")
          throw new Error("Invalid name"); 
      })
Transpiles to:
const User = sequelize.define("User", {
  name: {
    type: DataTypes.STRING(60)
  }
}, {
  validate: {
    function namesAreOk() {
      if (this.name == "Sam")
          throw new Error("Invalid name");
    }
  }
});

(...indexes)

The (...indexes) element is where custom indexes are declared.

Example:
SQLZ>
  (User)
    (name(type=DataTypes.STRING(60)))
    (status(type=DataType.STRING(60)))
    (...indexes)
      (user.unique(fields=['name']))
      (user_status)
        (unique=false)
        (fields=['status'])
        (where)
          (status='public')
Transpiles to:
const User = sequelize.define('User', {
  name: {
    type: DataTypes.STRING(60)
  },
  status: {
    type: DataType.STRING(60)
  }
}, {
  indexes: {
    user: {
      unique: true,
      fields: ['name']
    },
    user_status: {
      unique: false,
      fields: ['status'],
      where: {
        status: 'public'
      }
    }
  }
});

(...associations)

The (...associations) element is where table associations are declared. Note that these associatations need to be initialized by calling table.associate() unless you use SQLZINIT(db).

Example:
SQLZ>
  (User)
    (name(type=DataTypes.STRING(60)))
    (...associations)
      (Orgs=belongsTo.Organization)
      (Projects=belongsToMany.Project(through='UserProject'))
        (constraints=false)
Transpiles to:
const User = sequelize.define('User', {
  name: {
    type: DataTypes.STRING(60)
  }
});

User.associate = sequelize => {
  User.Orgs = User.belongsTo(sequelize.models.Organization, {});
  User.Projects = User.belongsToMany(sequelize.models.Project, {
    through: 'UserProject',
    constraints: false
  });
};

(...scopes)

The (...scopes) element is where custom query scoping is declared.

Example:
SQLZ>
  (User)
    (name(type=DataTypes.STRING(60)))
    (active(type=DataTypes.BOOLEAN))
    (...scopes)
      (activeUsers)
        (where(active=true))
Transpiles to:
const User = sequelize.define("User", {
  name: {
    type: DataTypes.STRING(60)
  },
  active: {
    type: DataTypes.BOOLEAN
  }
}, {
  scopes: {
    activeUsers: {
      where: {
        active: true
      }
    }
  }
});

(...hooks)

The (...hooks) element is where custom hooks are declared.

Example:
SQLZ>
  (User)
    (name(type=DataTypes.STRING(60)))
    (...hooks)
      (beforeValidate=(instance, options) => { })
      (afterValidate=(instance, options) => { })
Transpiles to:
const User = sequelize.define("User", {
  name: {
    type: DataTypes.STRING(60)
  }
}, {
  hooks: {
    beforeValidate: (instance, options) => {},
    afterValidate: (instance, options) => {}
  }
});

Conditional Declarations

The ($if), ($elseif), and ($else) elements conditionally declare model elements.

Example:
SQLZ>
  (User)
    ($if (firstAndLast))
      (firstName(type=DataTypes.STRING(60)))
      ($if (middle))
        (middleName(type=DataTypes.STRING(60))
      (lastName(type=DataTypes.STRING(60)))
    ($else)
      (name(type=DataTypes.STRING(60)))
    (...options)
      ($if (mysql))
        (engine="MYISAM")
Transpiles to:
const User = sequelize.define("User", Object.assign({}, firstAndLast ? Object.assign({
  firstName: {
    type: DataTypes.STRING(60)
  },
  lastName: {
    type: DataTypes.STRING(60)
  }
}, middle ? {
  middleName: {
    type: DataTypes.STRING(60)
  }
} : undefined) : {
  name: {
    type: DataTypes.STRING(60)
  }
}), Object.assign({}, mysql ? {
  engine: "MYISAM"
} : undefined));