@arturwojnar/hermes-postgresql
Version:
Production-Ready TypeScript Outbox Pattern for PostgreSQL
81 lines • 3.37 kB
JavaScript
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