UNPKG

ffc-pay-etl-framework

Version:

A framework for creating ETL pipelines in node

140 lines (139 loc) 5.74 kB
const EventEmitter = require('node:events'); const { Transform } = require('node:stream'); const debug = require('debug')('destination'); const DEFAULT_PORT = 5432; function isKeyWord(column) { return ['USER'].includes(column.toUpperCase()); } function getMappingForColumn(mapping, column) { if (mapping.length === 0) { return {}; } const [map] = mapping.filter(m => m.column === column); return map; } function hasReturningColumns(mapping) { return mapping.filter(m => m.returning === true).length > 0; } function getReturningColumns(mapping) { return mapping.filter(m => m.returning === true).map(m => m === null || m === void 0 ? void 0 : m.targetColumn); } function writeInsertStatement(columnMapping, table, chunk, schema, ignoredColumns = []) { const filteredColumns = chunk._columns.filter(column => { const mapping = getMappingForColumn(columnMapping, column); const targetColumn = (mapping === null || mapping === void 0 ? void 0 : mapping.targetColumn) ? mapping === null || mapping === void 0 ? void 0 : mapping.targetColumn : mapping === null || mapping === void 0 ? void 0 : mapping.column; return !ignoredColumns.includes(targetColumn); }); let statement = `INSERT INTO ${schema !== null && schema !== void 0 ? schema : 'public'}."${table}" (${filteredColumns.map(column => { const mapping = getMappingForColumn(columnMapping, column); return (mapping === null || mapping === void 0 ? void 0 : mapping.targetColumn) ? `"${mapping.targetColumn}"` : `"${mapping === null || mapping === void 0 ? void 0 : mapping.column}"`; }) .join(",")}) VALUES (${filteredColumns.map(column => { const index = chunk._columns.indexOf(column); const mapping = getMappingForColumn(columnMapping, column); if ((mapping === null || mapping === void 0 ? void 0 : mapping.targetType) === "number" && (isNaN(chunk[index]) || chunk[index] === '')) { debug('Source data is not a number.'); return 0; } if ((mapping === null || mapping === void 0 ? void 0 : mapping.targetType) === "varchar" || (mapping === null || mapping === void 0 ? void 0 : mapping.targetType) === "char") { return `'${chunk[index]}'`; } if ((mapping === null || mapping === void 0 ? void 0 : mapping.targetType) === "date") { if (!chunk[index]) { return `''`; } return `to_timestamp('${chunk[index]}','${mapping === null || mapping === void 0 ? void 0 : mapping.format}')`; } return chunk[index] ? chunk[index] : 'null'; })})`; if (hasReturningColumns(columnMapping)) { statement = statement + ` RETURNING ${getReturningColumns(columnMapping).join(',')}`; } return statement; } /** * * @param {Object} options * @param {Object} options.table * @param {Object} options.connectionname * @param {Object} options.mapping * @param {Object} options.includeErrors * @param {String} [options.schema] * @param {Array<String>} [options.ignoredColumns] * @returns Transform */ function PostgresDestination(options) { var _a; EventEmitter.call(this); const table = options.table; const connectionname = options.connectionname; const mapping = options.mapping; const includeErrors = options.includeErrors; const schema = options.schema; const ignoredColumns = (_a = options.ignoredColumns) !== null && _a !== void 0 ? _a : []; let lastChunk; const transform = new Transform({ objectMode: true, emitClose: true, construct(callback) { // @ts-ignore this.connectionname = connectionname; callback(); }, write(chunk, _, callback) { let insertStatement; // @ts-ignore if (chunk.errors.length === 0 || options.includeErrors) { insertStatement = writeInsertStatement(mapping, table, chunk, schema, ignoredColumns); debug('Insert statement: [%s]', insertStatement); // @ts-ignore this.connection.db.query(insertStatement) .then(result => { var _a; debug('result %o', result); chunk._result = result; lastChunk = chunk; // @ts-ignore (_a = this.tasks) === null || _a === void 0 ? void 0 : _a.forEach(task => task.write(chunk)); // @ts-ignore callback(null, chunk); }).catch(error => { debug('error %o', error); chunk.errors.push(error); lastChunk = chunk; // @ts-ignore callback(error, chunk); }); } else { debug('Chunk has errors %o', chunk); } }, final(callback) { this.emit('result', lastChunk); callback(); } }); Object.assign(Transform.prototype, { type: 'PostgresDestination', setConnection: function (connection) { this.connection = connection; }.bind(transform), getConnectionName: function () { var _a; return (_a = this.connection) === null || _a === void 0 ? void 0 : _a.name; }.bind(transform), setTasks: function (tasks) { this.tasks = tasks; }.bind(transform) }); return transform; } module.exports = { PostgresDestination, writeInsertStatement, isKeyWord, getMappingForColumn, hasReturningColumns, getReturningColumns };