To jest kod, który mam dla mojego polecenia ostrzegawczego, odczytuje go z bazy danych 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)

Po uruchomieniu wyświetla wiersz na konsoli, ale element osadzony jest pusty i nie zawiera pól. Problem polega na tym, że wysyła osadzenie, zanim otrzyma wyniki z db.each()

Db.each to wywołanie zwrotne, a nie obietnica, więc nie mogę używać await .then() itp.

Czy istnieje sposób na przekształcenie wywołania zwrotnego w obietnicę, abym mógł używać funkcji asynchronicznej

To jest pełny dziennik konsoli, nie ma błędów itp. tylko wiersze

{
  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'
}
0
mmoomocow 2 kwiecień 2020, 11:21

5 odpowiedzi

Najlepsza odpowiedź

Myślę, że byłoby to trochę czystsze, gdybyś zrobił to w ten sposób.

Zmień db.each na db.all, twój wiersz w wywołaniu zwrotnym będzie teraz wierszami

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)
    });
});

Pozwoliłoby ci to również spełnić obietnicę, jeśli chodzi o zbieranie wierszy. Następnie utworzyłbyś funkcję asynchroniczną i wywołał tę funkcję, która zwraca obietnicę. Oto ta funkcja.

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}`});
    })
}

Po rozwiązaniu wszystkich obietnic użyje metody embed.addFields, która pobiera tablicę obiektów javascript i zbiorczo dodaje pola. Wreszcie można wysłać osadzenie po zakończeniu całego przetwarzania.

Mam nadzieję że to pomoże,

1
awrfisher 9 kwiecień 2020, 17:12

Spójrz na to, stwórz nową obietnicę i zdecyduj, kiedy rozwiązać lub odrzucić, możesz po cichu zawieść odrzucone, jeśli zechcesz.

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
razki 8 kwiecień 2020, 23:38

Ponieważ chcesz uzyskać wspomniany identyfikator użytkownika, możesz użyć user.id w poleceniu SQL, więc w twoim przypadku musisz użyć następującego zapytania SQL:

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

W ten sposób będziesz mógł sprawdzić czyjś identyfikator użytkownika, a stamtąd znaleźć potrzebne informacje ostrzegawcze. Jeśli potrzebujesz więcej wyjaśnień, daj mi znać :)

0
GBadlon 7 kwiecień 2020, 17:34

Tomi Kordos miał prawie właściwą odpowiedź. Problem polega na wykonywaniu asynchronicznym. Jednak w tym przypadku sqllite używa wywołań zwrotnych zamiast obietnic, więc await i .then nie będzie działać, gdy zostanie użyty bezpośrednio w db.each.

Jest jednak sposób. Węzeł zapewnia narzędzie „promisify”. Działa to na każdej funkcji, której ostatnim parametrem jest pierwsze wywołanie zwrotne błędu, czyli dokładnie tym, czym jest db.each.

Najpierw musisz wprowadzić narzędzie.

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

Następnie utwórz obiecane odniesienie do funkcji.

const dbeachpr = promisify(db.each);

Teraz możesz użyć tego odwołania tak, jakby to była funkcja zwracająca obietnicę. W tym przypadku sugeruję przechowywanie ich w tablicy i używanie Promise.all do określenia, kiedy są gotowe.

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
Tarazed 8 kwiecień 2020, 20:54

Nie jestem pewien, ponieważ nie korzystałem z sqlite, ale zakładam, że próbujesz wysłać osadzenie, zanim pola zostaną faktycznie dodane. (Uruchamiasz funkcję synchronicznie)

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

Ustaw swoją funkcję jako asynchroniczną i użyj await db.each, aby czekała aż pętla się zakończy, wszystkie pola zostaną dodane, a następnie wyśle osadzenie.

Możesz też użyć .then()

1
Tomi Kordos 7 kwiecień 2020, 12:12