Quak
Quak

Reputation: 7433

I can't receive data from custom module in node.js

I wrote a module called accountManager.js

var sqlite3 = require('sqlite3');

var db = new sqlite3.Database("./users.db");

exports.userExists = function userExists(nickName) {
    var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
    db.each(stmt,function(err,row) {
        if(row) {
            if(row.login==nickName) return true;
            else return false;
        }
    });
}

In my main app.js file I've got

var accountManager = require('./lib/accountManager');
console.log(accountManager.userExists('user1'));

This app says 'undefined' in console... I checked that module is working fine, I guess it's problem with callback? Please, give me some help, I don't understand what is wrong with this code...

Upvotes: 1

Views: 310

Answers (2)

ThiefMaster
ThiefMaster

Reputation: 318498

You need to understand how asynchronous functions and callbacks work.

Basically you cannot return anything inside the callback but need to invoke another callback which you pass to userExists.

var sqlite3 = require('sqlite3');
var db = new sqlite3.Database("./users.db");

exports.userExists = function userExists(nickName, cb) {
    var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
    db.each(stmt,function(err,row) {
        if(row) {
            cb(row.login == nickName);
        }
    });
}

To use it:

accountManager.userExists('user1', function(found) {
    console.log(found);
});

Besides that, your code has a gaping SQL injection hole and might not do what you intend to do. Here's a fixed version of the userExists function:

exports.userExists = function userExists(nickName, cb) {
    var stmt = 'SELECT COUNT(*) AS cnt FROM users WHERE login = ?';
    db.get(stmt, nickName, function(err, row) {
        cb(row.cnt > 0);
    });
};

Why is this better?

  1. You do not interpolate the value in the SQL string (which is bad, you would have to escape stuff to avoid SQL injection). Passing it separately is much cleaner and better
  2. You just want to know if a user exists. So retrieve the count (which will be exactly one row). If it's not zero the user exists.
  3. Now the callback is always invoked. In the first example that is more closely based on your code it would only be invoked in case a user has been found - most likely not what you wanted.

Upvotes: 2

David Pearson
David Pearson

Reputation: 86

You're returning a value from within the callback from db.each. However, this value is not returned by the outer function (userExists), which may return before the function passed to db.each is ever called.

You may want to provide a callback to the userExists function, like so:

exports.userExists = function (nickName, cb) {
    var stmt = 'SELECT * FROM users WHERE login="' + nickName + '"';
    var found=false;
    db.each(stmt,function(err,row) {
        if(row) {
            if(row.login==nickName) {
                found=true;
                cb(true);
            }
        }
    }, function () {
        if (!found) {
            cb(false);
        }
    });
}

Then, call it like:

 var accountManager = require('./lib/accountManager');
 accountManager.userExists('user1', function (found) {
     console.log(found);
 });

Upvotes: 0

Related Questions