danecando/hapi-sequelize

Model Association

iwanjunaid opened this issue · 4 comments

I wonder how to implement model association in this plugin as shown in sequelize site

var Player = this.sequelize.define('Player', {/* attributes */})
  , Team  = this.sequelize.define('Team', {/* attributes */});

Player.belongsTo(Team);

@iwanjunaid Had the same question. A quick look into the code revealed that a little nice third-party module called sqlizr is used.

@iwanjunaid this plugin use to handle that itself and then one of the users built a little module called sqlizr to handle the imports and associations and this plugin has been using that for a little while now.

You can add your associations in your classMethods on the sequelize.define options arg http://docs.sequelizejs.com/en/latest/api/sequelize/#definemodelname-attributes-options-model

        {
            tableName: 'state',
            classMethods: {
                associate: function(db) {
                    State.belongsTo(db.Country);
                    State.belongsTo(db.Zone);
                }
            },
            getterMethods: {

            },
            setterMethods: {

            }
        }

I'll add this to the readme

I could only get this to work with some modifications. It kept complaining that what was passed to the method was not a model.

I wanted set up a couple "belongsToMany" associations and added the associate classMethods. Once the associate is called I can see the foreign keys added when sync is called. But there does not seem to be any "get" or "add" methods added. I don't know if it is due to hapi-sequelized or sequelize.

Here is are the models Game and GameUser

var Game = function(sequelize, DataTypes){
         sequelize.define(
         'Game',
         {
            gid: {
                type: DataTypes.INTEGER.UNSIGNED,
                unique: true,
                allowNull: false,
                autoIncrement: true,
                primaryKey : true
            },
            game_type: {
                type: DataTypes.INTEGER(6)
            },
            game_status: {
                type: DataTypes.INTEGER(6),
            },

           start_time: {
                type: DataTypes.DATE
            }
            },
         {
            tableName: 'games',
            timestamps: true,

            classMethods: {
               associate: function(model) {
                return this.belongsToMany(model.GameUser, {through:'Player', foreignKey:'gid'});
                   }
            },
       getterMethods:{
            game_type: function(){
                return this.getDataValue('game_type') == 1 ? "free" : "prize";
            }
        },
        setterMethods:{
            game_type: function(value){
                var t =  value == "free" ? 1 : 2;
                return this.setDataValue('game_type', t);
            }
        }
         }
     );
 };
module.exports = Game
var GameUser = function(sequelize, DataTypes){
         sequelize.define(
         'GameUser',
         {
            uid: {
                type: DataTypes.INTEGER.UNSIGNED,
                unique: true,
                allowNull: false,
                autoIncrement: true,
                primaryKey : true
            },
            user_name: {
                type: DataTypes.STRING
            },
            email: {
                type: DataTypes.STRING
            },
        balance: {
        type: DataTypes.DECIMAL(10,2)
                },
        status: {
        type: DataTypes.STRING
                }
       },
         { 
            tableName: 'users',
            timestamps: true,

       classMethods: {
                associate: function(model) {
                    return this.belongsToMany(model.Game, {through:'Player', foreignKey:'uid'});
                   }
            },
             } 
     );
 };
module.exports = GameUser

Player

var Player = function(sequelize, DataTypes){
         sequelize.define(
         'Player',
         {
            pid: {
                type: DataTypes.INTEGER.UNSIGNED,
                unique: true,
                allowNull: false,
                autoIncrement: true,
                primaryKey : true
            },
            gid: {
                type: DataTypes.INTEGER.UNSIGNED
            },
            uid: {
                type: DataTypes.INTEGER.UNSIGNED

            },
            credits: {
                type: DataTypes.DECIMAL(10,2)
            },
            status: {
                type: DataTypes.STRING
            },
            unreg_at: {
                type: DataTypes.DATE
            }

        },
         {
            tableName: 'players',
            timestamps: true
         }
     );

 };

module.exports = Player;

The associate is done just before server start and db.sync();

var Composer = require('./index');
Composer(function (err, server) {
    if (err) {
        throw err;
    }
    var db = server.plugins['hapi-sequelized'].db;
    var Models = db.sequelize.models;
    var Game = Models.Game;
    var GameUser = Models.GameUser;

    Game.associate(Models);
    GameUser.associate(Models);

    db.sequelize.sync().then(function() {
         console.log('models synced');

        server.start(function () {
                     console.log('Started the plot device on port ' + server.info.port);
        });
    });

});

And the output from the sync():

Executing (default): CREATE TABLE IF NOT EXISTS `players` (`pid` INTEGER UNSIGNED NOT NULL auto_increment UNIQUE , `gid` INTEGER UNSIGNED, `uid` INTEGER UNSIGNE
D, `credits` DECIMAL(10,2), `status` VARCHAR(255), `unreg_at` DATETIME, `created_at` DATETIME NOT NULL, `updated_at` DATETIME NOT NULL, UNIQUE `players_uid_gid_
unique` (`gid`, `uid`), PRIMARY KEY (`pid`), FOREIGN KEY (`gid`) REFERENCES `games` (`gid`) ON DELETE CASCADE ON UPDATE CASCADE, FOREIGN KEY (`uid`) REFERENCES
`users` (`uid`) ON DELETE CASCADE ON UPDATE CASCADE) ENGINE=InnoDB;
Executing (default): SHOW INDEX FROM `players`

When I try to use the methods that the sequelize docs say are supposed to be created, they are not available. http://docs.sequelizejs.com/en/latest/docs/associations/#belongs-to-many-associations

server.route({
        method: 'GET',
        path: options.basePath + '/games/{id}',
        config: {
            auth: {
               strategy: 'session',
               scope: ['admin','account']
            }
        },
        handler: function (request, reply) {
                var Models = request.server.plugins['hapi-sequelized'].db.sequelize.models;
                var Game = Models.Game;

                Game.getGameUsers().then( function (err, game) {
                if (err) {
                    return reply(err);
                }

                if (!game) {
                    return reply({ message: 'Record not found.' }).code(404);
                }

                reply(game);
            }); 

       // });
        }
    });

I have tried "getGameUser()", "getGameUsers", getusers(), getuser() and none of them exist. Is this an issue with this module or sequelize or am I doing something wrong?

+1

I noticed there are no associations in the README and the test/ folder. The code from @ADumaine might be a good template for a test. Is this issue closed when it should be opened, or should a new one be re-opened?