how can access property of class in promise? - node.js

I have a class that have one method .I want change return type of my method to promise . but in promise can not access to properties of class .how can resolve this .But get this exception
Reason: TypeError: Cannot read property 'bot' of undefined
const SDK = require('balebot');
const Promise = require('bluebird');
import incoming from './incoming';
const _ = require('lodash');
class Bale {
constructor(bp, config) {
if (!bp || !config) {
throw new Error('You need to specify botpress and config');
}
this.bot = null;
this.connected = false;
this.bot = new SDK.BaleBot(config.botToken);
bp.logger.info('bale bot created');
}
setConfig(config) {
this.config = Object.assign({}, this.config, config);
}
sendText(chat, text, options) {
let msg = new SDK.TextMessage(text);
return new Promise(function (resolve, reject) {
var response = this.bot.send(msg, receiver);
if (response) {
reject(err);
} else {
resolve(response);
}
});
}
}
module.exports = Bale;

You need to bind this or use Arrow functions to preserve this context:
const SDK = require('balebot');
const Promise = require('bluebird');
import incoming from './incoming';
const _ = require('lodash');
class Bale {
constructor(bp, config) {
if (!bp || !config) {
throw new Error('You need to specify botpress and config');
}
this.bot = null;
this.connected = false;
this.bot = new SDK.BaleBot(config.botToken);
bp.logger.info('bale bot created');
}
setConfig(config) {
this.config = Object.assign({}, this.config, config);
}
sendText(chat, text, options) {
let msg = new SDK.TextMessage(text);
// Use an arrow function instead of function
return new Promise((resolve, reject) => {
var response = this.bot.send(msg, receiver);
if (response) {
reject(err);
} else {
resolve(response);
}
});
}
}
module.exports = Bale;

This would work
sendText() {
return new Promise((resolve, reject) => {
console.log(this.bot); // it will not be undefined
});
}
The reason this works is because arrow functions lexically bind their context so this actually refers to the originating context.

Related

async/await troubles in a recursive Redis function

Ima rookie using async/await but must now to use Redis-om. NN_walkd walks through a Redis database looking for loop-chains and does this by recursion. So the 2 questions I have is:
Am I calling the inner recursive NN_walkd calls correctly via async/await?
At runtime, the compSearchM proc is called first and seems to work (it gets 5 entries so it has to call NN_walkd 5 times). A NN_walkd is then recursively called, and then when it loops the 1st time it then calls compSearchK where the problems are. It seems to sit on the first Redis call in compSearchK (.search). Yet the code for compSearchK and compSearchM look basically identical.
main call
NN_walk = async function(req, db, cnode, pnode, chain, cb) {
var vegas, sneaker;
req.session.walk = [];
await NN_walkd(req, cnode, pnode, [], 1);
req.session.walk = null;
console.log('~~~~~~~~~~~~ Out of Walk ~~~~~~~~~~~~~~~');
cb();
};
redis.mjs
export class RedisDB {
constructor() {
...
this._companyRepo = ...
}
compSearchK(ckey) { // doesn't matter if I have a async or not here
return new Promise(async (resolve) => {
const sckey = await this._companyRepo.search()
.where('COMPANYKEY').equals(ckey)
.return.all();
if (sckey.length) {
const ttrr = await this._companyRepo.fetch(sckey[0].entityId);
resolve(ttrr.toJSON());
} else
resolve(null);
});
}
compSearchM(mkey) {
var tArr=[];
return new Promise(async (resolve) => {
const smkey = await this._companyRepo.search()
.where('MASTERKEY').equals(mkey)
.and('TBLNUM').equals(10)
.return.all();
if (smkey.length) {
for (var spot in smkey) {
const ttrr = await this._companyRepo.fetch(smkey[spot].entityId);
tArr.push(ttrr.toJSON());
}
resolve(tArr);
} else {
resolve(null);
}
});
}
walk.js
NN_walkd = async function(req, cnode, pnode, chain, lvl) {
...
if (cnode[1]) {
const sObj = await req.app.get('redis').compSearchK(cnode[1]);
if (sObj) {
int1 = (sObj.TBLNUM==1) ? null : sObj.CLIENTKEY;
(async () => await NN_walkd(req, [sObj.COMPANYKEY,int1], cnode, Array.from(chain), tlvl))()
}
} else {
const sArr = await req.app.get('redis').compSearchM(cnode[0]);
if (sArr.length) {
for (sneaker in sArr) {
(async () => await NN_walkd(req, [sArr[sneaker].COMPANYKEY,sArr[sneaker].CLIENTKEY], cnode, Array.from(chain), tlvl))()
}
} else {
console.log('no more links on this chain: ',cnode);
}
}
}
"doesn't matter if i have async or not here"
compSearchK(ckey) { // doesn't matter if I have a async or not here
return new Promise(async (resolve) => {
const sckey = await this._companyRepo.search()
.where('COMPANYKEY').equals(ckey)
.return.all();
if (sckey.length) {
const ttrr = await this._companyRepo.fetch(sckey[0].entityId);
resolve(ttrr.toJSON());
} else
resolve(null);
});
}
Of course it doesn't matter, because you're not using await inside of compSearchK!
You are using the explicit promise contructor anti-pattern. You should avoid it as it demonstrates lack of understanding. Here is compSearchK rewritten without the anti-pattern -
async compSearchK(ckey) {
// await key
const sckey =
await this._companyRepo.search()
.where('COMPANYKEY').equals(ckey)
.return.all();
// return null if key is not found
if (sckey.length == 0) return null;
// otherwise get ttrr
const ttrr = await this._companyRepo.fetch(sckey[0].entityId);
// return ttrr as json
return ttrr.toJSON();
}

async await function return blank array problem in node js

sessionFilter.js
'use strict';
const knex = require('../config/database')
class SessionFilter{
async setPermissionFilterArray(data){
return new Promise(async (resolve, reject) => {
try {
const sql_data = await knex.select(knex.raw(sql));
var all_permission = [];
sql_data.forEach(function(val) {
if (all_permission[val.event_ref] === undefined) all_permission[val.event_ref] = [];
if (all_permission[val.event_ref][val.event_slug] === undefined) all_permission[val.event_ref][val.event_slug] = [];
all_permission[val.event_ref][val.event_slug][val.event_slug_key] = {
permission:val.permission,
no_permission:val.no_permission,
sql_where_clause:val.sql_where_clause
}
});
resolve(all_permission);
} catch (error) {
reject(error.message);
}
})
}
}
module.exports = SessionFilter;
server.js
const filter = new SessionFilter();
const set_permission_filter_array = await filter.testFunction(data);
console.log(set_permission_filter_array);
return res.json(set_permission_filter_array);
when i console set_permission_filter_array variable showing data well but when i return set_permission_filter_array variable showing blank array at frontend. how can i get data? please help me.
Your function will automaticaly return a promise because of the async keyword.
This promise will be resolved at the return all_permission; statement.
class SessionFilter{
async setPermissionFilterArray(data){
try {
//don't know were this sql var comes from
const sql_data = await knex.select(knex.raw(sql));
var all_permission = [];
sql_data.forEach((val) => {
...
});
return all_permission;
} catch (error) {
throw error;
}
}
}
Then you can get the result of your promise using async await keywords like this :
const set_permission_filter_array = await setPermissionFilterArray(data);

Question about nodejs using 'async-lock' return value

I used async-lock module for my typescript program of concurrency.
As I use this, I want to return the result in lock.acquire(...) {...}, but it's not working well.
How can I return the value? I'll be grateful for any advice about this. Thanks!
public async getValue(key: string): Promise<any> {
const base = this;
lock.acquire(key, async function (done) {
base.logger.info(`${key} lock enter`);
if (!await base.myRepository.checkDBTable(key)) {
const valueFromNetwork: number = await base.getValueFromNetwork(key);
const initResult: MyEntity = await base.myRepository.initNonce(key, valueFromNetwork);
if (!initResult) {
throw new Error('initValue failed...');
}
base.logger.debug(JSON.stringify(initResult, null, 4));
}
const valueFromDB: number = await base.myRepository.getValueFromDB(key);
if (valueFromDB === -1 || valueFromDB === undefined) {
throw new Error('getValueFromDB failed...');
} else {
const updateResult: MyEntity = await base.myRepository.updateValue(key, valueFromDB);
if (!updateResult) {
throw new Error('updateValue failed...');
}
base.logger.info(`${valueFromDB}`);
base.logger.info(`${key} lock done`);
done();
}
// I'd like to return valueFromDB above.
});
}
You have two options:
You can implement a wrapper around lock.aquire (Recommended as it is a little easier to read and can handle acquisition errors):
public async getValue(key: string): Promise<any> {
const base = this;
const done = await this.aquireLock(key);
base.logger.info(`${key} lock enter`);
if (!await base.myRepository.checkDBTable(key)) {
const valueFromNetwork: number = await base.getValueFromNetwork(key);
const initResult: MyEntity = await base.myRepository.initNonce(key, valueFromNetwork);
if (!initResult) {
throw new Error('initValue failed...');
}
base.logger.debug(JSON.stringify(initResult, null, 4));
}
const valueFromDB: number = await base.myRepository.getValueFromDB(key);
if (valueFromDB === -1 || valueFromDB === undefined) {
throw new Error('getValueFromDB failed...');
} else {
const updateResult: MyEntity = await base.myRepository.updateValue(key, valueFromDB);
if (!updateResult) {
throw new Error('updateValue failed...');
}
base.logger.info(`${valueFromDB}`);
base.logger.info(`${key} lock done`);
done();
}
return valueFromDB;
}
private async aquireLock(key: string): Promise<() => void> {
return new Promise((resolve, reject) => {
lock.acquire(key, done => {
resolve(done);
}, (err)=>{ // in case our aquire fails(times out, etc.)
if(err){
reject(err);
}
})
})
}
Playground
Or, you can use a function constructor (even if it is an anti-pattern):
getValue(key: string): Promise<any> {
return new Promise((resolve, reject) => {
const base = this;
lock.acquire(key, async function (done) {
base.logger.info(`${key} lock enter`);
if (!await base.myRepository.checkDBTable(key)) {
const valueFromNetwork: number = await base.getValueFromNetwork(key);
const initResult: MyEntity = await base.myRepository.initNonce(key, valueFromNetwork);
if (!initResult) {
reject(new Error('initValue failed...'));
}
base.logger.debug(JSON.stringify(initResult, null, 4));
}
const valueFromDB: number = await base.myRepository.getValueFromDB(key);
if (valueFromDB === -1 || valueFromDB === undefined) {
reject(new Error('getValueFromDB failed...'));
} else {
const updateResult: MyEntity = await base.myRepository.updateValue(key, valueFromDB);
if (!updateResult) {
reject(new Error('updateValue failed...'));
}
base.logger.info(`${valueFromDB}`);
base.logger.info(`${key} lock done`);
done();
}
resolve(valueFromDB)
});
})
}
Playground (Many things stubbed out, but it gets the general idea across)

Module.export a 'default' function

I want to write a module that exports a default function and a list of properties (they are functions too).
Basically this module will allows this usage consumer-side:
let db_connection = fake_database_connection_instance()
let db = require('./db.js')(db_connection)
db.find({id:1})
So the default function should only pass the database connection instance to the module.
This is the not working code
module.exports = {
//init should go away and replaced by a 'default' function when this module is called
init: function (connection) {
this.connection= connection;
return this;
},
find: function (query) {
return new Promise(function (resolve, reject) {
this.connection.find(query, function (err, docs) {
if (err) {
return reject(err);
}
return resolve(docs);
});
});
}
}
I want to avoid the new keyword (consumer-side), so I have to remove those this, I know. The problem here are 2:
how to export a default function called on require('./db.js')() and other functions e.g. require('./db.js').find()?
how pass the connection instance from the default function to find()?
EDIT following the #Igor Raush ES6 Class solution I wrote this, but still db is not defined
class DB {
constructor(db) {
this.db = db;
}
find(query) {
return new Promise( (resolve, reject) => {
this.db.find(query, function (err, docs) {
if (err) {
return reject(err);
}
return resolve(docs);
});
});
}
}
You can add a default function to module.exports and use an external variable _conn to store the connection:
let _conn;
module.exports = (connection) => {
_conn = connection;
};
After that you could add find function to module.exports object:
module.exports.find = (query) => {
return new Promise(function(resolve, reject) {
_conn.find(query, function(err, docs) {
if (err) {
return reject(err);
}
resolve(docs);
});
});
}
One option is to create a class and export an instance factory function.
// db.js
function DB(connection) {
this.connection = connection;
}
DB.prototype.find = function find(query) {
let connection = this.connection;
// ...
}
// export instance factory function
module.exports = function (connection) { return new DB(connection); };
or, if you're in an ES6 environment,
// db.js
class DB {
constructor(connection) {
this.connection = connection;
}
find(query) {
let connection = this.connection;
// ...
}
}
// export instance factory function
module.exports = connection => new DB(connection);
Then you can do
let db = require('./db')(db_connection);
db.find({ id: 1 });
If you'd like to enforce the singleton pattern (only one DB instance can exist), lazily create a module-local instance and return the reference on subsequent calls:
let _instance = null;
module.exports = connection => {
// return existing instance, or create a new one
return _instance || (_instance = new DB(connection));
}

Promise is pending

I have a class in my nodejs application with the following code:
var mongoose = require('mongoose');
var Roles = mongoose.model('roles');
var Promise = require("bluebird");
module.exports = Role;
var err = null;
var id;
function Role(name, companyId) {
this.err = err;
this.name = name;
this.companyId = companyId;
this.id = getId(name, companyId);
}
var getId = function (name, companyId) {
return new Promise(function(resolve, reject) {
Roles.findOne({companyId:companyId, name:name}, function(err,result) {
resolve(result._id);
});
});
};
When I am calling the class, the id is pending:
var currentRole = new Role(myRole, comId);
console.log(currentRole);
How can I get the values from the class when they are resolved?
currentRole.id is a promise so you can call then() on it to wait for it to be resolved:
var currentRole = new Role(myRole, comId);
currentRole.id.then(function (result) {
// do something with result
});
This feels like a strange API though, you expect your object to be "ready to use" when its constructor returns. Might be better to have getId be a promise returning function on the prototype of Role so you instead do something like:
var currentRole = new Role(myRole, comId);
currentRole.getId().then(function (result) {
// do something with result
});
You should also consider handling that error to reject the promise:
var getId = function (name, companyId) {
return new Promise(function(resolve, reject) {
Roles.findOne({companyId:companyId, name:name}, function(err,result) {
if (err) {
return reject(err);
}
resolve(result._id);
});
});
};
and add a rejection handler to your call to getId:
var currentRole = new Role(myRole, comId);
currentRole.getId().then(function (result) {
// do something with result
}, function (err) {
// do something with err
});
or equivalently:
var currentRole = new Role(myRole, comId);
currentRole.getId().then(function (result) {
// do something with result
}).catch(function (err) {
// do something with err
});

Resources