You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

189 lines
6.6 KiB

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.serialize = void 0;
const buffer_writer_1 = require("./buffer-writer");
const writer = new buffer_writer_1.Writer();
const startup = (opts) => {
// protocol version
writer.addInt16(3).addInt16(0);
for (const key of Object.keys(opts)) {
writer.addCString(key).addCString(opts[key]);
}
writer.addCString('client_encoding').addCString('UTF8');
var bodyBuffer = writer.addCString('').flush();
// this message is sent without a code
var length = bodyBuffer.length + 4;
return new buffer_writer_1.Writer().addInt32(length).add(bodyBuffer).flush();
};
const requestSsl = () => {
const response = Buffer.allocUnsafe(8);
response.writeInt32BE(8, 0);
response.writeInt32BE(80877103, 4);
return response;
};
const password = (password) => {
return writer.addCString(password).flush(112 /* startup */);
};
const sendSASLInitialResponseMessage = function (mechanism, initialResponse) {
// 0x70 = 'p'
writer.addCString(mechanism).addInt32(Buffer.byteLength(initialResponse)).addString(initialResponse);
return writer.flush(112 /* startup */);
};
const sendSCRAMClientFinalMessage = function (additionalData) {
return writer.addString(additionalData).flush(112 /* startup */);
};
const query = (text) => {
return writer.addCString(text).flush(81 /* query */);
};
const emptyArray = [];
const parse = (query) => {
// expect something like this:
// { name: 'queryName',
// text: 'select * from blah',
// types: ['int8', 'bool'] }
// normalize missing query names to allow for null
const name = query.name || '';
if (name.length > 63) {
/* eslint-disable no-console */
console.error('Warning! Postgres only supports 63 characters for query names.');
console.error('You supplied %s (%s)', name, name.length);
console.error('This can cause conflicts and silent errors executing queries');
/* eslint-enable no-console */
}
const types = query.types || emptyArray;
var len = types.length;
var buffer = writer
.addCString(name) // name of query
.addCString(query.text) // actual query text
.addInt16(len);
for (var i = 0; i < len; i++) {
buffer.addInt32(types[i]);
}
return writer.flush(80 /* parse */);
};
const paramWriter = new buffer_writer_1.Writer();
const writeValues = function (values, valueMapper) {
for (let i = 0; i < values.length; i++) {
const mappedVal = valueMapper ? valueMapper(values[i], i) : values[i];
if (mappedVal == null) {
// add the param type (string) to the writer
writer.addInt16(0 /* STRING */);
// write -1 to the param writer to indicate null
paramWriter.addInt32(-1);
}
else if (mappedVal instanceof Buffer) {
// add the param type (binary) to the writer
writer.addInt16(1 /* BINARY */);
// add the buffer to the param writer
paramWriter.addInt32(mappedVal.length);
paramWriter.add(mappedVal);
}
else {
// add the param type (string) to the writer
writer.addInt16(0 /* STRING */);
paramWriter.addInt32(Buffer.byteLength(mappedVal));
paramWriter.addString(mappedVal);
}
}
};
const bind = (config = {}) => {
// normalize config
const portal = config.portal || '';
const statement = config.statement || '';
const binary = config.binary || false;
const values = config.values || emptyArray;
const len = values.length;
writer.addCString(portal).addCString(statement);
writer.addInt16(len);
writeValues(values, config.valueMapper);
writer.addInt16(len);
writer.add(paramWriter.flush());
// format code
writer.addInt16(binary ? 1 /* BINARY */ : 0 /* STRING */);
return writer.flush(66 /* bind */);
};
const emptyExecute = Buffer.from([69 /* execute */, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00]);
const execute = (config) => {
// this is the happy path for most queries
if (!config || (!config.portal && !config.rows)) {
return emptyExecute;
}
const portal = config.portal || '';
const rows = config.rows || 0;
const portalLength = Buffer.byteLength(portal);
const len = 4 + portalLength + 1 + 4;
// one extra bit for code
const buff = Buffer.allocUnsafe(1 + len);
buff[0] = 69 /* execute */;
buff.writeInt32BE(len, 1);
buff.write(portal, 5, 'utf-8');
buff[portalLength + 5] = 0; // null terminate portal cString
buff.writeUInt32BE(rows, buff.length - 4);
return buff;
};
const cancel = (processID, secretKey) => {
const buffer = Buffer.allocUnsafe(16);
buffer.writeInt32BE(16, 0);
buffer.writeInt16BE(1234, 4);
buffer.writeInt16BE(5678, 6);
buffer.writeInt32BE(processID, 8);
buffer.writeInt32BE(secretKey, 12);
return buffer;
};
const cstringMessage = (code, string) => {
const stringLen = Buffer.byteLength(string);
const len = 4 + stringLen + 1;
// one extra bit for code
const buffer = Buffer.allocUnsafe(1 + len);
buffer[0] = code;
buffer.writeInt32BE(len, 1);
buffer.write(string, 5, 'utf-8');
buffer[len] = 0; // null terminate cString
return buffer;
};
const emptyDescribePortal = writer.addCString('P').flush(68 /* describe */);
const emptyDescribeStatement = writer.addCString('S').flush(68 /* describe */);
const describe = (msg) => {
return msg.name
? cstringMessage(68 /* describe */, `${msg.type}${msg.name || ''}`)
: msg.type === 'P'
? emptyDescribePortal
: emptyDescribeStatement;
};
const close = (msg) => {
const text = `${msg.type}${msg.name || ''}`;
return cstringMessage(67 /* close */, text);
};
const copyData = (chunk) => {
return writer.add(chunk).flush(100 /* copyFromChunk */);
};
const copyFail = (message) => {
return cstringMessage(102 /* copyFail */, message);
};
const codeOnlyBuffer = (code) => Buffer.from([code, 0x00, 0x00, 0x00, 0x04]);
const flushBuffer = codeOnlyBuffer(72 /* flush */);
const syncBuffer = codeOnlyBuffer(83 /* sync */);
const endBuffer = codeOnlyBuffer(88 /* end */);
const copyDoneBuffer = codeOnlyBuffer(99 /* copyDone */);
const serialize = {
startup,
password,
requestSsl,
sendSASLInitialResponseMessage,
sendSCRAMClientFinalMessage,
query,
parse,
bind,
execute,
describe,
close,
flush: () => flushBuffer,
sync: () => syncBuffer,
end: () => endBuffer,
copyData,
copyDone: () => copyDoneBuffer,
copyFail,
cancel,
};
exports.serialize = serialize;
//# sourceMappingURL=serializer.js.map