pg-protocol
Advanced tools
Comparing version 1.2.1 to 1.2.2
"use strict"; | ||
// file for microbenchmarking | ||
// file for microbenchmarking | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
@@ -4,0 +4,0 @@ const buffer_writer_1 = require("./buffer-writer"); |
@@ -39,3 +39,2 @@ "use strict"; | ||
while (this.buffer[end++] !== 0) { } | ||
; | ||
this.offset = end; | ||
@@ -42,0 +41,0 @@ return this.buffer.toString(this.encoding, start, end - 1); |
@@ -24,6 +24,6 @@ "use strict"; | ||
this.ensure(4); | ||
this.buffer[this.offset++] = (num >>> 24 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 16 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 8 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 0 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 24) & 0xff; | ||
this.buffer[this.offset++] = (num >>> 16) & 0xff; | ||
this.buffer[this.offset++] = (num >>> 8) & 0xff; | ||
this.buffer[this.offset++] = (num >>> 0) & 0xff; | ||
return this; | ||
@@ -33,4 +33,4 @@ } | ||
this.ensure(2); | ||
this.buffer[this.offset++] = (num >>> 8 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 0 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 8) & 0xff; | ||
this.buffer[this.offset++] = (num >>> 0) & 0xff; | ||
return this; | ||
@@ -51,3 +51,3 @@ } | ||
} | ||
addString(string = "") { | ||
addString(string = '') { | ||
var len = Buffer.byteLength(string); | ||
@@ -54,0 +54,0 @@ this.ensure(len); |
@@ -29,3 +29,4 @@ "use strict"; | ||
var addRow = function (bufferList, name, offset) { | ||
return bufferList.addCString(name) // field name | ||
return bufferList | ||
.addCString(name) // field name | ||
.addInt32(offset++) // table id | ||
@@ -45,7 +46,9 @@ .addInt16(offset++) // attribute of column number | ||
typeModifier: 5, | ||
formatCode: 0 | ||
formatCode: 0, | ||
}; | ||
var oneRowDescBuff = test_buffers_1.default.rowDescription([row1]); | ||
row1.name = 'bang'; | ||
var twoRowBuf = test_buffers_1.default.rowDescription([row1, { | ||
var twoRowBuf = test_buffers_1.default.rowDescription([ | ||
row1, | ||
{ | ||
name: 'whoah', | ||
@@ -57,7 +60,6 @@ tableID: 10, | ||
typeModifier: 14, | ||
formatCode: 0 | ||
}]); | ||
var emptyRowFieldBuf = new buffer_list_1.default() | ||
.addInt16(0) | ||
.join(true, 'D'); | ||
formatCode: 0, | ||
}, | ||
]); | ||
var emptyRowFieldBuf = new buffer_list_1.default().addInt16(0).join(true, 'D'); | ||
var emptyRowFieldBuf = test_buffers_1.default.dataRow([]); | ||
@@ -72,3 +74,3 @@ var oneFieldBuf = new buffer_list_1.default() | ||
name: 'authenticationOk', | ||
length: 8 | ||
length: 8, | ||
}; | ||
@@ -79,3 +81,3 @@ var expectedParameterStatusMessage = { | ||
parameterValue: 'UTF8', | ||
length: 25 | ||
length: 25, | ||
}; | ||
@@ -85,3 +87,3 @@ var expectedBackendKeyDataMessage = { | ||
processID: 1, | ||
secretKey: 2 | ||
secretKey: 2, | ||
}; | ||
@@ -91,3 +93,3 @@ var expectedReadyForQueryMessage = { | ||
length: 5, | ||
status: 'I' | ||
status: 'I', | ||
}; | ||
@@ -97,3 +99,3 @@ var expectedCommandCompleteMessage = { | ||
length: 13, | ||
text: 'SELECT 3' | ||
text: 'SELECT 3', | ||
}; | ||
@@ -113,3 +115,4 @@ var emptyRowDescriptionBuffer = new buffer_list_1.default() | ||
fieldCount: 1, | ||
fields: [{ | ||
fields: [ | ||
{ | ||
name: 'id', | ||
@@ -121,4 +124,5 @@ tableID: 1, | ||
dataTypeModifier: 5, | ||
format: 'text' | ||
}] | ||
format: 'text', | ||
}, | ||
], | ||
}; | ||
@@ -129,3 +133,4 @@ var expectedTwoRowMessage = { | ||
fieldCount: 2, | ||
fields: [{ | ||
fields: [ | ||
{ | ||
name: 'bang', | ||
@@ -137,3 +142,3 @@ tableID: 1, | ||
dataTypeModifier: 5, | ||
format: 'text' | ||
format: 'text', | ||
}, | ||
@@ -147,4 +152,5 @@ { | ||
dataTypeModifier: 14, | ||
format: 'text' | ||
}] | ||
format: 'text', | ||
}, | ||
], | ||
}; | ||
@@ -166,11 +172,11 @@ var testForMessage = function (buffer, expectedMessage) { | ||
var expectedPlainPasswordMessage = { | ||
name: 'authenticationCleartextPassword' | ||
name: 'authenticationCleartextPassword', | ||
}; | ||
var expectedMD5PasswordMessage = { | ||
name: 'authenticationMD5Password', | ||
salt: Buffer.from([1, 2, 3, 4]) | ||
salt: Buffer.from([1, 2, 3, 4]), | ||
}; | ||
var expectedSASLMessage = { | ||
name: 'authenticationSASL', | ||
mechanisms: ['SCRAM-SHA-256'] | ||
mechanisms: ['SCRAM-SHA-256'], | ||
}; | ||
@@ -190,3 +196,3 @@ var expectedSASLContinueMessage = { | ||
channel: 'hi', | ||
payload: 'boom' | ||
payload: 'boom', | ||
}; | ||
@@ -220,3 +226,3 @@ const parseBuffers = (buffers) => __awaiter(void 0, void 0, void 0, function* () { | ||
testForMessage(Buffer.from([0x6e, 0, 0, 0, 4]), { | ||
name: 'noData' | ||
name: 'noData', | ||
}); | ||
@@ -232,3 +238,3 @@ describe('rowDescription messages', function () { | ||
name: 'dataRow', | ||
fieldCount: 0 | ||
fieldCount: 0, | ||
}); | ||
@@ -240,3 +246,3 @@ }); | ||
fieldCount: 1, | ||
fields: ['test'] | ||
fields: ['test'], | ||
}); | ||
@@ -250,49 +256,63 @@ }); | ||
name: 'notice', | ||
code: 'code' | ||
code: 'code', | ||
}); | ||
}); | ||
testForMessage(test_buffers_1.default.error([]), { | ||
name: 'error' | ||
name: 'error', | ||
}); | ||
describe('with all the fields', function () { | ||
var buffer = test_buffers_1.default.error([{ | ||
var buffer = test_buffers_1.default.error([ | ||
{ | ||
type: 'S', | ||
value: 'ERROR' | ||
}, { | ||
value: 'ERROR', | ||
}, | ||
{ | ||
type: 'C', | ||
value: 'code' | ||
}, { | ||
value: 'code', | ||
}, | ||
{ | ||
type: 'M', | ||
value: 'message' | ||
}, { | ||
value: 'message', | ||
}, | ||
{ | ||
type: 'D', | ||
value: 'details' | ||
}, { | ||
value: 'details', | ||
}, | ||
{ | ||
type: 'H', | ||
value: 'hint' | ||
}, { | ||
value: 'hint', | ||
}, | ||
{ | ||
type: 'P', | ||
value: '100' | ||
}, { | ||
value: '100', | ||
}, | ||
{ | ||
type: 'p', | ||
value: '101' | ||
}, { | ||
value: '101', | ||
}, | ||
{ | ||
type: 'q', | ||
value: 'query' | ||
}, { | ||
value: 'query', | ||
}, | ||
{ | ||
type: 'W', | ||
value: 'where' | ||
}, { | ||
value: 'where', | ||
}, | ||
{ | ||
type: 'F', | ||
value: 'file' | ||
}, { | ||
value: 'file', | ||
}, | ||
{ | ||
type: 'L', | ||
value: 'line' | ||
}, { | ||
value: 'line', | ||
}, | ||
{ | ||
type: 'R', | ||
value: 'routine' | ||
}, { | ||
value: 'routine', | ||
}, | ||
{ | ||
type: 'Z', | ||
value: 'alsdkf' | ||
}]); | ||
value: 'alsdkf', | ||
}, | ||
]); | ||
testForMessage(buffer, { | ||
@@ -311,20 +331,20 @@ name: 'error', | ||
line: 'line', | ||
routine: 'routine' | ||
routine: 'routine', | ||
}); | ||
}); | ||
testForMessage(parseCompleteBuffer, { | ||
name: 'parseComplete' | ||
name: 'parseComplete', | ||
}); | ||
testForMessage(bindCompleteBuffer, { | ||
name: 'bindComplete' | ||
name: 'bindComplete', | ||
}); | ||
testForMessage(bindCompleteBuffer, { | ||
name: 'bindComplete' | ||
name: 'bindComplete', | ||
}); | ||
testForMessage(test_buffers_1.default.closeComplete(), { | ||
name: 'closeComplete' | ||
name: 'closeComplete', | ||
}); | ||
describe('parses portal suspended message', function () { | ||
testForMessage(portalSuspendedBuffer, { | ||
name: 'portalSuspended' | ||
name: 'portalSuspended', | ||
}); | ||
@@ -335,3 +355,3 @@ }); | ||
name: 'replicationStart', | ||
length: 4 | ||
length: 4, | ||
}); | ||
@@ -344,3 +364,3 @@ }); | ||
binary: false, | ||
columnTypes: [] | ||
columnTypes: [], | ||
}); | ||
@@ -351,3 +371,3 @@ testForMessage(test_buffers_1.default.copyIn(2), { | ||
binary: false, | ||
columnTypes: [0, 1] | ||
columnTypes: [0, 1], | ||
}); | ||
@@ -358,3 +378,3 @@ testForMessage(test_buffers_1.default.copyOut(0), { | ||
binary: false, | ||
columnTypes: [] | ||
columnTypes: [], | ||
}); | ||
@@ -365,3 +385,3 @@ testForMessage(test_buffers_1.default.copyOut(3), { | ||
binary: false, | ||
columnTypes: [0, 1, 2] | ||
columnTypes: [0, 1, 2], | ||
}); | ||
@@ -375,3 +395,3 @@ testForMessage(test_buffers_1.default.copyDone(), { | ||
length: 7, | ||
chunk: Buffer.from([5, 6, 7]) | ||
chunk: Buffer.from([5, 6, 7]), | ||
}); | ||
@@ -436,3 +456,3 @@ }); | ||
length: 11, | ||
fields: ['!'] | ||
fields: ['!'], | ||
}); | ||
@@ -443,3 +463,3 @@ assert_1.default.equal(messages[0].fields[0], '!'); | ||
length: 5, | ||
status: 'I' | ||
status: 'I', | ||
}); | ||
@@ -472,10 +492,7 @@ }; | ||
splitAndVerifyTwoMessages(fullBuffer.length - 4), | ||
splitAndVerifyTwoMessages(fullBuffer.length - 6) | ||
splitAndVerifyTwoMessages(fullBuffer.length - 6), | ||
]); | ||
}); | ||
it('at the end', function () { | ||
return Promise.all([ | ||
splitAndVerifyTwoMessages(8), | ||
splitAndVerifyTwoMessages(1) | ||
]); | ||
return Promise.all([splitAndVerifyTwoMessages(8), splitAndVerifyTwoMessages(1)]); | ||
}); | ||
@@ -482,0 +499,0 @@ }); |
@@ -17,3 +17,3 @@ "use strict"; | ||
name: "noData" /* noData */, | ||
length: 5 | ||
length: 5, | ||
}; | ||
@@ -20,0 +20,0 @@ exports.portalSuspended = { |
@@ -13,3 +13,3 @@ "use strict"; | ||
user: 'brian', | ||
database: 'bang' | ||
database: 'bang', | ||
}); | ||
@@ -25,3 +25,4 @@ assert_1.default.deepEqual(actual, new buffer_list_1.default() | ||
.addCString("'utf-8'") | ||
.addCString('').join(true)); | ||
.addCString('') | ||
.join(true)); | ||
}); | ||
@@ -53,6 +54,3 @@ it('builds password message', function () { | ||
const actual = serializer_1.serialize.parse({ text: '!' }); | ||
var expected = new buffer_list_1.default() | ||
.addCString('') | ||
.addCString('!') | ||
.addInt16(0).join(true, 'P'); | ||
var expected = new buffer_list_1.default().addCString('').addCString('!').addInt16(0).join(true, 'P'); | ||
assert_1.default.deepEqual(actual, expected); | ||
@@ -64,8 +62,5 @@ }); | ||
text: 'select * from boom', | ||
types: [] | ||
types: [], | ||
}); | ||
var expected = new buffer_list_1.default() | ||
.addCString('boom') | ||
.addCString('select * from boom') | ||
.addInt16(0).join(true, 'P'); | ||
var expected = new buffer_list_1.default().addCString('boom').addCString('select * from boom').addInt16(0).join(true, 'P'); | ||
assert_1.default.deepEqual(actual, expected); | ||
@@ -77,3 +72,3 @@ }); | ||
text: 'select * from bang where name = $1', | ||
types: [1, 2, 3, 4] | ||
types: [1, 2, 3, 4], | ||
}); | ||
@@ -87,3 +82,4 @@ var expected = new buffer_list_1.default() | ||
.addInt32(3) | ||
.addInt32(4).join(true, 'P'); | ||
.addInt32(4) | ||
.join(true, 'P'); | ||
assert_1.default.deepEqual(actual, expected); | ||
@@ -108,3 +104,3 @@ }); | ||
statement: 'woo', | ||
values: ['1', 'hi', null, 'zing'] | ||
values: ['1', 'hi', null, 'zing'], | ||
}); | ||
@@ -132,3 +128,3 @@ var expectedBuffer = new buffer_list_1.default() | ||
statement: 'woo', | ||
values: ['1', 'hi', null, Buffer.from('zing', 'utf8')] | ||
values: ['1', 'hi', null, Buffer.from('zing', 'utf8')], | ||
}); | ||
@@ -158,6 +154,3 @@ var expectedBuffer = new buffer_list_1.default() | ||
const actual = serializer_1.serialize.execute(); | ||
var expectedBuffer = new buffer_list_1.default() | ||
.addCString('') | ||
.addInt32(0) | ||
.join(true, 'E'); | ||
var expectedBuffer = new buffer_list_1.default().addCString('').addInt32(0).join(true, 'E'); | ||
assert_1.default.deepEqual(actual, expectedBuffer); | ||
@@ -168,8 +161,5 @@ }); | ||
portal: 'my favorite portal', | ||
rows: 100 | ||
rows: 100, | ||
}); | ||
var expectedBuffer = new buffer_list_1.default() | ||
.addCString('my favorite portal') | ||
.addInt32(100) | ||
.join(true, 'E'); | ||
var expectedBuffer = new buffer_list_1.default().addCString('my favorite portal').addInt32(100).join(true, 'E'); | ||
assert_1.default.deepEqual(actual, expectedBuffer); | ||
@@ -176,0 +166,0 @@ }); |
@@ -34,3 +34,3 @@ "use strict"; | ||
let offset = 0; | ||
while ((offset + HEADER_LENGTH) <= combinedBuffer.byteLength) { | ||
while (offset + HEADER_LENGTH <= combinedBuffer.byteLength) { | ||
// code is 1 byte long - it identifies the message type | ||
@@ -240,3 +240,5 @@ const code = combinedBuffer[offset]; | ||
const messageValue = fields.M; | ||
const message = name === "notice" /* notice */ ? new messages_1.NoticeMessage(length, messageValue) : new messages_1.DatabaseError(messageValue, length, name); | ||
const message = name === "notice" /* notice */ | ||
? new messages_1.NoticeMessage(length, messageValue) | ||
: new messages_1.DatabaseError(messageValue, length, name); | ||
message.severity = fields.S; | ||
@@ -243,0 +245,0 @@ message.code = fields.C; |
@@ -15,6 +15,3 @@ "use strict"; | ||
var length = bodyBuffer.length + 4; | ||
return new buffer_writer_1.Writer() | ||
.addInt32(length) | ||
.add(bodyBuffer) | ||
.flush(); | ||
return new buffer_writer_1.Writer().addInt32(length).add(bodyBuffer).flush(); | ||
}; | ||
@@ -32,6 +29,3 @@ const requestSsl = () => { | ||
// 0x70 = 'p' | ||
writer | ||
.addCString(mechanism) | ||
.addInt32(Buffer.byteLength(initialResponse)) | ||
.addString(initialResponse); | ||
writer.addCString(mechanism).addInt32(Buffer.byteLength(initialResponse)).addString(initialResponse); | ||
return writer.flush(112 /* startup */); | ||
@@ -83,5 +77,3 @@ }; | ||
} | ||
var buffer = writer | ||
.addCString(portal) | ||
.addCString(statement); | ||
var buffer = writer.addCString(portal).addCString(statement); | ||
if (!useBinary) { | ||
@@ -123,3 +115,3 @@ buffer.addInt16(0); | ||
// this is the happy path for most queries | ||
if (!config || !config.portal && !config.rows) { | ||
if (!config || (!config.portal && !config.rows)) { | ||
return emptyExecute; | ||
@@ -163,7 +155,7 @@ } | ||
const describe = (msg) => { | ||
return msg.name ? | ||
cstringMessage(68 /* describe */, `${msg.type}${msg.name || ''}`) : | ||
msg.type === 'P' ? | ||
emptyDescribePortal : | ||
emptyDescribeStatement; | ||
return msg.name | ||
? cstringMessage(68 /* describe */, `${msg.type}${msg.name || ''}`) | ||
: msg.type === 'P' | ||
? emptyDescribePortal | ||
: emptyDescribeStatement; | ||
}; | ||
@@ -203,5 +195,5 @@ const close = (msg) => { | ||
copyFail, | ||
cancel | ||
cancel, | ||
}; | ||
exports.serialize = serialize; | ||
//# sourceMappingURL=serializer.js.map |
@@ -12,3 +12,3 @@ "use strict"; | ||
addInt16(val, front) { | ||
return this.add(Buffer.from([(val >>> 8), (val >>> 0)]), front); | ||
return this.add(Buffer.from([val >>> 8, val >>> 0]), front); | ||
} | ||
@@ -21,8 +21,3 @@ getByteLength(initial) { | ||
addInt32(val, first) { | ||
return this.add(Buffer.from([ | ||
(val >>> 24 & 0xFF), | ||
(val >>> 16 & 0xFF), | ||
(val >>> 8 & 0xFF), | ||
(val >>> 0 & 0xFF) | ||
]), first); | ||
return this.add(Buffer.from([(val >>> 24) & 0xff, (val >>> 16) & 0xff, (val >>> 8) & 0xff, (val >>> 0) & 0xff]), first); | ||
} | ||
@@ -29,0 +24,0 @@ addCString(val, front) { |
@@ -10,15 +10,9 @@ "use strict"; | ||
readyForQuery: function () { | ||
return new buffer_list_1.default() | ||
.add(Buffer.from('I')) | ||
.join(true, 'Z'); | ||
return new buffer_list_1.default().add(Buffer.from('I')).join(true, 'Z'); | ||
}, | ||
authenticationOk: function () { | ||
return new buffer_list_1.default() | ||
.addInt32(0) | ||
.join(true, 'R'); | ||
return new buffer_list_1.default().addInt32(0).join(true, 'R'); | ||
}, | ||
authenticationCleartextPassword: function () { | ||
return new buffer_list_1.default() | ||
.addInt32(3) | ||
.join(true, 'R'); | ||
return new buffer_list_1.default().addInt32(3).join(true, 'R'); | ||
}, | ||
@@ -32,36 +26,18 @@ authenticationMD5Password: function () { | ||
authenticationSASL: function () { | ||
return new buffer_list_1.default() | ||
.addInt32(10) | ||
.addCString('SCRAM-SHA-256') | ||
.addCString('') | ||
.join(true, 'R'); | ||
return new buffer_list_1.default().addInt32(10).addCString('SCRAM-SHA-256').addCString('').join(true, 'R'); | ||
}, | ||
authenticationSASLContinue: function () { | ||
return new buffer_list_1.default() | ||
.addInt32(11) | ||
.addString('data') | ||
.join(true, 'R'); | ||
return new buffer_list_1.default().addInt32(11).addString('data').join(true, 'R'); | ||
}, | ||
authenticationSASLFinal: function () { | ||
return new buffer_list_1.default() | ||
.addInt32(12) | ||
.addString('data') | ||
.join(true, 'R'); | ||
return new buffer_list_1.default().addInt32(12).addString('data').join(true, 'R'); | ||
}, | ||
parameterStatus: function (name, value) { | ||
return new buffer_list_1.default() | ||
.addCString(name) | ||
.addCString(value) | ||
.join(true, 'S'); | ||
return new buffer_list_1.default().addCString(name).addCString(value).join(true, 'S'); | ||
}, | ||
backendKeyData: function (processID, secretKey) { | ||
return new buffer_list_1.default() | ||
.addInt32(processID) | ||
.addInt32(secretKey) | ||
.join(true, 'K'); | ||
return new buffer_list_1.default().addInt32(processID).addInt32(secretKey).join(true, 'K'); | ||
}, | ||
commandComplete: function (string) { | ||
return new buffer_list_1.default() | ||
.addCString(string) | ||
.join(true, 'C'); | ||
return new buffer_list_1.default().addCString(string).join(true, 'C'); | ||
}, | ||
@@ -73,3 +49,4 @@ rowDescription: function (fields) { | ||
fields.forEach(function (field) { | ||
buf.addCString(field.name) | ||
buf | ||
.addCString(field.name) | ||
.addInt32(field.tableID || 0) | ||
@@ -122,7 +99,3 @@ .addInt16(field.attributeNumber || 0) | ||
notification: function (id, channel, payload) { | ||
return new buffer_list_1.default() | ||
.addInt32(id) | ||
.addCString(channel) | ||
.addCString(payload) | ||
.join(true, 'A'); | ||
return new buffer_list_1.default().addInt32(id).addCString(channel).addCString(payload).join(true, 'A'); | ||
}, | ||
@@ -165,5 +138,5 @@ emptyQuery: function () { | ||
return new buffer_list_1.default().join(true, 'c'); | ||
} | ||
}, | ||
}; | ||
exports.default = buffers; | ||
//# sourceMappingURL=test-buffers.js.map |
{ | ||
"name": "pg-protocol", | ||
"version": "1.2.1", | ||
"version": "1.2.2", | ||
"description": "The postgres client/server binary protocol, implemented in TypeScript", | ||
@@ -25,3 +25,3 @@ "main": "dist/index.js", | ||
}, | ||
"gitHead": "da03b3f9050c85a7722413a03c199cc3bdbcf5bf" | ||
"gitHead": "35328807e3612cb267bee86dccb2551ad186624a" | ||
} |
@@ -1,2 +0,2 @@ | ||
// file for microbenchmarking | ||
// file for microbenchmarking | ||
@@ -18,6 +18,6 @@ import { Writer } from './buffer-writer' | ||
console.log(Date.now() - start) | ||
return; | ||
return | ||
} | ||
count++ | ||
for(let i = 0; i < LOOPS; i++) { | ||
for (let i = 0; i < LOOPS; i++) { | ||
reader.setBuffer(0, buffer) | ||
@@ -24,0 +24,0 @@ reader.cstring() |
@@ -1,54 +0,53 @@ | ||
const emptyBuffer = Buffer.allocUnsafe(0); | ||
const emptyBuffer = Buffer.allocUnsafe(0) | ||
export class BufferReader { | ||
private buffer: Buffer = emptyBuffer; | ||
private buffer: Buffer = emptyBuffer | ||
// TODO(bmc): support non-utf8 encoding? | ||
private encoding: string = 'utf-8'; | ||
private encoding: string = 'utf-8' | ||
constructor(private offset: number = 0) { | ||
} | ||
constructor(private offset: number = 0) {} | ||
public setBuffer(offset: number, buffer: Buffer): void { | ||
this.offset = offset; | ||
this.buffer = buffer; | ||
this.offset = offset | ||
this.buffer = buffer | ||
} | ||
public int16(): number { | ||
const result = this.buffer.readInt16BE(this.offset); | ||
this.offset += 2; | ||
return result; | ||
const result = this.buffer.readInt16BE(this.offset) | ||
this.offset += 2 | ||
return result | ||
} | ||
public byte(): number { | ||
const result = this.buffer[this.offset]; | ||
this.offset++; | ||
return result; | ||
const result = this.buffer[this.offset] | ||
this.offset++ | ||
return result | ||
} | ||
public int32(): number { | ||
const result = this.buffer.readInt32BE(this.offset); | ||
this.offset += 4; | ||
return result; | ||
const result = this.buffer.readInt32BE(this.offset) | ||
this.offset += 4 | ||
return result | ||
} | ||
public string(length: number): string { | ||
const result = this.buffer.toString(this.encoding, this.offset, this.offset + length); | ||
this.offset += length; | ||
return result; | ||
const result = this.buffer.toString(this.encoding, this.offset, this.offset + length) | ||
this.offset += length | ||
return result | ||
} | ||
public cstring(): string { | ||
const start = this.offset; | ||
const start = this.offset | ||
let end = start | ||
while(this.buffer[end++] !== 0) { }; | ||
this.offset = end; | ||
return this.buffer.toString(this.encoding, start, end - 1); | ||
while (this.buffer[end++] !== 0) {} | ||
this.offset = end | ||
return this.buffer.toString(this.encoding, start, end - 1) | ||
} | ||
public bytes(length: number): Buffer { | ||
const result = this.buffer.slice(this.offset, this.offset + length); | ||
this.offset += length; | ||
return result; | ||
const result = this.buffer.slice(this.offset, this.offset + length) | ||
this.offset += length | ||
return result | ||
} | ||
} |
//binary data writer tuned for encoding binary specific to the postgres binary protocol | ||
export class Writer { | ||
private buffer: Buffer; | ||
private offset: number = 5; | ||
private headerPosition: number = 0; | ||
private buffer: Buffer | ||
private offset: number = 5 | ||
private headerPosition: number = 0 | ||
constructor(private size = 256) { | ||
@@ -12,10 +12,10 @@ this.buffer = Buffer.alloc(size) | ||
private ensure(size: number): void { | ||
var remaining = this.buffer.length - this.offset; | ||
var remaining = this.buffer.length - this.offset | ||
if (remaining < size) { | ||
var oldBuffer = this.buffer; | ||
var oldBuffer = this.buffer | ||
// exponential growth factor of around ~ 1.5 | ||
// https://stackoverflow.com/questions/2269063/buffer-growth-strategy | ||
var newSize = oldBuffer.length + (oldBuffer.length >> 1) + size; | ||
this.buffer = Buffer.alloc(newSize); | ||
oldBuffer.copy(this.buffer); | ||
var newSize = oldBuffer.length + (oldBuffer.length >> 1) + size | ||
this.buffer = Buffer.alloc(newSize) | ||
oldBuffer.copy(this.buffer) | ||
} | ||
@@ -25,45 +25,44 @@ } | ||
public addInt32(num: number): Writer { | ||
this.ensure(4); | ||
this.buffer[this.offset++] = (num >>> 24 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 16 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 8 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 0 & 0xFF); | ||
return this; | ||
this.ensure(4) | ||
this.buffer[this.offset++] = (num >>> 24) & 0xff | ||
this.buffer[this.offset++] = (num >>> 16) & 0xff | ||
this.buffer[this.offset++] = (num >>> 8) & 0xff | ||
this.buffer[this.offset++] = (num >>> 0) & 0xff | ||
return this | ||
} | ||
public addInt16(num: number): Writer { | ||
this.ensure(2); | ||
this.buffer[this.offset++] = (num >>> 8 & 0xFF); | ||
this.buffer[this.offset++] = (num >>> 0 & 0xFF); | ||
return this; | ||
this.ensure(2) | ||
this.buffer[this.offset++] = (num >>> 8) & 0xff | ||
this.buffer[this.offset++] = (num >>> 0) & 0xff | ||
return this | ||
} | ||
public addCString(string: string): Writer { | ||
if (!string) { | ||
this.ensure(1); | ||
this.ensure(1) | ||
} else { | ||
var len = Buffer.byteLength(string); | ||
this.ensure(len + 1); // +1 for null terminator | ||
var len = Buffer.byteLength(string) | ||
this.ensure(len + 1) // +1 for null terminator | ||
this.buffer.write(string, this.offset, 'utf-8') | ||
this.offset += len; | ||
this.offset += len | ||
} | ||
this.buffer[this.offset++] = 0; // null terminator | ||
return this; | ||
this.buffer[this.offset++] = 0 // null terminator | ||
return this | ||
} | ||
public addString(string: string = ""): Writer { | ||
var len = Buffer.byteLength(string); | ||
this.ensure(len); | ||
this.buffer.write(string, this.offset); | ||
this.offset += len; | ||
return this; | ||
public addString(string: string = ''): Writer { | ||
var len = Buffer.byteLength(string) | ||
this.ensure(len) | ||
this.buffer.write(string, this.offset) | ||
this.offset += len | ||
return this | ||
} | ||
public add(otherBuffer: Buffer): Writer { | ||
this.ensure(otherBuffer.length); | ||
otherBuffer.copy(this.buffer, this.offset); | ||
this.offset += otherBuffer.length; | ||
return this; | ||
this.ensure(otherBuffer.length) | ||
otherBuffer.copy(this.buffer, this.offset) | ||
this.offset += otherBuffer.length | ||
return this | ||
} | ||
@@ -73,3 +72,3 @@ | ||
if (code) { | ||
this.buffer[this.headerPosition] = code; | ||
this.buffer[this.headerPosition] = code | ||
//length is everything in this packet minus the code | ||
@@ -79,13 +78,12 @@ const length = this.offset - (this.headerPosition + 1) | ||
} | ||
return this.buffer.slice(code ? 0 : 5, this.offset); | ||
return this.buffer.slice(code ? 0 : 5, this.offset) | ||
} | ||
public flush(code?: number): Buffer { | ||
var result = this.join(code); | ||
this.offset = 5; | ||
this.headerPosition = 0; | ||
var result = this.join(code) | ||
this.offset = 5 | ||
this.headerPosition = 0 | ||
this.buffer = Buffer.allocUnsafe(this.size) | ||
return result; | ||
return result | ||
} | ||
} | ||
@@ -18,3 +18,4 @@ import buffers from './testing/test-buffers' | ||
var addRow = function (bufferList: BufferList, name: string, offset: number) { | ||
return bufferList.addCString(name) // field name | ||
return bufferList | ||
.addCString(name) // field name | ||
.addInt32(offset++) // table id | ||
@@ -35,3 +36,3 @@ .addInt16(offset++) // attribute of column number | ||
typeModifier: 5, | ||
formatCode: 0 | ||
formatCode: 0, | ||
} | ||
@@ -41,15 +42,16 @@ var oneRowDescBuff = buffers.rowDescription([row1]) | ||
var twoRowBuf = buffers.rowDescription([row1, { | ||
name: 'whoah', | ||
tableID: 10, | ||
attributeNumber: 11, | ||
dataTypeID: 12, | ||
dataTypeSize: 13, | ||
typeModifier: 14, | ||
formatCode: 0 | ||
}]) | ||
var twoRowBuf = buffers.rowDescription([ | ||
row1, | ||
{ | ||
name: 'whoah', | ||
tableID: 10, | ||
attributeNumber: 11, | ||
dataTypeID: 12, | ||
dataTypeSize: 13, | ||
typeModifier: 14, | ||
formatCode: 0, | ||
}, | ||
]) | ||
var emptyRowFieldBuf = new BufferList() | ||
.addInt16(0) | ||
.join(true, 'D') | ||
var emptyRowFieldBuf = new BufferList().addInt16(0).join(true, 'D') | ||
@@ -68,3 +70,3 @@ var emptyRowFieldBuf = buffers.dataRow([]) | ||
name: 'authenticationOk', | ||
length: 8 | ||
length: 8, | ||
} | ||
@@ -76,3 +78,3 @@ | ||
parameterValue: 'UTF8', | ||
length: 25 | ||
length: 25, | ||
} | ||
@@ -83,3 +85,3 @@ | ||
processID: 1, | ||
secretKey: 2 | ||
secretKey: 2, | ||
} | ||
@@ -90,3 +92,3 @@ | ||
length: 5, | ||
status: 'I' | ||
status: 'I', | ||
} | ||
@@ -97,3 +99,3 @@ | ||
length: 13, | ||
text: 'SELECT 3' | ||
text: 'SELECT 3', | ||
} | ||
@@ -114,11 +116,13 @@ var emptyRowDescriptionBuffer = new BufferList() | ||
fieldCount: 1, | ||
fields: [{ | ||
name: 'id', | ||
tableID: 1, | ||
columnID: 2, | ||
dataTypeID: 3, | ||
dataTypeSize: 4, | ||
dataTypeModifier: 5, | ||
format: 'text' | ||
}] | ||
fields: [ | ||
{ | ||
name: 'id', | ||
tableID: 1, | ||
columnID: 2, | ||
dataTypeID: 3, | ||
dataTypeSize: 4, | ||
dataTypeModifier: 5, | ||
format: 'text', | ||
}, | ||
], | ||
} | ||
@@ -130,20 +134,22 @@ | ||
fieldCount: 2, | ||
fields: [{ | ||
name: 'bang', | ||
tableID: 1, | ||
columnID: 2, | ||
dataTypeID: 3, | ||
dataTypeSize: 4, | ||
dataTypeModifier: 5, | ||
format: 'text' | ||
}, | ||
{ | ||
name: 'whoah', | ||
tableID: 10, | ||
columnID: 11, | ||
dataTypeID: 12, | ||
dataTypeSize: 13, | ||
dataTypeModifier: 14, | ||
format: 'text' | ||
}] | ||
fields: [ | ||
{ | ||
name: 'bang', | ||
tableID: 1, | ||
columnID: 2, | ||
dataTypeID: 3, | ||
dataTypeSize: 4, | ||
dataTypeModifier: 5, | ||
format: 'text', | ||
}, | ||
{ | ||
name: 'whoah', | ||
tableID: 10, | ||
columnID: 11, | ||
dataTypeID: 12, | ||
dataTypeSize: 13, | ||
dataTypeModifier: 14, | ||
format: 'text', | ||
}, | ||
], | ||
} | ||
@@ -154,3 +160,3 @@ | ||
const messages = await parseBuffers([buffer]) | ||
const [lastMessage] = messages; | ||
const [lastMessage] = messages | ||
@@ -170,3 +176,3 @@ for (const key in expectedMessage) { | ||
var expectedPlainPasswordMessage = { | ||
name: 'authenticationCleartextPassword' | ||
name: 'authenticationCleartextPassword', | ||
} | ||
@@ -176,3 +182,3 @@ | ||
name: 'authenticationMD5Password', | ||
salt: Buffer.from([1, 2, 3, 4]) | ||
salt: Buffer.from([1, 2, 3, 4]), | ||
} | ||
@@ -182,3 +188,3 @@ | ||
name: 'authenticationSASL', | ||
mechanisms: ['SCRAM-SHA-256'] | ||
mechanisms: ['SCRAM-SHA-256'], | ||
} | ||
@@ -201,11 +207,9 @@ | ||
channel: 'hi', | ||
payload: 'boom' | ||
payload: 'boom', | ||
} | ||
const parseBuffers = async (buffers: Buffer[]): Promise<BackendMessage[]> => { | ||
const stream = new PassThrough(); | ||
const stream = new PassThrough() | ||
for (const buffer of buffers) { | ||
stream.write(buffer); | ||
stream.write(buffer) | ||
} | ||
@@ -237,3 +241,3 @@ stream.end() | ||
testForMessage(Buffer.from([0x6e, 0, 0, 0, 4]), { | ||
name: 'noData' | ||
name: 'noData', | ||
}) | ||
@@ -251,3 +255,3 @@ | ||
name: 'dataRow', | ||
fieldCount: 0 | ||
fieldCount: 0, | ||
}) | ||
@@ -260,3 +264,3 @@ }) | ||
fieldCount: 1, | ||
fields: ['test'] | ||
fields: ['test'], | ||
}) | ||
@@ -271,3 +275,3 @@ }) | ||
name: 'notice', | ||
code: 'code' | ||
code: 'code', | ||
}) | ||
@@ -277,46 +281,60 @@ }) | ||
testForMessage(buffers.error([]), { | ||
name: 'error' | ||
name: 'error', | ||
}) | ||
describe('with all the fields', function () { | ||
var buffer = buffers.error([{ | ||
type: 'S', | ||
value: 'ERROR' | ||
}, { | ||
type: 'C', | ||
value: 'code' | ||
}, { | ||
type: 'M', | ||
value: 'message' | ||
}, { | ||
type: 'D', | ||
value: 'details' | ||
}, { | ||
type: 'H', | ||
value: 'hint' | ||
}, { | ||
type: 'P', | ||
value: '100' | ||
}, { | ||
type: 'p', | ||
value: '101' | ||
}, { | ||
type: 'q', | ||
value: 'query' | ||
}, { | ||
type: 'W', | ||
value: 'where' | ||
}, { | ||
type: 'F', | ||
value: 'file' | ||
}, { | ||
type: 'L', | ||
value: 'line' | ||
}, { | ||
type: 'R', | ||
value: 'routine' | ||
}, { | ||
type: 'Z', // ignored | ||
value: 'alsdkf' | ||
}]) | ||
var buffer = buffers.error([ | ||
{ | ||
type: 'S', | ||
value: 'ERROR', | ||
}, | ||
{ | ||
type: 'C', | ||
value: 'code', | ||
}, | ||
{ | ||
type: 'M', | ||
value: 'message', | ||
}, | ||
{ | ||
type: 'D', | ||
value: 'details', | ||
}, | ||
{ | ||
type: 'H', | ||
value: 'hint', | ||
}, | ||
{ | ||
type: 'P', | ||
value: '100', | ||
}, | ||
{ | ||
type: 'p', | ||
value: '101', | ||
}, | ||
{ | ||
type: 'q', | ||
value: 'query', | ||
}, | ||
{ | ||
type: 'W', | ||
value: 'where', | ||
}, | ||
{ | ||
type: 'F', | ||
value: 'file', | ||
}, | ||
{ | ||
type: 'L', | ||
value: 'line', | ||
}, | ||
{ | ||
type: 'R', | ||
value: 'routine', | ||
}, | ||
{ | ||
type: 'Z', // ignored | ||
value: 'alsdkf', | ||
}, | ||
]) | ||
@@ -336,3 +354,3 @@ testForMessage(buffer, { | ||
line: 'line', | ||
routine: 'routine' | ||
routine: 'routine', | ||
}) | ||
@@ -342,15 +360,15 @@ }) | ||
testForMessage(parseCompleteBuffer, { | ||
name: 'parseComplete' | ||
name: 'parseComplete', | ||
}) | ||
testForMessage(bindCompleteBuffer, { | ||
name: 'bindComplete' | ||
name: 'bindComplete', | ||
}) | ||
testForMessage(bindCompleteBuffer, { | ||
name: 'bindComplete' | ||
name: 'bindComplete', | ||
}) | ||
testForMessage(buffers.closeComplete(), { | ||
name: 'closeComplete' | ||
name: 'closeComplete', | ||
}) | ||
@@ -360,3 +378,3 @@ | ||
testForMessage(portalSuspendedBuffer, { | ||
name: 'portalSuspended' | ||
name: 'portalSuspended', | ||
}) | ||
@@ -368,3 +386,3 @@ }) | ||
name: 'replicationStart', | ||
length: 4 | ||
length: 4, | ||
}) | ||
@@ -378,3 +396,3 @@ }) | ||
binary: false, | ||
columnTypes: [] | ||
columnTypes: [], | ||
}) | ||
@@ -386,3 +404,3 @@ | ||
binary: false, | ||
columnTypes: [0, 1] | ||
columnTypes: [0, 1], | ||
}) | ||
@@ -394,3 +412,3 @@ | ||
binary: false, | ||
columnTypes: [] | ||
columnTypes: [], | ||
}) | ||
@@ -402,3 +420,3 @@ | ||
binary: false, | ||
columnTypes: [0, 1, 2] | ||
columnTypes: [0, 1, 2], | ||
}) | ||
@@ -414,7 +432,6 @@ | ||
length: 7, | ||
chunk: Buffer.from([5, 6, 7]) | ||
chunk: Buffer.from([5, 6, 7]), | ||
}) | ||
}) | ||
// since the data message on a stream can randomly divide the incomming | ||
@@ -427,3 +444,3 @@ // tcp packets anywhere, we need to make sure we can parse every single | ||
it('parses when full buffer comes in', async function () { | ||
const messages = await parseBuffers([fullBuffer]); | ||
const messages = await parseBuffers([fullBuffer]) | ||
const message = messages[0] as any | ||
@@ -443,3 +460,3 @@ assert.equal(message.fields.length, 5) | ||
fullBuffer.copy(secondBuffer, 0, firstBuffer.length) | ||
const messages = await parseBuffers([fullBuffer]); | ||
const messages = await parseBuffers([fullBuffer]) | ||
const message = messages[0] as any | ||
@@ -482,3 +499,3 @@ assert.equal(message.fields.length, 5) | ||
length: 11, | ||
fields: ['!'] | ||
fields: ['!'], | ||
}) | ||
@@ -489,3 +506,3 @@ assert.equal(messages[0].fields[0], '!') | ||
length: 5, | ||
status: 'I' | ||
status: 'I', | ||
}) | ||
@@ -516,3 +533,3 @@ } | ||
splitAndVerifyTwoMessages(fullBuffer.length - 4), | ||
splitAndVerifyTwoMessages(fullBuffer.length - 6) | ||
splitAndVerifyTwoMessages(fullBuffer.length - 6), | ||
]) | ||
@@ -522,10 +539,6 @@ }) | ||
it('at the end', function () { | ||
return Promise.all([ | ||
splitAndVerifyTwoMessages(8), | ||
splitAndVerifyTwoMessages(1) | ||
]) | ||
return Promise.all([splitAndVerifyTwoMessages(8), splitAndVerifyTwoMessages(1)]) | ||
}) | ||
}) | ||
}) | ||
}) |
@@ -1,3 +0,3 @@ | ||
import { BackendMessage } from './messages'; | ||
import { serialize } from './serializer'; | ||
import { BackendMessage } from './messages' | ||
import { serialize } from './serializer' | ||
import { Parser, MessageCallback } from './parser' | ||
@@ -11,2 +11,2 @@ | ||
export { serialize }; | ||
export { serialize } |
@@ -1,2 +0,2 @@ | ||
export type Mode = 'text' | 'binary'; | ||
export type Mode = 'text' | 'binary' | ||
@@ -33,4 +33,4 @@ export const enum MessageName { | ||
export interface BackendMessage { | ||
name: MessageName; | ||
length: number; | ||
name: MessageName | ||
length: number | ||
} | ||
@@ -41,3 +41,3 @@ | ||
length: 5, | ||
}; | ||
} | ||
@@ -56,3 +56,3 @@ export const bindComplete: BackendMessage = { | ||
name: MessageName.noData, | ||
length: 5 | ||
length: 5, | ||
} | ||
@@ -81,38 +81,38 @@ | ||
interface NoticeOrError { | ||
message: string | undefined; | ||
severity: string | undefined; | ||
code: string | undefined; | ||
detail: string | undefined; | ||
hint: string | undefined; | ||
position: string | undefined; | ||
internalPosition: string | undefined; | ||
internalQuery: string | undefined; | ||
where: string | undefined; | ||
schema: string | undefined; | ||
table: string | undefined; | ||
column: string | undefined; | ||
dataType: string | undefined; | ||
constraint: string | undefined; | ||
file: string | undefined; | ||
line: string | undefined; | ||
routine: string | undefined; | ||
message: string | undefined | ||
severity: string | undefined | ||
code: string | undefined | ||
detail: string | undefined | ||
hint: string | undefined | ||
position: string | undefined | ||
internalPosition: string | undefined | ||
internalQuery: string | undefined | ||
where: string | undefined | ||
schema: string | undefined | ||
table: string | undefined | ||
column: string | undefined | ||
dataType: string | undefined | ||
constraint: string | undefined | ||
file: string | undefined | ||
line: string | undefined | ||
routine: string | undefined | ||
} | ||
export class DatabaseError extends Error implements NoticeOrError { | ||
public severity: string | undefined; | ||
public code: string | undefined; | ||
public detail: string | undefined; | ||
public hint: string | undefined; | ||
public position: string | undefined; | ||
public internalPosition: string | undefined; | ||
public internalQuery: string | undefined; | ||
public where: string | undefined; | ||
public schema: string | undefined; | ||
public table: string | undefined; | ||
public column: string | undefined; | ||
public dataType: string | undefined; | ||
public constraint: string | undefined; | ||
public file: string | undefined; | ||
public line: string | undefined; | ||
public routine: string | undefined; | ||
public severity: string | undefined | ||
public code: string | undefined | ||
public detail: string | undefined | ||
public hint: string | undefined | ||
public position: string | undefined | ||
public internalPosition: string | undefined | ||
public internalQuery: string | undefined | ||
public where: string | undefined | ||
public schema: string | undefined | ||
public table: string | undefined | ||
public column: string | undefined | ||
public dataType: string | undefined | ||
public constraint: string | undefined | ||
public file: string | undefined | ||
public line: string | undefined | ||
public routine: string | undefined | ||
constructor(message: string, public readonly length: number, public readonly name: MessageName) { | ||
@@ -124,12 +124,15 @@ super(message) | ||
export class CopyDataMessage { | ||
public readonly name = MessageName.copyData; | ||
constructor(public readonly length: number, public readonly chunk: Buffer) { | ||
} | ||
public readonly name = MessageName.copyData | ||
constructor(public readonly length: number, public readonly chunk: Buffer) {} | ||
} | ||
export class CopyResponse { | ||
public readonly columnTypes: number[]; | ||
constructor(public readonly length: number, public readonly name: MessageName, public readonly binary: boolean, columnCount: number) { | ||
this.columnTypes = new Array(columnCount); | ||
public readonly columnTypes: number[] | ||
constructor( | ||
public readonly length: number, | ||
public readonly name: MessageName, | ||
public readonly binary: boolean, | ||
columnCount: number | ||
) { | ||
this.columnTypes = new Array(columnCount) | ||
} | ||
@@ -139,9 +142,16 @@ } | ||
export class Field { | ||
constructor(public readonly name: string, public readonly tableID: number, public readonly columnID: number, public readonly dataTypeID: number, public readonly dataTypeSize: number, public readonly dataTypeModifier: number, public readonly format: Mode) { | ||
} | ||
constructor( | ||
public readonly name: string, | ||
public readonly tableID: number, | ||
public readonly columnID: number, | ||
public readonly dataTypeID: number, | ||
public readonly dataTypeSize: number, | ||
public readonly dataTypeModifier: number, | ||
public readonly format: Mode | ||
) {} | ||
} | ||
export class RowDescriptionMessage { | ||
public readonly name: MessageName = MessageName.rowDescription; | ||
public readonly fields: Field[]; | ||
public readonly name: MessageName = MessageName.rowDescription | ||
public readonly fields: Field[] | ||
constructor(public readonly length: number, public readonly fieldCount: number) { | ||
@@ -153,30 +163,33 @@ this.fields = new Array(this.fieldCount) | ||
export class ParameterStatusMessage { | ||
public readonly name: MessageName = MessageName.parameterStatus; | ||
constructor(public readonly length: number, public readonly parameterName: string, public readonly parameterValue: string) { | ||
} | ||
public readonly name: MessageName = MessageName.parameterStatus | ||
constructor( | ||
public readonly length: number, | ||
public readonly parameterName: string, | ||
public readonly parameterValue: string | ||
) {} | ||
} | ||
export class AuthenticationMD5Password implements BackendMessage { | ||
public readonly name: MessageName = MessageName.authenticationMD5Password; | ||
constructor(public readonly length: number, public readonly salt: Buffer) { | ||
} | ||
public readonly name: MessageName = MessageName.authenticationMD5Password | ||
constructor(public readonly length: number, public readonly salt: Buffer) {} | ||
} | ||
export class BackendKeyDataMessage { | ||
public readonly name: MessageName = MessageName.backendKeyData; | ||
constructor(public readonly length: number, public readonly processID: number, public readonly secretKey: number) { | ||
} | ||
public readonly name: MessageName = MessageName.backendKeyData | ||
constructor(public readonly length: number, public readonly processID: number, public readonly secretKey: number) {} | ||
} | ||
export class NotificationResponseMessage { | ||
public readonly name: MessageName = MessageName.notification; | ||
constructor(public readonly length: number, public readonly processId: number, public readonly channel: string, public readonly payload: string) { | ||
} | ||
public readonly name: MessageName = MessageName.notification | ||
constructor( | ||
public readonly length: number, | ||
public readonly processId: number, | ||
public readonly channel: string, | ||
public readonly payload: string | ||
) {} | ||
} | ||
export class ReadyForQueryMessage { | ||
public readonly name: MessageName = MessageName.readyForQuery; | ||
constructor(public readonly length: number, public readonly status: string) { | ||
} | ||
public readonly name: MessageName = MessageName.readyForQuery | ||
constructor(public readonly length: number, public readonly status: string) {} | ||
} | ||
@@ -186,11 +199,10 @@ | ||
public readonly name: MessageName = MessageName.commandComplete | ||
constructor(public readonly length: number, public readonly text: string) { | ||
} | ||
constructor(public readonly length: number, public readonly text: string) {} | ||
} | ||
export class DataRowMessage { | ||
public readonly fieldCount: number; | ||
public readonly fieldCount: number | ||
public readonly name: MessageName = MessageName.dataRow | ||
constructor(public length: number, public fields: any[]) { | ||
this.fieldCount = fields.length; | ||
this.fieldCount = fields.length | ||
} | ||
@@ -201,19 +213,19 @@ } | ||
constructor(public readonly length: number, public readonly message: string | undefined) {} | ||
public readonly name = MessageName.notice; | ||
public severity: string | undefined; | ||
public code: string | undefined; | ||
public detail: string | undefined; | ||
public hint: string | undefined; | ||
public position: string | undefined; | ||
public internalPosition: string | undefined; | ||
public internalQuery: string | undefined; | ||
public where: string | undefined; | ||
public schema: string | undefined; | ||
public table: string | undefined; | ||
public column: string | undefined; | ||
public dataType: string | undefined; | ||
public constraint: string | undefined; | ||
public file: string | undefined; | ||
public line: string | undefined; | ||
public routine: string | undefined; | ||
public readonly name = MessageName.notice | ||
public severity: string | undefined | ||
public code: string | undefined | ||
public detail: string | undefined | ||
public hint: string | undefined | ||
public position: string | undefined | ||
public internalPosition: string | undefined | ||
public internalQuery: string | undefined | ||
public where: string | undefined | ||
public schema: string | undefined | ||
public table: string | undefined | ||
public column: string | undefined | ||
public dataType: string | undefined | ||
public constraint: string | undefined | ||
public file: string | undefined | ||
public line: string | undefined | ||
public routine: string | undefined | ||
} |
@@ -9,14 +9,18 @@ import assert from 'assert' | ||
user: 'brian', | ||
database: 'bang' | ||
database: 'bang', | ||
}) | ||
assert.deepEqual(actual, new BufferList() | ||
.addInt16(3) | ||
.addInt16(0) | ||
.addCString('user') | ||
.addCString('brian') | ||
.addCString('database') | ||
.addCString('bang') | ||
.addCString('client_encoding') | ||
.addCString("'utf-8'") | ||
.addCString('').join(true)) | ||
assert.deepEqual( | ||
actual, | ||
new BufferList() | ||
.addInt16(3) | ||
.addInt16(0) | ||
.addCString('user') | ||
.addCString('brian') | ||
.addCString('database') | ||
.addCString('bang') | ||
.addCString('client_encoding') | ||
.addCString("'utf-8'") | ||
.addCString('') | ||
.join(true) | ||
) | ||
}) | ||
@@ -32,3 +36,3 @@ | ||
const expected = new BufferList().addInt32(80877103).join(true) | ||
assert.deepEqual(actual, expected); | ||
assert.deepEqual(actual, expected) | ||
}) | ||
@@ -41,3 +45,2 @@ | ||
it('builds SCRAMClientFinalMessage message', function () { | ||
@@ -48,3 +51,2 @@ const actual = serialize.sendSCRAMClientFinalMessage('data') | ||
it('builds query message', function () { | ||
@@ -56,11 +58,6 @@ var txt = 'select * from boom' | ||
describe('parse message', () => { | ||
it('builds parse message', function () { | ||
const actual = serialize.parse({ text: '!' }) | ||
var expected = new BufferList() | ||
.addCString('') | ||
.addCString('!') | ||
.addInt16(0).join(true, 'P') | ||
var expected = new BufferList().addCString('').addCString('!').addInt16(0).join(true, 'P') | ||
assert.deepEqual(actual, expected) | ||
@@ -73,8 +70,5 @@ }) | ||
text: 'select * from boom', | ||
types: [] | ||
types: [], | ||
}) | ||
var expected = new BufferList() | ||
.addCString('boom') | ||
.addCString('select * from boom') | ||
.addInt16(0).join(true, 'P') | ||
var expected = new BufferList().addCString('boom').addCString('select * from boom').addInt16(0).join(true, 'P') | ||
assert.deepEqual(actual, expected) | ||
@@ -87,3 +81,3 @@ }) | ||
text: 'select * from bang where name = $1', | ||
types: [1, 2, 3, 4] | ||
types: [1, 2, 3, 4], | ||
}) | ||
@@ -97,9 +91,8 @@ var expected = new BufferList() | ||
.addInt32(3) | ||
.addInt32(4).join(true, 'P') | ||
.addInt32(4) | ||
.join(true, 'P') | ||
assert.deepEqual(actual, expected) | ||
}) | ||
}) | ||
describe('bind messages', function () { | ||
@@ -123,6 +116,6 @@ it('with no values', function () { | ||
statement: 'woo', | ||
values: ['1', 'hi', null, 'zing'] | ||
values: ['1', 'hi', null, 'zing'], | ||
}) | ||
var expectedBuffer = new BufferList() | ||
.addCString('bang') // portal name | ||
.addCString('bang') // portal name | ||
.addCString('woo') // statement name | ||
@@ -148,12 +141,12 @@ .addInt16(0) | ||
statement: 'woo', | ||
values: ['1', 'hi', null, Buffer.from('zing', 'utf8')] | ||
values: ['1', 'hi', null, Buffer.from('zing', 'utf8')], | ||
}) | ||
var expectedBuffer = new BufferList() | ||
.addCString('bang') // portal name | ||
.addCString('bang') // portal name | ||
.addCString('woo') // statement name | ||
.addInt16(4)// value count | ||
.addInt16(0)// string | ||
.addInt16(0)// string | ||
.addInt16(0)// string | ||
.addInt16(1)// binary | ||
.addInt16(4) // value count | ||
.addInt16(0) // string | ||
.addInt16(0) // string | ||
.addInt16(0) // string | ||
.addInt16(1) // binary | ||
.addInt16(4) | ||
@@ -175,6 +168,3 @@ .addInt32(1) | ||
const actual = serialize.execute() | ||
var expectedBuffer = new BufferList() | ||
.addCString('') | ||
.addInt32(0) | ||
.join(true, 'E') | ||
var expectedBuffer = new BufferList().addCString('').addInt32(0).join(true, 'E') | ||
assert.deepEqual(actual, expectedBuffer) | ||
@@ -186,8 +176,5 @@ }) | ||
portal: 'my favorite portal', | ||
rows: 100 | ||
rows: 100, | ||
}) | ||
var expectedBuffer = new BufferList() | ||
.addCString('my favorite portal') | ||
.addInt32(100) | ||
.join(true, 'E') | ||
var expectedBuffer = new BufferList().addCString('my favorite portal').addInt32(100).join(true, 'E') | ||
assert.deepEqual(actual, expectedBuffer) | ||
@@ -246,3 +233,3 @@ }) | ||
const actual = serialize.copyData(Buffer.from([1, 2, 3])) | ||
const expected = new BufferList().add(Buffer.from([1, 2,3 ])).join(true, 'd') | ||
const expected = new BufferList().add(Buffer.from([1, 2, 3])).join(true, 'd') | ||
assert.deepEqual(actual, expected) | ||
@@ -249,0 +236,0 @@ }) |
@@ -1,20 +0,45 @@ | ||
import { TransformOptions } from 'stream'; | ||
import { Mode, bindComplete, parseComplete, closeComplete, noData, portalSuspended, copyDone, replicationStart, emptyQuery, ReadyForQueryMessage, CommandCompleteMessage, CopyDataMessage, CopyResponse, NotificationResponseMessage, RowDescriptionMessage, Field, DataRowMessage, ParameterStatusMessage, BackendKeyDataMessage, DatabaseError, BackendMessage, MessageName, AuthenticationMD5Password, NoticeMessage } from './messages'; | ||
import { BufferReader } from './buffer-reader'; | ||
import { TransformOptions } from 'stream' | ||
import { | ||
Mode, | ||
bindComplete, | ||
parseComplete, | ||
closeComplete, | ||
noData, | ||
portalSuspended, | ||
copyDone, | ||
replicationStart, | ||
emptyQuery, | ||
ReadyForQueryMessage, | ||
CommandCompleteMessage, | ||
CopyDataMessage, | ||
CopyResponse, | ||
NotificationResponseMessage, | ||
RowDescriptionMessage, | ||
Field, | ||
DataRowMessage, | ||
ParameterStatusMessage, | ||
BackendKeyDataMessage, | ||
DatabaseError, | ||
BackendMessage, | ||
MessageName, | ||
AuthenticationMD5Password, | ||
NoticeMessage, | ||
} from './messages' | ||
import { BufferReader } from './buffer-reader' | ||
import assert from 'assert' | ||
// every message is prefixed with a single bye | ||
const CODE_LENGTH = 1; | ||
const CODE_LENGTH = 1 | ||
// every message has an int32 length which includes itself but does | ||
// NOT include the code in the length | ||
const LEN_LENGTH = 4; | ||
const LEN_LENGTH = 4 | ||
const HEADER_LENGTH = CODE_LENGTH + LEN_LENGTH; | ||
const HEADER_LENGTH = CODE_LENGTH + LEN_LENGTH | ||
export type Packet = { | ||
code: number; | ||
packet: Buffer; | ||
code: number | ||
packet: Buffer | ||
} | ||
const emptyBuffer = Buffer.allocUnsafe(0); | ||
const emptyBuffer = Buffer.allocUnsafe(0) | ||
@@ -49,8 +74,8 @@ type StreamOptions = TransformOptions & { | ||
export type MessageCallback = (msg: BackendMessage) => void; | ||
export type MessageCallback = (msg: BackendMessage) => void | ||
export class Parser { | ||
private remainingBuffer: Buffer = emptyBuffer; | ||
private reader = new BufferReader(); | ||
private mode: Mode; | ||
private remainingBuffer: Buffer = emptyBuffer | ||
private reader = new BufferReader() | ||
private mode: Mode | ||
@@ -61,28 +86,28 @@ constructor(opts?: StreamOptions) { | ||
} | ||
this.mode = opts?.mode || 'text'; | ||
this.mode = opts?.mode || 'text' | ||
} | ||
public parse(buffer: Buffer, callback: MessageCallback) { | ||
let combinedBuffer = buffer; | ||
let combinedBuffer = buffer | ||
if (this.remainingBuffer.byteLength) { | ||
combinedBuffer = Buffer.allocUnsafe(this.remainingBuffer.byteLength + buffer.byteLength); | ||
combinedBuffer = Buffer.allocUnsafe(this.remainingBuffer.byteLength + buffer.byteLength) | ||
this.remainingBuffer.copy(combinedBuffer) | ||
buffer.copy(combinedBuffer, this.remainingBuffer.byteLength) | ||
} | ||
let offset = 0; | ||
while ((offset + HEADER_LENGTH) <= combinedBuffer.byteLength) { | ||
let offset = 0 | ||
while (offset + HEADER_LENGTH <= combinedBuffer.byteLength) { | ||
// code is 1 byte long - it identifies the message type | ||
const code = combinedBuffer[offset]; | ||
const code = combinedBuffer[offset] | ||
// length is 1 Uint32BE - it is the length of the message EXCLUDING the code | ||
const length = combinedBuffer.readUInt32BE(offset + CODE_LENGTH); | ||
const length = combinedBuffer.readUInt32BE(offset + CODE_LENGTH) | ||
const fullMessageLength = CODE_LENGTH + length; | ||
const fullMessageLength = CODE_LENGTH + length | ||
if (fullMessageLength + offset <= combinedBuffer.byteLength) { | ||
const message = this.handlePacket(offset + HEADER_LENGTH, code, length, combinedBuffer); | ||
const message = this.handlePacket(offset + HEADER_LENGTH, code, length, combinedBuffer) | ||
callback(message) | ||
offset += fullMessageLength; | ||
offset += fullMessageLength | ||
} else { | ||
break; | ||
break | ||
} | ||
@@ -92,7 +117,6 @@ } | ||
if (offset === combinedBuffer.byteLength) { | ||
this.remainingBuffer = emptyBuffer; | ||
this.remainingBuffer = emptyBuffer | ||
} else { | ||
this.remainingBuffer = combinedBuffer.slice(offset) | ||
} | ||
} | ||
@@ -103,43 +127,43 @@ | ||
case MessageCodes.BindComplete: | ||
return bindComplete; | ||
return bindComplete | ||
case MessageCodes.ParseComplete: | ||
return parseComplete; | ||
return parseComplete | ||
case MessageCodes.CloseComplete: | ||
return closeComplete; | ||
return closeComplete | ||
case MessageCodes.NoData: | ||
return noData; | ||
return noData | ||
case MessageCodes.PortalSuspended: | ||
return portalSuspended; | ||
return portalSuspended | ||
case MessageCodes.CopyDone: | ||
return copyDone; | ||
return copyDone | ||
case MessageCodes.ReplicationStart: | ||
return replicationStart; | ||
return replicationStart | ||
case MessageCodes.EmptyQuery: | ||
return emptyQuery; | ||
return emptyQuery | ||
case MessageCodes.DataRow: | ||
return this.parseDataRowMessage(offset, length, bytes); | ||
return this.parseDataRowMessage(offset, length, bytes) | ||
case MessageCodes.CommandComplete: | ||
return this.parseCommandCompleteMessage(offset, length, bytes); | ||
return this.parseCommandCompleteMessage(offset, length, bytes) | ||
case MessageCodes.ReadyForQuery: | ||
return this.parseReadyForQueryMessage(offset, length, bytes); | ||
return this.parseReadyForQueryMessage(offset, length, bytes) | ||
case MessageCodes.NotificationResponse: | ||
return this.parseNotificationMessage(offset, length, bytes); | ||
return this.parseNotificationMessage(offset, length, bytes) | ||
case MessageCodes.AuthenticationResponse: | ||
return this.parseAuthenticationResponse(offset, length, bytes); | ||
return this.parseAuthenticationResponse(offset, length, bytes) | ||
case MessageCodes.ParameterStatus: | ||
return this.parseParameterStatusMessage(offset, length, bytes); | ||
return this.parseParameterStatusMessage(offset, length, bytes) | ||
case MessageCodes.BackendKeyData: | ||
return this.parseBackendKeyData(offset, length, bytes); | ||
return this.parseBackendKeyData(offset, length, bytes) | ||
case MessageCodes.ErrorMessage: | ||
return this.parseErrorMessage(offset, length, bytes, MessageName.error); | ||
return this.parseErrorMessage(offset, length, bytes, MessageName.error) | ||
case MessageCodes.NoticeMessage: | ||
return this.parseErrorMessage(offset, length, bytes, MessageName.notice); | ||
return this.parseErrorMessage(offset, length, bytes, MessageName.notice) | ||
case MessageCodes.RowDescriptionMessage: | ||
return this.parseRowDescriptionMessage(offset, length, bytes); | ||
return this.parseRowDescriptionMessage(offset, length, bytes) | ||
case MessageCodes.CopyIn: | ||
return this.parseCopyInMessage(offset, length, bytes); | ||
return this.parseCopyInMessage(offset, length, bytes) | ||
case MessageCodes.CopyOut: | ||
return this.parseCopyOutMessage(offset, length, bytes); | ||
return this.parseCopyOutMessage(offset, length, bytes) | ||
case MessageCodes.CopyData: | ||
return this.parseCopyData(offset, length, bytes); | ||
return this.parseCopyData(offset, length, bytes) | ||
default: | ||
@@ -151,4 +175,4 @@ assert.fail(`unknown message code: ${code.toString(16)}`) | ||
private parseReadyForQueryMessage(offset: number, length: number, bytes: Buffer) { | ||
this.reader.setBuffer(offset, bytes); | ||
const status = this.reader.string(1); | ||
this.reader.setBuffer(offset, bytes) | ||
const status = this.reader.string(1) | ||
return new ReadyForQueryMessage(length, status) | ||
@@ -158,10 +182,10 @@ } | ||
private parseCommandCompleteMessage(offset: number, length: number, bytes: Buffer) { | ||
this.reader.setBuffer(offset, bytes); | ||
const text = this.reader.cstring(); | ||
return new CommandCompleteMessage(length, text); | ||
this.reader.setBuffer(offset, bytes) | ||
const text = this.reader.cstring() | ||
return new CommandCompleteMessage(length, text) | ||
} | ||
private parseCopyData(offset: number, length: number, bytes: Buffer) { | ||
const chunk = bytes.slice(offset, offset + (length - 4)); | ||
return new CopyDataMessage(length, chunk); | ||
const chunk = bytes.slice(offset, offset + (length - 4)) | ||
return new CopyDataMessage(length, chunk) | ||
} | ||
@@ -178,28 +202,28 @@ | ||
private parseCopyMessage(offset: number, length: number, bytes: Buffer, messageName: MessageName) { | ||
this.reader.setBuffer(offset, bytes); | ||
const isBinary = this.reader.byte() !== 0; | ||
this.reader.setBuffer(offset, bytes) | ||
const isBinary = this.reader.byte() !== 0 | ||
const columnCount = this.reader.int16() | ||
const message = new CopyResponse(length, messageName, isBinary, columnCount); | ||
const message = new CopyResponse(length, messageName, isBinary, columnCount) | ||
for (let i = 0; i < columnCount; i++) { | ||
message.columnTypes[i] = this.reader.int16(); | ||
message.columnTypes[i] = this.reader.int16() | ||
} | ||
return message; | ||
return message | ||
} | ||
private parseNotificationMessage(offset: number, length: number, bytes: Buffer) { | ||
this.reader.setBuffer(offset, bytes); | ||
const processId = this.reader.int32(); | ||
const channel = this.reader.cstring(); | ||
const payload = this.reader.cstring(); | ||
return new NotificationResponseMessage(length, processId, channel, payload); | ||
this.reader.setBuffer(offset, bytes) | ||
const processId = this.reader.int32() | ||
const channel = this.reader.cstring() | ||
const payload = this.reader.cstring() | ||
return new NotificationResponseMessage(length, processId, channel, payload) | ||
} | ||
private parseRowDescriptionMessage(offset: number, length: number, bytes: Buffer) { | ||
this.reader.setBuffer(offset, bytes); | ||
this.reader.setBuffer(offset, bytes) | ||
const fieldCount = this.reader.int16() | ||
const message = new RowDescriptionMessage(length, fieldCount); | ||
const message = new RowDescriptionMessage(length, fieldCount) | ||
for (let i = 0; i < fieldCount; i++) { | ||
message.fields[i] = this.parseField() | ||
} | ||
return message; | ||
return message | ||
} | ||
@@ -214,3 +238,3 @@ | ||
const dataTypeModifier = this.reader.int32() | ||
const mode = this.reader.int16() === 0 ? 'text' : 'binary'; | ||
const mode = this.reader.int16() === 0 ? 'text' : 'binary' | ||
return new Field(name, tableID, columnID, dataTypeID, dataTypeSize, dataTypeModifier, mode) | ||
@@ -220,16 +244,16 @@ } | ||
private parseDataRowMessage(offset: number, length: number, bytes: Buffer) { | ||
this.reader.setBuffer(offset, bytes); | ||
const fieldCount = this.reader.int16(); | ||
const fields: any[] = new Array(fieldCount); | ||
this.reader.setBuffer(offset, bytes) | ||
const fieldCount = this.reader.int16() | ||
const fields: any[] = new Array(fieldCount) | ||
for (let i = 0; i < fieldCount; i++) { | ||
const len = this.reader.int32(); | ||
const len = this.reader.int32() | ||
// a -1 for length means the value of the field is null | ||
fields[i] = len === -1 ? null : this.reader.string(len) | ||
} | ||
return new DataRowMessage(length, fields); | ||
return new DataRowMessage(length, fields) | ||
} | ||
private parseParameterStatusMessage(offset: number, length: number, bytes: Buffer) { | ||
this.reader.setBuffer(offset, bytes); | ||
const name = this.reader.cstring(); | ||
this.reader.setBuffer(offset, bytes) | ||
const name = this.reader.cstring() | ||
const value = this.reader.cstring() | ||
@@ -240,3 +264,3 @@ return new ParameterStatusMessage(length, name, value) | ||
private parseBackendKeyData(offset: number, length: number, bytes: Buffer) { | ||
this.reader.setBuffer(offset, bytes); | ||
this.reader.setBuffer(offset, bytes) | ||
const processID = this.reader.int32() | ||
@@ -247,5 +271,4 @@ const secretKey = this.reader.int32() | ||
public parseAuthenticationResponse(offset: number, length: number, bytes: Buffer) { | ||
this.reader.setBuffer(offset, bytes); | ||
this.reader.setBuffer(offset, bytes) | ||
const code = this.reader.int32() | ||
@@ -256,7 +279,7 @@ // TODO(bmc): maybe better types here | ||
length, | ||
}; | ||
} | ||
switch (code) { | ||
case 0: // AuthenticationOk | ||
break; | ||
break | ||
case 3: // AuthenticationCleartextPassword | ||
@@ -270,4 +293,4 @@ if (message.length === 8) { | ||
message.name = MessageName.authenticationMD5Password | ||
const salt = this.reader.bytes(4); | ||
return new AuthenticationMD5Password(length, salt); | ||
const salt = this.reader.bytes(4) | ||
return new AuthenticationMD5Password(length, salt) | ||
} | ||
@@ -278,3 +301,3 @@ break | ||
message.mechanisms = [] | ||
let mechanism: string; | ||
let mechanism: string | ||
do { | ||
@@ -287,19 +310,19 @@ mechanism = this.reader.cstring() | ||
} while (mechanism) | ||
break; | ||
break | ||
case 11: // AuthenticationSASLContinue | ||
message.name = MessageName.authenticationSASLContinue | ||
message.data = this.reader.string(length - 4) | ||
break; | ||
break | ||
case 12: // AuthenticationSASLFinal | ||
message.name = MessageName.authenticationSASLFinal | ||
message.data = this.reader.string(length - 4) | ||
break; | ||
break | ||
default: | ||
throw new Error('Unknown authenticationOk message type ' + code) | ||
} | ||
return message; | ||
return message | ||
} | ||
private parseErrorMessage(offset: number, length: number, bytes: Buffer, name: MessageName) { | ||
this.reader.setBuffer(offset, bytes); | ||
this.reader.setBuffer(offset, bytes) | ||
const fields: Record<string, string> = {} | ||
@@ -314,3 +337,6 @@ let fieldType = this.reader.string(1) | ||
const message = name === MessageName.notice ? new NoticeMessage(length, messageValue) : new DatabaseError(messageValue, length, name) | ||
const message = | ||
name === MessageName.notice | ||
? new NoticeMessage(length, messageValue) | ||
: new DatabaseError(messageValue, length, name) | ||
@@ -333,4 +359,4 @@ message.severity = fields.S | ||
message.routine = fields.R | ||
return message; | ||
return message | ||
} | ||
} |
@@ -16,3 +16,3 @@ import { Writer } from './buffer-writer' | ||
copyDone = 0x63, | ||
copyFail = 0x66 | ||
copyFail = 0x66, | ||
} | ||
@@ -36,6 +36,3 @@ | ||
return new Writer() | ||
.addInt32(length) | ||
.add(bodyBuffer) | ||
.flush() | ||
return new Writer().addInt32(length).add(bodyBuffer).flush() | ||
} | ||
@@ -45,3 +42,3 @@ | ||
const response = Buffer.allocUnsafe(8) | ||
response.writeInt32BE(8, 0); | ||
response.writeInt32BE(8, 0) | ||
response.writeInt32BE(80877103, 4) | ||
@@ -57,6 +54,3 @@ return response | ||
// 0x70 = 'p' | ||
writer | ||
.addCString(mechanism) | ||
.addInt32(Buffer.byteLength(initialResponse)) | ||
.addString(initialResponse) | ||
writer.addCString(mechanism).addInt32(Buffer.byteLength(initialResponse)).addString(initialResponse) | ||
@@ -75,5 +69,5 @@ return writer.flush(code.startup) | ||
type ParseOpts = { | ||
name?: string; | ||
types?: number[]; | ||
text: string; | ||
name?: string | ||
types?: number[] | ||
text: string | ||
} | ||
@@ -116,6 +110,6 @@ | ||
type BindOpts = { | ||
portal?: string; | ||
binary?: boolean; | ||
statement?: string; | ||
values?: any[]; | ||
portal?: string | ||
binary?: boolean | ||
statement?: string | ||
values?: any[] | ||
} | ||
@@ -137,5 +131,3 @@ | ||
var buffer = writer | ||
.addCString(portal) | ||
.addCString(statement) | ||
var buffer = writer.addCString(portal).addCString(statement) | ||
if (!useBinary) { | ||
@@ -173,4 +165,4 @@ buffer.addInt16(0) | ||
type ExecOpts = { | ||
portal?: string; | ||
rows?: number; | ||
portal?: string | ||
rows?: number | ||
} | ||
@@ -182,4 +174,4 @@ | ||
// this is the happy path for most queries | ||
if (!config || !config.portal && !config.rows) { | ||
return emptyExecute; | ||
if (!config || (!config.portal && !config.rows)) { | ||
return emptyExecute | ||
} | ||
@@ -197,5 +189,5 @@ | ||
buff.write(portal, 5, 'utf-8') | ||
buff[portalLength + 5] = 0; // null terminate portal cString | ||
buff[portalLength + 5] = 0 // null terminate portal cString | ||
buff.writeUInt32BE(rows, buff.length - 4) | ||
return buff; | ||
return buff | ||
} | ||
@@ -210,8 +202,8 @@ | ||
buffer.writeInt32BE(secretKey, 12) | ||
return buffer; | ||
return buffer | ||
} | ||
type PortalOpts = { | ||
type: 'S' | 'P', | ||
name?: string; | ||
type: 'S' | 'P' | ||
name?: string | ||
} | ||
@@ -235,7 +227,7 @@ | ||
const describe = (msg: PortalOpts): Buffer => { | ||
return msg.name ? | ||
cstringMessage(code.describe,`${msg.type}${msg.name || ''}`) : | ||
msg.type === 'P' ? | ||
emptyDescribePortal : | ||
emptyDescribeStatement; | ||
return msg.name | ||
? cstringMessage(code.describe, `${msg.type}${msg.name || ''}`) | ||
: msg.type === 'P' | ||
? emptyDescribePortal | ||
: emptyDescribeStatement | ||
} | ||
@@ -253,3 +245,3 @@ | ||
const copyFail = (message: string): Buffer => { | ||
return cstringMessage(code.copyFail, message); | ||
return cstringMessage(code.copyFail, message) | ||
} | ||
@@ -282,5 +274,5 @@ | ||
copyFail, | ||
cancel | ||
cancel, | ||
} | ||
export { serialize } |
export default class BufferList { | ||
constructor(public buffers: Buffer[] = []) { | ||
constructor(public buffers: Buffer[] = []) {} | ||
} | ||
public add(buffer: Buffer, front?: boolean) { | ||
@@ -12,3 +10,3 @@ this.buffers[front ? 'unshift' : 'push'](buffer) | ||
public addInt16(val: number, front?: boolean) { | ||
return this.add(Buffer.from([(val >>> 8), (val >>> 0)]), front) | ||
return this.add(Buffer.from([val >>> 8, val >>> 0]), front) | ||
} | ||
@@ -23,8 +21,6 @@ | ||
public addInt32(val: number, first?: boolean) { | ||
return this.add(Buffer.from([ | ||
(val >>> 24 & 0xFF), | ||
(val >>> 16 & 0xFF), | ||
(val >>> 8 & 0xFF), | ||
(val >>> 0 & 0xFF) | ||
]), first) | ||
return this.add( | ||
Buffer.from([(val >>> 24) & 0xff, (val >>> 16) & 0xff, (val >>> 8) & 0xff, (val >>> 0) & 0xff]), | ||
first | ||
) | ||
} | ||
@@ -31,0 +27,0 @@ |
@@ -6,17 +6,11 @@ // http://developer.postgresql.org/pgdocs/postgres/protocol-message-formats.html | ||
readyForQuery: function () { | ||
return new BufferList() | ||
.add(Buffer.from('I')) | ||
.join(true, 'Z') | ||
return new BufferList().add(Buffer.from('I')).join(true, 'Z') | ||
}, | ||
authenticationOk: function () { | ||
return new BufferList() | ||
.addInt32(0) | ||
.join(true, 'R') | ||
return new BufferList().addInt32(0).join(true, 'R') | ||
}, | ||
authenticationCleartextPassword: function () { | ||
return new BufferList() | ||
.addInt32(3) | ||
.join(true, 'R') | ||
return new BufferList().addInt32(3).join(true, 'R') | ||
}, | ||
@@ -32,41 +26,23 @@ | ||
authenticationSASL: function () { | ||
return new BufferList() | ||
.addInt32(10) | ||
.addCString('SCRAM-SHA-256') | ||
.addCString('') | ||
.join(true, 'R') | ||
return new BufferList().addInt32(10).addCString('SCRAM-SHA-256').addCString('').join(true, 'R') | ||
}, | ||
authenticationSASLContinue: function () { | ||
return new BufferList() | ||
.addInt32(11) | ||
.addString('data') | ||
.join(true, 'R') | ||
return new BufferList().addInt32(11).addString('data').join(true, 'R') | ||
}, | ||
authenticationSASLFinal: function () { | ||
return new BufferList() | ||
.addInt32(12) | ||
.addString('data') | ||
.join(true, 'R') | ||
return new BufferList().addInt32(12).addString('data').join(true, 'R') | ||
}, | ||
parameterStatus: function (name: string, value: string) { | ||
return new BufferList() | ||
.addCString(name) | ||
.addCString(value) | ||
.join(true, 'S') | ||
return new BufferList().addCString(name).addCString(value).join(true, 'S') | ||
}, | ||
backendKeyData: function (processID: number, secretKey: number) { | ||
return new BufferList() | ||
.addInt32(processID) | ||
.addInt32(secretKey) | ||
.join(true, 'K') | ||
return new BufferList().addInt32(processID).addInt32(secretKey).join(true, 'K') | ||
}, | ||
commandComplete: function (string: string) { | ||
return new BufferList() | ||
.addCString(string) | ||
.join(true, 'C') | ||
return new BufferList().addCString(string).join(true, 'C') | ||
}, | ||
@@ -79,3 +55,4 @@ | ||
fields.forEach(function (field) { | ||
buf.addCString(field.name) | ||
buf | ||
.addCString(field.name) | ||
.addInt32(field.tableID || 0) | ||
@@ -122,3 +99,3 @@ .addInt16(field.attributeNumber || 0) | ||
}) | ||
return buf.add(Buffer.from([0]))// terminator | ||
return buf.add(Buffer.from([0])) // terminator | ||
}, | ||
@@ -135,7 +112,3 @@ | ||
notification: function (id: number, channel: string, payload: string) { | ||
return new BufferList() | ||
.addInt32(id) | ||
.addCString(channel) | ||
.addCString(payload) | ||
.join(true, 'A') | ||
return new BufferList().addInt32(id).addCString(channel).addCString(payload).join(true, 'A') | ||
}, | ||
@@ -160,5 +133,5 @@ | ||
// column count | ||
.addInt16(cols); | ||
.addInt16(cols) | ||
for (let i = 0; i < cols; i++) { | ||
list.addInt16(i); | ||
list.addInt16(i) | ||
} | ||
@@ -173,5 +146,5 @@ return list.join(true, 'G') | ||
// column count | ||
.addInt16(cols); | ||
.addInt16(cols) | ||
for (let i = 0; i < cols; i++) { | ||
list.addInt16(i); | ||
list.addInt16(i) | ||
} | ||
@@ -182,3 +155,3 @@ return list.join(true, 'H') | ||
copyData: function (bytes: Buffer) { | ||
return new BufferList().add(bytes).join(true, 'd'); | ||
return new BufferList().add(bytes).join(true, 'd') | ||
}, | ||
@@ -188,5 +161,5 @@ | ||
return new BufferList().join(true, 'c') | ||
} | ||
}, | ||
} | ||
export default buffers |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
222977
4286