UNPKG

autosql

Version:

An auto-parser of JSON into SQL.

163 lines (162 loc) 7.6 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PostgresInsertQueryBuilder = void 0; const pgsqlConfig_1 = require("../../config/pgsqlConfig"); const utilities_1 = require("../../../helpers/utilities"); const dialectConfig = pgsqlConfig_1.pgsqlConfig; class PostgresInsertQueryBuilder { static getInsertStatementQuery(tableOrInput, data, metaData, databaseConfig, inputInsertType) { let table; let rows; let header; let insertType; const schemaPrefix = databaseConfig?.schema ? `"${databaseConfig.schema}".` : ""; if (typeof tableOrInput === "object" && "table" in tableOrInput) { table = tableOrInput.table; rows = tableOrInput.data; header = tableOrInput.comparedMetaData?.updatedMetaData || tableOrInput.metaData; insertType = tableOrInput?.insertType || databaseConfig?.insertType || "UPDATE"; } else { table = tableOrInput; rows = data; header = metaData; insertType = inputInsertType || databaseConfig?.insertType || "UPDATE"; } if (!rows || rows.length === 0) { throw new Error(`No data provided for insert into table "${table}"`); } const columns = Object.keys(header); // Flatten values let params = []; if (typeof rows[0] === "object" && !Array.isArray(rows[0])) { const normalisedChunk = rows.map(row => (0, utilities_1.getInsertValues)(header, row, undefined, undefined, false) // ⬅ false = flatten ); params = normalisedChunk.flat(); } else { params = rows.flat(); } const quotedCols = columns.map(col => `"${col}"`).join(", "); const valuePlaceholders = rows .map((_, rowIndex) => { const baseIndex = rowIndex * columns.length; const placeholders = columns.map((_, colIndex) => `$${baseIndex + colIndex + 1}`); return `(${placeholders.join(", ")})`; }) .join(", "); let query = `INSERT INTO ${schemaPrefix}"${table}" (${quotedCols}) VALUES ${valuePlaceholders}`; if (insertType === "UPDATE") { const primaryKeys = Object.keys(header).filter((col) => header[col].primary === true); if (primaryKeys.length === 0) { throw new Error(`Postgres requires primary key(s) to use ON CONFLICT for table "${table}"`); } const updateCols = columns.filter((col) => { const colMeta = header[col]; const isPrimary = primaryKeys.includes(col); const isProtectedCalc = colMeta.calculated === true && colMeta.updatedCalculated === false; return !isPrimary && !isProtectedCalc; }); const conflictClause = `ON CONFLICT (${primaryKeys.map(col => `"${col}"`).join(", ")})`; if (updateCols.length > 0) { const updateSet = updateCols .map(col => `"${col}" = EXCLUDED."${col}"`) .join(", "); query += ` ${conflictClause} DO UPDATE SET ${updateSet}`; } else { query += ` ${conflictClause} DO NOTHING`; } } const result = { query, params }; return result; } static getInsertFromStagingQuery(tableOrInput, metaData, databaseConfig, inputInsertType) { let table; let header; let insertType; const schemaPrefix = databaseConfig?.schema ? `"${databaseConfig.schema}".` : ""; if (typeof tableOrInput === "object" && "table" in tableOrInput) { table = tableOrInput.table; header = tableOrInput.comparedMetaData?.updatedMetaData || tableOrInput.metaData; insertType = tableOrInput?.insertType || databaseConfig?.insertType || "UPDATE"; } else { table = tableOrInput; header = metaData; insertType = inputInsertType || databaseConfig?.insertType || "UPDATE"; } const tempTable = (0, utilities_1.getTempTableName)(table); const columns = Object.keys(header); const escapedCols = columns.map(col => `"${col}"`).join(", "); const selectCols = columns.map(col => `"${col}"`).join(", "); let query = `INSERT INTO ${schemaPrefix}"${table}" (${escapedCols}) SELECT ${selectCols} FROM ${schemaPrefix}"${tempTable}"`; if (insertType === "UPDATE") { const primaryKeys = Object.keys(header).filter(col => header[col].primary === true); const updateCols = columns.filter((col) => { const colMeta = header[col]; const isPrimary = primaryKeys.includes(col); const isProtectedCalc = colMeta.calculated === true && colMeta.updatedCalculated === false; return !isPrimary && !isProtectedCalc; }); if (primaryKeys.length > 0 && updateCols.length > 0) { const updateSet = updateCols .map(col => `"${col}" = EXCLUDED."${col}"`) .join(", "); query += ` ON CONFLICT (${primaryKeys.map(pk => `"${pk}"`).join(", ")}) DO UPDATE SET ${updateSet}`; } else { // Optional: skip conflict update if nothing valid to update query += ` ON CONFLICT DO NOTHING`; } } return { query, params: [] }; } static getInsertChangedRowsToHistoryQuery(tableOrInput, metaData, databaseConfig) { let table; let header; const schemaPrefix = databaseConfig?.schema ? `"${databaseConfig.schema}".` : ""; if (typeof tableOrInput === "object" && "table" in tableOrInput) { table = (0, utilities_1.getTrueTableName)(tableOrInput.table); header = tableOrInput.comparedMetaData?.updatedMetaData || tableOrInput.metaData; } else { table = (0, utilities_1.getTrueTableName)(tableOrInput); header = metaData; } const historyTable = (0, utilities_1.getHistoryTableName)(table); const tempTable = (0, utilities_1.getTempTableName)(table); const filteredCols = Object.keys(header).filter(col => col !== "dwh_as_at"); const primaryKeys = filteredCols.filter(col => header[col].primary); const nonPrimaryCols = filteredCols.filter(col => !header[col].primary && header[col].calculated !== true); const t1 = "t1"; const t2 = "t2"; const valuesCols = filteredCols.map(col => `"${col}"`).join(", "); const selectCols = filteredCols.map(col => `${t1}."${col}"`).join(", "); const joinCondition = primaryKeys .map(pk => `${t1}."${pk}" = ${t2}."${pk}"`) .join(" AND "); const diffCondition = nonPrimaryCols .map(col => `${t1}."${col}" IS DISTINCT FROM ${t2}."${col}"`) .join(" OR "); const query = ` INSERT INTO ${schemaPrefix}"${historyTable}" (${valuesCols}, "dwh_as_at") SELECT ${selectCols}, CURRENT_TIMESTAMP FROM ${schemaPrefix}"${table}" ${t1} LEFT JOIN ${schemaPrefix}"${tempTable}" ${t2} ON ${joinCondition} WHERE ${diffCondition}; `.trim(); return { query, params: [] }; } } exports.PostgresInsertQueryBuilder = PostgresInsertQueryBuilder;