UNPKG

@opengis/fastify-table

Version:

core-plugins

116 lines (95 loc) 3.96 kB
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;