I just followed the tutorial for authentication on node from scotch.io. They used mongodb as a backend, and I ported this to mysql. This is my first node app connecting to a database.
I used bluebird to promisify
the mysqljs/mysql
package in config/database.js
const mysql = require('mysql');
const Promise = require("bluebird");
Promise.promisifyAll(mysql);
Promise.promisifyAll(require("mysql/lib/Connection").prototype);
Promise.promisifyAll(require("mysql/lib/Pool").prototype);
Here is the code of my model/user.js
:
const mysqlPool = require('../../config/database'),
bcrypt = require('bcrypt-nodejs'),
Promise = require("bluebird");
getDb = function(){
return mysqlPool.getConnectionAsync();
}
let user = {
create(user, done) {
getDb().then((db) => {
return db.queryAsync(`insert into bot_users (name, token, type, external_id) values (?, ?, ?, ?)`,
[user.name, user.token, user.type, user.external_id])
}).then((results, fields) => {
console.log(results, fields)
user.id = results.insertId
return done(null, user)
})
},
There is something that does not look good to me:
getDb().then((db) => {
return db.queryAsync(...)
}).then(...)
looks somehow convoluted. I would like to have a variable db
that I could use directly as db.queryAsync(...).then(...)
, but I'm not able to find out how to assign such a promise to the variable db
.
Also I would like an advice on my approach. Is this a good approach to use promises here or is there a better one ?
Is it necessary to return done(null, user)
inside the then
callback in order to stick to the general node convention, or is this no longer required when using promises (bluebird) ?
The most important advice for any work with promises is: Ditch callbacks.
Your code currently is a hybrid between callbacks (done()
) and promises. Don't do that. Use promises exclusively. The key point of promises is that you can return something from your async functions. You don't need to rely on the calling side passing in a callback.
Promisify all APIs. Emphasize on returning things.
const Promise = require("bluebird"),
mysqlPool = Promise.promisifyAll(require('../../config/database')),
bcrypt = Promise.promisifyAll(require('bcrypt-nodejs'));
let user = {
create: params => mysqlPool
.getConnectionAsync()
.then(db => db.queryAsync(
'insert into bot_users (name, token, type, external_id) values (?, ?, ?, ?)',
[params.name, params.token, params.type, params.external_id]
))
.then((results, fields) => ({
name: params.name,
token: params.token,
type: params.type,
external_id: params.external_id,
id: results.insertId
}))
};
Note how user.create()
returns an unbroken chain of values. A mySQL connection turns into a query result turns into a new user object. I dislike overriding the existing instance. Avoid side-effects.
Usage is straight-forward.
user.create({
name: "foo",
token: 12345,
type: "user",
external_id: 67890
}).then(newUser => {
console.log(newUser);
}).catch(err => {
console.error(err);
});