0

All I want to do is run a query, check if an email address is already registered and if so reject the request, if not run some validation and then create the user in my users table. This is a bit of a shell, the code was originally based off https://github.com/vitaly-t/pg-promise-demo, that code is amazing, but I am not. Promises are completely nonsensical to me, I have no clue what I should be returning or where.

This code runs and achieves what it's supposed to, but then it hits the catch and send back "Cannot read property 'then' of undefined". When I try chaining the second .then so that it's not within the first .then() I get errors that I'm trying to alter res after it's already been sent.

Can someone please help me understand what's wrong here and how to fix it?

useradd: function (req, res) {
    db.users.findbyemail(req.body.email)
        .then(function(data){
            if( typeof data === undefined || data === null) {
                 db.users.add({
                    provider: 'local',
                    email: req.body.email, 
                    password: req.body.password, 
                    salt: 'salt', 
                    displayName: req.body.displayName })
                    .then(function(data){
                        res.json({
                            success: true,
                            data: "Account created"
                        })
                    }) 
            } else {
                 res.json({
                    success: false,
                    error: "Email address " + req.body.email + " is already registered on this site"
                })
            }
        })    

        .catch(function(error){
            res.json({
                success: false,
                error: error.message || error
            })
        })
}
  • "*I have no clue*" - you might want to have a look at [my rules of thumb](http://stackoverflow.com/a/25756564/1048572). – Bergi Sep 08 '16 at 12:06
  • If you are getting the error "Cannot read property 'then' of undefined" in the catch, that suggests that `db.users.add` does not return a promise - which, to me, sounds like a bug in the library. – Bergi Sep 08 '16 at 12:11
  • That can only happen when your method `users.add` fails to return a promise. @Bergi LOL, you posted it seconds ahead of me :) Though it is not library-related, method `users.add` is his own code ;) – vitaly-t Sep 08 '16 at 12:20
  • In addition, calling `db.users.add` instead of `return db.users.add` will result in code without a `.catch`. – vitaly-t Sep 08 '16 at 13:45
  • Thanks for the replies guys, I'm still not getting it. Based on Vitaly-T's responses (since he wrote both the library and the demo I'm basing this code off) I thought I would need to have a return before my call to db.users.add, so I tried: return db.users.add({ which still gives me the error. For Reference the add function in the users.js file looks like this in Vitaly-T's code: `add: name => rep.one(sql.add, name, user => user.id),` while mine looks like: `add: (values) => { rep.one(sql.add, values, user => user.id)},` where should I have a return? I – user2338041 Sep 08 '16 at 23:05
  • 1
    @user2338041 there's your problem right there, you do not return anything from the method. Are you seriously asking us now how to return a value from a function? :) – vitaly-t Sep 09 '16 at 11:54
  • @vitaly-t one of my many mistakes was wrapping my function in {} which stops the implied return, I see that now, I'm very new to arrow functions so that's wasn't something I was taking into consideration. Also, since I'm not yet up to speed on promises I was wondering if I needed to return something specific to get the expected results. Anyway thanks for taking the time to help with my questions. – user2338041 Sep 10 '16 at 03:26

1 Answers1

0

I eventually got something working, applying Bergi's rules did nudge me in the right direction and I also decided to refactor to use throws so there's only one success path and all other paths use .catch thus avoiding the altering res after it's been sent problem. Main code now looks like this:

useradd: function (req, res) {
    return db.users.findbyemail(req.body.email)
       .then(function(data){
           return module.exports.validateUser(data, req);
        })
        .then(function(){
            return db.users.add({
                provider: 'local',
                email: req.body.email, 
                password: req.body.password, 
                salt: 'salt', 
                displayName: req.body.displayName })  
        })
        .then(function(){
            res.json({
                success: true,
                data: "Account created"
            })
            return "acct created";
        }) 
        .catch(function(error){
            res.json({
                success: false,
                error: error.message || error
            })
        })
},
validateUser: function(data, req) {
    console.log("got to validateUser, data " + data + " req " + req);
    if (typeof data !== 'undefined' && data !== null) {
        throw new Error("Email address " + req.body.email + " is already registered on this site");
    } else {
        //validation goes here
        return null;
}
},

//with the db.users.add function modified from the version in my comment to:
add: (values)  => {    
        var reponeres = rep.one(sql.add, values);
        return reponeres; 
    },
  • 1
    You should consider use of [tasks](https://github.com/vitaly-t/pg-promise/wiki/Learn-by-Example#tasks) and [transactions](https://github.com/vitaly-t/pg-promise/wiki/Learn-by-Example#transactions) when executing multiple queries at once. – vitaly-t Sep 10 '16 at 15:28