Pg-обещание: правильный способ возврата результата запроса - PullRequest
0 голосов
/ 03 мая 2018

Я хочу проверить, используется ли уже имя пользователя, используя 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
}

Ответы [ 2 ]

0 голосов
/ 03 мая 2018

Самый простой способ сделать это:

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 - контексту задачи, чтобы разделить соединение.

0 голосов
/ 03 мая 2018

Вы не можете использовать асинхронную операцию синхронно, вам нужно переписать код, который проверяет, существует ли пользователь асинхронно. I.e.:

// returns a promise 
function existsUsername(username){
   return this.db.one('SELECT EXISTS(SELECT 1 FROM users WHERE username = $1)', username);
}

И затем используйте его в приложении, как

db.users.existsUsername(username)
   .then( data => {
      data.exists ? handleUserExistsAsync() : handleUserNotExistsAsync();
   })
   .catch( err => {
      // some err occurs, db fail or something
      // however, you can catch it in an upper level
   });

РЕДАКТИРОВАТЬ: Использование Promise.all для нескольких задач, может иметь проблемы с производительностью и подключением (как упоминал Виталий).

Лучше использовать db.batch внутри db.task

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...