【问题标题】:SQLite "SELECT" wrapper function returns empty objectSQLite“SELECT”包装函数返回空对象
【发布时间】:2019-07-03 10:20:30
【问题描述】:

我正在使用 Electron 与 Node.js 和 SQLite 3 制作一个简单的应用程序。我的目标是用我的函数来完成一个基本的 SELECT 查询。但是,它无法从数据库中获取内容。

我知道我可以像这样选择一行的firstname 列:

storage.all('select firstname from users where id = 1', [], ( err, rows ) => {
    if ( err ) {
        throw `Error while retrieving ${q}`;
    };
    rows.forEach(( row ) => {
        n.webContents.send( 'userName', row.firstname );
        console.log( 'query output sent: ' + row.firstname );
    });
});

storage 这里是我的设置数据库。上面的工作很好,允许我将我的用户名发送到我的前端视图。

但如果我将它包装成如下函数:

let select = ( items, db, where, sign, whereNew ) => {
    // preset sql query
    let q = `select ${items} from ${db}`;
    if ( where && sign && whereNew ) { q += ` where ${where} ${sign} ${whereNew}`};
    let arr;
    console.log(q);

    // perform query on the database
    return storage.each(q, [], ( err, row ) => {
        if ( err ) {
            throw `Error while retrieving ${q}`;
        };
        return row[items];
    });
};

然后我的控制台上的输出将是一个空的Database 对象(见下文)。

这就是我调用此函数并将其记录在控制台中的方式:

let u = select( 'firstname', 'users', 'id', '=', 1 );
console.log( 'this log ' + u );

这是控制台输出:

> szwaczki-react@0.1.0 dev /Users/middleman/Documents/Programowanie/MyApps/szwaczki-react-sqlite
> concurrently "BROWSER=none npm run start" "wait-on http://localhost:3000 && electron ."

[0]
[0] > szwaczki-react@0.1.0 start /Users/middleman/Documents/Programowanie/MyApps/szwaczki-react-sqlite
[0] > react-scripts start
[0]
[0] Starting the development server...
[0]
[1] Connected to the database.sqlite
[0] Compiled with warnings.
[0]
[0] ./src/app.js
[0]   Line 2:  'ReactDOM' is defined but never used  no-unused-vars
[0]
[0] ./src/view/button.js
[0]   Line 2:  'ReactDOM' is defined but never used  no-unused-vars
[0]
[0] Search for the keywords to learn more about each warning.
[0] To ignore, add // eslint-disable-next-line to the line before.
[0]
[1] select firstname from users where id = 1
[1] this log [object Database]
[1] query output sent: Mateusz
^C[0] BROWSER=none npm run start exited with code 0
[1] wait-on http://localhost:3000 && electron . exited with code 0

我做错了什么?

【问题讨论】:

  • 能否显示console.log(q)输出
  • 我已经编辑了原始帖子以添加这些信息
  • [object Database] 在控制台输出中并不表示空对象。它只是说该对象是Database 的一个实例。但是,该查询的返回值是 Database 实例而不是像前者的结果那样的字符串,这似乎很奇怪。除此之外,each function does not seem to take 3, but rather two arguments (documentation)...
  • 有趣的是,当我删除第二个参数时,即使我使用“所有”函数而不是每个函数,我也会得到相同的输出。那么如果它不是一个空对象并且它包含某种返回的内容,我该如何检索它呢?

标签: javascript node.js sqlite electron


【解决方案1】:

问题在于 each 函数返回一个 Database 对象以允许链接,而不是您的回调函数 (as per the documentation) 的 return 值。

要解决这个问题,由于 SQLite 的异步行为,您可以将 SQLite API 函数包装到 Promise 中,等待它,然后返回您要检索的值:

async function select (items, db, where, sign, whereNew) {
    // preset sql query
    let q = `select ${items} from ${db}`;
    if (where && sign && whereNew) {q += ` where ${where} ${sign} ${whereNew}`};

    console.log(q);

    // perform query on the database
    function fetch () {
        return new Promise ((resolve, reject) => {
            storage.each(q, [], ( err, row ) => {
                if (err) {
                    reject (`Error while retrieving ${q}`);
                } else {
                    resolve (row [items]);
                }
            });
        });
    }

    try {
        const result = await fetch ();
        return result;
    } catch (error) {
        throw error;
    }
}

顺便说一句,构建这样的 SQL 查询并不是一个好主意,因为它对SQL injection 开放。您应该“准备”您的查询,例如使用Database#prepare (...) function,这基本上可以确保除了您的查询之外没有任何 SQL 代码可以执行(通过转义任何特殊字符、命令等)。

【讨论】:

  • 谢谢。上面的代码抛出错误“等待仅在异步函数中有效”。至于 SQL 注入的危险——我正在构建的应用程序模板是一个不会连接到任何网络的桌面软件。另外我正在测试 SQLite3 :) 但是谢谢你的提示,我会记住这一点。
【解决方案2】:

我想我有点回答了我自己的问题,但我仍然有一些小问题。我遵循了异步线索,这是工作代码:

JS

storage.select = function ( items, db, where, sign, whereNew ) {
    let that = this;
    // preset sql query
    let query = `select ${items} from ${db}`;
    if ( where && sign && whereNew ) { query += ` where ${where} ${sign} ${whereNew}` };

    return new Promise ( function ( resolve, reject ) {
        storage.each( query, [], function ( err, row ) {
            if ( err ) { reject( err )}
            else resolve( row );
        })
    })
};

const result = storage.select( '*', 'users', 'id', '=', 1 )
    .then( row => { l( row ) })
        .catch( err => { l( err ) });

如果我想记录结果或将其发送到 IPC.Renderer,这可以正常工作。但我不能把它放到后端的变量或其他任何地方,这就是这场斗争背后的想法。

【讨论】:

    猜你喜欢
    • 2020-04-24
    • 2019-05-31
    • 2023-03-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-05-22
    相关资源
    最近更新 更多