bind value of callack to property of instance nodejs - javascript

I want to permanently store a result of a callback function, here is the code:
class constants {
constructor(){
this.acquire()
}
acquire() {
this.last_refresh = new Date().getDate();
require('./db_slave').then(conn => {
return conn.query("SELECT table_name FROM information_schema.tables where table_schema='gen'").then(result => {
this.tables = result
console.log(result)
});
}).catch(err => {
// handle error here
});
}
tables() {
this.refresh()
return this.tables
}
refresh() { if (new Date().getDate() != this.last_refresh) this.acquire() }
}
module.exports = constants
but this is obviously not working because this.tables = result doesnt do anything...
Here is the file that is being called by this promise:
var mysql = require('promise-mysql');
var db = require('./db')
module.exports = mysql.createConnection({
host: db.host,
user: db.user,
password: db.password
}).then(conn => {
console.log("connected to the DB");
return conn;
}).catch(err => {
console.log("error connecting to the DB", err);
throw err;
});
How do i permanently store the result in that callback?
here is how i used these:
var db_constants = require('./database_service/db_constants')
let cons = new db_constants()
console.log(cons.tables())

Related

Can't to get connection to PostgreSQL from Node.js

During the launch my website i can't connection to my database. It doesn't get errors and the page is loading infinitely. Who know answer on this question give me some advise.
I work in (Node.js,PostgreSQL,Express)
from file config_db
const client_admin1 = {
user:'a_role',
database:'road_db',
password: '12345',
host:'localhost',
port:5432,
max:10,
idleTimeoutMillis: 30000
}
const pg = require("pg")
const client_login = require("../config/config_db");
searchUser(req, res) {
const db = new pg.Pool(client_login.client_admin1)
db.connect(function(err, client, done){
if(err){
return console.error('connection problems')
}
client.query('SELECT * FROM login_phone WHERE phone = $1 AND password1 = $2',[req.body.login, req.body.password], function(err, result){
done()
if (err || result.rowCount <= 0){
res.render('error_login_choice')
return console.error("")
}
if(result.rows[0].role_name === "client")
{
cln.getClients(req,res)
}
})
}
try this executeQuery method
const pg = require('pg');
const pgconfig = {
user: process.env.DATA_BASE_USER,
database: process.env.DATA_BASE_NAME,
password: process.env.DATA_BASE_PASSWORD,
host: process.env.DATA_BASE_HOST,
port: process.env.DATA_BASE_PORT,
};
console.log(`DB | Settings: ${JSON.stringify(pgconfig)}`);
const pool = new pg.Pool(pgconfig);
pool.on('connect', () => {
console.log('DB | new client connection establish.');
});
pool.on('error', err => {
console.error(`idle client error, ${err.message} | ${err.stack}`);
});
pool.connect(err => {
if (err) {
console.error(`PostgreSQL input: ${err}`);
} else console.log('DB | connection establish.');
});
const executeQuery = async(sql, data) => {
logger.debug(`sqlToDB() sql: ${sql} | data: ${data}`);
try {
const result = await pool.query(sql, data);
return result;
} catch (error) {
console.error(error.message);
}
};
module.exports = {
executeQuery,
};
usage:
const dbHandler = require('./db');
const getLogedInUser = login,password => {
const selectFieldsQuery = `'SELECT * FROM login_phone WHERE phone = $1 AND password1 = $2'`;
return dbHandler.executeQuery(selectFieldsQuery, [login,password]).then(e => e.rows);
};

Express dosn't get return of other function querying Mongodb [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I'm working in a simple API Key authentication, I just want to verify the given key against the user provied key.
I have a seperate file with the function querying the database, and returning true/false and the user object.
But in my route.js file, the return object is undefined even tough in my auth.js file it isn't.
I tried making the the function in router.get an async function using express-promise-router and making the function an await return var user = await auth.verify(req.params.uid, req.get("token")) but I don't realy know how async works.
router.js
[...]
router.get('/list/:uid', function(req, res) {
var user = auth.verify(req.params.uid, req.get("token"))
console.log("User: " + user) // <-- Undefined
if (user.status) {
res.send("Success")
} else {
res.status(403)
res.json({status: 403, error: "Unkown User / Token"})
}
})
[...]
auth.js
var db = require('./db')
var ObjectId = require('mongodb').ObjectId;
module.exports = {
verify: (uid, key) => {
try {
var collection = db.get().collection('users')
const obj_id = new ObjectId(uid)
const query = { _id: obj_id }
collection.find(query).limit(1).toArray(function(err, user) {
var status = 0;
var usr = {};
if (err) {throw err}else{status=1}
if (user.length <= 0) {throw "NotExistingExc"; status = 0}else{
usr = user[0];
if (key != usr.api) status = 0
}
var returnObj = {
status: status,
user: usr
} /* --> Is {
status: 1,
user: {
_id: d47a2b30b3d2770606942bf0,
name: 'Sh4dow',
groups: [ 0 ],
api: 'YWFiMDI1MGE4NjAyZTg0MWE3N2U0M2I1NzEzZGE1YjE='
}
}
*/
return returnObj;
})
} catch (e) {
console.error(e)
return {
status: 0,
user: {},
error: e
}
}
}
}
db.js (Idk if needed)
var MongoClient = require('mongodb').MongoClient
var state = {
db: null,
}
exports.connect = function(url, done) {
if (state.db) return done()
MongoClient.connect(url, { useNewUrlParser: true }, function(err, db) {
if (err) return done(err)
state.db = db
done()
})
}
exports.get = function() {
return state.db.db("database")
}
exports.close = function(done) {
if (state.db) {
state.db.close(function(err, result) {
state.db = null
state.mode = null
done(err)
})
}
}
I want to have the returnObjin auth.js in the router.get of my route.js file.
Make auth.verify return a Promise which we can then await for it inside router, You can just make the callback async no need for express-promise-router
router.get('/list/:uid', async function(req, res) {
try {
var user = await auth.verify(req.params.uid, req.get("token"))
console.log("User: " + user)
if (user.status) {
res.send("Success")
} else {
res.status(403).json({status: 403, error: "Unkown User / Token"})
}
} catch (e) {
console.error(e)
res.status(/* */).json(/* */)
}
})
auth
module.exports = {
verify: (uid, key) => new Promise((resolve, reject) => {
var collection = db.get().collection('users')
const obj_id = new ObjectId(uid)
const query = { _id: obj_id }
collection.find(query).limit(1).toArray(function(err, user) {
var status = 0;
var usr = {};
if (err) {
reject(err)
return
} else {
status = 1
}
if (user.length <= 0) {
reject(new Error("NotExistingExc"))
return
} else {
usr = user[0]
if (key != usr.api) status = 0
}
var returnObj = {
status: status,
user: usr
}
resolve(returnObj);
})
}
}
In short, the reason you get undefined is because the code in auth.js is asyncronous. But you're really close. The toArray method in MongoDB returns a promise, so you need to make sure you return that promise and then use it in the router correctly.
In auth.js, make sure verify returns a promise - just add return!
return collection.find(query).limit(1).toArray(...)
And then, change your usage of the verify to the async/await you originally tried:
router.get('/list/:uid', async function(req, res) {
var user = await auth.verify(req.params.uid, req.get("token"))
// More code here...
})

How to return a value from within activedirectory method

I've got a method in a class which does query an ActiveDirectory.
Therefore I'm using 'activedirectory2' npm package.
I successfully authenticated and successfully logged my result to console.
Now that I have instanciated my class and have tried to call the method, I'm not abled to get a non-empty result.
I tried it with getters/setters to make the _result value available after instaciating the class.
I tried to solve my issue with research on asynchronous calls, but obviously wasn't able to ask the right question.
class Activedirectory
var ActiveDirectory = require("activedirectory2");
class AuthenticateWithLDAP {
constructor(user, password){
this._result = [];
this.user = user;
this.password = password;
this.config = {
url: "ldaps://someldap",
baseDN: "somebasdn",
username: this.user,
password: this.password,
filter: 'somefilter',
}
this.ad = new ActiveDirectory(this.config);
}
//Auth Method
auth() {
var result = this._result;
this.config.entryParser = function(entry,raw,callback){
if(entry.hasOwnProperty('info')) {
result.push(entry.info);
this._result = result;
}
callback(entry);
}
this.ad.authenticate(config.username, config.password, (err,auth)=>{
if (err) {
//some error handling
}
if (auth) {
this.ad.find(config,async (err, userDetails) => {
var result = this._result;
{
if (err) {
//some error handling
}
if(!userDetails) {
console.log("No users found.");
} else {
this._result = result[0]; //I want this result!
console.log('result: ', this._result);
return await this._result;
}
}
})
} else {
console.log("Authentication failed!");
}
});
}
//getter/setter
get result(){
return this._result;
}
set result(value) {
this._result.push(value);
}
}
module.exports = AuthenticateWithLDAP;
route module
const express = require('express');
const AuthwithLDAP = require('AuthenticateWithLDAP');
const router = express.Router();
router.post('/', async (req,res,next) => {
let x = async ()=> {
authwithldap = new AuthwithLDAP(req.body.user,req.body.password);
return await authwithldap.auth();
}
x().then((res)=>{
console.log('res: ', res); //always []
})
})
I expected to be able to use the _result value of AuthenticateWithLDAP class in my router.post method handler.
Actually i only get [] (empty array) in router.post.
Could you please tell me how to alter the value _result in a way, so that the instance of the class knows it and can use it outside the class itself.
Thank you very much.
Micha
I am not 100% sure but I think this should work.
In your code you cant return the result because the return is in a callback.
There are to ways to fix that.
Pass a callback to the auth() method (This is bad since callbacks suck)
Return a promise and that resolves to the result
I've decided to go for promises.
var ActiveDirectory = require("activedirectory2");
class AuthenticateWithLDAP {
constructor(user, password){
this._result = [];
this.user = user;
this.password = password;
this.config = {
url: "ldaps://someldap",
baseDN: "somebasdn",
username: this.user,
password: this.password,
filter: 'somefilter',
}
this.ad = new ActiveDirectory(this.config);
}
//Auth Method
auth() {
return new Promise((resolve, reject) => {
this.ad.authenticate(config.username, config.password, (err,auth)=>{
if (err) {
//Call reject here
}
if (auth) {
this.ad.find(config,async (err, userDetails) => {
var result = this._result;
{
if (err) {
//some error handling
}
if(!userDetails) {
console.log("No users found.");
} else {
this._result = result[0]; //I want this result!
resolve(await this._result);
}
}
})
} else {
console.log("Authentication failed!");
}
});
});
}
}
module.exports = AuthenticateWithLDAP;
const express = require('express');
const AuthwithLDAP = require('AuthenticateWithLDAP');
const router = express.Router();
router.post('/', async (req,res,next) => {
/* This code can be simplifed
let x = async () => {
authwithldap = new AuthwithLDAP(req.body.user,req.body.password);
return await authwithldap.auth();
}
x().then((res)=>{
console.log('res: ', res); //always []
})
*/
(async () => {
authwithldap = new AuthwithLDAP(req.body.user,req.body.password);
var res = await authwithldap.auth();
console.log('res: ', res);
})();
})
Could you try to add syntax "await" like this?
await x().then((res)=>{
console.log('res: ', res); //always []
})
As your "x" method is in async mode, maybe you have to wait for the Promise to be resolved...

How to access a function in a function with `this`

My question is similar to this.
However, mine runs in Node.js and it seems like a bit more complicated.
The server side wasn't built by me, but someone else that I can't contact. And he wrote code very differently.
And I have db.js and it looks like this:
And routes/email.js it uses db.js like this:
And when I click a button. I get this error:
db.emailRequest is not a function
in db.js, at the end of the file. It originally had this:
module.exports = new dbHelper;
And my style to use db.js in routers.
db.get().query(sql, input, function(err,res){
//TODO:
});
But it didn't work. So, I changed the end of db.js like this:
exports.get = function(){
console.log("exports.get");
return pool;
}
And also added some code in app.js like this:
db.connect(function(err){
if(err){
console.log('Unable to connect to MariaDB');
process.exit(1);
}
});
What should I do?
The full code of db.js is here:
const mariadb = require('mariadb');
var pool;
exports.connect = function(done){
console.log("Trying to connect DB...");
pool = mariadb.createPool({
host: 'localhost',
user: 'root',
password: 'xxxxxxx',
database:"XXXXX",
connectionLimit: 5 // Why 5 ???
});
pool.getConnection()
.then(conn => {
console.log("DB connected. id: " + conn.threadId);
conn.end(); //release to pool
}).catch(err => {
console.log("DB failed connection: " + err);
});
}
function makeToken(){
console.log("makeToken()");
var text = "";
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
for(var i=0;i<32;i++){
text+=possible.charAt(Math.floor(Math.random()*possible.length));
}
return text;
}
function dbHelper() {
console.log("dbHelper()");
this.emailRequest = function(email,num){
console.log("emailRequest");
pool.getConnection().then(conn => {
conn.query("INSERT INTO email_verification(email, code) VALUES(?,?)",[email,num]);
conn.end(); //release to pool
})
.catch(err => {
console.log("not connected due to error: " + err);
});
}
// wait and process until getting return value because rv is needed.
this.verify = async function(email,num){
console.log("verify");
let conn;
var result = false;
try {
conn = await pool.getConnection();
// within 3minutes
const rows = await conn.query("SELECT count(*) FROM email_verificaiton WHERE email=? AND code=? AND req_time >= NOW() - INTERVAL 3 MINUTE",[email,num]);
if(rows[0]["count(*)"]>0){
result = true;
}
} catch (err) {
throw err;
} finally {
if (conn) conn.end();
}
return result;
}
this.verifyUpdate = function(email,num){
console.log("verifyUpdate");
pool.getConnection()
.then(conn => {
conn.query("UPDATE email_verification SET status = 1 WHERE email=? AND code=?",[email,num]);
conn.end(); //release to pool
})
.catch(err => {
console.log("not connected due to error: " + err);
});
}
// wait and process until getting return value because rv is needed.
this.emailRegister = async function(email,pass,nick,devid){
console.log("emailRegister");
let conn;
var result;
try {
conn = await pool.getConnection();
var rows = await conn.query("SELECT count(*) FROM email_verification WHERE email=? AND status = 1",[email]);
if(rows[0]["count(*)"]>0){
rows = await conn.query("SELECT count(*) FROM member WHERE email=?",[email]);
if(rows[0]["count(*)"]==0){
var token = makeToken();
rows = await conn.query("INSERT INTO member (email,password,username,device_id,login_method,token) VALUES(?,?,?,?,0,?)",[email,pass,nick,devid,token]);
if(rows["affectedRows"]>0){
result = {result:true, code:200, message: "success",data:[{email:email,token:token}]};
} else{
result = {result:false,code:401, message:"db error"};
}
}else {
result = {result:false,code:402, message:"already registered id"};
}
} else {
result = {result:false,code:403, meesage:"email not verified"};
}
} catch (err) {
throw err;
} finally {
if (conn) conn.end();
}
return result;
}
// wait and process until getting return value because rv is needed.
this.emailLogin = async function(email,pass,devid){
console.log("emailLogin");
let conn;
var result;
try {
conn = await pool.getConnection();
rows = await conn.query("SELECT * FROM member WHERE email=?",[email]);
if(rows.length==1){
if(rows[0]["password"]==pass){
var token = makeToken();
rows = await conn.query("UPDATE member SET device_id = ?, token = ? WHERE email=?",[devid,token,email]);
console.log(rows)
if(rows["affectedRows"]>0){
result = {result:true,message:"Sign up Success.", code:200, data:[{email:email,token:token}]};
} else{
result = {result:false,message:"db error",code:401};
}
} else {
result = {result:false,message:"wrong password",code:402};
}
}else {
result = {result:false,message:"not registered id",code:403};
}
} catch (err) {
throw err;
} finally {
if (conn) conn.end();
}
return result;
}
}
//module.exports = new dbHelper;
exports.get = function(){
console.log("exports.get");
return pool;
}

Node.js mysql results to array

I've been slowly learning node.js so that I can integrate things better between a lot of our current ops (mysql) and Xero accounting.
I have several tables in mysql, one each for ["invoices","accounts","items","organisations","receipts","taxRates","users","trackingCategories"]
and each of those tables has a JSON column with the same name as the table it's in. This is NOT a json question.
Sending a query like ""select "+ wewant1[i] + " from "+wewant1[i]" is basically simple "select invoices from invoices" and easy to iterate through.
I can get the mysql results to list, but need to get each separate "list" as an array of results.
I would ultimately like to be able to reference the results from "select invoices from invoices" as an "invoices" array in node (invoices[0], invoices[1], etc).
I've tried avoiding "callback hell" and still cannot get this to work...
Any tips are very welcome!
Here is the current code:
var mysql = require('mysql');
var con = mysql.createConnection({
host: "10.0.1.103",
user: "badayaba",
password: "yadabuba",
database: "xeroetc"
});
(async function() {
let wewant1 = ["invoices", "accounts", "items", "organisations", "receipts", "taxRates", "users", "trackingCategories"];
function getmydata(sql, result, callback) {
var query = con.query(sql);
query.on('result', function(row) {
callback(null, row);
});
};
for (let i = 0; i < wewant1.length; i++) {
var sql = "select " + wewant1[i] + " from " + wewant1[i];
getmydata(sql, wewant1[i], function querydata(err, result) {
console.log(err || result);
return result;
});
};
con.end();
})();
20180910 22:00 GMT-6
Thanks Steven!
I think I got it with this:
const XeroClient = require('xero-node').AccountingAPIClient;
const XeroErrors = require('xero-node').XeroError;
var mysql = require('mysql');
const config = {
appType: "private",
consumerKey: "_____",
consumerSecret: "_____",
privateKeyPath: "../../../ssl/_____.pem"
};
var con = mysql.createConnection({
host: "_____",
user: "_____",
password: "_____",
database: "xeroetc"
});
(async function(){
let wewant1 = ["invoices","accounts","items","organisations","receipts","taxRates","users","trackingCategories"];
let xero = new XeroClient(config);
function getmydata(it, callback) {
var sql = "select "+it+" from "+it;
con.query(sql, function (err, result, fields) {
if (err) throw err;
callback(null,result);
});
};
const promises = wewant1.map(it => {
return new Promise((resolve, reject) => {
getmydata(it, function querydata(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
})
});
Promise.all(promises)
.then(results => {
//results is a array of the resolved promises
invoices=results[0];
accounts=results[1];
items=results[2];
organisations=results[3];
receipts=results[4];
taxRates=results[5];
users=results[6];
trackingCategories=results[7];
console.log(invoices);
})
.catch(err => {})
.then(() => {
con.end();
})
})();
Map your array to promises, and then use Promise.all. This also solves your unstated problem of closing your connection too early.
var mysql = require('mysql');
var con = mysql.createConnection({
host: "10.0.1.103",
user: "badayaba",
password: "yadabuba",
database: "xeroetc"
});
let wewant1 = ["invoices", "accounts", "items", "organisations", "receipts", "taxRates", "users", "trackingCategories"];
function getmydata(sql, result, callback) {
var query = con.query(sql);
query.on('result', function(row) {
callback(null, row);
});
};
const promises = weweant1.map(it => {
return new Promise((resolve, reject) => {
getmydata(sql, it, function querydata(err, result) {
if (err) {
reject(err);
} else {
resolve(result);
}
});
})
});
Promise.all(promises)
.then(results => {
//results is a array of the resolved promises
})
.catch(err => {})
.then(() => {
// then after catch is a finally block
con.end();
})
Of course you can also use async/await and get rid of the then nesting. You can additionally promisify getmydata. All use the same principle though: Wait on an array of promises.
Using async/await
If getmydata returned a promise or was declared async, the following snippet would do, assuming it was in an async function. So much cleaner...
const promises = weweant1.map(it => getmydata(sql, it))
try {
const results = await Promise.all(promises)
} catch (e) {
// handle error
} finally {
con.end();
}

Categories