Pass 'this' to a class variable inside constructor - node.js

I am interested, how to pass this to a class variable inside a constructor of a parent, so I could use parents methods and access other variables of the parent and call their methods?
Here is my parent class:
var async = require('async');
var Rater = require('./rater')
var Similars = require('./similars')
var Suggestions = require('./suggestions');
module.exports = class Engine {
constructor() {
this.likes = new Rater(this,'likes');
this.dislikes = new Rater(this,'dislikes');
this.similars = new Similars(this);
this.suggestions = new Suggestions(this);
}
And here is the example of usage and where is get the following error:
Cannot read property 'engine' of undefined
at --\\classes\rater.js:89:19
module.exports = class Rater {
constructor(engine,kind) {
this.type = kind;
this.engine = engine;
if(kind == 'likes') //database schemes
this.db = Likes_db;
else if(kind == 'dislikes')
this.db = Dislikes_db;
else if(kind == 'similars')
this.db = Similars_db;
else if(kind == 'suggestions')
this.db = Suggestions_db;
}
//..
//other methods
//..
remove(user,item,done) {
this.db.remove({user: user,item: item},(err) => {
if(err)
return done(err);
async.series([
function(done) {
this.engine.similars.update(user,done); //error-cant enter the method
},
function(done) {
this.engine.suggestions.update(user,done);
}
],function(done) {
});
});
}
}

It has nothing to do with the constructor.
The problem appears because you are using a regular function as the callback and the context switches (you get another this in there).
Use an arrow function instead to keep the same context.
async.series([
(done) => {
this.engine.similars.update(user,done); //error-cant enter the method
},
(done) => {
this.engine.suggestions.update(user,done);
}
],function(done) {
});
Simply doing this works fine:
class Rather {
constructor(engine: Engine) {
engine.method();
}
}
class Engine {
constructor() {
new Rather(this);
}
method() {
console.log('ENgine');
}
}
new Engine();
You can see a working example here.
Note: As an OOP design decision though this is not very clean, you are introducing a cyclic dependency. Try going injection or at least introduce an interface to separate the 2 classes.

Try to define a _this var and then give it to parameter:
module.exports = class Engine {
var _this = this, _constructor = (<any>this).constructor;
constructor() {
this.likes = new Rater(_this,'likes');
this.dislikes = new Rater(_this,'dislikes');
this.similars = new Similars(_this);
this.suggestions = new Suggestions(_this);
}

Related

Module.exports: is not a constructor error

Can someone explain why the first export throws a is not a constructor error, while the second export works?
// Throws a `is not a constructor` error
module.exports = {
Person: function () {
constructor()
{
this.firstname;
this.lastname;
}
}
}
// Works
class Person {
constructor()
{
this.firstname = '';
this.lastname = '';
}
}
module.exports = Person;
// Usage:
const Person = require("person");
let person = new Person();
Because the first time you actually export an object containing a property:
module.exports = { /*...*/ };
And you can't construct that object. However you could get the Person property and construct that:
const Person = require("person").Person;
new Person();
You could also destructure the imported object:
const { Person } = require("person");
new Person();
... but that only makes sense if there are other things exported there otherwise I would go with v2.

How to test setInterval on a method?

I have a class
class Dummy {
constructor() {
this.prop1 = null;
this.prop2 = null;
this.prop3 = setInterval(() => {
this.method1()
}, 1000);
}
method1() {
// Method logic
}
}
var dummyObject = new Dummy();
module.exports = dummyObject;
I'd like to write tests to verify that method1 is being invoked after every 1s.
Following is the test code
const dummyObject = require('./dummy.js');
describe("Test setInterval", function () {
it("Test setInterval", function () {
const clock = sinon.useFakeTimers();
const spy = sinon.spy(dummyObject, 'method1');
clock.tick(1001);
expect(spy.calledOnce).to.be.true;
clock.restore();
})
})
When I run the tests however, I get an error 'Expected false to equal to true' and on further digging I realized I am not able to spy on the method which is being called via setInterval.
Please share any thoughts on what I can do to test this scenario?
This is not going to work the way you want it to, because the method (method1) is already called when you require the module and hence there is no chance to spy it afterwards in your test.
I recommend to refactor your Module to export the class, not the instance like:
module.exports = class Dummy {
constructor() {
this.prop1 = null;
this.prop2 = null;
this.prop3 = setInterval(() => {
this.method1()
}, 1000);
}
method1() {
// Method logic
}
}
Then in you test, require the class and spy on the method before you instantiate it:
const sinon = require('sinon');
const Dummy = require('./dummy.js');
describe("Test setInterval", function () {
it("Test setInterval", function () {
const clock = sinon.useFakeTimers();
// Spy on the method using the class' prototype
const spy = sinon.spy(Dummy.prototype, 'method1');
// Initialize the class and make sure its `constructor` is called after you spied on the method
new Dummy();
clock.tick(1001);
expect(spy.calledOnce).to.be.true;
clock.restore();
})
})

sequelize ORM asynchronous method calls

How can I call methods asynchronously in sequelize ORM? (because I have to use returned value inside other methods).
user.dao.js:
var User = require('./user.model');
class UserDao {
constructor() {}
insert(user) {
var pk;
User.sync({ force: false }).then(() => {
User.create(user).then(function(user) {
console.log('Entry successful from dao: ' +
JSON.stringify(user));
//return generated pk
pk = user.id;
console.log('ID: ' + pk);
});
});
return pk;
}
user.test.js:
class UserDaoTest {
constructor() {
this.userDao = new UserDao();
this.compare = new UtilsObject();
}
/*
all CRUD method calls
*/
testAll() {
this.testInsert();
this.testUpdate();
//this.testDelete();
//this.testRead();
//this.compare();
}
/*
insert method
*/
testInsert() {
// composite form
var user = {
name: 'nisha',
email: 'nisha#gmail.com',
phoneNo: 8978,
picUrl: 'nisha',
description: 'SI',
status: 'active',
waitingTime: 10,
rating: 7
};
/*
calling insert user with above data
*/
var pk = this.userDao.insert(user);
console.log('pk value: ' + pk);
//var obj1 = this.userDao.readById(pk);
console.log('obj1 value: ' + user);
//this.testReadById(obj1);
}
testReadById(obj1) {
var obj2 = this.userDao.readById(obj1);
this.compare.compare(obj1, obj2);
this.testDelete(obj1);
}
}
export default UserDaoTest;
Here in user.test.js, in testInsert() method want to get the value of pk which is returned from insert() method of user.dao.js, but right now I am getting pk value as undefined.
Use a promise chain.
Suppose you need to get an entry for a particular user & do some operations on it.
Model.User.findById(someId)
.then((user) => {
// Do something with user.
})
You shouldn't be calling methods synchronously, NodeJs is not designed this way. It works with callbacks or promises.
Your code won't work because it is async code.
Watch the famous Youtube video about the event loop
But in short, if you will run the following example, which is like your code but without your logic:
var User = require('./user.model');
class UserDao {
constructor() {}
insert(user) {
var pk;
console.log('1');
User.sync({ force: false }).then(() => {
pk = 123;
console.log('3');
});
console.log('2');
return pk;
}
The variable pk will be undefined and your console will look like this:
1
2
3
If you want it to work, you should "wait" for the async functions like this:
var User = require('./user.model');
class UserDao {
constructor() {}
// #return Promise
insert(user) {
return User.sync({ force: false }).then(() => {
return User.create(user)
}).then((user) => {
console.log('Entry successful from dao: ' + JSON.stringify(user));
return user.id
})
}
And when you use it:
class UserDaoTest {
constructor() {
this.userDao = new UserDao();
this.compare = new UtilsObject();
}
/*
all CRUD method calls
*/
testAll() {
// if testInsert and testUpdate can run simultaneously you can keep it like this.
// Otherwise, use Promise.then as well
this.testInsert();
this.testUpdate();
}
/*
insert method
*/
testInsert() {
var user = {
// ...
};
/*
calling insert user with above data
*/
this.userDao.insert(user).then((userId) => {
// YOUR COMPARE CODE
}).then(done); // Where done is a function to let you test framework that you async code is done
}
}
export default UserDaoTest;
Another way of doing that is using the new async and await. That way you will get a code which is more readable and maintainable.
You can read more here

How to pass data to next middleware function in NodeJS

I'm writing my own implementation of middleware for a socket system. I've read through the source code of Laravel's middleware and some documentation on ExpressJS's implementation for inspiration.
However, I'm getting stuck on passing the data from one middleware handler to another.
I wrote a very basic example below. The output should be 4 but I don't know how to pass the output from one handler to the other. I'm guessing by setting a temporary variable, but I'm not sure how performant that is.
let each = require('lodash/each')
class Middleware {
constructor() {
this.handlers = [
function (data) {return data + 1},
function (data) {return data + 2}
]
}
}
class Router {
constructor() {
this.middleware = new Middleware
}
route(data) {
each(this.middleware.handlers, function(handler) {
handler(data) // no idea what to do here
})
}
}
class Socket {
constructor() {
this.router = new Router
}
write(data) {
return this.router.route(data)
}
}
let router = new Router
console.log(socket.write(1)) // should be 4
Change the route function inside Router class as following and the result of socket.write(1) will be 4:
class Router {
constructor() {
this.middleware = new Middleware
}
route(data) {
each(this.middleware.handlers, function (handler) {
data = handler(data)
})
return data
}
}

How to override a method in Node.js?

I have a module that defines functions that will be shared by other modules. Some of those functions need to be overridden. This is what I was thinking, but it doesn't work:
// shared_module.js
module.exports = {
alternativeFun() {
exports.doSomething()
sharedFun()
},
sharedFun() {
console.log('shared')
}
}
// alternative_module1.js
module.exports = {
doSomething() {
console.log('alternative 1')
}
}
// alternative_module2.js
module.exports = {
doSomething() {
console.log('alternative 2')
}
}
// main.js
const shared1 = require('./shared_module')
shared1.doSomething = require('./alternative_module1').doSomething
shared1.alternativeFun()
const shared2 = require('./shared_module')
shared2.doSomething = require('./alternative_module2').doSomething
shared2.alternativeFun()
Setting module.exports does not magically change the value of exports. You will need to also assign it to the same value (module.exports = exports = ...) if you want to use it inside your module's functions.

Resources