@opengis/fastify-table
Version:
core-plugins
116 lines (95 loc) • 3.96 kB
JavaScript
import { createHash } from 'node:crypto';
import config from '../../../../config.js';
import getRedis from '../../redis/funcs/getRedis.js';
import logger from '../../logger/getLogger.js';
const rclient = getRedis({ db: 0 });
async function init(client) {
if (!client?.options?.database) {
return;
}
const textQuery = `select
(select json_object_agg(conrelid::regclass ,(SELECT attname FROM pg_attribute WHERE attrelid = c.conrelid and attnum = c.conkey[1]))
from pg_constraint c where contype='p' and connamespace::regnamespace::text not in ('sde')) as pk,
(SELECT json_object_agg(t.oid::text,pg_catalog.format_type(t.oid, NULL)) FROM pg_catalog.pg_type t) as "pgType"`;
const { pgType, pk } = await client.query(textQuery).then((d) => d.rows[0]);
const tlist = await client.query(`select array_agg((select nspname from pg_namespace where oid=relnamespace)||'.'||relname) tlist
from pg_class where relkind in ('r','v')`).then((d) => d.rows[0].tlist);
const { rows = [] } = await client.query(`select (select nspname from pg_namespace where oid=relnamespace)||'.'||relname as tname, relkind
from pg_class where relkind in ('r','v')`);
const relkinds = rows.reduce((acc, curr) => Object.assign(acc, { [curr.tname]: curr.relkind }), {});
async function query(q, args = [], isstream = false) {
try {
if (isstream) {
await client.query('set statement_timeout to 100000000');
}
const data = await client.query(q, args);
await client.query('set statement_timeout to 0');
return data;
}
catch (err) {
await client.query('set statement_timeout to 0');
if (err.message === 'canceling statement due to statement timeout') {
logger.file('timeout/query', { q, stack: err.stack });
return { rows: [], timeout: true };
}
throw new Error(err);
}
}
async function querySafe(q, param = {}) {
const { args, isstream } = param;
const data = await query(q, args, isstream);
return data;
}
async function one(q, param = {}) {
const data = await query(q, Array.isArray(param) ? param : param.args || []);
const result = ((Array.isArray(data) ? data.pop() : data)?.rows || [])[0] || {};
return result;
}
async function queryNotice(q, args = [], cb = () => { }) {
const clientCb = await client.connect();
clientCb.on('notice', (e) => {
cb(e.message);
});
let result;
try {
result = await clientCb.query(q, args);
clientCb.end();
}
catch (err) {
clientCb.end();
cb(err.toString(), 1);
throw err;
}
return result;
}
async function queryCache(q, param = {}) {
const { table, args = [], time = 15 } = param;
const seconds = typeof time !== 'number' || time < 0 ? 0 : time * 60;
if (seconds === 0 || config.disableCache) {
const data = await query(q, args || []);
return data;
}
// CRUD table state
const keyCacheTable = `pg:${table}:crud`;
const crudInc = table && config.redis ? (await rclient.get(keyCacheTable) || 0) : 0;
//
const hash = createHash('sha1').update([q, JSON.stringify(args)].join()).digest('base64');
const keyCache = `pg:${hash}:${crudInc}`;
const cacheData = config.redis ? await rclient.get(keyCache) : null;
if (cacheData && !config.local) {
// console.log('from cache', table, query);
return JSON.parse(cacheData);
}
const data = await query(q, args || []);
if (seconds > 0 && config.redis) {
rclient.set(keyCache, JSON.stringify(data), 'EX', seconds);
}
// console.log('no cache', table, crudInc, query);
return data;
}
Object.assign(client, {
one, pgType, pk, tlist, relkinds, queryCache, queryNotice, querySafe,
});
}
// export default client;
export default init;