UNPKG

@opengis/fastify-table

Version:

core-plugins

202 lines (200 loc) 7.76 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] === "" ? null : data[el]]; // ensure '' on number does not throw }) .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((el) => el.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?.status !== "end") { rclient.incr(`pg:${table}:crud`); } if (!isClient) { await client.query("commit;"); } return { ...(res || {}), id }; } 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(); } } }