@baumdigital/joi-sequelize

Libreria para crear un modelo de JOI a partir de un modelo de Sequelize. Toma en cuenta tipos de datos, constraints y validadores de sequelize.

Usage no npm install needed!

<script type="module">
  import baumdigitalJoiSequelize from 'https://cdn.skypack.dev/@baumdigital/joi-sequelize';
</script>

README

@baumdigital/joi-sequelize

Libreria para crear un modelo de JOI a partir de un modelo de Sequelize. Toma en cuenta tipos de datos, constraints y validadores de sequelize.

Usage

Model example

'use strict'; // jshint ignore:line

var config = require('../../config/config'),
    bcrypt = require('bcrypt'),
    salt   = config.saltGen;

module.exports = function(sequelize, DataTypes) {
  var User = sequelize.define('User', {
    id: {
      allowNull: false, /* will generate a .required() on joi schema */
      autoIncrement: true,
      primaryKey: true,
      type: DataTypes.INTEGER,
      description: 'User`s identifier' /* will generate a .description() on joi schema tha can be used by swagger */
    },
    firstname: {
      type: DataTypes.STRING(64), /* will generate .string().max(64) */
      allowNull: false, 
      description: 'User`s first name'
    },
    lastname: {
      type: DataTypes.STRING(64), /* will generate .string().max(64) */
      allowNull: false,
      description: 'User`s last name'
    },
    email: {
      type: DataTypes.STRING(64), /* will generate .string().max(64) */
      allowNull: false,
      description: 'User`s email',
      validate:{
        isEmail: true // /* Will generate .string().email().max(64).required()
      }
    },
    password: {
      type: DataTypes.STRING, /* will generate .string() */
      allowNull: false,
      description: 'User`s password'
    },
    role: {
      type: DataTypes.ENUM('admin', 'common user'), /* will generate .valid('admin', 'common user') */
      allowNull: false,
      description: 'User`s role'
    },
    active: {
      type: DataTypes.BOOLEAN, /* will generate .boolean() */
      allowNull: false
    }
  }, {
    classMethods: {
      associate: function(models) {
        // associations can be defined here
      }
    }
  });
  return User;
};

Loading models

'use strict';

var fs        = require('fs'),
    path      = require('path'),
    Sequelize = require('sequelize'),
    JoiSequelize = require('joi-sequelize'),
    basename  = path.basename(module.filename),
    env       = process.env.NODE_ENV || 'development',
    log       = (!process.env.LOG || process.env.LOG === 'false') ? false : true,
    config    = require(__dirname + '/../../config/database.json')[env],
    db,
    sequelize;

function init() {
  db = {};
  config.logging = (env === 'development' && log) ? console.log : false;

  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);
  }

  db.sequelize = sequelize;
  db.Sequelize = Sequelize;
  db.JS = {};
  fs
    .readdirSync(__dirname)
    .filter(file => (
        (file.indexOf('.') !== 0) &&
        (file !== basename) &&
        (file.slice(-3) === '.js')
      )
    )
    .forEach(function (file) {
      var model = sequelize['import'](path.join(__dirname, file));
      db[model.name] = model;
      db.JS[model.name] = new JoiSequelize(require(path.join(__dirname, file)));
    });
    
  Object.keys(db).forEach(function (modelName) {
        if (db[modelName].associate) {
          db[modelName].associate(db);
        }
      });

  Object.keys(db).forEach(function (modelName) {
    if (db[modelName].addScopes) {
      db[modelName].addScopes(db);
    }

    if (db[modelName].addHooks) {
      db[modelName].addHooks(db);
    }
  });
  
  return db;
}

module.exports = db || init();

Apply joi-sequelize generated schemas on routes (@Hapi)

'use strict';

const Hapi = require('hapi');
const db = require('./model');
const JS = db.JS;

const server = new Hapi.Server();
server.connection({ port: 3000 });

server.route({
  method:  'POST',
  path:    '/hello',
  handler: (request, reply) => reply(request.payload),
  config:  {
    validate: {
      payload: JS.User.joi()
    }
  }
});

server.start((err) => {
  if (err) throw err;
  console.log('Server running at:', server.info.uri);
});

Other functions

Omit

Return a joi object with all items except the ones passed as arguments

JS.User.omit('role', ...);

Pick

Return a joi object with all fields passed as arguments

JS.User.pick('active', ...);

Include

Return a joi object with like JS.User.joi() but with field picture of joi type .any()

JS.User.include({picture: joi.any()});

withRequired

Get joi objects that have property allowNull:false as required

JS.User.withRequired();

withRequiredOmit

Same as withRequired but omiting the fields passed as arguments

JS.User.withRequiredOmit('id', 'created_at', 'updated_at', 'deleted_at'); // useful on create routes payloads

withRequiredPick

Same as withRequired but omiting the fields passed as arguments

JS.User.withRequiredPick('id'); // useful on get, update, delete routes with id param