узел postgres синхронизирует / асинхронный запрос по тому же методу - PullRequest
0 голосов
/ 16 января 2019

Я использую пакет pg и хочу подготовить метод, который выполняет синхронизацию или асинхронный запрос к базе данных в зависимости от того, отправлен метод обратного вызова или нет.

К настоящему времени я создал скрипт ниже:

const { Pool } = require('pg');
module.exports = function(options) {
const pool = new Pool(options);

var typeStr = (obj) => ({}).toString.call(obj).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
var prepareArgs = (args) => {
    let callback = false,
        query = {
            text: "",
            values: []
        };
    var argLen = args.length;
    while (argLen--) {
        let arg = args[argLen],
            type = typeStr(arg);
        switch (type) {
            case "string": query.text = arg; break;
            case "array": query.values = arg; break;
            case "object": query = arg; break;
            case "function": callback = arg; break;
        }
    }
    return callback
        ? [query, callback]
        : [query.text, query.values] ;
}

this.query = function() {  
    var args = prepareArgs(arguments);
    console.log("args", args);

    if (typeStr(args[0]) == "string") { // sync
        return (async () => {
            const client = await pool.connect()
            try {
              const res = await client.query.apply(client, args);
              return res.rows;
            } finally {
              client.release()
            }
        })()
    } else { // async
        pool.connect().then(client => {
            return client.query(args[0])
                .then(args[1])
                .then(res => {
                    client.release();
                })
        })
    }        
}
}

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

Это мой тестовый код:

console.log("START")
let query = {
    text: "SELECT value FROM public.settings WHERE key=$1::text",
    values: ["index"]
}
let cbfn = (res) => { console.log("async", res.rows)}
db.query(query, cbfn);
var rows = db.query(query)
console.log("sync", rows)
console.log("FINISH")

В этом случае я ожидаю увидеть в консоли

START
синхронизация [...]
FINISH
асинхронный [...]

но фактический результат похож на

START
sync Promise {}
FINISH
асинхронный [...]

Если я передам cbfn в качестве третьего параметра, я ожидаю увидеть журнал async в конце консоли. Кажется, все в порядке, кроме результата синхронизации!

Я также пытался преобразовать функцию query в асинхронную функцию и изменить свой тестовый код

(async () => {
    console.log("START")
    let query = {
        text: "SELECT value FROM public.settings WHERE key=$1::text",
        values: ["index"]
    }
    let cbfn = (res) => { console.log("async", res.rows)}
    db.query(query, cbfn);
    var rows = await db.query(query)
    console.log("sync", rows)
    console.log("FINISH")
})()

теперь вывод на консоль

START
асинхронный [...]
синхронизация [...]
FINISH

выглядит как асинхронный запрос, действующий как синхронизация!

Есть ли способ заставить этот метод работать?

РЕШЕНИЕ:
Я нашел deasync пакет

query = function() {  
    var args = prepareArgs(arguments),
        isSync = typeStr(args[0]) == "string";

    if (isSync) { // sync
        let rows;
        (async () => {
            const client = await pool.connect();
            try {
                const res = await client.query.apply(client, args);
                rows = res.rows;
            } finally {
                client.release();
            }
        })()
        while (rows === undefined) require('deasync').sleep(10);
        return rows;
    } else { // async
        pool.connect().then(client => {
            return client.query(args[0])
                .then(args[1])
                .then(res => {
                    client.release();
                })
        })
    }        
}
...