UNPKG

@arturwojnar/hermes-postgresql

Version:

Production-Ready TypeScript Outbox Pattern for PostgreSQL

81 lines 3.37 kB
import { assert } from '@arturwojnar/hermes'; import { offset } from '../common/offset.js'; import { Bytes, MessageType, TopLevelType } from './types.js'; const readIntFn = { '1': 'readUInt8', '2': 'readUInt16BE', '4': 'readUInt32BE', '8': 'readBigUInt64BE', }; const readUInt = (buffer, pos) => { const columnType = String.fromCharCode(buffer.readInt8(pos.value())); const columnLength = buffer.readUInt32BE(pos.addInt8()).toString(); assert(columnType === 't', 'readUInt.columnType'); assert(['1', '2', '4', '8'].includes(columnLength), 'readUInt.columnLength'); const value = buffer[readIntFn[columnLength]](pos.addInt32()); pos.add(Number(columnLength)); return value; }; const readBigInt = (buffer, pos) => { const columnType = String.fromCharCode(buffer.readInt8(pos.value())); const columnLength = buffer.readUInt32BE(pos.addInt8()); assert(columnType === 't', 'readUInt.columnType'); const strValue = buffer.subarray(pos.addInt32(), pos.value() + columnLength).toString('utf-8'); const value = columnLength > 8 ? BigInt(strValue) : parseInt(strValue, 10); pos.add(columnLength); return value; }; const readText = (buffer, pos) => { const columnType = String.fromCharCode(buffer.readInt8(pos.value())); const columnLength = buffer.readUInt32BE(pos.addInt8()); assert(columnType === 't', 'readText.columnType'); const value = buffer.subarray(pos.addInt32(), pos.add(columnLength)); return value.toString('utf-8'); }; const readJsonb = (buffer, pos) => { const columnType = String.fromCharCode(buffer.readInt8(pos.value())); const columnLength = buffer.readUInt32BE(pos.addInt8()); assert(columnType === 't', 'readText.readJsonb'); const value = buffer.subarray(pos.addInt32(), pos.add(columnLength)); return value.toString('utf-8'); }; const columnReaders = { uint: readUInt, bigint: readBigInt, text: readText, jsonb: readJsonb, }; const processInsertMessage = (columnConfig) => { const entries = Object.entries(columnConfig); const readers = entries.map(([columnName, columnType]) => ({ columnName, reader: columnReaders[columnType], })); readers.forEach(({ reader }) => assert(reader, `Unknown column type`)); const readTuple = (pos, tuplesBuffer) => { return readers.reduce((result, { columnName, reader }) => { Object.defineProperty(result, columnName, { value: reader(tuplesBuffer, pos), writable: false, enumerable: true, }); return result; }, {}); }; return (data) => { const relationId = data.readUInt32BE(Bytes.Int8); const newMessageId = String.fromCharCode(data.readInt8(Bytes.Int8 + Bytes.Int32)); const TUPLE_START_BYTE = Bytes.Int8 + Bytes.Int32 + Bytes.Int8; const tuplesBuffer = data.subarray(TUPLE_START_BYTE); const columnsCount = tuplesBuffer.readInt16BE(0); const pos = offset(Bytes.Int16); const result = readTuple(pos, tuplesBuffer); return { topLevelType: TopLevelType.XLogData, messageType: MessageType.Insert, result, }; }; }; export { processInsertMessage, readBigInt, readJsonb, readText, readUInt }; //# sourceMappingURL=processInsertMessage.js.map