@m2k-5f/pgtx 2.1.0 → 2.3.0
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/README.md +66 -13
- package/dist/clauses/abstract.clause.js +1 -5
- package/dist/clauses/array.clause.js +3 -7
- package/dist/clauses/empty.clause.js +3 -7
- package/dist/clauses/exclude.clause.js +2 -6
- package/dist/clauses/fragment.clause.js +4 -8
- package/dist/clauses/iden.caluse.js +2 -6
- package/dist/clauses/index.js +9 -25
- package/dist/clauses/insert.clause.js +2 -6
- package/dist/clauses/literal.clause.js +2 -6
- package/dist/clauses/update.clause.js +2 -6
- package/dist/clauses/where.clause.js +2 -6
- package/dist/connection.d.ts +56 -10
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +220 -117
- package/dist/error.d.ts +1 -1
- package/dist/error.d.ts.map +1 -1
- package/dist/error.js +2 -6
- package/dist/index.js +24 -37
- package/dist/pool.d.ts +20 -6
- package/dist/pool.d.ts.map +1 -1
- package/dist/pool.js +40 -41
- package/dist/protocol/connection-request-writer.js +13 -18
- package/dist/protocol/connection-response-reader.d.ts +5 -0
- package/dist/protocol/connection-response-reader.d.ts.map +1 -1
- package/dist/protocol/connection-response-reader.js +11 -9
- package/dist/protocol/constants.d.ts +1 -0
- package/dist/protocol/constants.d.ts.map +1 -1
- package/dist/protocol/constants.js +6 -8
- package/dist/protocol/socket-authorization.d.ts +5 -1
- package/dist/protocol/socket-authorization.d.ts.map +1 -1
- package/dist/protocol/socket-authorization.js +38 -34
- package/dist/protocol/socket-connector.d.ts.map +1 -1
- package/dist/protocol/socket-connector.js +4 -7
- package/dist/query.js +2 -6
- package/dist/queue.js +1 -5
- package/dist/security/md5.js +4 -8
- package/dist/security/sasl.js +7 -11
- package/dist/transaction.d.ts +7 -5
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +18 -26
- package/dist/types.js +0 -2
- package/dist/utils/template-compiler.js +3 -6
- package/dist/utils/value-parser.js +2 -7
- package/package.json +5 -2
|
@@ -1,85 +1,86 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
1
|
+
import { createConnection } from "node:net";
|
|
2
|
+
import { calculateScramAuth, generateNonce } from "../security/sasl";
|
|
3
|
+
import { SocketConnector } from "./socket-connector";
|
|
4
|
+
import { AuthenticationCodes, ResponseTypes } from "./constants";
|
|
5
|
+
import { encryptMd5 } from "../security/md5";
|
|
6
|
+
import { PostgresError } from "../error";
|
|
7
|
+
import { Future } from "fluent-future";
|
|
8
|
+
export const ErrNonceMismatch = new PostgresError("Protocol violation: server nonce doesn't match client nonce");
|
|
9
|
+
export const ErrPasswordRequired = new PostgresError('The authorization method requires a password.');
|
|
10
|
+
export const createAuthorizedSocket = (writer, params) => {
|
|
11
|
+
return Future.of(new Promise((resolve, reject) => {
|
|
12
|
+
const nonce = generateNonce();
|
|
12
13
|
let clientMessage = '';
|
|
13
14
|
let serverMessage = '';
|
|
14
|
-
const socket =
|
|
15
|
-
const connector = new
|
|
15
|
+
const socket = createConnection({ host: params.host, port: params.port });
|
|
16
|
+
const connector = new SocketConnector(socket, (type, reader) => {
|
|
16
17
|
writer.clear();
|
|
17
18
|
switch (type) {
|
|
18
|
-
case
|
|
19
|
+
case ResponseTypes.Authentication: {
|
|
19
20
|
switch (reader.readAuthentication()) {
|
|
20
|
-
case
|
|
21
|
-
case
|
|
21
|
+
case AuthenticationCodes.Ok: break;
|
|
22
|
+
case AuthenticationCodes.CleartextPassword: {
|
|
22
23
|
if (!params.password)
|
|
23
|
-
throw
|
|
24
|
+
throw ErrPasswordRequired;
|
|
24
25
|
connector.write(writer.writePassword(params.password));
|
|
25
26
|
break;
|
|
26
27
|
}
|
|
27
|
-
case
|
|
28
|
+
case AuthenticationCodes.MD5Password: {
|
|
28
29
|
const salt = reader.readMD5Salt();
|
|
29
30
|
if (!params.password)
|
|
30
|
-
throw
|
|
31
|
-
const password =
|
|
31
|
+
throw ErrPasswordRequired;
|
|
32
|
+
const password = encryptMd5(params.password, params.user, salt);
|
|
32
33
|
connector.write(writer.writePassword(password));
|
|
33
34
|
break;
|
|
34
35
|
}
|
|
35
|
-
case
|
|
36
|
+
case AuthenticationCodes.SASL: {
|
|
36
37
|
reader.readSaslMechanisms();
|
|
37
38
|
if (!params.password)
|
|
38
|
-
throw
|
|
39
|
+
throw ErrPasswordRequired;
|
|
39
40
|
clientMessage = `n=${params.user},r=${nonce}`;
|
|
40
41
|
connector.write(writer.writeSaslInitial('SCRAM-SHA-256', `n,,${clientMessage}`));
|
|
41
42
|
break;
|
|
42
43
|
}
|
|
43
|
-
case
|
|
44
|
+
case AuthenticationCodes.SASLContinue: {
|
|
44
45
|
serverMessage = reader.readSaslMessage();
|
|
45
46
|
if (!params.password)
|
|
46
|
-
throw
|
|
47
|
+
throw ErrPasswordRequired;
|
|
47
48
|
const parts = Object.fromEntries(serverMessage.split(',').map(x => x.split('=')));
|
|
48
49
|
const serverNonce = parts.r;
|
|
49
50
|
const saltBase64 = parts.s;
|
|
50
51
|
const iterations = parseInt(parts.i, 10);
|
|
51
52
|
if (!serverNonce.startsWith(nonce)) {
|
|
52
53
|
connector.destroy();
|
|
53
|
-
return reject(
|
|
54
|
+
return reject(ErrNonceMismatch);
|
|
54
55
|
}
|
|
55
56
|
const clientFinalMessageWithoutProof = `c=biws,r=${serverNonce}`;
|
|
56
57
|
const authMessage = `${clientMessage},${serverMessage},${clientFinalMessageWithoutProof}`;
|
|
57
|
-
const { clientProof } =
|
|
58
|
+
const { clientProof } = calculateScramAuth(params.password, saltBase64, iterations, authMessage);
|
|
58
59
|
const clientFinalMessage = `${clientFinalMessageWithoutProof},p=${clientProof}`;
|
|
59
60
|
connector.write(writer.writeSaslResponse(clientFinalMessage));
|
|
60
61
|
break;
|
|
61
62
|
}
|
|
62
|
-
case
|
|
63
|
+
case AuthenticationCodes.SASLFinal: {
|
|
63
64
|
reader.readSaslMessage();
|
|
64
65
|
break;
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
break;
|
|
68
69
|
}
|
|
69
|
-
case
|
|
70
|
+
case ResponseTypes.ParamaterStatus: {
|
|
70
71
|
reader.readParameterStatus();
|
|
71
72
|
break;
|
|
72
73
|
}
|
|
73
|
-
case
|
|
74
|
-
const
|
|
74
|
+
case ResponseTypes.ErrorResponse: {
|
|
75
|
+
const error = reader.readErrorResponse();
|
|
75
76
|
connector.destroy();
|
|
76
|
-
reject(
|
|
77
|
+
reject(error);
|
|
77
78
|
return;
|
|
78
79
|
}
|
|
79
|
-
case
|
|
80
|
+
case ResponseTypes.BackendKeyData: {
|
|
80
81
|
reader.readBackendKeyData();
|
|
81
82
|
}
|
|
82
|
-
case
|
|
83
|
+
case ResponseTypes.ReadyForQuery: {
|
|
83
84
|
reader.readReadyForQuery();
|
|
84
85
|
resolve(connector.unwrapSocket());
|
|
85
86
|
return;
|
|
@@ -90,6 +91,9 @@ const createAuthorizedSocket = (writer, params) => {
|
|
|
90
91
|
});
|
|
91
92
|
connector.write(writer.writeStartup(params.user, params.database));
|
|
92
93
|
writer.clear();
|
|
94
|
+
}), error => {
|
|
95
|
+
if (error instanceof PostgresError)
|
|
96
|
+
return error;
|
|
97
|
+
return new PostgresError(error.message);
|
|
93
98
|
});
|
|
94
99
|
};
|
|
95
|
-
exports.createAuthorizedSocket = createAuthorizedSocket;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"socket-connector.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAE/E,qBAAa,eAAe;IAKpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IANpB,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,YAAY,CAAQ;gBAGhB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,wBAAwB,KAAK,IAAI,EACvE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;
|
|
1
|
+
{"version":3,"file":"socket-connector.d.ts","sourceRoot":"","sources":["../../src/protocol/socket-connector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAC1C,OAAO,EAAE,wBAAwB,EAAE,MAAM,wCAAwC,CAAA;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,uCAAuC,CAAA;AAE/E,qBAAa,eAAe;IAKpB,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,OAAO;IACf,OAAO,CAAC,QAAQ;IANpB,OAAO,CAAC,cAAc,CAAsB;IAC5C,OAAO,CAAC,YAAY,CAAQ;gBAGhB,OAAO,EAAE,MAAM,EACf,OAAO,EAAE,CAAC,IAAI,EAAE,YAAY,EAAE,MAAM,EAAE,wBAAwB,KAAK,IAAI,EACvE,QAAQ,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI;IA6B5C,KAAK,CAAC,MAAM,EAAE,uBAAuB;IAOrC,YAAY;IAQZ,OAAO;IAMP,IAAI,WAAW,YAA6B;CAC/C"}
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.SocketConnector = void 0;
|
|
4
|
-
const connection_response_reader_1 = require("../protocol/connection-response-reader");
|
|
5
|
-
class SocketConnector {
|
|
1
|
+
import { ConnectionResponseReader } from '../protocol/connection-response-reader';
|
|
2
|
+
export class SocketConnector {
|
|
6
3
|
constructor(_socket, _onData, _onError) {
|
|
7
4
|
this._socket = _socket;
|
|
8
5
|
this._onData = _onData;
|
|
9
6
|
this._onError = _onError;
|
|
10
7
|
this.residualBuffer = null;
|
|
11
8
|
this._isDestroyed = false;
|
|
9
|
+
_socket.setKeepAlive(true, 10000);
|
|
12
10
|
_socket.on('data', buffer => {
|
|
13
11
|
const currentBuffer = this.residualBuffer
|
|
14
12
|
? Buffer.concat([this.residualBuffer, buffer])
|
|
15
13
|
: buffer;
|
|
16
14
|
this.residualBuffer = null;
|
|
17
|
-
const reader =
|
|
15
|
+
const reader = ConnectionResponseReader.from(currentBuffer);
|
|
18
16
|
while (reader.hasMore()) {
|
|
19
17
|
if (!reader.hasFullPacket()) {
|
|
20
18
|
this.residualBuffer = reader.getResidualBuffer();
|
|
@@ -45,4 +43,3 @@ class SocketConnector {
|
|
|
45
43
|
}
|
|
46
44
|
get isDestroyed() { return this._isDestroyed; }
|
|
47
45
|
}
|
|
48
|
-
exports.SocketConnector = SocketConnector;
|
package/dist/query.js
CHANGED
|
@@ -1,14 +1,11 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Query = exports.QueryState = void 0;
|
|
4
|
-
exports.QueryState = {
|
|
1
|
+
export const QueryState = {
|
|
5
2
|
Parsing: 0,
|
|
6
3
|
Describing: 1,
|
|
7
4
|
Executing: 2,
|
|
8
5
|
Completed: 3,
|
|
9
6
|
Failed: 4
|
|
10
7
|
};
|
|
11
|
-
class Query {
|
|
8
|
+
export class Query {
|
|
12
9
|
constructor(text, args, state, statementName, columns) {
|
|
13
10
|
this.text = text;
|
|
14
11
|
this.args = args;
|
|
@@ -25,4 +22,3 @@ class Query {
|
|
|
25
22
|
this.state = state;
|
|
26
23
|
}
|
|
27
24
|
}
|
|
28
|
-
exports.Query = Query;
|
package/dist/queue.js
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.Queue = void 0;
|
|
4
|
-
class Queue {
|
|
1
|
+
export class Queue {
|
|
5
2
|
constructor() {
|
|
6
3
|
this._queue = new Array();
|
|
7
4
|
this._pointer = 0;
|
|
@@ -36,4 +33,3 @@ class Queue {
|
|
|
36
33
|
}
|
|
37
34
|
get isFree() { return this._pointer >= this._queue.length; }
|
|
38
35
|
}
|
|
39
|
-
exports.Queue = Queue;
|
package/dist/security/md5.js
CHANGED
|
@@ -1,12 +1,8 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const
|
|
5
|
-
const encryptMd5 = (password, user, salt) => {
|
|
6
|
-
const stage1 = (0, crypto_1.createHash)('md5').update(password + user).digest('hex');
|
|
7
|
-
const stage2 = (0, crypto_1.createHash)('md5')
|
|
1
|
+
import { createHash } from "crypto";
|
|
2
|
+
export const encryptMd5 = (password, user, salt) => {
|
|
3
|
+
const stage1 = createHash('md5').update(password + user).digest('hex');
|
|
4
|
+
const stage2 = createHash('md5')
|
|
8
5
|
.update(Buffer.concat([Buffer.from(stage1), salt]))
|
|
9
6
|
.digest('hex');
|
|
10
7
|
return 'md5' + stage2;
|
|
11
8
|
};
|
|
12
|
-
exports.encryptMd5 = encryptMd5;
|
package/dist/security/sasl.js
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
exports.calculateScramAuth = calculateScramAuth;
|
|
5
|
-
const crypto_1 = require("crypto");
|
|
6
|
-
function generateNonce() {
|
|
7
|
-
return (0, crypto_1.randomBytes)(18).toString('base64').replace(/[^a-zA-Z0-9]/g, '').substring(0, 24);
|
|
1
|
+
import { randomBytes, createHmac, pbkdf2Sync, createHash } from 'crypto';
|
|
2
|
+
export function generateNonce() {
|
|
3
|
+
return randomBytes(18).toString('base64').replace(/[^a-zA-Z0-9]/g, '').substring(0, 24);
|
|
8
4
|
}
|
|
9
5
|
function hmac(key, data) {
|
|
10
|
-
return
|
|
6
|
+
return createHmac('sha256', key).update(data).digest();
|
|
11
7
|
}
|
|
12
8
|
function hi(password, salt, iterations) {
|
|
13
|
-
return
|
|
9
|
+
return pbkdf2Sync(password, salt, iterations, 32, 'sha256');
|
|
14
10
|
}
|
|
15
|
-
function calculateScramAuth(password, saltBase64, iterations, authMessage) {
|
|
11
|
+
export function calculateScramAuth(password, saltBase64, iterations, authMessage) {
|
|
16
12
|
const salt = Buffer.from(saltBase64, 'base64');
|
|
17
13
|
const saltedPassword = hi(password, salt, iterations);
|
|
18
14
|
const clientKey = hmac(saltedPassword, 'Client Key');
|
|
19
|
-
const storedKey =
|
|
15
|
+
const storedKey = createHash('sha256').update(clientKey).digest();
|
|
20
16
|
const clientSignature = hmac(storedKey, authMessage);
|
|
21
17
|
const clientProofBuf = Buffer.alloc(32);
|
|
22
18
|
for (let i = 0; i < 32; i++) {
|
package/dist/transaction.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { Future } from "fluent-future";
|
|
1
2
|
import { Connection } from "./connection";
|
|
3
|
+
import { PostgresError } from "./error";
|
|
2
4
|
/**
|
|
3
5
|
* Represents an active SQL transaction.
|
|
4
6
|
* All queries are executed on a single dedicated connection.
|
|
@@ -15,15 +17,15 @@ export declare class Transaction {
|
|
|
15
17
|
/**
|
|
16
18
|
* Commits the current transaction.
|
|
17
19
|
*/
|
|
18
|
-
commit():
|
|
20
|
+
commit(): Future<[], PostgresError>;
|
|
19
21
|
/**
|
|
20
22
|
* Rolls back the current transaction.
|
|
21
23
|
*/
|
|
22
|
-
rollback():
|
|
24
|
+
rollback(): Future<[], PostgresError>;
|
|
23
25
|
/**
|
|
24
26
|
* Executes a query within the current transaction.
|
|
25
27
|
*/
|
|
26
|
-
query<T extends Record<string, any>>(strings: TemplateStringsArray, ...values: any[]):
|
|
28
|
+
query<T extends Record<string, any>>(strings: TemplateStringsArray, ...values: any[]): Future<T[], PostgresError>;
|
|
27
29
|
/**
|
|
28
30
|
* Creates a sub-transaction using PostgreSQL SAVEPOINT.
|
|
29
31
|
* If the callback throws, only the actions within this savepoint are rolled back.
|
|
@@ -31,9 +33,9 @@ export declare class Transaction {
|
|
|
31
33
|
* @example
|
|
32
34
|
* await tx.savepoint('my_point', async (stx) => {
|
|
33
35
|
* await stx.query`INSERT ...`;
|
|
34
|
-
* if (error) throw new Error()
|
|
36
|
+
* if (error) throw new Error() // Only this insert rolls back
|
|
35
37
|
* });
|
|
36
38
|
*/
|
|
37
|
-
savepoint(name: string, callback: (tx: Transaction) => Promise<
|
|
39
|
+
savepoint<T>(name: string, callback: (tx: Transaction) => Promise<T>): Future<T, Error>;
|
|
38
40
|
}
|
|
39
41
|
//# sourceMappingURL=transaction.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"transaction.d.ts","sourceRoot":"","sources":["../src/transaction.ts"],"names":[],"mappings":"AAAA,OAAO,EAAS,MAAM,EAAE,MAAM,eAAe,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AACzC,OAAO,EAAE,aAAa,EAAE,MAAM,SAAS,CAAA;AAEvC;;;GAGG;AACH,qBAAa,WAAW;IAIhB,QAAQ,CAAC,IAAI,EAAE,UAAU;IAH7B,OAAO,CAAC,UAAU,CAAiB;gBAGtB,IAAI,EAAE,UAAU;IAG7B;;OAEG;IACH,IAAW,QAAQ,IAAI,OAAO,CAE7B;IAED,OAAO,CAAC,WAAW;IAMnB;;OAEG;IACI,MAAM,IAIiC,MAAM,CAAC,EAAE,EAAE,aAAa,CAAC;IAGvE;;OAEG;IACI,QAAQ,IAI+B,MAAM,CAAC,EAAE,EAAE,aAAa,CAAC;IAGvE;;OAEG;IACI,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE;IAK3F;;;;;;;;;OASG;IACI,SAAS,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,KAAK,CAAC;CAWjG"}
|
package/dist/transaction.js
CHANGED
|
@@ -1,12 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.Transaction = void 0;
|
|
4
|
-
const clauses_1 = require("./clauses");
|
|
1
|
+
import { Begin, Future } from "fluent-future";
|
|
2
|
+
import { IdentifierClause } from "./clauses";
|
|
5
3
|
/**
|
|
6
4
|
* Represents an active SQL transaction.
|
|
7
5
|
* All queries are executed on a single dedicated connection.
|
|
8
6
|
*/
|
|
9
|
-
class Transaction {
|
|
7
|
+
export class Transaction {
|
|
10
8
|
constructor(conn) {
|
|
11
9
|
this.conn = conn;
|
|
12
10
|
this.isFinished = false;
|
|
@@ -25,25 +23,25 @@ class Transaction {
|
|
|
25
23
|
/**
|
|
26
24
|
* Commits the current transaction.
|
|
27
25
|
*/
|
|
28
|
-
|
|
26
|
+
commit() {
|
|
29
27
|
this.checkActive();
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
return this.conn.query `COMMIT`
|
|
29
|
+
.tap(() => this.isFinished = true);
|
|
32
30
|
}
|
|
33
31
|
/**
|
|
34
32
|
* Rolls back the current transaction.
|
|
35
33
|
*/
|
|
36
|
-
|
|
34
|
+
rollback() {
|
|
37
35
|
this.checkActive();
|
|
38
|
-
|
|
39
|
-
|
|
36
|
+
return this.conn.query `ROLLBACK`
|
|
37
|
+
.tap(() => this.isFinished = true);
|
|
40
38
|
}
|
|
41
39
|
/**
|
|
42
40
|
* Executes a query within the current transaction.
|
|
43
41
|
*/
|
|
44
|
-
|
|
42
|
+
query(strings, ...values) {
|
|
45
43
|
this.checkActive();
|
|
46
|
-
return
|
|
44
|
+
return this.conn.query(strings, ...values);
|
|
47
45
|
}
|
|
48
46
|
/**
|
|
49
47
|
* Creates a sub-transaction using PostgreSQL SAVEPOINT.
|
|
@@ -52,21 +50,15 @@ class Transaction {
|
|
|
52
50
|
* @example
|
|
53
51
|
* await tx.savepoint('my_point', async (stx) => {
|
|
54
52
|
* await stx.query`INSERT ...`;
|
|
55
|
-
* if (error) throw new Error()
|
|
53
|
+
* if (error) throw new Error() // Only this insert rolls back
|
|
56
54
|
* });
|
|
57
55
|
*/
|
|
58
|
-
|
|
56
|
+
savepoint(name, callback) {
|
|
59
57
|
this.checkActive();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
catch (err) {
|
|
67
|
-
await this.conn.query `ROLLBACK TO SAVEPOINT ${clauses_1.IdentifierClause.create(name)}`;
|
|
68
|
-
return err instanceof Error ? err : new Error(String(err));
|
|
69
|
-
}
|
|
58
|
+
return Begin()
|
|
59
|
+
.andThen(() => this.conn.query `SAVEPOINT ${IdentifierClause.create(name)}`)
|
|
60
|
+
.andThen(() => Future.of(callback(this))
|
|
61
|
+
.tap(() => this.conn.query `RELEASE SAVEPOINT ${IdentifierClause.create(name)}`)
|
|
62
|
+
.tapErr(() => this.conn.query `ROLLBACK TO SAVEPOINT ${IdentifierClause.create(name)}`));
|
|
70
63
|
}
|
|
71
64
|
}
|
|
72
|
-
exports.Transaction = Transaction;
|
package/dist/types.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
exports.compileSqlTemplate = compileSqlTemplate;
|
|
4
|
-
const abstract_clause_1 = require("../clauses/abstract.clause");
|
|
5
|
-
function compileSqlTemplate(params, argOffset = 0) {
|
|
1
|
+
import { Clause } from "../clauses/abstract.clause";
|
|
2
|
+
export function compileSqlTemplate(params, argOffset = 0) {
|
|
6
3
|
const templateLength = params.templates.length;
|
|
7
4
|
const query = {
|
|
8
5
|
text: [],
|
|
@@ -13,7 +10,7 @@ function compileSqlTemplate(params, argOffset = 0) {
|
|
|
13
10
|
if (index === templateLength - 1)
|
|
14
11
|
return;
|
|
15
12
|
const value = params.args[index];
|
|
16
|
-
if (value instanceof
|
|
13
|
+
if (value instanceof Clause) {
|
|
17
14
|
value.mapIntoQuery(query);
|
|
18
15
|
}
|
|
19
16
|
else {
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.setTypeParser = void 0;
|
|
4
|
-
exports.parseRowValues = parseRowValues;
|
|
5
1
|
const parsePostgresArray = (v) => {
|
|
6
2
|
if (v === '{}')
|
|
7
3
|
return [];
|
|
@@ -70,7 +66,7 @@ const Parsers = {
|
|
|
70
66
|
3807: (v) => parsePostgresArray(v).map(el => JSON.parse(el)), // jsonb[]
|
|
71
67
|
};
|
|
72
68
|
const defaultParser = (v) => v;
|
|
73
|
-
function parseRowValues(columns, rows) {
|
|
69
|
+
export function parseRowValues(columns, rows) {
|
|
74
70
|
const result = [];
|
|
75
71
|
const columnsLength = columns.length;
|
|
76
72
|
const columnParsers = columns.map(col => Parsers[col.typeOID] || defaultParser);
|
|
@@ -95,7 +91,6 @@ function parseRowValues(columns, rows) {
|
|
|
95
91
|
}
|
|
96
92
|
return result;
|
|
97
93
|
}
|
|
98
|
-
const setTypeParser = (typeOID, parser) => {
|
|
94
|
+
export const setTypeParser = (typeOID, parser) => {
|
|
99
95
|
Parsers[typeOID] = parser;
|
|
100
96
|
};
|
|
101
|
-
exports.setTypeParser = setTypeParser;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m2k-5f/pgtx",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "Blazing-fast PostgreSQL driver with pipeline support.",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
11
|
"prepublishOnly": "npm run build",
|
|
12
|
-
"testGitHub": "node --import tsx --test $(find tests -name '*.test.ts')",
|
|
12
|
+
"testGitHub": "node --import tsx --test 0 $(find tests -name '*.test.ts')",
|
|
13
13
|
"test": "node --import tsx --test ./tests/*.test.ts"
|
|
14
14
|
},
|
|
15
15
|
"repository": {
|
|
@@ -44,5 +44,8 @@
|
|
|
44
44
|
"pg": "^8.22.0",
|
|
45
45
|
"tsx": "^4.21.0",
|
|
46
46
|
"typescript": "^5.0.0"
|
|
47
|
+
},
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"fluent-future": "^1.3.2"
|
|
47
50
|
}
|
|
48
51
|
}
|