UNPKG

@opengis/bi

Version:

BI data visualization module

158 lines (131 loc) 5.71 kB
import yaml from 'js-yaml'; import { pgClients, getTemplatePath, getTemplate, getPGAsync, getMeta, } from '@opengis/fastify-table/utils.js'; export default async function dashboard({ pg: pg1 = pgClients.client, params = {}, }) { const time = Date.now(); const { id } = params; if (!id) { return { message: 'not enough params: dashboard required', status: 400 }; } const dashboards = getTemplatePath('dashboard'); const fileDashboard = dashboards.find((el) => el[0] === id); if (!fileDashboard) { const sql = `select title, description, table_name, panels, grid, widgets, filters, style, words, db, public from bi.dashboard where $1 in (dashboard_id, name)`; const data = await pg1.query(sql, [id]).then(el => el.rows?.[0] || {}); let pg = pg1; try { pg = data.pg || (data.db ? await getPGAsync(data.db) : null) || pg1; } catch (err) { data.error = err.toString(); } data.type = 'bd'; const { table_name: table } = data; if (!table) { return { message: 'not enough params: table required', status: 400 }; } const loadTemplate = pg.pk?.['admin.doc_template'] ? await pg.query( 'select body from admin.doc_template where doc_type=5 and title=$1', [table] ).then(el => el.rows?.[0]?.body) : null; const sqlList = loadTemplate?.sql ? loadTemplate?.sql ?.filter?.(el => !el.disabled && el?.sql?.replace) ?.map?.((el, i) => `left join lateral (${el.sql.replace(/limit 1/ig, '')}) t${i} on 1=1`)?.join?.(' ') : ''; const { fields = [] } = table && pg.pk?.[loadTemplate?.table || table] ? await pg.query(`select * from ${loadTemplate?.table || table} t ${sqlList || ''} limit 0`) : {}; data?.widgets?.forEach?.(el => { const { style, data = {}, type, title, x, metrics } = el; el.yml = yaml.dump({ title, type, data: { x, metrics, ...data }, style, }) // el.yml = yaml.dump({ style, data, type, title }); }); data.panels?.forEach?.(el => { const { title, type } = data?.widgets?.find(item => item.name === el.widget) || {}; Object.assign(el, { title, type }); }); const meta = table ? await getMeta({ pg, table: loadTemplate?.table || table }) : {}; const columnIndexes = meta?.columns?.reduce((acc, curr, idx) => Object.assign(acc, { [curr.name]: idx }), {}) || []; const columns = fields?.map(el => ({ name: el.name, title: meta?.columns[columnIndexes[el.name]]?.title || el.name, type: pg.pgType?.[el.dataTypeID] })); return { ...data || {}, widgets: data?.widgets?.filter?.(el => el?.widget_id) || [], panels: data?.panels?.filter?.(el => el?.widget) || [], geom: !meta?.geom, error: table && !pg.pk?.[loadTemplate?.table || table] ? `table pkey not found: ${loadTemplate?.table || table}` : undefined, table_name: table, templateTable: loadTemplate?.table, time: Date.now() - time, columns, }; } const fileData = await getTemplate('dashboard', id); const index = fileData.find((el) => el[0] === 'index.yml')[1]; if (!index) { return { message: `not found ${id}`, status: 404 }; } const data = index; data.type = 'file'; const { table } = data?.data || { table: data?.table_name }; let pg = pg1; try { pg = data.pg || (data.db ? await getPGAsync(data.db) : null) || pg1; } catch (err) { data.error = err.toString(); } const { fields = [] } = table ? await pg.query(`select * from ${table} limit 0`) : {}; const meta = await getMeta({ pg: pg1, table }); const columns = meta?.columns ?.filter(el => fields.map(field => field.name).includes(el.name)) ?.map(el => ({ name: el.name, title: el.title, type: pg.pgType?.[el.dataTypeID] })); const checks = index?.filters?.filter((el) => el?.id && fields.map((el) => el?.name).includes(el?.id) && el?.type === 'Check'); if (checks?.length) { await Promise.all(checks.map(async (el) => { if (el?.data) { const options = await getTemplate('cls', el.data); Object.assign(el, { options }); } else if (index?.table_name || index?.table) { const { rows = [] } = await pg.query(`select "${el.id}" as id, count(*) from ${index?.table_name || index?.table} group by "${el.id}"`); Object.assign(el, { options: rows }); } })); } const ranges = index?.filters?.filter((el) => el?.id && fields.map((el) => el?.name).includes(el?.id) && el?.type === 'Range'); if (ranges?.length) { await Promise.all(ranges.map(async (el) => { const rows = await pg.query(`select array[ percentile_cont(0) within group (order by ${el.id}), percentile_cont(0.25) within group (order by ${el.id}), percentile_cont(0.5) within group (order by ${el.id}), percentile_cont(0.75) within group (order by ${el.id}), percentile_cont(1.0) within group (order by ${el.id}) ] from ${index?.table_name || index?.table}`).then(el => el.rows?.[0]?.array || []); Object.assign(el, { options: rows }); })); } // console.log(fileData) const widgets = fileData .filter((el) => el[0] !== 'index.yml') .map((el) => el[1].data ? { name: el[0].split('.')[0], type: el[1].type, title: el[1].title, style: el[1].style, data: el[1].data, } : { name: el[0].split('.')[0], title: el[1] } ); return { ...data, geom: !!meta?.geom, table_name: table, time: Date.now() - time, columns, widgets, }; }