postgrejs 2.23.0 → 3.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +162 -1
- package/LICENSE +26 -17
- package/README.md +195 -175
- package/connection/connection.d.ts +152 -13
- package/connection/connection.js +296 -49
- package/connection/copy-stream.d.ts +88 -0
- package/connection/copy-stream.js +244 -0
- package/connection/cursor.js +20 -13
- package/connection/intl-connection.d.ts +68 -3
- package/connection/intl-connection.js +414 -57
- package/connection/large-object.d.ts +65 -0
- package/connection/large-object.js +151 -0
- package/connection/logical-replication.d.ts +121 -0
- package/connection/logical-replication.js +279 -0
- package/connection/pool.d.ts +61 -4
- package/connection/pool.js +177 -29
- package/connection/portal.d.ts +18 -4
- package/connection/portal.js +53 -59
- package/connection/prepared-statement.d.ts +22 -1
- package/connection/prepared-statement.js +117 -97
- package/data-type-map.d.ts +2 -2
- package/data-type-map.js +4 -2
- package/data-types/bool-type.js +14 -10
- package/data-types/box-type.js +15 -8
- package/data-types/bytea-type.js +9 -5
- package/data-types/char-type.js +11 -5
- package/data-types/circle-type.js +15 -7
- package/data-types/date-type.js +25 -19
- package/data-types/float4-type.js +10 -3
- package/data-types/float8-type.js +12 -3
- package/data-types/int2-type.js +9 -4
- package/data-types/int2-vector-type.js +10 -4
- package/data-types/int4-type.js +11 -5
- package/data-types/int8-type.js +22 -7
- package/data-types/json-type.js +17 -8
- package/data-types/jsonb-type.js +20 -14
- package/data-types/lseg-type.js +16 -8
- package/data-types/numeric-type.d.ts +8 -0
- package/data-types/numeric-type.js +112 -8
- package/data-types/oid-type.d.ts +0 -1
- package/data-types/oid-type.js +9 -10
- package/data-types/oid-vector-type.d.ts +9 -0
- package/data-types/oid-vector-type.js +51 -0
- package/data-types/point-type.js +14 -6
- package/data-types/time-type.js +20 -13
- package/data-types/timestamp-type.js +32 -25
- package/data-types/timestamptz-type.d.ts +1 -1
- package/data-types/timestamptz-type.js +34 -21
- package/data-types/uuid-type.js +21 -11
- package/data-types/varchar-type.js +16 -4
- package/index.d.ts +5 -0
- package/index.js +5 -0
- package/interfaces/data-type.d.ts +5 -3
- package/interfaces/database-connection-params.d.ts +95 -0
- package/interfaces/query-options.d.ts +17 -0
- package/interfaces/script-execute-options.d.ts +17 -0
- package/package.json +3 -4
- package/protocol/backend.d.ts +6 -1
- package/protocol/backend.js +70 -45
- package/protocol/buffer-reader.d.ts +0 -2
- package/protocol/buffer-reader.js +3 -10
- package/protocol/cert-signature.d.ts +12 -0
- package/protocol/cert-signature.js +114 -0
- package/protocol/database-error.js +1 -0
- package/protocol/frontend.d.ts +16 -0
- package/protocol/frontend.js +58 -6
- package/protocol/pg-socket.d.ts +221 -10
- package/protocol/pg-socket.js +539 -102
- package/protocol/pgoutput.d.ts +76 -0
- package/protocol/pgoutput.js +155 -0
- package/protocol/protocol.d.ts +3 -4
- package/protocol/protocol.js +1 -1
- package/protocol/sasl.d.ts +11 -1
- package/protocol/sasl.js +35 -4
- package/protocol/smart-buffer.d.ts +0 -2
- package/protocol/smart-buffer.js +11 -16
- package/types.d.ts +5 -3
- package/util/abort-signal.d.ts +24 -0
- package/util/abort-signal.js +63 -0
- package/util/array-calculatedim.js +3 -1
- package/util/bigint-methods.js +1 -1
- package/util/connection-config.js +77 -3
- package/util/decode-binaryarray.d.ts +1 -1
- package/util/decode-binaryarray.js +15 -6
- package/util/encode-binaryarray.js +7 -3
- package/util/escape-identifier.d.ts +14 -0
- package/util/escape-identifier.js +32 -0
- package/util/escape-literal.js +3 -0
- package/util/fast-parseint.d.ts +1 -0
- package/util/fast-parseint.js +12 -17
- package/util/format-datetime.d.ts +10 -0
- package/util/format-datetime.js +71 -0
- package/util/get-parsers.js +31 -10
- package/util/parse-array.js +2 -2
- package/util/parse-bytea.d.ts +2 -0
- package/util/parse-bytea.js +83 -0
- package/util/parse-datetime.d.ts +3 -1
- package/util/parse-datetime.js +86 -17
- package/util/parse-row.d.ts +3 -1
- package/util/parse-row.js +60 -5
- package/util/parse-time.js +8 -1
- package/util/sql-tag.d.ts +60 -0
- package/util/sql-tag.js +202 -0
- package/util/starts-transaction.d.ts +38 -0
- package/util/starts-transaction.js +148 -0
- package/util/stringify-arrayliteral.js +13 -1
- package/util/wrap-row-description.js +13 -4
- package/util/convert-row-to-object.d.ts +0 -2
- package/util/convert-row-to-object.js +0 -9
|
@@ -3,9 +3,8 @@ import { DEFAULT_COLUMN_FORMAT } from '../constants.js';
|
|
|
3
3
|
import { GlobalTypeMap } from '../data-type-map.js';
|
|
4
4
|
import { Protocol } from '../protocol/protocol.js';
|
|
5
5
|
import { SafeEventEmitter } from '../safe-event-emitter.js';
|
|
6
|
-
import {
|
|
6
|
+
import { withAbortSignal } from '../util/abort-signal.js';
|
|
7
7
|
import { getParsers } from '../util/get-parsers.js';
|
|
8
|
-
import { parseRow } from '../util/parse-row.js';
|
|
9
8
|
import { wrapRowDescription } from '../util/wrap-row-description.js';
|
|
10
9
|
import { Cursor } from './cursor.js';
|
|
11
10
|
import { getIntlConnection } from './intl-connection.js';
|
|
@@ -17,8 +16,10 @@ export class PreparedStatement extends SafeEventEmitter {
|
|
|
17
16
|
_sql = '';
|
|
18
17
|
_name = '';
|
|
19
18
|
_paramTypes;
|
|
19
|
+
_fields;
|
|
20
20
|
_onErrorSavePoint;
|
|
21
21
|
_refCount = 0;
|
|
22
|
+
_closed = false;
|
|
22
23
|
constructor(connection, sql, paramTypes) {
|
|
23
24
|
super();
|
|
24
25
|
this._connection = connection;
|
|
@@ -30,39 +31,9 @@ export class PreparedStatement extends SafeEventEmitter {
|
|
|
30
31
|
static async prepare(connection, sql, options) {
|
|
31
32
|
const intoCon = getIntlConnection(connection);
|
|
32
33
|
intoCon.assertConnected();
|
|
33
|
-
const socket = intoCon.socket;
|
|
34
34
|
const statement = new PreparedStatement(connection, sql, options?.paramTypes);
|
|
35
|
-
await intoCon.
|
|
36
|
-
|
|
37
|
-
intoCon.ref();
|
|
38
|
-
try {
|
|
39
|
-
socket.sendParseMessage({
|
|
40
|
-
statement: statement.name,
|
|
41
|
-
sql: statement.sql,
|
|
42
|
-
paramTypes: statement.paramTypes,
|
|
43
|
-
});
|
|
44
|
-
socket.sendFlushMessage();
|
|
45
|
-
try {
|
|
46
|
-
await socket.capture(async (code, msg, done) => {
|
|
47
|
-
if (code === Protocol.BackendMessageCode.ParseComplete)
|
|
48
|
-
done();
|
|
49
|
-
// May be Protocol.BackendMessageCode.NoticeResponse
|
|
50
|
-
});
|
|
51
|
-
}
|
|
52
|
-
finally {
|
|
53
|
-
socket.sendSyncMessage();
|
|
54
|
-
await socket.capture(async (code, msg, done) => {
|
|
55
|
-
if (code === Protocol.BackendMessageCode.ReadyForQuery)
|
|
56
|
-
done();
|
|
57
|
-
// May be Protocol.BackendMessageCode.NoticeResponse
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
}
|
|
61
|
-
finally {
|
|
62
|
-
intoCon.unref();
|
|
63
|
-
}
|
|
64
|
-
})
|
|
65
|
-
.toPromise();
|
|
35
|
+
const { fields } = await intoCon.prepareOnce(sql, statement.paramTypes, statement.name);
|
|
36
|
+
statement._fields = fields;
|
|
66
37
|
statement._refCount = 1;
|
|
67
38
|
return statement;
|
|
68
39
|
}
|
|
@@ -79,6 +50,12 @@ export class PreparedStatement extends SafeEventEmitter {
|
|
|
79
50
|
return this._paramTypes;
|
|
80
51
|
}
|
|
81
52
|
async execute(options = {}) {
|
|
53
|
+
const intlCon = getIntlConnection(this.connection);
|
|
54
|
+
if (options.signal)
|
|
55
|
+
return withAbortSignal(options.signal, () => intlCon.cancel(), () => this._executeWithTransaction(options));
|
|
56
|
+
return this._executeWithTransaction(options);
|
|
57
|
+
}
|
|
58
|
+
async _executeWithTransaction(options = {}) {
|
|
82
59
|
const intlCon = getIntlConnection(this.connection);
|
|
83
60
|
const transactionCommand = this.sql.match(/^(\bBEGIN\b|\bCOMMIT\b|\bSTART\b|\bROLLBACK|SAVEPOINT|RELEASE\b)/i);
|
|
84
61
|
let beginFirst = false;
|
|
@@ -102,9 +79,7 @@ export class PreparedStatement extends SafeEventEmitter {
|
|
|
102
79
|
if (intlCon.inTransaction && rollbackOnError)
|
|
103
80
|
await intlCon.execute('SAVEPOINT ' + this._onErrorSavePoint);
|
|
104
81
|
try {
|
|
105
|
-
const result = await
|
|
106
|
-
.enqueue(() => this._execute(options))
|
|
107
|
-
.toPromise();
|
|
82
|
+
const result = await this._execute(options);
|
|
108
83
|
if (commitLast)
|
|
109
84
|
await intlCon.execute('COMMIT');
|
|
110
85
|
else if (intlCon.inTransaction && rollbackOnError) {
|
|
@@ -120,99 +95,144 @@ export class PreparedStatement extends SafeEventEmitter {
|
|
|
120
95
|
}
|
|
121
96
|
}
|
|
122
97
|
async close() {
|
|
98
|
+
if (this._closed)
|
|
99
|
+
return;
|
|
123
100
|
--this._refCount;
|
|
124
101
|
if (this._refCount > 0)
|
|
125
102
|
return;
|
|
126
|
-
|
|
127
|
-
await
|
|
103
|
+
this._closed = true;
|
|
104
|
+
await this._close();
|
|
128
105
|
}
|
|
106
|
+
/**
|
|
107
|
+
* Asks the server to cancel whatever this statement's connection is
|
|
108
|
+
* currently running. See Connection.cancel(); prefer the per-call `signal`
|
|
109
|
+
* option, which reports the abort to the caller that asked for it.
|
|
110
|
+
*/
|
|
129
111
|
async cancel() {
|
|
130
|
-
|
|
112
|
+
return getIntlConnection(this.connection).cancel();
|
|
131
113
|
}
|
|
132
114
|
async _execute(options = {}) {
|
|
133
|
-
let portal;
|
|
134
115
|
const intlCon = getIntlConnection(this.connection);
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
result
|
|
152
|
-
result.rowType = options.objectRows ? 'object' : 'array';
|
|
153
|
-
if (options.cursor) {
|
|
154
|
-
result.cursor = new Cursor(this, portal, resultFields, parsers, options);
|
|
155
|
-
this._refCount++;
|
|
156
|
-
portal = undefined;
|
|
157
|
-
return result;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
const executeResult = await portal.execute(options.fetchCount);
|
|
161
|
-
result.executeTime = Date.now() - t;
|
|
162
|
-
if (executeResult.command)
|
|
163
|
-
result.command = executeResult.command;
|
|
164
|
-
if (resultFields && parsers && executeResult.rows) {
|
|
165
|
-
if (!result.command)
|
|
166
|
-
result.command = 'SELECT';
|
|
167
|
-
const rows = (result.rows = executeResult.rows);
|
|
168
|
-
const l = rows.length;
|
|
169
|
-
let row;
|
|
170
|
-
for (let i = 0; i < l; i++) {
|
|
171
|
-
row = rows[i];
|
|
172
|
-
parseRow(parsers, row, options);
|
|
173
|
-
if (options.objectRows) {
|
|
174
|
-
rows[i] = convertRowToObject(resultFields, row);
|
|
175
|
-
}
|
|
176
|
-
}
|
|
116
|
+
if (options.cursor && this._fields) {
|
|
117
|
+
intlCon.ref();
|
|
118
|
+
let portal = new Portal(this, 'P_' + ++portalCounter);
|
|
119
|
+
try {
|
|
120
|
+
const fields = await portal.bindAndRetrieveFields(options.params, options);
|
|
121
|
+
const typeMap = options.typeMap || GlobalTypeMap;
|
|
122
|
+
const parsers = getParsers(typeMap, fields);
|
|
123
|
+
const resultFields = wrapRowDescription(typeMap, fields, options.columnFormat || DEFAULT_COLUMN_FORMAT);
|
|
124
|
+
const result = {
|
|
125
|
+
command: undefined,
|
|
126
|
+
fields: resultFields,
|
|
127
|
+
rowType: options.objectRows ? 'object' : 'array',
|
|
128
|
+
cursor: new Cursor(this, portal, resultFields, parsers, options),
|
|
129
|
+
};
|
|
130
|
+
this._refCount++;
|
|
131
|
+
portal = undefined;
|
|
132
|
+
return result;
|
|
177
133
|
}
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
134
|
+
finally {
|
|
135
|
+
intlCon.unref();
|
|
136
|
+
if (portal)
|
|
137
|
+
await portal.close().catch(() => undefined);
|
|
182
138
|
}
|
|
183
|
-
|
|
184
|
-
|
|
139
|
+
}
|
|
140
|
+
// Non-cursor path: Bind+Execute+Sync as a single round trip against an
|
|
141
|
+
// unnamed portal, reusing the RowDescription prepare() already fetched
|
|
142
|
+
// instead of re-Describing (and re-Close-ing) a fresh named portal on
|
|
143
|
+
// every call.
|
|
144
|
+
return intlCon.executeReused(this.name, this._fields, this.paramTypes, options.params, options);
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Called by Cursor.close() instead of separately awaiting
|
|
148
|
+
* Portal.close() then this.close(). Returns false (no wire action taken,
|
|
149
|
+
* caller must still close just the portal itself) when either this
|
|
150
|
+
* statement was already fully closed by someone else (mirrors close()'s
|
|
151
|
+
* own `if (this._closed) return;` idempotency guard - re-sending
|
|
152
|
+
* Close(statement) for an already-closed name would error) or the
|
|
153
|
+
* decremented refcount is still > 0 (statement still referenced
|
|
154
|
+
* elsewhere - e.g. another cursor from the same PreparedStatement, or
|
|
155
|
+
* the statement's own +1 from prepare()). Returns true only when it
|
|
156
|
+
* actually performed the combined Close(portal)+Close(statement)+Sync.
|
|
157
|
+
*/
|
|
158
|
+
async _maybeCloseWithPortal(portalName) {
|
|
159
|
+
if (this._closed)
|
|
160
|
+
return false;
|
|
161
|
+
--this._refCount;
|
|
162
|
+
if (this._refCount > 0)
|
|
163
|
+
return false;
|
|
164
|
+
this._closed = true;
|
|
165
|
+
const intoCon = getIntlConnection(this.connection);
|
|
166
|
+
intoCon.ref();
|
|
167
|
+
try {
|
|
168
|
+
const socket = intoCon.socket;
|
|
169
|
+
let error;
|
|
170
|
+
await socket.sendClosePortalAndStatementMessages({
|
|
171
|
+
portal: { type: 'P', name: portalName },
|
|
172
|
+
statement: { type: 'S', name: this.name },
|
|
173
|
+
}, (code, msg, done) => {
|
|
174
|
+
switch (code) {
|
|
175
|
+
case Protocol.BackendMessageCode.NoticeResponse:
|
|
176
|
+
this.emit('notice', msg);
|
|
177
|
+
break;
|
|
178
|
+
case Protocol.BackendMessageCode.CloseComplete:
|
|
179
|
+
// Arrives twice (once per Close) - neither call is terminal.
|
|
180
|
+
break;
|
|
181
|
+
case Protocol.BackendMessageCode.ErrorResponse:
|
|
182
|
+
error = msg;
|
|
183
|
+
break;
|
|
184
|
+
case Protocol.BackendMessageCode.ReadyForQuery:
|
|
185
|
+
intoCon.transactionStatus = msg.status;
|
|
186
|
+
done(error);
|
|
187
|
+
break;
|
|
188
|
+
default:
|
|
189
|
+
done(new Error(`Server returned unexpected response message (0x${code.toString(16)})`));
|
|
190
|
+
}
|
|
191
|
+
});
|
|
185
192
|
}
|
|
186
193
|
finally {
|
|
187
|
-
|
|
188
|
-
if (portal)
|
|
189
|
-
await portal.close();
|
|
194
|
+
intoCon.unref();
|
|
190
195
|
}
|
|
196
|
+
this.emit('close');
|
|
197
|
+
return true;
|
|
191
198
|
}
|
|
192
199
|
async _close() {
|
|
193
|
-
if (--this._refCount > 0)
|
|
194
|
-
return;
|
|
195
200
|
const intoCon = getIntlConnection(this.connection);
|
|
196
201
|
intoCon.ref();
|
|
197
202
|
try {
|
|
198
203
|
const socket = intoCon.socket;
|
|
199
|
-
socket.sendCloseMessage({ type: 'S', name: this.name })
|
|
200
|
-
socket.sendSyncMessage();
|
|
201
|
-
await socket.capture(async (code, msg, done) => {
|
|
204
|
+
const closePromise = socket.sendCloseMessage({ type: 'S', name: this.name }, (code, msg, done) => {
|
|
202
205
|
switch (code) {
|
|
203
206
|
case Protocol.BackendMessageCode.NoticeResponse:
|
|
204
207
|
this.emit('notice', msg);
|
|
205
208
|
break;
|
|
206
209
|
case Protocol.BackendMessageCode.CloseComplete:
|
|
210
|
+
done();
|
|
211
|
+
break;
|
|
212
|
+
case Protocol.BackendMessageCode.ErrorResponse:
|
|
213
|
+
done(msg);
|
|
214
|
+
break;
|
|
215
|
+
default:
|
|
216
|
+
done(new Error(`Server returned unexpected response message (0x${code.toString(16)})`));
|
|
217
|
+
}
|
|
218
|
+
});
|
|
219
|
+
const syncPromise = socket.sendSyncMessage((code, msg, done) => {
|
|
220
|
+
switch (code) {
|
|
221
|
+
case Protocol.BackendMessageCode.NoticeResponse:
|
|
222
|
+
this.emit('notice', msg);
|
|
207
223
|
break;
|
|
208
224
|
case Protocol.BackendMessageCode.ReadyForQuery:
|
|
209
225
|
intoCon.transactionStatus = msg.status;
|
|
210
226
|
done();
|
|
211
227
|
break;
|
|
228
|
+
case Protocol.BackendMessageCode.ErrorResponse:
|
|
229
|
+
done(msg);
|
|
230
|
+
break;
|
|
212
231
|
default:
|
|
213
232
|
done(new Error(`Server returned unexpected response message (0x${code.toString(16)})`));
|
|
214
233
|
}
|
|
215
234
|
});
|
|
235
|
+
await Promise.all([closePromise, syncPromise]);
|
|
216
236
|
}
|
|
217
237
|
finally {
|
|
218
238
|
intoCon.unref();
|
package/data-type-map.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DataType } from './interfaces/data-type.js';
|
|
2
|
-
import { OID } from './types.js';
|
|
1
|
+
import type { DataType } from './interfaces/data-type.js';
|
|
2
|
+
import type { OID } from './types.js';
|
|
3
3
|
export declare class DataTypeMap {
|
|
4
4
|
private _itemsByOID;
|
|
5
5
|
private _items;
|
package/data-type-map.js
CHANGED
|
@@ -15,7 +15,8 @@ import { ArrayJsonType, JsonType } from './data-types/json-type.js';
|
|
|
15
15
|
import { ArrayJsonbType, JsonbType } from './data-types/jsonb-type.js';
|
|
16
16
|
import { ArrayLsegType, LsegType } from './data-types/lseg-type.js';
|
|
17
17
|
import { ArrayNumericType, NumericType } from './data-types/numeric-type.js';
|
|
18
|
-
import { ArrayOidType, OidType
|
|
18
|
+
import { ArrayOidType, OidType } from './data-types/oid-type.js';
|
|
19
|
+
import { ArrayOidVectorType, OidVectorType, } from './data-types/oid-vector-type.js';
|
|
19
20
|
import { ArrayPointType, PointType } from './data-types/point-type.js';
|
|
20
21
|
import { ArrayTimeType, TimeType } from './data-types/time-type.js';
|
|
21
22
|
import { ArrayTimestampType, TimestampType, } from './data-types/timestamp-type.js';
|
|
@@ -62,7 +63,8 @@ export class DataTypeMap {
|
|
|
62
63
|
}
|
|
63
64
|
}
|
|
64
65
|
export const GlobalTypeMap = new DataTypeMap();
|
|
65
|
-
GlobalTypeMap.register([OidType,
|
|
66
|
+
GlobalTypeMap.register([OidType, ArrayOidType]);
|
|
67
|
+
GlobalTypeMap.register([OidVectorType, ArrayOidVectorType]);
|
|
66
68
|
GlobalTypeMap.register([JsonbType, ArrayJsonbType]);
|
|
67
69
|
GlobalTypeMap.register([JsonType, ArrayJsonType]);
|
|
68
70
|
GlobalTypeMap.register([BoolType, ArrayBoolType]);
|
package/data-types/bool-type.js
CHANGED
|
@@ -3,20 +3,24 @@ export const BoolType = {
|
|
|
3
3
|
name: 'bool',
|
|
4
4
|
oid: DataTypeOIDs.bool,
|
|
5
5
|
jsType: 'boolean',
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
fixedBinarySize: 1,
|
|
7
|
+
// 't'/'f', the form decodeText above reads and the server itself
|
|
8
|
+
// emits - encodeText and decodeText are a public pair and have to stay
|
|
9
|
+
// each other's inverse.
|
|
10
|
+
encodeText(v) {
|
|
11
|
+
return v ? 't' : 'f';
|
|
8
12
|
},
|
|
9
13
|
encodeBinary(buf, v) {
|
|
10
14
|
buf.writeInt8(v ? 1 : 0);
|
|
11
15
|
},
|
|
12
|
-
|
|
13
|
-
return (
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
16
|
+
decodeBinary(v, offset = 0) {
|
|
17
|
+
return !!v.readUInt8(offset);
|
|
18
|
+
},
|
|
19
|
+
decodeText(v) {
|
|
20
|
+
return v === 't';
|
|
21
|
+
},
|
|
22
|
+
decodeTextBuffer(buf, offset) {
|
|
23
|
+
return buf[offset] === 0x74; /* 't' */
|
|
20
24
|
},
|
|
21
25
|
isType(v) {
|
|
22
26
|
return typeof v === 'boolean';
|
package/data-types/box-type.js
CHANGED
|
@@ -7,13 +7,9 @@ export const BoxType = {
|
|
|
7
7
|
oid: DataTypeOIDs.box,
|
|
8
8
|
jsType: 'object',
|
|
9
9
|
arraySeparator: ';',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
y1: v.readDoubleBE(8),
|
|
14
|
-
x2: v.readDoubleBE(16),
|
|
15
|
-
y2: v.readDoubleBE(24),
|
|
16
|
-
};
|
|
10
|
+
fixedBinarySize: 32,
|
|
11
|
+
encodeText(v) {
|
|
12
|
+
return `(${v.x1},${v.y1}),(${v.x2},${v.y2})`;
|
|
17
13
|
},
|
|
18
14
|
encodeBinary(buf, v) {
|
|
19
15
|
buf.writeDoubleBE(v.x1);
|
|
@@ -21,7 +17,15 @@ export const BoxType = {
|
|
|
21
17
|
buf.writeDoubleBE(v.x2);
|
|
22
18
|
buf.writeDoubleBE(v.y2);
|
|
23
19
|
},
|
|
24
|
-
|
|
20
|
+
decodeBinary(v, offset = 0) {
|
|
21
|
+
return {
|
|
22
|
+
x1: v.readDoubleBE(offset),
|
|
23
|
+
y1: v.readDoubleBE(offset + 8),
|
|
24
|
+
x2: v.readDoubleBE(offset + 16),
|
|
25
|
+
y2: v.readDoubleBE(offset + 24),
|
|
26
|
+
};
|
|
27
|
+
},
|
|
28
|
+
decodeText(v) {
|
|
25
29
|
const m = v.match(BOX_PATTERN1) || v.match(BOX_PATTERN2) || v.match(BOX_PATTERN3);
|
|
26
30
|
if (!m)
|
|
27
31
|
return undefined;
|
|
@@ -32,6 +36,9 @@ export const BoxType = {
|
|
|
32
36
|
y2: parseFloat(m[4]),
|
|
33
37
|
};
|
|
34
38
|
},
|
|
39
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
40
|
+
return BoxType.decodeText(buf.toString('latin1', offset, offset + len), options);
|
|
41
|
+
},
|
|
35
42
|
isType(v) {
|
|
36
43
|
return (typeof v === 'object' &&
|
|
37
44
|
Object.keys(v).length === 4 &&
|
package/data-types/bytea-type.js
CHANGED
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
// @ts-ignore -- no type definitions for decodeBytea
|
|
2
|
-
import decodeBytea from 'postgres-bytea';
|
|
3
1
|
import { DataTypeOIDs } from '../constants.js';
|
|
2
|
+
import { parseBytea, parseByteaBuffer } from '../util/parse-bytea.js';
|
|
4
3
|
export const ByteaType = {
|
|
5
4
|
name: 'bytea',
|
|
6
5
|
oid: DataTypeOIDs.bytea,
|
|
7
6
|
jsType: 'Buffer',
|
|
8
|
-
|
|
9
|
-
|
|
7
|
+
// The hex form PostgreSQL has emitted by default since 9.0.
|
|
8
|
+
encodeText(v) {
|
|
9
|
+
return '\\x' + v.toString('hex');
|
|
10
10
|
},
|
|
11
11
|
encodeBinary(buf, v) {
|
|
12
12
|
buf.writeBuffer(v);
|
|
13
13
|
},
|
|
14
|
-
|
|
14
|
+
decodeBinary(v, offset = 0) {
|
|
15
|
+
return offset ? v.subarray(offset) : v;
|
|
16
|
+
},
|
|
17
|
+
decodeText: parseBytea,
|
|
18
|
+
decodeTextBuffer: parseByteaBuffer,
|
|
15
19
|
isType(v) {
|
|
16
20
|
return v instanceof Buffer;
|
|
17
21
|
},
|
package/data-types/char-type.js
CHANGED
|
@@ -3,17 +3,23 @@ export const CharType = {
|
|
|
3
3
|
name: 'char',
|
|
4
4
|
oid: DataTypeOIDs.char,
|
|
5
5
|
jsType: 'string',
|
|
6
|
-
|
|
7
|
-
return
|
|
6
|
+
encodeText(v) {
|
|
7
|
+
return '' + v;
|
|
8
8
|
},
|
|
9
9
|
encodeBinary(buf, v) {
|
|
10
10
|
buf.writeString((v ? '' + v : ' ')[0], 'utf8');
|
|
11
11
|
},
|
|
12
|
-
|
|
13
|
-
return ''
|
|
12
|
+
decodeBinary(v, offset = 0) {
|
|
13
|
+
return v.toString('utf8', offset);
|
|
14
|
+
},
|
|
15
|
+
decodeText(v) {
|
|
16
|
+
return v;
|
|
17
|
+
},
|
|
18
|
+
decodeTextBuffer(buf, offset, len) {
|
|
19
|
+
return buf.toString('utf8', offset, offset + len);
|
|
14
20
|
},
|
|
15
21
|
isType(v) {
|
|
16
|
-
return typeof v === 'string' && v
|
|
22
|
+
return typeof v === 'string' && Buffer.byteLength(v, 'utf8') === 1;
|
|
17
23
|
},
|
|
18
24
|
};
|
|
19
25
|
export const ArrayCharType = {
|
|
@@ -7,19 +7,23 @@ export const CircleType = {
|
|
|
7
7
|
name: 'circle',
|
|
8
8
|
oid: DataTypeOIDs.circle,
|
|
9
9
|
jsType: 'object',
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
y: v.readDoubleBE(8),
|
|
14
|
-
r: v.readDoubleBE(16),
|
|
15
|
-
};
|
|
10
|
+
fixedBinarySize: 24,
|
|
11
|
+
encodeText(v) {
|
|
12
|
+
return `<(${v.x},${v.y}),${v.r}>`;
|
|
16
13
|
},
|
|
17
14
|
encodeBinary(buf, v) {
|
|
18
15
|
buf.writeDoubleBE(v.x);
|
|
19
16
|
buf.writeDoubleBE(v.y);
|
|
20
17
|
buf.writeDoubleBE(v.r);
|
|
21
18
|
},
|
|
22
|
-
|
|
19
|
+
decodeBinary(v, offset = 0) {
|
|
20
|
+
return {
|
|
21
|
+
x: v.readDoubleBE(offset),
|
|
22
|
+
y: v.readDoubleBE(offset + 8),
|
|
23
|
+
r: v.readDoubleBE(offset + 16),
|
|
24
|
+
};
|
|
25
|
+
},
|
|
26
|
+
decodeText(v) {
|
|
23
27
|
const m = v.match(CIRCLE_PATTERN1) ||
|
|
24
28
|
v.match(CIRCLE_PATTERN2) ||
|
|
25
29
|
v.match(CIRCLE_PATTERN3) ||
|
|
@@ -32,6 +36,10 @@ export const CircleType = {
|
|
|
32
36
|
r: parseFloat(m[3]),
|
|
33
37
|
};
|
|
34
38
|
},
|
|
39
|
+
// See box-type.ts's decodeTextBuffer comment - same rationale.
|
|
40
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
41
|
+
return CircleType.decodeText(buf.toString('latin1', offset, offset + len), options);
|
|
42
|
+
},
|
|
35
43
|
isType(v) {
|
|
36
44
|
return (typeof v === 'object' &&
|
|
37
45
|
Object.keys(v).length === 3 &&
|
package/data-types/date-type.js
CHANGED
|
@@ -1,27 +1,18 @@
|
|
|
1
1
|
import { DataTypeOIDs } from '../constants.js';
|
|
2
|
-
import {
|
|
2
|
+
import { formatDate } from '../util/format-datetime.js';
|
|
3
|
+
import { parseDate } from '../util/parse-datetime.js';
|
|
3
4
|
const timeShift = 946684800000;
|
|
4
5
|
export const DateType = {
|
|
5
6
|
name: 'date',
|
|
6
7
|
oid: DataTypeOIDs.date,
|
|
7
8
|
jsType: 'Date',
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
const t = v.readInt32BE();
|
|
12
|
-
if (t === 0x7fffffff)
|
|
13
|
-
return fetchAsString ? 'infinity' : Infinity;
|
|
14
|
-
if (t === -0x80000000)
|
|
15
|
-
return fetchAsString ? '-infinity' : -Infinity;
|
|
16
|
-
// Shift from 2000 to 1970
|
|
17
|
-
let d = new Date(t * 1000 * 86400 + timeShift);
|
|
18
|
-
if (fetchAsString || !options.utcDates)
|
|
19
|
-
d = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
|
|
20
|
-
return fetchAsString ? dateToDateString(d) : d;
|
|
9
|
+
fixedBinarySize: 4,
|
|
10
|
+
encodeText(v, options) {
|
|
11
|
+
return formatDate(v, options);
|
|
21
12
|
},
|
|
22
13
|
encodeBinary(buf, v, options) {
|
|
23
14
|
if (typeof v === 'string')
|
|
24
|
-
v =
|
|
15
|
+
v = parseDate(v, options.utcDates);
|
|
25
16
|
if (v === Infinity) {
|
|
26
17
|
buf.writeInt32BE(0x7fffffff);
|
|
27
18
|
return;
|
|
@@ -39,12 +30,27 @@ export const DateType = {
|
|
|
39
30
|
const t = Math.trunc(n + Number.EPSILON);
|
|
40
31
|
buf.writeInt32BE(t);
|
|
41
32
|
},
|
|
42
|
-
|
|
43
|
-
const fetchAsString = options.fetchAsString
|
|
44
|
-
|
|
33
|
+
decodeBinary(v, offset = 0, options) {
|
|
34
|
+
const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.date);
|
|
35
|
+
const t = v.readInt32BE(offset);
|
|
36
|
+
if (t === 0x7fffffff)
|
|
37
|
+
return fetchAsString ? 'infinity' : Infinity;
|
|
38
|
+
if (t === -0x80000000)
|
|
39
|
+
return fetchAsString ? '-infinity' : -Infinity;
|
|
40
|
+
// Shift from 2000 to 1970
|
|
41
|
+
let d = new Date(t * 1000 * 86400 + timeShift);
|
|
42
|
+
if (fetchAsString || !options.utcDates)
|
|
43
|
+
d = new Date(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate());
|
|
44
|
+
return fetchAsString ? dateToDateString(d) : d;
|
|
45
|
+
},
|
|
46
|
+
decodeText(v, options) {
|
|
47
|
+
const fetchAsString = options.fetchAsString?.includes(DataTypeOIDs.date);
|
|
45
48
|
if (fetchAsString)
|
|
46
49
|
return v;
|
|
47
|
-
return
|
|
50
|
+
return parseDate(v, options.utcDates);
|
|
51
|
+
},
|
|
52
|
+
decodeTextBuffer(buf, offset, len, options) {
|
|
53
|
+
return DateType.decodeText(buf.toString('latin1', offset, offset + len), options);
|
|
48
54
|
},
|
|
49
55
|
isType(v) {
|
|
50
56
|
return (v instanceof Date &&
|
|
@@ -3,13 +3,20 @@ export const Float4Type = {
|
|
|
3
3
|
name: 'float4',
|
|
4
4
|
oid: DataTypeOIDs.float4,
|
|
5
5
|
jsType: 'number',
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
fixedBinarySize: 4,
|
|
7
|
+
encodeText(v) {
|
|
8
|
+
return '' + v;
|
|
8
9
|
},
|
|
9
10
|
encodeBinary(buf, v) {
|
|
10
11
|
buf.writeFloatBE(typeof v === 'number' ? v : parseFloat(v));
|
|
11
12
|
},
|
|
12
|
-
|
|
13
|
+
decodeBinary(v, offset = 0) {
|
|
14
|
+
return v.readFloatBE(offset);
|
|
15
|
+
},
|
|
16
|
+
decodeText: parseFloat,
|
|
17
|
+
decodeTextBuffer(buf, offset, len) {
|
|
18
|
+
return parseFloat(buf.toString('latin1', offset, offset + len));
|
|
19
|
+
},
|
|
13
20
|
isType(v) {
|
|
14
21
|
return typeof v === 'number';
|
|
15
22
|
},
|
|
@@ -3,13 +3,22 @@ export const Float8Type = {
|
|
|
3
3
|
name: 'float8',
|
|
4
4
|
oid: DataTypeOIDs.float8,
|
|
5
5
|
jsType: 'number',
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
fixedBinarySize: 8,
|
|
7
|
+
// Infinity/NaN stringify to the words PostgreSQL itself uses.
|
|
8
|
+
encodeText(v) {
|
|
9
|
+
return '' + v;
|
|
8
10
|
},
|
|
9
11
|
encodeBinary(buf, v) {
|
|
10
12
|
buf.writeDoubleBE(typeof v === 'number' ? v : parseFloat(v));
|
|
11
13
|
},
|
|
12
|
-
|
|
14
|
+
decodeBinary(v, offset = 0) {
|
|
15
|
+
return v.readDoubleBE(offset);
|
|
16
|
+
},
|
|
17
|
+
decodeText: parseFloat,
|
|
18
|
+
// See float4-type.ts's decodeTextBuffer comment - same rationale.
|
|
19
|
+
decodeTextBuffer(buf, offset, len) {
|
|
20
|
+
return parseFloat(buf.toString('latin1', offset, offset + len));
|
|
21
|
+
},
|
|
13
22
|
isType(v) {
|
|
14
23
|
return typeof v === 'number';
|
|
15
24
|
},
|
package/data-types/int2-type.js
CHANGED
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import { DataTypeOIDs } from '../constants.js';
|
|
2
|
-
import { fastParseInt } from '../util/fast-parseint.js';
|
|
2
|
+
import { fastParseInt, fastParseIntBuffer } from '../util/fast-parseint.js';
|
|
3
3
|
export const Int2Type = {
|
|
4
4
|
name: 'int2',
|
|
5
5
|
oid: DataTypeOIDs.int2,
|
|
6
6
|
jsType: 'number',
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
fixedBinarySize: 2,
|
|
8
|
+
encodeText(v) {
|
|
9
|
+
return '' + v;
|
|
9
10
|
},
|
|
10
11
|
encodeBinary(buf, v) {
|
|
11
12
|
buf.writeInt16BE(fastParseInt(v));
|
|
12
13
|
},
|
|
13
|
-
|
|
14
|
+
decodeBinary(v, offset = 0) {
|
|
15
|
+
return v.readInt16BE(offset);
|
|
16
|
+
},
|
|
17
|
+
decodeText: fastParseInt,
|
|
18
|
+
decodeTextBuffer: fastParseIntBuffer,
|
|
14
19
|
isType(v) {
|
|
15
20
|
return (typeof v === 'number' && Number.isInteger(v) && v >= -32768 && v <= 32767);
|
|
16
21
|
},
|