首页 > 解决方案 > pg-promise:返回查询结果的正确方法

问题描述

我想检查用户名是否已经在使用中pg-promise

我使用以下查询:

this.db.one('SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)', username);

我试图将此查询封装在一个函数中,如果用户名存在则返回 true,否则返回 false。

就像是:

existsUsername(username){
  this.db.one('SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)', username)
         .then(data => {
           if(data.exists == true){
             return true;
           } else {
             return false;
           }
         });
}

我可以像这样简单地使用:

if(db.users.existsUsername(username)){
  // this username is already taken
}

但是,在查询完成之前评估 if 条件,从而导致未定义的变量。

返回查询结果的正确方法是什么?

编辑:外部调用者执行多个异步检查并返回用户是否有效:

function signUp(username, email, ...){
  // perform username existence check existsUser(username)

  // perform email existence check existsEmail(username)

  // ...

  // if everything OK, put user in DB
}

标签: node.jsexpressasynchronouspg-promise

解决方案


最简单的做法:

existsUsername(username) {
  return this.db.oneOrNone('SELECT * FROM users WHERE username = $1 LIMIT 1', username, a => !!a);
}

然后使用它:

db.users.existsUsername(username)
   .then(exists => {
      // exists - boolean
   })
   .catch(error => {
   });

你不能做这样的事情if(db.users.existsUsername(username)),那就是把同步代码和异步代码混为一谈。但是if(await db.users.existsUsername(username)),如果您可以使用 ES7 语法,您可以这样做。


如果你有三个像这样的独立函数 ( checkUserName, checkEmail, checkWhateverElse) 并且想要全部执行它们,那么最好的方法是:

db.task(t => {
   return t.batch([checkUserName(t), checkEmail(t), checkWhateverElse(t)]);
})
.then(data => {
    // data = result of the batch operation;
})
.catch(error => {
   // error
});

与 ES7 语法相同:

db.task(async t => {
   const a = await checkUserName(t);
   const b = await checkEmail(t);
   const c = await checkWhateverElse(t);
   return {a, b, c};
})
.then(data => {
    // data = {a, b, c} object;
})
.catch(error => {
   // error
});

注意:这些函数中的每一个都应该针对t任务上下文执行查询,以便共享连接。


推荐阅读