Monday, May 20, 2024
 Popular · Latest · Hot · Upcoming
162
rated 0 times [  167] [ 5]  / answers: 1 / hits: 25401  / 11 Years ago, wed, february 12, 2014, 12:00:00

I'm writing a simple server/client to keep track of the amount of times a user has logged in. A user can create an account and have their count set to 1. Following logins will increase their count in the backend SQLITE3 database.



In the example below, I run the add function which correctly checks if the user exists already, then if not, adds the username, password, and 1 to the table of users.



This properly returns 1 as you can see in the output, but why is it erroring at the end? I'm not making any other calls, but it's returning a no such table error. The only call I make is console.log(UsersModel.add('kpam', '123'));, which is on the last line of the code. I tried looking into the line 72 of events.js, but it didn't really give me much. I added print statements to make it trace more obvious, but I have a feeling something is going on behind the scenes?



Basically, I'm confused why if I only called one function, and that function returns successfully, theres an error at the end of execution?



Here is the error returned:



:$ node warmup.js 
Creating DB file.
making table!
adding user!
1

events.js:72
throw er; // Unhandled 'error' event
^
Error: SQLITE_ERROR: no such table: Users
:$


And here is my code:



var http = require('http');

var fs = require('fs');
var file = 'data.db';
var exists = fs.existsSync(file);

if (!exists) {
console.log(Creating DB file.);
fs.openSync(file, 'w');
}

var sqlite3 = require('sqlite3').verbose();
var db = new sqlite3.Database(file);

var UsersModel = {

// success, no errors/problems
SUCCESS: 1,

// cannot find the user/password pair in the database (for 'login' only)
ERR_BAD_CREDENTIALS: -1,

// trying to add a user that already exists (for 'add' only)
ERR_USER_EXISTS: -2,

// invalid user name (empty or longer than MAX_USERNAME_LENGTH) (for 'add'/'login')
ERR_BAD_USERNAME: -3,

// invalid password name (longer than MAX_PASSWORD_LENGTH) (for 'add')
ERR_BAD_PASSWORD: -4,

// maximum user name length
MAX_USERNAME_LENGTH: 128,

// maximum password length
MAX_PASSWORD_LENGTH: 128,

login: function(user, password) {
if (!UsersModel.userExists(user, false)) {
return UsersModel.ERR_BAD_CREDENTIALS;
}

if (!UsersModel.checkPassword(user, password)) {
return UsersModel.ERR_BAD_CREDENTIALS;
}

count = UsersModel.increaseCount(user);
return count;
},

add: function(user, password) {
if (UsersModel.userExists(user, true)) {
return UsersModel.ERR_USER_EXISTS;
}

if (!UsersModel.isValidUsername(user)) {
return UsersModel.ERR_BAD_USERNAME;
}

if (!UsersModel.isValidPassword(password)) {
return UsersModel.ERR_BAD_PASSWORD;
}

UsersModel.addUser(user, password);
return 1;
},

userExists: function(user, makeTable) {
if (!exists) {
if (makeTable) {
console.log('making table!');
db.run('CREATE TABLE Users (name TEXT, password TEXT, count INT)');
}
return false;
}

db.serialize(function() {
console.log('checking user!');
row = db.get(SELECT name FROM Users WHERE name = ' + user + ');
});

return !(typeof(row.name) === 'undefined');
},

increaseCount: function(user) {
db.serialize(function() {
console.log('increasing count!');
count = db.get(SELECT count FROM Users WHERE name = ' + user + ') + 1;
db.run(UPDATE Users SET count = ' + count + ' WHERE name = ' + user + ');
return count;
});
},

addUser: function(user, password) {
count = 0;
console.log('adding user!');
db.run(INSERT INTO Users (name, password, count) VALUES (' + user + ',' + password + ',' + 0 + '));
},

checkPassword: function(user, password) {
db.serialize(function() {
console.log('checking pw!');
row = db.get(SELECT password FROM Users WHERE name = ' + user + ');
});

return row.password == password;
},

isValidUsername: function(user) {
return user.length < 129;
},

isValidPassword: function(password) {
return password.length < 129;
}
}

console.log(UsersModel.add('kpam', '123'));

More From » node.js

 Answers
12

The db.run(...) calls are asynchronous. So they return immediately, and look like success to your code. However they're still running in the background. Because of this, the SELECT statement is likely starting to run before the CREATE TABLE completes. And that's why you get that error.



I notice that the SELECT statement is inside of a db.serialize(...) call. Unfortunately, that call only serializes statements that are directly inside its scope. All calls outside of the serialize block continue to run in parallel (this includes the INSERT statement that comes up later).



Your code needs to be restructured to use the callbacks that the node sqlite3 module relies on. Take a look at the simple example at:
https://github.com/mapbox/node-sqlite3/blob/master/examples/simple-chaining.js



Notice how the last parameter to each db operation is the name of the function to call after the operation is completed.


[#72578] Monday, February 10, 2014, 11 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
jazminkyrap

Total Points: 631
Total Questions: 89
Total Answers: 109

Location: Finland
Member since Fri, Oct 21, 2022
2 Years ago
;