UNPKG

@opengis/fastify-table

Version:

core-plugins

180 lines (155 loc) 6.68 kB
import getPG from '../../pg/funcs/getPG.js'; import getMeta from '../../pg/funcs/getMeta.js'; import getRedis from '../../redis/funcs/getRedis.js'; import pgClients from '../../pg/pgClients.js'; import getTemplate from '../../table/funcs/getTemplate.js'; import config from '../../../../config.js'; import extraData from '../../extra/extraData.js'; import logChanges from './utils/logChanges.js'; import logger from '../../logger/getLogger.js'; import getInsertQuery from './utils/getInsertQuery.js'; const rclient = getRedis(); const srids = {}; function assignValue(key, i, srid = 4326, columnType = 'text') { if (key === 'geom' && columnType === 'geometry') { return `"${key}"=st_setsrid(st_geomfromgeojson($${i + 2}::json),4326)`; } if (key?.includes('geom') && columnType === 'geometry') { return `"${key}"=st_setsrid(st_geomfromgeojson($${i + 2}::json),${srid})`; } return `"${key}"=$${i + 2}`; } export default async function dataUpdate({ table, tokenData, referer, id, data, pg: pg1, uid, }) { if (!data || !table || !id) return null; const pg = pg1 || getPG({ name: 'client' }); if (!pg) return null; // pg client single transaction support if (!pg?.pk && config.pg) { pg.options = pgClients.client?.options; pg.tlist = pgClients.client?.tlist; pg.pgType = pgClients.client?.pgType; pg.relkinds = pgClients.client?.relkinds; pg.pk = pgClients.client?.pk; } const { columns, pk } = await getMeta({ pg, table }); if (!columns) return null; const names = columns.map((el) => el.name); const types = columns.reduce((acc, { name, dataTypeID }) => ({ ...acc, [name]: pg.pgType?.[dataTypeID] }), {}); const filterData = Object.keys(data) .filter((el) => (/* typeof data[el] === 'boolean' ? true : data[el] && */ names?.includes(el) && !['editor_date', 'editor_id', 'updated_by', 'updated_at'].includes(el))); const systemColumns = [['editor_date', 'now()'], ['updated_at', 'now()'], uid ? ['editor_id', `'${uid.replace(/'/g, "''")}'`] : null, uid ? ['updated_by', `'${uid.replace(/'/g, "''")}'`] : null].filter((el) => el && names.includes(el[0])).map((el) => `${el[0]} = ${el[1]}`).join(','); const filterValue = filterData.map((el) => { const { dataTypeID = 25 } = columns.find((col) => col?.name === el) || {}; if (pg.pgType[dataTypeID]?.endsWith('[]') && ['string', 'number'].includes(typeof data[el])) { Object.assign(data, { [el]: data[el].split(',') }); } return [el, data[el]]; }).map((el) => (typeof el[1] === 'object' && types[el[0]]?.includes?.('json') && el[1] ? JSON.stringify(el[1]) : el[1])); // update geometry with srid if (!srids[table] && pg.tlist?.includes('public.geometry_columns')) { const { srids1 } = await pg.query(`select json_object_agg(_table,rel) as srids1 from ( select f_table_schema||'.'||f_table_name as _table, json_object_agg(f_geometry_column, case when srid = 0 then 4326 else srid end) as rel from public.geometry_columns group by f_table_schema||'.'||f_table_name )q`).then((res1) => res1.rows?.[0] || {}); Object.assign(srids, srids1); } const updateQuery = `UPDATE ${table} SET ${systemColumns ? `${systemColumns}${filterData?.length ? ',' : ''}` : ''} ${filterData?.map((key, i) => assignValue(key, i, srids[table]?.[key] || 4326, pg.pgType?.[columns.find(col => col.name === key)?.dataTypeID || '']))?.join(',')} WHERE ${pk}::text = $1::text returning *`; // console.log(updateQuery, filterValue); // for transactions const isClient = typeof pg.query === 'function' && typeof pg.release === 'function'; const client = isClient ? pg : await pg.connect(); if (isClient || !client.pk) { client.options = pg.options; client.tlist = pg.tlist; client.pgType = pg.pgType; client.relkinds = pg.relkinds; client.pk = pg.pk; } try { if (!isClient) { await client.query('begin;'); } const res = await client.query(updateQuery, [id, ...filterValue]) .catch(err => { logger.file('crud/update', { error: err.toString(), stack: err.stack, table, id, referer, uid, data, q: updateQuery, }); throw err; }) .then(el => el?.rows?.[0]) || {}; await extraData({ table, form: tokenData?.form, id, data, uid, row: res, }, client); // foreign key dataTable (table + parent_id) const formData = tokenData?.form ? (await getTemplate('form', tokenData.form) || {}) : {}; const schema = formData?.schema || formData; const parentKeys = Object.keys(schema || {})?.filter((key) => Array.isArray(data[key]) && schema?.[key]?.table && schema?.[key]?.parent_id /* && body[key].length */); if (parentKeys?.length) { await Promise.all(parentKeys?.map(async (key) => { const objId = data[schema[key].parent_id] || data?.id || res?.[schema[key]?.parent_id] || res?.[pg.pk?.[table] || '']; // delete old extra data await client.query(`delete from ${schema[key].table} where ${schema[key].parent_id}=$1`, [objId]); // rewrite? // insert new extra data if (Array.isArray(data[key]) && data[key]?.length) { const parentKey = schema[key].parent_id; const extraRows = await Promise.all(data[key]?.map?.(async (row) => { Object.assign(row, { [parentKey]: objId }); const parentRes = await getInsertQuery({ pg: client, table: schema[key].table, data: row, uid, }); if (!parentRes?.insertQuery || !parentRes?.args?.length) return null; const { rows = [] } = await client.query(parentRes.insertQuery, parentRes.args); return rows[0]; })); Object.assign(res, { [key]: extraRows.filter(Boolean) }); } })); } await logChanges({ pg, table, tokenData, referer, data, id, uid, type: 'UPDATE', }); if (config.redis) { rclient.incr(`pg:${table}:crud`); } if (!isClient) { await client.query('commit;'); } return res || {}; } catch (err) { logger.file('crud/update', { error: err.toString(), stack: err.stack, table, id, referer, uid, form: tokenData?.form, }); if (!isClient) { await client.query('rollback;'); } throw err; } finally { if (!isClient) { client.release(); } } }