Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.js Sequelize getter/setter RangeError

I'm creating a table to store user sessions in. I'm going to store the IP address as an integer, using these methods: IP-addresses stored as int results in overflow?

I would like to specify a getter and setter for the IP field so that it may automatically convert between an IP and int.

Unfortunately I get the following error and I have no idea what's happening. I've been trying to fix it for hours and Google yields me no results:

RangeError: Maximum call stack size exceeded

Model:

model = db.define(name, {
    id: {type: Sequelize.STRING, allowNull: false, primaryKey: true},
    ipAddress: {type: Sequelize.INTEGER(11).UNSIGNED, allowNull: false},
    userAgent: {type: Sequelize.STRING, allowNull: false},
    username: {type: Sequelize.STRING, allowNull: false},
    password: {type: Sequelize.STRING, allowNull: false},
    firstName: {type: Sequelize.STRING, allowNull: false},
    lastName: {type: Sequelize.STRING, allowNull: false},
    email: {type: Sequelize.STRING}
}, {
    getterMethods: {
        name: function() { return this.firstName + this.lastName },
        ipAddress: function() {
            ip = this.getDataValue("ipAddress");
            return ((ip >> 24) & 255) + "." + ((ip >> 16) & 255) + "." + ((ip >> 8) & 255) + "." + (ip & 255);
        }
    },
    setterMethods: {
        ipAddress: function(ip) {
            var parts = ip.split(".");
            var ret = 0;
            ret += parseInt(parts[0], 10) << 24;
            ret += parseInt(parts[1], 10) << 16;
            ret += parseInt(parts[2], 10) << 8;
            ret += parseInt(parts[3], 10);
            return ret;
        }
    }
});

Inserting an IP:

model.findOrCreate({id: sessionId}, {
    id: sessionId,
    ipAddress: req.ip, // === "192.168.1.79"
    userAgent: req.get("user-agent"),
    username: "test",
    password: "test",
    firstName: "first",
    lastName: "last",
    email: "email"
})

I can confirm that the getter/setter code does convert as desired, but it is not functioning in Sequelize properly.

like image 686
Jacob Brunson Avatar asked Mar 23 '23 21:03

Jacob Brunson


2 Answers

I too ran into this problem with Sequelize. I was reading and re-reading the official documentation, searching everywhere I knew to search on the internet, and I finally wound up here. Once I found your question, with no answers, I decided to search the source code of Sequelize itself. Sure enough, I found the answer!

If you look at the file sequelize/test/dao-factory.test.js in Sequelize's source code, you'll discover the following bit of code lurking inside a test case:

setterMethods: {
  price1: function(v) { this.setDataValue('price1', v * 100) }
},

I copied the syntax above, used it in my own setter method, and it works!

They really should update the documentation on the sequelize website.. Hmm.. Perhaps I should look into helping them out with that? Any way, best of luck to you!

like image 140
c.hill Avatar answered Apr 05 '23 21:04

c.hill


I don't know if someone is still running this error, but if you are having troubles with this here is how I've solved the issue.

I had a similar situation where I had a UserModel object which was looking like this:

var UserModel = sequelize.define("users", {
    ID: {
        type: Sequelize.INTEGER,
        field: "ID",
        primaryKey: true,
        autoIncrement: true
    },
    Username: {
        type: Sequelize.STRING,
        field: "Username"
    },
    Password: {
        type: Sequelize.STRING,
        field: "Password"
    },
    Sector: {
        type: Sequelize.INTEGER,
        field: "Sector"
    },
    SubSector: {
        type: Sequelize.INTEGER,
        field: "SubSector"
    },
    Email: {
        type: Sequelize.STRING,
        field: "email"
    },
    Status: {
        type: Sequelize.INTEGER,
        field: "status"
    }
}

And my setters and getters were:

{
    getterMethods: {
        Sector:  function() {
            return this.Sector;
        },
        Status:  function() {
            return this.Status;
        }
    },
    setterMethods: {
        Sector:  function(val) {
            this.setDataValue('Sector',val);
        },
        Status: function(val) {
            this.setDataValue('Status',val);
        }
    }
});

And of course I had the stack error.

To solve this, I've just changed my setters and getters to this:

 {
    getterMethods: {
        currSector:  function() {
            return this.Sector;
        },
        currStatus:  function() {
            return this.Status;
        }
    },
    setterMethods: {
        newSector:  function(val) {
            this.setDataValue('Sector',val);
        },
        newStatus: function(val) {
            this.setDataValue('Status',val);
        }
    }
});

And everything went magically well, despite in many examples online I've seen people suggesting the approach of providing the same setters / getters name as the fields.

So, in a nutshell, changing to setters and getters name so that their name won't match any of the defined fields solved my issue. Good practice? I'm not sure, but it solved my problem.

like image 20
briosheje Avatar answered Apr 05 '23 21:04

briosheje