@opengis/fastify-table
Version:
core-plugins
149 lines (148 loc) • 5.38 kB
JavaScript
import getPG from "../../pg/funcs/getPG.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 logChanges from "./utils/logChanges.js";
import getInsertQuery from "./utils/getInsertQuery.js";
import logger from "../../logger/getLogger.js";
import extraData from "../../extra/extraData.js";
const rclient = getRedis();
export default async function dataUpsert({ id, table: table1, referer, data, pg: pg1, uid, tokenData = {}, update = true, constraint, }) {
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;
}
if (config.trace)
console.log("form", tokenData?.form);
const table = pg.pk?.[table1] ? table1 : table1.replace(/"/g, "");
const { insertQuery, args = [], keys = [], systemColumns = [], } = (await getInsertQuery({
pg,
table,
data,
id,
uid,
})) || {};
const updatedAtColumn = systemColumns
.map((el) => el[0])
.find((colname) => ["editor_date", "updated_at"].includes(colname));
const upsert = () => {
if (!update || !keys.length) {
const p1 = `on conflict(${constraint || pg.pk?.[table]}) do `;
const p2 = updatedAtColumn
? `update set ${updatedAtColumn}=now()`
: "nothing";
return p1 + p2 + "returning *";
}
return `on conflict(${constraint || pg.pk?.[table]}) do update set ${typeof update === "string"
? update
: keys.map((colname) => `${colname} = EXCLUDED."${colname}"`).join(", ")} ${keys.includes(updatedAtColumn) || !updatedAtColumn
? ""
: `,${updatedAtColumn}=now()`} returning *`;
};
if (!insertQuery || !args.length)
return null;
const q = [insertQuery.replace("returning *", ""), upsert()]
.filter(Boolean)
.join(" ");
// 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 row = await client.query(q, args).then((el) => el.rows?.[0]);
const id1 = row?.[pg.pk?.[table] || ""];
if (!id1)
return null;
await extraData({
table,
form: tokenData?.form,
id: id1,
data,
uid,
row,
}, 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) => data[key]?.length &&
Array.isArray(data[key]) &&
schema?.[key]?.table &&
schema?.[key]?.parent_id);
if (parentKeys?.length) {
await Promise.all(parentKeys?.map(async (key) => {
const parentKey = schema[key].parent_id;
const objId = data[parentKey] || data?.id || row?.[parentKey] || id1;
const parentRows = 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(row, { [key]: parentRows.filter(Boolean) });
}));
}
await logChanges({
pg: client,
table,
tokenData,
referer,
data,
id: id1,
uid,
type: "UPSERT",
});
if (config.redis) {
rclient.incr(`pg:${table}:crud`);
}
if (!isClient) {
await client.query("commit;");
}
return row;
}
catch (err) {
logger.file("crud/upsert", {
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?.();
}
}
}