I'll try to explain this as briefly as possible but the question is long (I know). I have to show you the structure of the code so you can understand why I need to do what I am hopelessly trying to!
I'm working on an Electron/AngularJS project which uses SQLite as its database. I have installed the 'node-sqlite3' npm package and the problem is with my usage of one of this package's APIs.
There is a login page that needs to do simple login stuff, e.g. check the username and password provided by the user, to the ones stored in the database.
For the sake of testing, I am just checking the username input and returning that user's 'username' plus 'password' in an object; really simple... or so I thought.
The process includes 2 Angularjs services, one 'Login.controller' and the view for the login page.
The code for each one is shown below:
Login.view.html :
<md-button ng-click="vm.login(vm.username)"> Login </md-button>
vm.username
is the username field that the user types into.
vm.login()
is a function inside the Login.controller.
Login.controller.js :
function LoginController($scope, authService, dbService) {
var vm = this;
//=== Variables ===//
vm.username = '';
//=== Function declarations ===//
vm.login = login;
//=== Function implementations ===//
function login(username) {
authService.authUser(username);
}
}
I have also used 'requirejs' in this project so I have omitted the lines about dependency injection and 'define'. The controller works fine.
authService
is the service responsible for further authentication stuff but for now doesn't have much in it.
dbService
is the service which connects to SQLite database and (hopefully later) performs the queries and returns the results to other services/controllers which need them.
As shown in the code, login()
function accepts a username
parameter and passes the data to authUser
function in authService
.
authService.js :
function authService(dbService) {
// The main service object which is exposed to other components.
var exposedObj = {
authUser: authUser
};
return exposedObj;
//=== Function implementations ===//
function authUser(username) {
dbService.findUser(username);
}
}
As you can see, this service also connects to dbService
.
authUser()
does the same thing as login()
function did in the controller; accepts the username and passes it along to findUser()
function in dbService
. As I said earlier, these are just baby steps, so forgive the redundancy of files and services, they are meant to be filled with meaningful code later on.
dbService.js :
function dbService() {
.
.
.
//=== Function implementations ===//
function findUser(username) {
var result = {};
let sql = `SELECT username, password
FROM auth_user
WHERE username = ?;`;
db.serialize(() => {
db.get(sql, username, (err, row) => {
if (err) {
console.error(err);
}
result = row;
});
});
return result;
}
}
The database connection and other irrelevant lines have been removed. This is the actual pit that I'm stuck at.
The query results in ONE row only which is an Object and that is the guy whom I'm after.
I have defined a result
object at the top and that is the main thing that I want to return from findUser()
function.
Therefore, the result of the query should be poured into result
object. If this is to happen, I can easily use the returned value of findUser()
in the previous service (authService
) and move forward in my code.
At the moment, the line return result
naturally returns nothing, an empty object. The node-sqlite .get()
(here) function is an asynchronous function. Therefore, return result
is executed earlier than result = row;
. Ultimately I just want to fill the result
object.
I have to mention that I have tried Promises, async/await
and another solution mentioned here and also here. None of them were helpful. It is most probably me who hasn't understood those solutions properly and implemented them wrong, but either way, I have been stuck with this seemingly simple problem for several hours. Any help is truly appreciated.
Purya
** *EDIT:
If anyone ever gets stuck in async calls and comes here along their way, I've got the solution:
The last file (dbService.js
) should be changed to return a Promise. This example may help your problem:
function findUser(username) {
let sql = `SELECT username, password
FROM auth_user
WHERE username = ?;`;
return new Promise((dbResolve, dbReject) => {
db.serialize(() => {
db.get(sql, username, (err, res) => {
if (err) dbReject(err);
dbResolve(res);
});
});
});
}
And on your recieving end (the function which needs the result of this Promise), you can do something like this:
let dbPromise = dbService.findUser(username);
dbPromise
.then((dbResolve) => {
/* do something with the result which is inside "dbResolve" */
})
.catch((dbReject) => {
console.log(dbReject);
});