Reputation: 19895
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) ?
Upvotes: 2
Views: 5795
Reputation: 11173
There are now at least two npm libraries to provide Node access to MySQL with Promises:
node-mysql2 has its own "promise wrapper"
promise-mysql - "...a wrapper for mysqljs/mysql that wraps function calls with Bluebird promises"
mysql2-promise - "...small promises wrapper for mysql2, it's forked and compatible with mysql-promise"
Upvotes: 1
Reputation: 338158
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);
});
Upvotes: 1
Reputation: 2040
You can simple return a promise from create
method of the user
model.
create(user) {
return 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 user;
})
},
This promise will then resolve with the value of the user. So anywhere else you can use the method as
User.create(user)
.then(createdUser => { // do something with user here })
If you have access to latest versions of node (anything above 8), you can use async-await
, to make the code even more simpler to understand.
async create(user) {
const db = await getDb();
const results = await db.queryAsync(`insert into bot_users (name, token, type, external_id) values (?, ?, ?, ?)`,
[user.name, user.token, user.type, user.external_id]);
user.id = results.insertId;
return user;
},
An async
function can be called like any other function, but it will return a promise which will resolve with the value returned. So the usage of the method still remains the same.
User.create(user)
.then(createdUser => { // do something with user here })
Upvotes: 1