asyn c получить данные из базы данных sqlite в nodeJS - PullRequest
0 голосов
/ 02 апреля 2020

это код, который у меня есть для моей команды предупреждения, она читает из базы данных sqlite.

user = message.mentions.users.first()
embed = new Discord.MessageEmbed()
    .setTitle(`warnings of ${user.username}`)
    .setTimestamp()
    .setFooter('shadowcraft - **Test Mode!!**');

sql = 'SELECT * from moderation WHERE userID = ?'
db.each(sql, [user.id], (err, row) => {
    if (err) throw err;
    mod = client.user.fetch(toString(row.moderatorID))
    console.log(row)
    embed.addField(`${mod.tag}`, `${row.reason} \n${row.date}`);
});
message.channel.send(embed)

Когда я ее запускаю, она печатает строку в консоли, но код для вставки пуст и имеет нет полей Проблема в том, что он отправляет встраивание до получения результатов от db.each()

db.each - это обратный вызов, а не обещание, поэтому я не могу использовать await .then() et c

Есть ли способ превратить обратный вызов в обещание, чтобы я мог использовать функцию asyn c

это полный консольный журнал, ошибок нет и c только строки

{
  id: 1,
  date: '2020-04-02',
  userID: 'some user id',
  action: 'WARN',
  reason: 'some reason',
  moderatorID: 'some user id'
}
{
  id: 2,
  date: '2020-04-02',
  userID: 'some user id',
  action: 'WARN',
  reason: 'some reason',
  moderatorID: 'some user id'
}

Ответы [ 5 ]

1 голос
/ 09 апреля 2020

Я думаю, было бы немного чище, если бы вы сделали это таким образом.

Измените db.each на db.all, теперь ваша строка в обратном вызове будет теперь иметь строки

user = message.mentions.users.first()
embed = new Discord.MessageEmbed()
    .setTitle(`warnings of ${user.username}`)
    .setTimestamp()
    .setFooter('shadowcraft - **Test Mode!!**');

sql = 'SELECT * from moderation WHERE userID = ?'

db.all(sql, [user.id], (err, rows) => {
    if (err) throw err;
    Promise.all(rows.map((row) => {
        return processRow(row)
    })).then(result => {
        embed.addFields(result);
        message.channel.send(embed)
    });
});

Это также позволит вам выполнить обещание все в коллекции строк. Затем вы должны создать асинхронную функцию c и вызвать эту функцию, которая возвращает обещание. Вот эта функция.

var processRow = async function(row) {
    return new Promise((resolve, reject) => {
        let mod = client.user.fetch(toString(row.moderatorID))
        console.log(row);
        resolve({name: mod.tag, value: `${row.reason} \n ${row.date}`});
    })
}

После того, как все обещания будут разрешены, он будет использовать метод embed.addFields, который принимает массив объектов javascript и добавляет поля оптом. Наконец, можно отправить код для вставки после завершения всей обработки.

Надеюсь, это поможет,

1 голос
/ 08 апреля 2020

У Томи Кордоса почти был правильный ответ. Проблема заключается в асинхронном выполнении. Однако в этом случае sqllite использует обратные вызовы вместо обещаний, поэтому ожидайте и .then не будет работать при непосредственном использовании в db.each.

Однако есть способ. Узел предоставляет утилиту «обещание». Это работает для любой функции, чей последний параметр является обратным вызовом «ошибка в первую очередь», и это именно то, чем является db.each.

Сначала необходимо ввести утилиту.

const {promisify} = require('util');

Затем создайте Обещанная ссылка на функцию.

const dbeachpr = promisify(db.each);

Теперь вы можете использовать эту ссылку, как если бы это была функция, возвращающая обещание. В этом случае я предлагаю сохранить их в массиве и использовать Promise.all, чтобы определить, когда они закончатся.

user = message.mentions.users.first()
embed = new Discord.MessageEmbed()
    .setTitle(`warnings of ${user.username}`)
    .setTimestamp()
    .setFooter('shadowcraft - **Test Mode!!**');

sql = 'SELECT * from moderation WHERE userID = ?'
let promises = [];
promises.push(dbeachpr(sql, [user.id]).then(row => {
        mod = client.user.fetch(toString(row.moderatorID))
        console.log(row)
        embed.addField(`${mod.tag}`, `${row.reason} \n${row.date}`);
    }).catch(err => throw err); // You may want do something more useful with this.
);

Promise.all(promises).then(() => message.channel.send(embed));
1 голос
/ 07 апреля 2020

Я не уверен, так как я не использовал sqlite, но я предполагаю, что вы пытаетесь отправить embed до того, как поля будут фактически добавлены. (Вы запускаете функцию синхронно)

https://www.npmjs.com/package/sqlite#each

Сделайте вашу функцию асинхронной c и используйте await db.each, поэтому она будет ждать, пока l oop закончен, все поля добавлены, затем отправьте код для вставки.

Или вы можете использовать .then()

0 голосов
/ 09 апреля 2020

Посмотрите на это, создайте новое обещание и решите, когда разрешить или отклонить, вы можете молча отказаться от отклонения, если захотите.

const updateField = db =>
    new Promise((resolve, reject) => {
        db.each(
            'SELECT * from moderation WHERE userID = ?',
            (err, row) => {
                if (err) {
                    reject(err)
                } else {
                    mod = client.user.fetch(toString(row.moderatorID))
                    embed.addField(`${mod.tag}`, `${row.reason} \n${row.date}`)
                }
            },
            (err, _) => {
                if (err) {
                    reject(err)
                } else {
                    resolve()
                }
            }
        )
    })

module.exports.main = async () => {
    //no idea what your imports/other code looks like...

    user = message.mentions.users.first()
    embed = new Discord.MessageEmbed()
        .setTitle(`warnings of ${user.username}`)
        .setTimestamp()
        .setFooter('shadowcraft - **Test Mode!!**')

    await updateField(db)

    message.channel.send(embed)
}
0 голосов
/ 07 апреля 2020

Поскольку вы хотите получить упомянутый идентификатор пользователя, вы можете использовать user.id в команде SQL, поэтому в вашем случае вам нужно использовать следующий запрос SQL:

`SELECT * from moderation WHERE userID = ${user.id}`

Таким образом, вы сможете запросить чей-то идентификатор пользователя и найти необходимую информацию для предупреждения. Если вам нужно больше объяснений, дайте мне знать:)

...