NodeJS mysql2 Bluebird? - javascript

Been testing mysql vs mysql2, seems like 2 has made some improvments however it's not an exact drop in replacement. At the same time Q is a good library which seems easier to integrate with however bluebird seems to take less memory and run faster so...
My current mysql-bluebird connector is as follows and allows for straight forward use of query('SELECT email FROM users.users WHERE id=?',id).then(function(res){var email=res[0][0];});
/* global module, require */
var conf=require('./conf.js').conf;
var mysql = require('mysql');
var Promise = require('bluebird');
var using = Promise.using;
Promise.promisifyAll(require('mysql/lib/Connection').prototype);
Promise.promisifyAll(require('mysql/lib/Pool').prototype);
var pool = mysql.createPool(conf.mysql);
var getConnection = function () {
return pool.getConnectionAsync().disposer(function (connection) {
return connection.release();
});
};
var query = function (command) {
return using(getConnection(), function (connection) {
return connection.queryAsync(command);
});
};
function queryWrapper(q,a){
if(a){
return query(mysql.format(q,a));
}
else{
return query(mysql.format(q));
}
}
module.exports = {
query: queryWrapper
};
So far my attempts ad doing this with mysql2 haven't panned out.
Does anyone have any insights on how to convert this?
Thanks, Jegsar

You can use mysql2-promise. It's a simple wrapper, using q, that promisifies mysql2. If you'd rather use Bluebird, you can look at how this wrapper was created and do it yourself.

node-mysql2 now has Promise api built in, and you can choose which promise implementation you want to use
var mysql = require('mysql2/promise');
mysql.createConnection({
Promise: require('bluebird'), // if not set, global Promise is used
user: 'foo',
password: 'bar',
database: 'baz'
})
.then((conn) => conn.query('select 1+1 as test'))
.then(([rows, fields]) => console.log(rows[0]))

Related

Code not breaking after promise has been executed

I currently have an issue in Node.js whereby I make a call to a mysql database using the promise-mysql and bluebird packages. I followed the tutorials on the webpage and it seems to work. I keep ending up with a timeout error as once the database has been queried the process doesn't break (if that's the right term) and I either have to terminate the process using ctrl + c or when testing on Alexa when the skill replies with there was a problem. Is there a way to end the promise and db connection once I have retrieved the value of my query? Below is an example of the code.
index.js
'use strict';
const Alexa = require('alexa-sdk');
const mysql = require('promise-mysql');
const querydb = require('./sqlQuery.js');
const insertdb = require('./sqlInsert.js');
var testSQL = 'SELECT weight, height from users where pin=1100';
var valuesPromise = querydb.getItem(testSQL);
valuesPromise.then((result)=>{
rows = result.height;
row2 = result.weight;
console.log(rows);
console.log (row2);
return true;
}).catch(function(error){
console.log (error);
});
databaseConnection.js
var mysql = require('promise-mysql');
pool = mysql.createPool({
host: "hostURL",
database: "dbName",
user: "dbUser",
password: "dbPassword",
connectionLimit: 1
});
function getSqlConnection() {
return pool.getConnection().disposer(function(connection) {
pool.releaseConnection(connection);
});
}
module.exports = getSqlConnection;
sqlQuery.js
var Promise = require("bluebird");
var getSqlConnection = require('./databaseConnection');
function getItem(sql){
return Promise.using(getSqlConnection(), function(connection) {
return connection.query(sql).then(function(rows) {
return rows[0];
}).catch(function(error) {
return (error);
});
})
};
module.exports.getItem = getItem;
Since you are in node process you can just exit from it with process.exitCode = 1 and then process.exit() or process.exit(1).
Here is the documentation.
That however is not the best practice. The easiest way would be to just throw an error:
throw "Exit!" or some error you would like to catch and re-throw to exit (in the scenario where you have a catch statement)

the complications in javascript node.js?

I've learned node.js and javascript lately. I loved node.js a lot, but I am working on a project coded in node.js, mongodb, cordova etc. I notice that I needed to use Promise Object in the code a lot.
I create a module in the project to query the db and bring results. In every exported function I need to declare a local function, then use promise, for example:
I have the following local functions in the Module:
var Initialize = function() {
return new Promise(function(resolve, reject) {
try {
MongoClient.connect("db_url_conn", function(err, database) {
if (err) return console.log(err)
db = database;
return resolve(db);
})
} catch (e) {
console.error(e);
}
});
};
then in every exported function in the module I needed to use:
mongoOperation.prototype.getLength = function() {
Initialize(function(db) {
return db;
}).then(function(db) {
getSize(db).then(function(length) {
console.log(length);
});
});
}
The Question is:
Is that normal according to the nature of node.js and JavaScript nature to use promise a lot?
Do I have any other choices to fulfill that?
Since MongoClient.connect() already returns a promise, you can simplify your code:
var Initialize = function() {
return MongoClient.connect("db_url_conn");
};
...
Initialize().then(function(db) { ... });
However, this will create a new client each time you call Initialize, where you should be reusing the client for better performance and to leverage the built-in connection pool:
var client = MongoClient.connect("db_url_conn");
var Initialize = function() { return client };

How to reuse a mongo connection with promises

How can I change things around in my db connection call so that I can do db.collection():
// Create a Mongo connection
Job.prototype.getDb = function() {
if (!this.db)
this.db = Mongo.connectAsync(this.options.connection);
return this.db;
};
// I want to be able to do this
Job.prototype.test = function() {
return this.db.collection('abc').findAsync()...
};
// Instead of this
Job.prototype.test = function() {
return this.getDb().then(function(db) {
return db.collection('abc').findAsync()...
});
};
My code always calls getDb so the connection does get created so that is not an issue. ex:
this.getDb().then(test.bind(this));
But I actually string many of these calls around so looking for a cleaner approach.
This works - just wondering if there an overall better approach to dealing with this.
Job.prototype.getDb = function(id) {
var self = this;
return new P(function(resolve, reject) {
if (!self.db) {
return Mongo.connectAsync(self.options.connection)
.then(function(c) {
self.db = c;
debug('Got new connection');
resolve(c);
});
}
debug('Got existing connection');
resolve(self.db);
});
};
I suppose this is really just a mongo connection issue, perhaps not just promises. All the Mongo examples I see either just make all their calls inside of the connect callback or use some framework like Express and assign it on start.
I want to be able to do this
return this.db.collection('abc').findAsync()
No, that's impossible when you don't know whether the database is already connected or not. If you might need to connect at first, and that is asynchronous, then this.db must yield a promise, and you'll need to use then.
Notice that with Bluebird you can shorten that code a bit, and avoid that verbose .then() callback by using the .call() method:
Job.prototype.getDb = function() {
if (!this.db)
this.db = Mongo.connectAsync(this.options.connection);
return this.db;
};
Job.prototype.test = function() {
return this.getDb().call('collection', 'abc').call('findAsync');
};

Nodejs delay return for "require"

My setup is as follows:
Nodejs Server
server.js requires utils.js
utils.js loads data from mongodb into memory and exports it
server.js uses a variable that utils.js exports
The issue that I am worried about is the fact that the mongodb call is asynchronous. utils.js returns before the mongodb call is finished, meaning that server.js will use an undefined variable when it continues execution after the require.
What is the best to address this issue? The only thing I could think of is wrapping my server.js code in a giant callback and pass that to the function that makes the mongodb call. It seems a bit messy to me, is there a better way to do it?
Code:
server.js
var utils = require("./modules/utils.js");
console.log(utils);
//Do whatever
utils.js
var mods = [];
var db = require("mongojs").connect("localhost", ["modules"]);
db.modules.find({}, function(err, modules){
mods = modules;
});
module.exports = mods;
What you're referring to is called "callback hell". The easiest way to get out of that is to use a Promise library that simplifies it.
I used a node package called bluebird.
var mysql = require("mysql");
var hash = require("password-hash");
var Promise = require("bluebird");
var settings = require("../settings");
Promise.promisifyAll(require("mysql/lib/Connection").prototype);
Promise.promisifyAll(require("mysql/lib/Pool").prototype);
var db_config = {
user:settings.db.user,
password:settings.db.password,
database:settings.db.database
};
var con = mysql.createPool(db_config);
function query(sql) {
return con.getConnectionAsync().then(function(connection) {
return connection.queryAsync(sql)
.spread(function(rows,fields) {
return rows;
}).finally(function() {
connection.release();
});
});
}
This is a very basic database module I wrote that uses bluebird to promisify the database object.
And here's how it's used. It returns a promise! The benefit here is that not only does it return the clutter of callback hell, it makes sure that your code runs asynchronously and the function does not return before things have stopped processing, like in this case, a database query.
function login(user) {
//check for player existance
var query = 'SELECT p.name,p.password,p.id, pd.x, pd.y FROM player p INNER JOIN player_data pd ON p.id = pd.id WHERE p.name='+mysql.escape(user);
return db.select(query).then(function(rows) {
if (!rows.length) return;
return [
rows[0]
];
});
}
Notice how you return a promise, so that you call the then or spread method to get those database values you just queried, not having to worry about if rows will be undefined by the time you want to use it.
As you say, you need to wrap the entire server in a callback. Node.js works this way, it's asynchronous by nature. A server needs to pass through 3 stages: init, serve and deinit. In your case, that database code goes inside the init stage. You could write something like this.
//server.js
var utils = require ("./modules/utils");
var init = function (cb){
//init the utils module, the http server and whatever you need
utils.init (function (error){
if (error) return handleError (error);
cb ();
});
};
var serve = function (){
//Start listening to the http requests
};
var deinit = function (cb){
//This is typically executed when a SIGINT is received, see link1
};
init (serve);
//utils.js
//You could write a wrapper for the db instance, see link2
var mongodb = require ("mongojs");
var db;
module.exports.init = function (cb){
db = mongodb.connect ("localhost", ["modules"]);
db.modules.find ({}, function (err, modules){
if (err) return cb (err);
cb (null, modules);
});
};
I don't recommend using promises, they are slower than raw callbacks. You don't need them at all.
link1 - SIGINT
link2 - db wrapper

How to use node sqlite3 with q (promise)

I'm trying to use the promise with sqlite3. Here is a part of my source code:
this.deleteTag = function(tag, project){
var db = this.db;
if (project){
return q.nfcall(db.run, "DELETE FROM tag2project WHERE tag = ? AND project = ?",
[tag.id, project.id]);
}else{
return q.all([
q.nfcall(db.run, "DELETE FROM tag2project WHERE tag = ?", [tag.id]),
q.nfcall(db.run, "DELETE FROM tags WHERE id = ?", [tag.id])
]);
}
};
But those promises only enter in .fail where error is:
[TypeError: Database object expected]
Searching for this error only got me to the sourcecode of sqlite itself https://github.com/joyent/smartos-live/blob/master/src/node-sqlite3/src/statement.cc#L91
The old version using simple callback is working so there is not error in this.db or the sql query.
I think db.run is not function but method. from Q doc:
If you are working with methods, instead of simple functions, you can
easily run in to the usual problems where passing a method to another
function—like Q.nfcall—"un-binds" the method from its owner. To avoid
this, you can either use Function.prototype.bind or some nice
shortcut methods we provide:
return Q.ninvoke(redisClient, "get", "user:1:id");
return Q.npost(redisClient, "get", ["user:1:id"]);
But I always use Q.denodeify or Q.nbind. it is cleaner.
You can also create reusable wrappers with Q.denodeify or Q.nbind:
var readFile = Q.denodeify(FS.readFile);
return readFile("foo.txt", "utf-8");
var redisClientGet = Q.nbind(redisClient.get, redisClient);
return redisClientGet("user:1:id");
You could bind the object that you created when you promisify the function.
Example
const { promisify } = require('util');
const db = new lib_sqlite3.Database(_dirname + '/your-db-path');
const runAsync = promisify(db.run.bind(db));

Categories

Resources