2

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);
        });
Purya.A
  • 43
  • 4
  • 2
    If you have one asynchronous operation, then your whole function becomes asynchronous and you simply cannot return a synchronous value that has anything to do with the asynchronous operation. You just can't. Your function is now asynchronous and you need to return your value either via a callback or a promise. Your options are spelled out here: [How do I return response from an asynchronous call](https://stackoverflow.com/questions/14220321/how-do-i-return-the-response-from-an-asynchronous-call/14220323#14220323). `await` will not change things. – jfriend00 Mar 14 '18 at 14:48
  • @jfriend00 Thanks for answering and closing the question so quickly. Actually, I have read those notes before and was not able to implement them. I will try again anyway. – Purya.A Mar 14 '18 at 14:56
  • Your function will need an asynchronous interface, not a synchronous one for returning its value. I would suggest you learn the promise interface to your database and return that promise from your function. The caller will then use `.then()` on that promise to obtain the value. – jfriend00 Mar 14 '18 at 14:59
  • @jfriend00 I believe I got the general idea, will change accordingly. Thanks a lot again. – Purya.A Mar 14 '18 at 15:02
  • If you get stuck in trying to implement this, then post another question and show your actually code where you're trying to implement an asynchronous interface and folks can help you get it right. – jfriend00 Mar 14 '18 at 15:03

0 Answers0