Coder Social home page Coder Social logo

valtlfelipe / hapi-sequelizejs Goto Github PK

View Code? Open in Web Editor NEW
62.0 3.0 17.0 1.11 MB

A hapi.js plugin to connect with Sequelize ORM

License: MIT License

JavaScript 99.76% Shell 0.24%
hapi sequelize hapi-plugin javascript hapi-sequelizejs sequelize-orm nodejs hacktoberfest

hapi-sequelizejs's Introduction

hapi-sequelizejs

npm version Build Status

A hapi.js plugin to connect with Sequelize ORM.

Support me

If you like this plugin, please support my work and help maintaining it.

Buy Me A Coffee

Thanks in advance ❤️

Compatibility

Compatible with these versions:

  • hapi.js
    • 19.x
    • 20.x
    • 21.x
  • sequelize
    • 5.x
    • 6.x

Check the releases page for the changelog.

Installation

npm install hapi-sequelizejs

Configuration

Simply pass in your sequelize instance and a few basic options and voila. Options accepts a single object or an array for multiple dbs.

server.register([
    {
        plugin: require('hapi-sequelizejs'),
        options: [
            {
                name: 'dbname', // identifier
                models: [__dirname + '/server/models/**/*.js'], // paths/globs to model files
                ignoredModels: [__dirname + '/server/models/**/*.js'], // OPTIONAL: paths/globs to ignore files
                sequelize: new Sequelize(config, opts), // sequelize instance
                sync: true, // sync models - default false
                forceSync: false, // force sync (drops tables) - default false
            },
        ],
    },
]);

Model Definitions

A model should export a function that returns a Sequelize model definition (http://docs.sequelizejs.com/en/latest/docs/models-definition/).

module.exports = function (sequelize, DataTypes) {
    const Category = sequelize.define('Category', {
        name: DataTypes.STRING,
        rootCategory: DataTypes.BOOLEAN,
    });

    return Category;
};

Setting Model associations

Using the sequelize model instance, define a method called associate, that is a function, and receives as parameter all models defined.

module.exports = function (sequelize, DataTypes) {
    const Category = sequelize.define('Category', {
        name: DataTypes.STRING,
        rootCategory: DataTypes.BOOLEAN,
    });

    Category.associate = function (models) {
        models.Category.hasMany(models.Product);
    };

    return Category;
};

Database Instances

Each registration adds a DB instance to the server.plugins['hapi-sequelizejs'] object with the name option as the key.

function DB(sequelize, models) {
    this.sequelize = sequelize;
    this.models = models;
}

// something like this
server.plugins['hapi-sequelizejs'][opts.name] = new DB(opts.sequelize, models);

API

Using request object

getDb(name)

The request object gets decorated with the method getDb. This allows you to easily grab a DB instance in a route handler. If you have multiple registrations pass the name of the one you would like returned or else the single or first registration will be returned.

handler(request, reply) {
    const db1 = request.getDb('db1');
    console.log(db1.sequelize);
    console.log(db1.models);
}

If there isn't a db instance for the given name or no registered db instance, an Error is thrown: hapi-sequelizejs cannot find the ${dbName} database instance.

db.getModel('User')

Returns single model that matches the passed argument or null if the model doesn't exist.

db.getModels()

Returns all models on the db instance

getModels(dbName?)

Returns all models registered in the given db's name or the models from the first registered db instance if no name is given to the function.

handler(request, reply) {
    const models = request.getModels('db1');
    ...
}

If there isn't a db instance for the given name or no registered db instance, an Error is thrown: hapi-sequelizejs cannot find the ${dbName} database instance.

getModel(dbName, modelName?)

Return the model to the db's name instance. You may give only the model name to the function, if it's the case, it returns the model from the first registered db instance.

handler(request, reply) {
    const myModel = request.getModel('db1', 'myModel');
    ...
}

If there isn't a db instance for the given name or no registered db instance, an Error is thrown: hapi-sequelizejs cannot find the ${dbName} database instance. If there isn't a model for the given name, an Error is thrown: hapi-sequelizejs cannot find the ${modelName} model.


Without request object

To access the dbs intances without using the request object you may do this:

const instances = require('hapi-sequelizejs').instances;

instance.dbs

Returns an Object with all instances registered.

{
  [db.name]: db.instance
}
const instances = require('hapi-sequelizejs').instances;
const dbs = instances.dbs;

dbs.myDb.getModel('User');

getDb(name?)

Returns the db instance for the given name or the first registered db instance if no name is given to the function.

const instances = require('hapi-sequelizejs').instances;

const myDb = instances.getDb('myDb');

const firstRegisteredDb = instances.getDb();

If there isn't a db instance for the given name or no registered db instance, an Error is thrown: hapi-sequelizejs cannot find the ${dbName} database instance.

getModels(dbName?)

Returns all models registered in the given db's name or the models from the first registered db instance if no name is given to the function.

const instances = require('hapi-sequelizejs').instances;

const myDbModels = instances.getModels('myDb');

const firstRegisteredDbModels = instances.getModels();

If there isn't a db instance for the given name or no registered db instance, an Error is thrown: hapi-sequelizejs cannot find the ${dbName} database instance.

getModel(dbName, modelName?)

Return the model to the db's name instance. You may give only the model name to the function, if it's the case, it returns the model from the first registered db instance.

const instances = require('hapi-sequelizejs').instances;

const myDbMyModel = instances.getModel('myDb', 'myModel');

const firstRegisteredDbMyModel = instances.getModel('myModel');

If there isn't a db instance for the given name or no registered db instance, an Error is thrown: hapi-sequelizejs cannot find the ${dbName} database instance. If there isn't a model for the given name, an Error is thrown: hapi-sequelizejs cannot find the ${modelName} model.

hapi-sequelizejs's People

Contributors

adaxi avatar bodasia avatar dependabot[bot] avatar eyepulp avatar nargonath avatar nicgirault avatar sougiovn avatar valtlfelipe avatar zsevic avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

hapi-sequelizejs's Issues

Hapi 18

When do you think this will be available for v18?
Thanks

ValidationError: "sequelize" must be an instance of "Sequelize"

I'm trying to use this plugin but I'm having this error when bootstraping my app:

UnhandledPromiseRejectionWarning: ValidationError: "value" at position 0 fails because 
[child "sequelize" fails because ["sequelize" must be an instance of "Sequelize"]], 
"value" must be an object

Libs versions

My apps structure:

src
  server.js
  /models
  /routes
  /config
    config.js
    /hapi-sequelizejs
      hapi-sequelize.config.js
      sequelize.config.js

sequelize.config.js:

const Sequelize = require('Sequelize');

module.exports = new Sequelize('my-db', 'user', 'pwd', {
  host: 'localhost',
  port: 5432,
  dialect: 'postgres',
  operatorAliases: false,
  pool: {
    max: 5,
    min: 0,
    acquire: 30000,
    idle: 10000
  },
  define: {
    charset: 'utf8',
    dialectOptions: {
      collate: 'utf8_general_ci'
    }
  }
});

hapi-sequelizejs:

const HapiSequelizejs = require('hapi-sequelizejs');

const sequelize = require('./sequelize.config');

module.exports = (server) => {
  server.register({
    plugin: HapiSequelizejs,
    options: {
      name: 'pg',
      models: ['./../../../models/**/*.js'],
      sequelize,
      sync: true,
      forceSync: false
    }
  })
}

config.js:

const hapiSequelizejsConfig = require('./hapi-sequelizejs/hapi-sequelizejs.config')

module.exports = async function(server) {
  ... other plugins configs
  await hapiSequelizejsConfig(server);
}

server.js:

const Hapi = require('hapi');

const config = require('./config/config');
const routes = require('./routes/routes');

const server = Hapi.server({
  host: 'localhost',
  port: 8000
});

start();

async function start() {

  await config(server);
  await routes(server);

  try {
    await server.start();
  }
  catch (err) {
    console.log(err);
    process.exit(1);
  }
  console.log('Server running at:', server.info.uri);
};

Add .npmignore

Create .npmignore to ignore unnecessary files in the npm package, like .vscode, test and so on

Help needed

First of all thanks for this plugin, but I'm really new to Node.js Hapi and Sequelize, so I need help :)

Is there an example how to use the plugin. I would like to use the plugin and share the connection over all necessaries models. Whats the right way to archive this.

Generally thanks for creating this plugin.

Running migrations

Can you give a quick example of how I would run migrations generated by the CLI using this?

Registering to onClose server events to shutdown the database connections

When doing tests, even after my test runner has finished running the tests suites it keeps hanging because even though I do server.stop() the database pool connection is not closed. I think we should register to the server.on('close', ...) event and clean that up.

By the way I'm using Jest as my test runner.

I'll work on a PR if you are ok with it.

Plugin not detecting models

I am using postgres with sequelize. Here is what my code looks like:

server.register([
  {
    register: require('hapi-sequelizejs'), // eslint-disable-line global-require
    options: {
      name: Config.db.name,
      models: ['./models/*.js'],
      sequelize: new Sequelize(Config.db.name, Config.db.username, Config.db.password, {
        host: Config.db.host,
        dialect: 'postgres',
      }),
      sync: true,
    },
  },
])

When I log req.server.plugins['hapi-sequelizejs'][Config.db.name].getModels() I get an empty object. Here is what my model definition looks like:

module.exports = (sequelize, DataTypes) => {
  const schema = {
    id: {
      type: DataTypes.UUIDV4,
      primaryKey: true,
    },
    name: DataTypes.STRING,
    email: DataTypes.STRING,
    gender: DataTypes.ENUM('male', 'female', 'other'),
  };
  return sequelize.define('User', schema);
};

Not sure what the problem is here.

P.S. I have confirmed that the location of the models glob is correct by manually using node-glob.

publish after removing dependency?

I see you haven't published after removing sqlite as a dependency.
Can you publish it please ?
no open issues or pull requests are waiting for merging at this moment

How do I use the Sequelize.Op & Sequelize.literal?

I have a query on jsonb. I need to us the literal otherwise it escapes my where clause.
Any help is appreciated.

Sequelize.Op Sequelize.literal, sequelize.query

db.getModel(sequelizeModel).findAll( { where: { attachment_types: { '@>': '[{id:2}]::jsonb' } } })...
becomes:
WHERE "from_to_lob_state_status"."attachment_types" @> '"[{id:2}]::jsonb"'

On a side note how is the upgrade to hapi v17 going?

Thanks for the great work.
Jonathan

Question Testing

I'm looking at using sequelize-mocking for testing.
Does anyone have any experience with any mocking packages?
Thanks,
Jonathan

Models and Associations - Problem

Hi, I've got 3 models,

User

module.exports = (sequelize, DataTypes) => {
  const Users = sequelize.define('Users', {
    id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
    name: {
      type: DataTypes.STRING,
      allowNull: false,
    },
    dci: {
      type: DataTypes.INTEGER,
      unique: 'playerIndex',
    },
    email: {
      type: DataTypes.STRING(250),
      unique: 'playerIndex',
    },
  });

  Users.associate = (models) => {
    models.Users.hasMany(models.Players, {
      foreignKey: 'dci',
      targetKey: 'dci',
    });
  };

  return Users;
};

Players

module.exports = (sequelize, DataTypes) => {
  const Players = sequelize.define('Players', {
    playerId: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
    firstName: DataTypes.STRING,
    middleName: DataTypes.STRING,
    lastName: DataTypes.STRING,
    dci: {
      type: DataTypes.INTEGER,
      unique: 'playerDciEvent',
    },
    country: DataTypes.STRING(3),
    eventId: {
      type: DataTypes.INTEGER,
      unique: 'playerDciEvent',
    },
  });

  Players.associate = (models) => {
    models.Players.belongsToMany(models.Teams, {
      as: 'Team',
      through: 'TeamsPlayers',
      foreignKey: 'playerDciEvent',
    });

    models.Players.belongsTo(models.Users, {
      foreignKey: 'dci',
      targetKey: 'dci',
    });
  };

  return Players;
};

Teams

module.exports = (sequelize, DataTypes) => {
  const Teams = sequelize.define('Teams', {
    id: { type: DataTypes.INTEGER, autoIncrement: true, primaryKey: true },
    teamId: {
      type: DataTypes.INTEGER,
      unique: 'teamIdEvent',
    },
    name: DataTypes.STRING,
    status: DataTypes.INTEGER,
    eliminationRound: DataTypes.INTEGER,
    eventId: {
      type: DataTypes.INTEGER,
      unique: 'teamIdEvent',
    },
  });

  Teams.associate = (models) => {
    models.Teams.belongsToMany(models.Players, {
      as: 'Player',
      through: 'TeamsPlayers',
      foreignKey: 'teamIdEvent',
    });
  };

  return Teams;
};

Every time I try to start my node server, It gives an error

/usr/local/opt/node@10/bin/node /Users/heitor/Versionamento/MagicTournamentManager/index.js
Executing (default): SELECT 1+1 AS result
Executing (default): DROP TABLE IF EXISTS "TeamsPlayers" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Teams" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Players" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Users" CASCADE;
Executing (default): DROP TABLE IF EXISTS "Users" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Users" ("id"  SERIAL , "name" VARCHAR(255) NOT NULL, "dci" INTEGER, "email" VARCHAR(250), "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, UNIQUE ("dci", "email"), PRIMARY KEY ("id"));
Executing (default): SELECT i.relname AS name, ix.indisprimary AS primary, ix.indisunique AS unique, ix.indkey AS indkey, array_agg(a.attnum) as column_indexes, array_agg(a.attname) AS column_names, pg_get_indexdef(ix.indexrelid) AS definition FROM pg_class t, pg_class i, pg_index ix, pg_attribute a WHERE t.oid = ix.indrelid AND i.oid = ix.indexrelid AND a.attrelid = t.oid AND t.relkind = 'r' and t.relname = 'Users' GROUP BY i.relname, ix.indexrelid, ix.indisprimary, ix.indisunique, ix.indkey ORDER BY i.relname;
Executing (default): DROP TABLE IF EXISTS "Players" CASCADE;
Executing (default): CREATE TABLE IF NOT EXISTS "Players" ("playerId"  SERIAL , "firstName" VARCHAR(255), "middleName" VARCHAR(255), "lastName" VARCHAR(255), "dci" INTEGER REFERENCES "Users" ("dci") ON DELETE NO ACTION ON UPDATE CASCADE, "country" VARCHAR(3), "eventId" INTEGER, "createdAt" TIMESTAMP WITH TIME ZONE NOT NULL, "updatedAt" TIMESTAMP WITH TIME ZONE NOT NULL, UNIQUE ("dci", "eventId"), PRIMARY KEY ("playerId"));
{"name":"mtg-event-manager","hostname":"Heitors-MacBook-Pro.local","pid":21816,"level":50,"promise":{},"reason":{"name":"SequelizeDatabaseError","parent":{"name":"error","length":150,"severity":"ERROR","code":"42830","file":"tablecmds.c","line":"8381","routine":"transformFkeyCheckAttrs","sql":"CREATE TABLE IF NOT EXISTS \"Players\" (\"playerId\"  SERIAL , \"firstName\" VARCHAR(255), \"middleName\" VARCHAR(255), \"lastName\" VARCHAR(255), \"dci\" INTEGER REFERENCES \"Users\" (\"dci\") ON DELETE NO ACTION ON UPDATE CASCADE, \"country\" VARCHAR(3), \"eventId\" INTEGER, \"createdAt\" TIMESTAMP WITH TIME ZONE NOT NULL, \"updatedAt\" TIMESTAMP WITH TIME ZONE NOT NULL, UNIQUE (\"dci\", \"eventId\"), PRIMARY KEY (\"playerId\"));"},"original":{"name":"error","length":150,"severity":"ERROR","code":"42830","file":"tablecmds.c","line":"8381","routine":"transformFkeyCheckAttrs","sql":"CREATE TABLE IF NOT EXISTS \"Players\" (\"playerId\"  SERIAL , \"firstName\" VARCHAR(255), \"middleName\" VARCHAR(255), \"lastName\" VARCHAR(255), \"dci\" INTEGER REFERENCES \"Users\" (\"dci\") ON DELETE NO ACTION ON UPDATE CASCADE, \"country\" VARCHAR(3), \"eventId\" INTEGER, \"createdAt\" TIMESTAMP WITH TIME ZONE NOT NULL, \"updatedAt\" TIMESTAMP WITH TIME ZONE NOT NULL, UNIQUE (\"dci\", \"eventId\"), PRIMARY KEY (\"playerId\"));"},"sql":"CREATE TABLE IF NOT EXISTS \"Players\" (\"playerId\"  SERIAL , \"firstName\" VARCHAR(255), \"middleName\" VARCHAR(255), \"lastName\" VARCHAR(255), \"dci\" INTEGER REFERENCES \"Users\" (\"dci\") ON DELETE NO ACTION ON UPDATE CASCADE, \"country\" VARCHAR(3), \"eventId\" INTEGER, \"createdAt\" TIMESTAMP WITH TIME ZONE NOT NULL, \"updatedAt\" TIMESTAMP WITH TIME ZONE NOT NULL, UNIQUE (\"dci\", \"eventId\"), PRIMARY KEY (\"playerId\"));"},"msg":"unhandledRejection","time":"2019-01-18T21:23:35.763Z","v":0}

Process finished with exit code 1

Plan to support sequelize v6?

Howdy;
I haven't done much testing, other than seeing the current version of hapi-sequelizejs didn't work right off the bat with with the sequelize v6 beta.

I'm curious if it's on the roadmap to support it, and if it's just a matter of finding the time. If I get some free time I can try to work through it, but that may not be for several weeks.

Thanks for a useful plugin, regardless.

Add match parameter in configuration

Hey and thanks for the alternative to hapi-sequelize. I hope that this project will be well maintained and prospering :)

Sequelize has a match param in sync database options. This is used as a safety check for cases where force: true is used in tests but should not work for live code. Currently in this module we have a sync param, which validates as a boolean only and a another option forceSync for sync: { force: true }.

It's easy to add one more option, but I am wondering if we can create a better solution. Do you have any reason to keep this schema or maybe it will be better if we follow the original configuration schema (e.g allow an object for sync with all the options that sequelize has)? Of course, it can be achieved with backdwards-compatibility.

I just think that it's confusing to have different configuration schemas. At the end, users are reading the documentation for sequelize, not for hapi-sequelize.

I would be glad to submit a PR, but if you have any considerations why we should keep the sync option as a boolean only, I will create a new option like ...syncMatch, maybe?

onConnect shouldn't demand arity

Currently, the onConnect property validates against arity(1) but i don't think this is required because the database instance may not be required inside the onConnect function.

Currently
{
  onConnect: Joi.func().arity(1)
}
Proposed
{
  onConnect: Joi.func()
}

What do you think?

Hapi-sequelizejs dependency of @hapi/joi

I have a node application with hapi and I use hapi-swagger which no longer supports @hap joi (deprecated). Hapi-sequelizejs is dependent on @hapi/joi and therefore the app generates the error "Error: Cannot mix different versions of joi schemas"
The solution would be to eliminate the dependence on Hapi-sequelizejs @hapi/joi
Is there a prediction to solve this problem?
In my case, I made the changes myself and it works, but I had to create a customized version of Hapi-sequelizejs.

require db model outside a handler

Is there a way to require the models outside a handler?
Ex:
user.handler.js

const UserService = require('./../services/user.service');

module.exports = {
  create,
  get
}

function create(request, h) {
  return UserService.create(request.payload);
}
function get(request, h) {
  return UserService.get(request.params.id);
}

user.service.js

const UserModel = require('./../models/user.model');

module.exports = {
  save,
  get
}

function save(user) {
  return UserModel.create(user);
}
function get(id) {
  return UserModel.findById(id);
}

Because currently I'm doing this:
user.handler.js

const UserService = require('./../services/user.service');

module.exports = {
  create,
  get
}

function create(request, h) {
  return UserService.create(request.getDb('pg'), request.payload);
}
function get(request, h) {
  return UserService.get(request.getDb('pg'), request.params.id);
}

user.service.js

module.exports = {
  save,
  get
}

function getModel(db) {
  return db.getModel('User');
}
function save(db, user) {
  return getModel(db).create(user);
}
function get(db, id) {
  return getModel(db).findById(id);
}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.