| [62b2964] | 1 | "use strict";
|
|---|
| 2 | Object.defineProperty(exports, "__esModule", { value: true });
|
|---|
| 3 | exports.serialize = void 0;
|
|---|
| 4 | const buffer_writer_1 = require("./buffer-writer");
|
|---|
| 5 | const writer = new buffer_writer_1.Writer();
|
|---|
| 6 | const startup = (opts) => {
|
|---|
| 7 | // protocol version
|
|---|
| 8 | writer.addInt16(3).addInt16(0);
|
|---|
| 9 | for (const key of Object.keys(opts)) {
|
|---|
| 10 | writer.addCString(key).addCString(opts[key]);
|
|---|
| 11 | }
|
|---|
| 12 | writer.addCString('client_encoding').addCString('UTF8');
|
|---|
| 13 | const bodyBuffer = writer.addCString('').flush();
|
|---|
| 14 | // this message is sent without a code
|
|---|
| 15 | const length = bodyBuffer.length + 4;
|
|---|
| 16 | return new buffer_writer_1.Writer().addInt32(length).add(bodyBuffer).flush();
|
|---|
| 17 | };
|
|---|
| 18 | const requestSsl = () => {
|
|---|
| 19 | const response = Buffer.allocUnsafe(8);
|
|---|
| 20 | response.writeInt32BE(8, 0);
|
|---|
| 21 | response.writeInt32BE(80877103, 4);
|
|---|
| 22 | return response;
|
|---|
| 23 | };
|
|---|
| 24 | const password = (password) => {
|
|---|
| 25 | return writer.addCString(password).flush(112 /* code.startup */);
|
|---|
| 26 | };
|
|---|
| 27 | const sendSASLInitialResponseMessage = function (mechanism, initialResponse) {
|
|---|
| 28 | // 0x70 = 'p'
|
|---|
| 29 | writer.addCString(mechanism).addInt32PrefixedString(initialResponse);
|
|---|
| 30 | return writer.flush(112 /* code.startup */);
|
|---|
| 31 | };
|
|---|
| 32 | const sendSCRAMClientFinalMessage = function (additionalData) {
|
|---|
| 33 | return writer.addString(additionalData).flush(112 /* code.startup */);
|
|---|
| 34 | };
|
|---|
| 35 | const query = (text) => {
|
|---|
| 36 | return writer.addCString(text).flush(81 /* code.query */);
|
|---|
| 37 | };
|
|---|
| 38 | const emptyArray = [];
|
|---|
| 39 | const parse = (query) => {
|
|---|
| 40 | // expect something like this:
|
|---|
| 41 | // { name: 'queryName',
|
|---|
| 42 | // text: 'select * from blah',
|
|---|
| 43 | // types: ['int8', 'bool'] }
|
|---|
| 44 | // normalize missing query names to allow for null
|
|---|
| 45 | const name = query.name || '';
|
|---|
| 46 | if (name.length > 63) {
|
|---|
| 47 | console.error('Warning! Postgres only supports 63 characters for query names.');
|
|---|
| 48 | console.error('You supplied %s (%s)', name, name.length);
|
|---|
| 49 | console.error('This can cause conflicts and silent errors executing queries');
|
|---|
| 50 | }
|
|---|
| 51 | const types = query.types || emptyArray;
|
|---|
| 52 | const len = types.length;
|
|---|
| 53 | const buffer = writer
|
|---|
| 54 | .addCString(name) // name of query
|
|---|
| 55 | .addCString(query.text) // actual query text
|
|---|
| 56 | .addInt16(len);
|
|---|
| 57 | for (let i = 0; i < len; i++) {
|
|---|
| 58 | buffer.addInt32(types[i]);
|
|---|
| 59 | }
|
|---|
| 60 | return writer.flush(80 /* code.parse */);
|
|---|
| 61 | };
|
|---|
| 62 | const paramWriter = new buffer_writer_1.Writer();
|
|---|
| 63 | const writeValues = function (values, valueMapper) {
|
|---|
| 64 | for (let i = 0; i < values.length; i++) {
|
|---|
| 65 | const mappedVal = valueMapper ? valueMapper(values[i], i) : values[i];
|
|---|
| 66 | if (mappedVal == null) {
|
|---|
| 67 | // add the param type (string) to the writer
|
|---|
| 68 | writer.addInt16(0 /* ParamType.STRING */);
|
|---|
| 69 | // write -1 to the param writer to indicate null
|
|---|
| 70 | paramWriter.addInt32(-1);
|
|---|
| 71 | }
|
|---|
| 72 | else if (mappedVal instanceof Buffer) {
|
|---|
| 73 | // add the param type (binary) to the writer
|
|---|
| 74 | writer.addInt16(1 /* ParamType.BINARY */);
|
|---|
| 75 | // add the buffer to the param writer
|
|---|
| 76 | paramWriter.addInt32(mappedVal.length);
|
|---|
| 77 | paramWriter.add(mappedVal);
|
|---|
| 78 | }
|
|---|
| 79 | else {
|
|---|
| 80 | // add the param type (string) to the writer
|
|---|
| 81 | writer.addInt16(0 /* ParamType.STRING */);
|
|---|
| 82 | // length prefix + UTF-8 bytes in one pass (Buffer.byteLength computed once)
|
|---|
| 83 | paramWriter.addInt32PrefixedString(mappedVal);
|
|---|
| 84 | }
|
|---|
| 85 | }
|
|---|
| 86 | };
|
|---|
| 87 | const bind = (config = {}) => {
|
|---|
| 88 | // normalize config
|
|---|
| 89 | const portal = config.portal || '';
|
|---|
| 90 | const statement = config.statement || '';
|
|---|
| 91 | const binary = config.binary || false;
|
|---|
| 92 | const values = config.values || emptyArray;
|
|---|
| 93 | const len = values.length;
|
|---|
| 94 | writer.addCString(portal).addCString(statement);
|
|---|
| 95 | writer.addInt16(len);
|
|---|
| 96 | try {
|
|---|
| 97 | writeValues(values, config.valueMapper);
|
|---|
| 98 | }
|
|---|
| 99 | catch (err) {
|
|---|
| 100 | writer.clear();
|
|---|
| 101 | paramWriter.clear();
|
|---|
| 102 | throw err;
|
|---|
| 103 | }
|
|---|
| 104 | writer.addInt16(len);
|
|---|
| 105 | writer.add(paramWriter.flush());
|
|---|
| 106 | // all results use the same format code
|
|---|
| 107 | writer.addInt16(1);
|
|---|
| 108 | // format code
|
|---|
| 109 | writer.addInt16(binary ? 1 /* ParamType.BINARY */ : 0 /* ParamType.STRING */);
|
|---|
| 110 | return writer.flush(66 /* code.bind */);
|
|---|
| 111 | };
|
|---|
| 112 | const emptyExecute = Buffer.from([69 /* code.execute */, 0x00, 0x00, 0x00, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00]);
|
|---|
| 113 | const execute = (config) => {
|
|---|
| 114 | // this is the happy path for most queries
|
|---|
| 115 | if (!config || (!config.portal && !config.rows)) {
|
|---|
| 116 | return emptyExecute;
|
|---|
| 117 | }
|
|---|
| 118 | const portal = config.portal || '';
|
|---|
| 119 | const rows = config.rows || 0;
|
|---|
| 120 | const portalLength = Buffer.byteLength(portal);
|
|---|
| 121 | const len = 4 + portalLength + 1 + 4;
|
|---|
| 122 | // one extra bit for code
|
|---|
| 123 | const buff = Buffer.allocUnsafe(1 + len);
|
|---|
| 124 | buff[0] = 69 /* code.execute */;
|
|---|
| 125 | buff.writeInt32BE(len, 1);
|
|---|
| 126 | buff.write(portal, 5, 'utf-8');
|
|---|
| 127 | buff[portalLength + 5] = 0; // null terminate portal cString
|
|---|
| 128 | buff.writeUInt32BE(rows, buff.length - 4);
|
|---|
| 129 | return buff;
|
|---|
| 130 | };
|
|---|
| 131 | const cancel = (processID, secretKey) => {
|
|---|
| 132 | const buffer = Buffer.allocUnsafe(16);
|
|---|
| 133 | buffer.writeInt32BE(16, 0);
|
|---|
| 134 | buffer.writeInt16BE(1234, 4);
|
|---|
| 135 | buffer.writeInt16BE(5678, 6);
|
|---|
| 136 | buffer.writeInt32BE(processID, 8);
|
|---|
| 137 | buffer.writeInt32BE(secretKey, 12);
|
|---|
| 138 | return buffer;
|
|---|
| 139 | };
|
|---|
| 140 | const cstringMessage = (code, string) => {
|
|---|
| 141 | const stringLen = Buffer.byteLength(string);
|
|---|
| 142 | const len = 4 + stringLen + 1;
|
|---|
| 143 | // one extra bit for code
|
|---|
| 144 | const buffer = Buffer.allocUnsafe(1 + len);
|
|---|
| 145 | buffer[0] = code;
|
|---|
| 146 | buffer.writeInt32BE(len, 1);
|
|---|
| 147 | buffer.write(string, 5, 'utf-8');
|
|---|
| 148 | buffer[len] = 0; // null terminate cString
|
|---|
| 149 | return buffer;
|
|---|
| 150 | };
|
|---|
| 151 | const emptyDescribePortal = writer.addCString('P').flush(68 /* code.describe */);
|
|---|
| 152 | const emptyDescribeStatement = writer.addCString('S').flush(68 /* code.describe */);
|
|---|
| 153 | const describe = (msg) => {
|
|---|
| 154 | return msg.name
|
|---|
| 155 | ? cstringMessage(68 /* code.describe */, `${msg.type}${msg.name || ''}`)
|
|---|
| 156 | : msg.type === 'P'
|
|---|
| 157 | ? emptyDescribePortal
|
|---|
| 158 | : emptyDescribeStatement;
|
|---|
| 159 | };
|
|---|
| 160 | const close = (msg) => {
|
|---|
| 161 | const text = `${msg.type}${msg.name || ''}`;
|
|---|
| 162 | return cstringMessage(67 /* code.close */, text);
|
|---|
| 163 | };
|
|---|
| 164 | const copyData = (chunk) => {
|
|---|
| 165 | return writer.add(chunk).flush(100 /* code.copyFromChunk */);
|
|---|
| 166 | };
|
|---|
| 167 | const copyFail = (message) => {
|
|---|
| 168 | return cstringMessage(102 /* code.copyFail */, message);
|
|---|
| 169 | };
|
|---|
| 170 | const codeOnlyBuffer = (code) => Buffer.from([code, 0x00, 0x00, 0x00, 0x04]);
|
|---|
| 171 | const flushBuffer = codeOnlyBuffer(72 /* code.flush */);
|
|---|
| 172 | const syncBuffer = codeOnlyBuffer(83 /* code.sync */);
|
|---|
| 173 | const endBuffer = codeOnlyBuffer(88 /* code.end */);
|
|---|
| 174 | const copyDoneBuffer = codeOnlyBuffer(99 /* code.copyDone */);
|
|---|
| 175 | const serialize = {
|
|---|
| 176 | startup,
|
|---|
| 177 | password,
|
|---|
| 178 | requestSsl,
|
|---|
| 179 | sendSASLInitialResponseMessage,
|
|---|
| 180 | sendSCRAMClientFinalMessage,
|
|---|
| 181 | query,
|
|---|
| 182 | parse,
|
|---|
| 183 | bind,
|
|---|
| 184 | execute,
|
|---|
| 185 | describe,
|
|---|
| 186 | close,
|
|---|
| 187 | flush: () => flushBuffer,
|
|---|
| 188 | sync: () => syncBuffer,
|
|---|
| 189 | end: () => endBuffer,
|
|---|
| 190 | copyData,
|
|---|
| 191 | copyDone: () => copyDoneBuffer,
|
|---|
| 192 | copyFail,
|
|---|
| 193 | cancel,
|
|---|
| 194 | };
|
|---|
| 195 | exports.serialize = serialize;
|
|---|
| 196 | //# sourceMappingURL=serializer.js.map |
|---|