Я использую пакет 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();
})
})
}
}