@m2k-5f/pgtx 1.4.11 → 2.0.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/LICENSE +21 -0
- package/README.md +225 -128
- package/dist/clauses/array.clause.js +1 -1
- package/dist/clauses/empty.clause.d.ts +1 -1
- package/dist/clauses/empty.clause.d.ts.map +1 -1
- package/dist/clauses/empty.clause.js +2 -2
- package/dist/clauses/fragment.clause.d.ts +1 -1
- package/dist/clauses/fragment.clause.d.ts.map +1 -1
- package/dist/clauses/fragment.clause.js +3 -5
- package/dist/clauses/iden.caluse.d.ts +1 -1
- package/dist/clauses/iden.caluse.d.ts.map +1 -1
- package/dist/clauses/index.d.ts +10 -0
- package/dist/clauses/index.d.ts.map +1 -0
- package/dist/clauses/index.js +25 -0
- package/dist/clauses/insert.clause.d.ts +1 -1
- package/dist/clauses/insert.clause.d.ts.map +1 -1
- package/dist/clauses/insert.clause.js +1 -1
- package/dist/clauses/literal.clause.d.ts +1 -1
- package/dist/clauses/literal.clause.d.ts.map +1 -1
- package/dist/clauses/update.clause.d.ts +1 -1
- package/dist/clauses/update.clause.d.ts.map +1 -1
- package/dist/clauses/update.clause.js +1 -1
- package/dist/clauses/where.clause.d.ts +1 -1
- package/dist/clauses/where.clause.d.ts.map +1 -1
- package/dist/clauses/where.clause.js +1 -1
- package/dist/connection.d.ts +135 -31
- package/dist/connection.d.ts.map +1 -1
- package/dist/connection.js +290 -59
- package/dist/index.d.ts +2 -10
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -18
- package/dist/pool.d.ts +126 -32
- package/dist/pool.d.ts.map +1 -1
- package/dist/pool.js +203 -54
- package/dist/protocol/connection-request-writer.d.ts +38 -0
- package/dist/protocol/connection-request-writer.d.ts.map +1 -0
- package/dist/protocol/connection-request-writer.js +175 -0
- package/dist/protocol/connection-response-reader.d.ts +49 -0
- package/dist/protocol/connection-response-reader.d.ts.map +1 -0
- package/dist/protocol/connection-response-reader.js +185 -0
- package/dist/protocol/constants.d.ts +46 -0
- package/dist/protocol/constants.d.ts.map +1 -0
- package/dist/protocol/constants.js +43 -0
- package/dist/protocol/socket-authorization.d.ts +11 -0
- package/dist/protocol/socket-authorization.d.ts.map +1 -0
- package/dist/protocol/socket-authorization.js +95 -0
- package/dist/protocol/socket-connector.d.ts +17 -0
- package/dist/protocol/socket-connector.d.ts.map +1 -0
- package/dist/protocol/socket-connector.js +48 -0
- package/dist/queue.d.ts +10 -0
- package/dist/queue.d.ts.map +1 -0
- package/dist/queue.js +27 -0
- package/dist/security/md5.d.ts +2 -0
- package/dist/security/md5.d.ts.map +1 -0
- package/dist/security/md5.js +12 -0
- package/dist/security/sasl.d.ts +6 -0
- package/dist/security/sasl.d.ts.map +1 -0
- package/dist/security/sasl.js +29 -0
- package/dist/transaction.d.ts +1 -2
- package/dist/transaction.d.ts.map +1 -1
- package/dist/transaction.js +4 -4
- package/dist/types.d.ts +6 -8
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/template-compiler.d.ts +3 -0
- package/dist/utils/template-compiler.d.ts.map +1 -0
- package/dist/utils/template-compiler.js +64 -0
- package/dist/utils/value-parser.d.ts +6 -0
- package/dist/utils/value-parser.d.ts.map +1 -0
- package/dist/utils/value-parser.js +101 -0
- package/package.json +8 -9
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.SocketConnector = void 0;
|
|
4
|
+
const connection_response_reader_1 = require("../protocol/connection-response-reader");
|
|
5
|
+
class SocketConnector {
|
|
6
|
+
constructor(_socket, _onData, _onError) {
|
|
7
|
+
this._socket = _socket;
|
|
8
|
+
this._onData = _onData;
|
|
9
|
+
this._onError = _onError;
|
|
10
|
+
this.residualBuffer = null;
|
|
11
|
+
this._isDestroyed = false;
|
|
12
|
+
_socket.on('data', buffer => {
|
|
13
|
+
const currentBuffer = this.residualBuffer
|
|
14
|
+
? Buffer.concat([this.residualBuffer, buffer])
|
|
15
|
+
: buffer;
|
|
16
|
+
this.residualBuffer = null;
|
|
17
|
+
const reader = connection_response_reader_1.ConnectionResponseReader.from(currentBuffer);
|
|
18
|
+
while (reader.hasMore()) {
|
|
19
|
+
if (!reader.hasFullPacket()) {
|
|
20
|
+
this.residualBuffer = reader.getResidualBuffer();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
this._onData(reader.readType(), reader);
|
|
24
|
+
}
|
|
25
|
+
});
|
|
26
|
+
_socket.on('error', error => {
|
|
27
|
+
this._onError(error);
|
|
28
|
+
this._socket.destroy();
|
|
29
|
+
this._isDestroyed = true;
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
write(writer) {
|
|
33
|
+
if (this._isDestroyed)
|
|
34
|
+
throw new Error("SocketConnector is destroyed");
|
|
35
|
+
this._socket.write(writer.asBuffer());
|
|
36
|
+
}
|
|
37
|
+
unwrapSocket() {
|
|
38
|
+
this._socket.off('error', this._onError);
|
|
39
|
+
this._socket.off("data", this._onData);
|
|
40
|
+
return this._socket;
|
|
41
|
+
}
|
|
42
|
+
destroy() {
|
|
43
|
+
this._isDestroyed = true;
|
|
44
|
+
this._socket.destroy();
|
|
45
|
+
}
|
|
46
|
+
get isDestroyed() { return this._isDestroyed; }
|
|
47
|
+
}
|
|
48
|
+
exports.SocketConnector = SocketConnector;
|
package/dist/queue.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"queue.d.ts","sourceRoot":"","sources":["../src/queue.ts"],"names":[],"mappings":"AAAA,qBAAa,KAAK,CAAC,CAAC;IAChB,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,QAAQ,CAAI;IAEpB,IAAI;IAQJ,GAAG;IAIH,IAAI,CAAC,IAAI,EAAE,CAAC;IAIZ,IAAI,IAAI,WAEP;IAED,IAAI,MAAM,YAAgD;CAC7D"}
|
package/dist/queue.js
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.Queue = void 0;
|
|
4
|
+
class Queue {
|
|
5
|
+
constructor() {
|
|
6
|
+
this._queue = new Array();
|
|
7
|
+
this._pointer = 0;
|
|
8
|
+
}
|
|
9
|
+
next() {
|
|
10
|
+
this._pointer++;
|
|
11
|
+
if (this._pointer === this._queue.length) {
|
|
12
|
+
this._queue = [];
|
|
13
|
+
this._pointer = 0;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
get() {
|
|
17
|
+
return this._queue[this._pointer];
|
|
18
|
+
}
|
|
19
|
+
push(item) {
|
|
20
|
+
this._queue.push(item);
|
|
21
|
+
}
|
|
22
|
+
get size() {
|
|
23
|
+
return this._queue.length - this._pointer;
|
|
24
|
+
}
|
|
25
|
+
get isFree() { return this._pointer === this._queue.length; }
|
|
26
|
+
}
|
|
27
|
+
exports.Queue = Queue;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"md5.d.ts","sourceRoot":"","sources":["../../src/security/md5.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,UAAU,GAAI,UAAU,MAAM,EAAE,MAAM,MAAM,EAAE,MAAM,MAAM,WAQtE,CAAA"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.encryptMd5 = void 0;
|
|
4
|
+
const crypto_1 = require("crypto");
|
|
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')
|
|
8
|
+
.update(Buffer.concat([Buffer.from(stage1), salt]))
|
|
9
|
+
.digest('hex');
|
|
10
|
+
return 'md5' + stage2;
|
|
11
|
+
};
|
|
12
|
+
exports.encryptMd5 = encryptMd5;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sasl.d.ts","sourceRoot":"","sources":["../../src/security/sasl.ts"],"names":[],"mappings":"AAGA,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAaD,wBAAgB,kBAAkB,CAC9B,QAAQ,EAAE,MAAM,EAChB,UAAU,EAAE,MAAM,EAClB,UAAU,EAAE,MAAM,EAClB,WAAW,EAAE,MAAM,GACpB;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,eAAe,EAAE,MAAM,CAAA;CAAE,CAuBlD"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateNonce = generateNonce;
|
|
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);
|
|
8
|
+
}
|
|
9
|
+
function hmac(key, data) {
|
|
10
|
+
return (0, crypto_1.createHmac)('sha256', key).update(data).digest();
|
|
11
|
+
}
|
|
12
|
+
function hi(password, salt, iterations) {
|
|
13
|
+
return (0, crypto_1.pbkdf2Sync)(password, salt, iterations, 32, 'sha256');
|
|
14
|
+
}
|
|
15
|
+
function calculateScramAuth(password, saltBase64, iterations, authMessage) {
|
|
16
|
+
const salt = Buffer.from(saltBase64, 'base64');
|
|
17
|
+
const saltedPassword = hi(password, salt, iterations);
|
|
18
|
+
const clientKey = hmac(saltedPassword, 'Client Key');
|
|
19
|
+
const storedKey = (0, crypto_1.createHash)('sha256').update(clientKey).digest();
|
|
20
|
+
const clientSignature = hmac(storedKey, authMessage);
|
|
21
|
+
const clientProofBuf = Buffer.alloc(32);
|
|
22
|
+
for (let i = 0; i < 32; i++) {
|
|
23
|
+
clientProofBuf[i] = clientKey[i] ^ clientSignature[i];
|
|
24
|
+
}
|
|
25
|
+
const clientProof = clientProofBuf.toString('base64');
|
|
26
|
+
const serverKey = hmac(saltedPassword, 'Server Key');
|
|
27
|
+
const serverSignature = hmac(serverKey, authMessage).toString('base64');
|
|
28
|
+
return { clientProof, serverSignature };
|
|
29
|
+
}
|
package/dist/transaction.d.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { QueryResultRow } from "pg";
|
|
2
1
|
import { Connection } from "./connection";
|
|
3
2
|
/**
|
|
4
3
|
* Represents an active SQL transaction.
|
|
@@ -24,7 +23,7 @@ export declare class Transaction {
|
|
|
24
23
|
/**
|
|
25
24
|
* Executes a query within the current transaction.
|
|
26
25
|
*/
|
|
27
|
-
query<T extends
|
|
26
|
+
query<T extends Record<string, unknown>>(strings: TemplateStringsArray, ...values: any[]): Promise<T[]>;
|
|
28
27
|
/**
|
|
29
28
|
* Creates a sub-transaction using PostgreSQL SAVEPOINT.
|
|
30
29
|
* If the callback throws, only the actions within this savepoint are rolled back.
|
|
@@ -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":"AACA,OAAO,EAAE,UAAU,EAAE,MAAM,cAAc,CAAA;AAEzC;;;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;IACU,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAOpC;;OAEG;IACU,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOtC;;OAEG;IACU,KAAK,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,OAAO,EAAE,oBAAoB,EAAE,GAAG,MAAM,EAAE,GAAG,EAAE,GAAG,OAAO,CAAC,CAAC,EAAE,CAAC;IAKpH;;;;;;;;;OASG;IACU,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,EAAE,EAAE,WAAW,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,OAAO,CAAC,KAAK,GAAG,IAAI,CAAC;CAe5G"}
|
package/dist/transaction.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.Transaction = void 0;
|
|
4
|
-
const
|
|
4
|
+
const clauses_1 = require("./clauses");
|
|
5
5
|
/**
|
|
6
6
|
* Represents an active SQL transaction.
|
|
7
7
|
* All queries are executed on a single dedicated connection.
|
|
@@ -57,14 +57,14 @@ class Transaction {
|
|
|
57
57
|
*/
|
|
58
58
|
async savepoint(name, callback) {
|
|
59
59
|
this.checkActive();
|
|
60
|
-
await this.conn.query `SAVEPOINT ${
|
|
60
|
+
await this.conn.query `SAVEPOINT ${clauses_1.IdentifierClause.create(name)}`;
|
|
61
61
|
try {
|
|
62
62
|
await callback(this);
|
|
63
|
-
await this.conn.query `RELEASE SAVEPOINT ${
|
|
63
|
+
await this.conn.query `RELEASE SAVEPOINT ${clauses_1.IdentifierClause.create(name)}`;
|
|
64
64
|
return null;
|
|
65
65
|
}
|
|
66
66
|
catch (err) {
|
|
67
|
-
await this.conn.query `ROLLBACK TO SAVEPOINT ${
|
|
67
|
+
await this.conn.query `ROLLBACK TO SAVEPOINT ${clauses_1.IdentifierClause.create(name)}`;
|
|
68
68
|
return err instanceof Error ? err : new Error(String(err));
|
|
69
69
|
}
|
|
70
70
|
}
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { PoolConfig as PgPoolConfig } from "pg";
|
|
2
|
-
export type PoolConfig = PgPoolConfig & {
|
|
3
|
-
enableLogs?: boolean;
|
|
4
|
-
};
|
|
5
1
|
export type PreparedStatement<TResult extends any, Tparams extends any[]> = {
|
|
6
2
|
text: string;
|
|
7
3
|
name: string;
|
|
@@ -9,17 +5,19 @@ export type PreparedStatement<TResult extends any, Tparams extends any[]> = {
|
|
|
9
5
|
};
|
|
10
6
|
export type CompiledSqlQuery = {
|
|
11
7
|
text: string;
|
|
12
|
-
args:
|
|
13
|
-
counter: number;
|
|
8
|
+
args: (string | null)[];
|
|
14
9
|
};
|
|
15
10
|
export type ClauseStrategyParams = {
|
|
16
11
|
text: string[];
|
|
17
12
|
args: any[];
|
|
18
|
-
counter: number;
|
|
19
13
|
};
|
|
20
14
|
export type CompileSQLParams = {
|
|
21
15
|
templates: TemplateStringsArray;
|
|
22
16
|
args: any[];
|
|
23
|
-
counter: number;
|
|
24
17
|
};
|
|
18
|
+
export type ColumnDescription = {
|
|
19
|
+
name: string;
|
|
20
|
+
typeOID: number;
|
|
21
|
+
};
|
|
22
|
+
export type ValueOF<T extends Record<string, unknown>> = T[keyof T];
|
|
25
23
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,iBAAiB,CAAC,OAAO,SAAS,GAAG,EAAE,OAAO,SAAS,GAAG,EAAE,IAAI;IACxE,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,CAAC,GAAG,IAAI,EAAE,OAAO,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC,CAAA;CACpD,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,CAAC;CAC3B,CAAA;AAED,MAAM,MAAM,oBAAoB,GAAG;IAC/B,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,IAAI,EAAE,GAAG,EAAE,CAAC;CACf,CAAA;AAED,MAAM,MAAM,gBAAgB,GAAG;IAC3B,SAAS,EAAE,oBAAoB,CAAC;IAChC,IAAI,EAAE,GAAG,EAAE,CAAC;CACf,CAAA;AAGD,MAAM,MAAM,iBAAiB,GAAG;IAC5B,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;CAClB,CAAA;AAGD,MAAM,MAAM,OAAO,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"template-compiler.d.ts","sourceRoot":"","sources":["../../src/utils/template-compiler.ts"],"names":[],"mappings":"AACA,OAAO,EAAwB,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAInF,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,QAAQ,CAAC,gBAAgB,CAAC,EAAE,SAAS,SAAI,GAAG,gBAAgB,CA+BtG"}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.compileSqlTemplate = compileSqlTemplate;
|
|
4
|
+
const abstract_clause_1 = require("../clauses/abstract.clause");
|
|
5
|
+
function compileSqlTemplate(params, argOffset = 0) {
|
|
6
|
+
const templateLength = params.templates.length;
|
|
7
|
+
const query = {
|
|
8
|
+
text: [],
|
|
9
|
+
args: [],
|
|
10
|
+
};
|
|
11
|
+
params.templates.forEach((template, index) => {
|
|
12
|
+
query.text.push(template);
|
|
13
|
+
if (index === templateLength - 1)
|
|
14
|
+
return;
|
|
15
|
+
const value = params.args[index];
|
|
16
|
+
if (value instanceof abstract_clause_1.Clause) {
|
|
17
|
+
value.mapIntoQuery(query);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
if (value === undefined) {
|
|
21
|
+
throw new TypeError(`Query parameter at position ${query.args.length + argOffset + 1} is undefined.
|
|
22
|
+
Use null if you want NULL in SQL, or ensure the value is defined.`);
|
|
23
|
+
}
|
|
24
|
+
query.args.push(value);
|
|
25
|
+
query.text.push(`$${query.args.length + argOffset}`);
|
|
26
|
+
}
|
|
27
|
+
});
|
|
28
|
+
return { args: query.args.map(prepareValue), text: query.text.join('') };
|
|
29
|
+
}
|
|
30
|
+
const prepareValue = (value) => {
|
|
31
|
+
if (value === null || value === undefined) {
|
|
32
|
+
return null;
|
|
33
|
+
}
|
|
34
|
+
if (typeof value === 'object') {
|
|
35
|
+
if (value instanceof Date) {
|
|
36
|
+
return value.toISOString();
|
|
37
|
+
}
|
|
38
|
+
if (Array.isArray(value)) {
|
|
39
|
+
const elements = value.map(el => {
|
|
40
|
+
if (el === null || el === undefined)
|
|
41
|
+
return 'NULL';
|
|
42
|
+
if (typeof el === 'boolean')
|
|
43
|
+
return el ? 'true' : 'false';
|
|
44
|
+
if (typeof el === 'object') {
|
|
45
|
+
const res = prepareValue(el);
|
|
46
|
+
return `"${res?.replace(/"/g, '\\"')}"`;
|
|
47
|
+
}
|
|
48
|
+
if (typeof el === 'string') {
|
|
49
|
+
return `"${el.replace(/\\/g, '\\\\').replace(/"/g, '\\"')}"`;
|
|
50
|
+
}
|
|
51
|
+
return String(el);
|
|
52
|
+
});
|
|
53
|
+
return `{${elements.join(',')}}`;
|
|
54
|
+
}
|
|
55
|
+
return prepareObject(value);
|
|
56
|
+
}
|
|
57
|
+
return value.toString();
|
|
58
|
+
};
|
|
59
|
+
const prepareObject = (obj) => {
|
|
60
|
+
if (obj && typeof obj.toPG === 'function') {
|
|
61
|
+
return JSON.stringify(obj.toPG());
|
|
62
|
+
}
|
|
63
|
+
return JSON.stringify(obj);
|
|
64
|
+
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { ColumnDescription } from "../types";
|
|
2
|
+
declare const Parsers: Record<number, (value: string) => unknown>;
|
|
3
|
+
export declare function parseRowValues(columns: ColumnDescription[], rows: (string | null)[][]): Record<string, any>;
|
|
4
|
+
export declare const setTypeParser: (typeOID: keyof typeof Parsers, parser: (value: string) => unknown) => void;
|
|
5
|
+
export {};
|
|
6
|
+
//# sourceMappingURL=value-parser.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"value-parser.d.ts","sourceRoot":"","sources":["../../src/utils/value-parser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,MAAM,UAAU,CAAA;AA+B5C,QAAA,MAAM,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAkD9C,CAAA;AAMV,wBAAgB,cAAc,CAAC,OAAO,EAAE,iBAAiB,EAAE,EAAE,IAAI,EAAE,CAAC,MAAM,GAAG,IAAI,CAAC,EAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA8B3G;AAGD,eAAO,MAAM,aAAa,GAAI,SAAS,MAAM,OAAO,OAAO,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,SAE9F,CAAA"}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.setTypeParser = void 0;
|
|
4
|
+
exports.parseRowValues = parseRowValues;
|
|
5
|
+
const parsePostgresArray = (v) => {
|
|
6
|
+
if (v === '{}')
|
|
7
|
+
return [];
|
|
8
|
+
const str = v.substring(1, v.length - 1);
|
|
9
|
+
const matches = str.match(/"(?:\\.|[^"\\])*"|[^,]+/g);
|
|
10
|
+
if (!matches)
|
|
11
|
+
return [];
|
|
12
|
+
return matches.map(el => {
|
|
13
|
+
const trimmed = el.trim();
|
|
14
|
+
if (trimmed === 'NULL')
|
|
15
|
+
return null;
|
|
16
|
+
if (trimmed.startsWith('"') && trimmed.endsWith('"')) {
|
|
17
|
+
return trimmed
|
|
18
|
+
.substring(1, trimmed.length - 1)
|
|
19
|
+
.replace(/\\"/g, '"')
|
|
20
|
+
.replace(/\\\\/g, '\\');
|
|
21
|
+
}
|
|
22
|
+
return trimmed;
|
|
23
|
+
});
|
|
24
|
+
};
|
|
25
|
+
const parsePoint = (v) => {
|
|
26
|
+
const [x, y] = v.replace(/[()]/g, '').split(',');
|
|
27
|
+
return { x: parseFloat(x), y: parseFloat(y) };
|
|
28
|
+
};
|
|
29
|
+
const Parsers = {
|
|
30
|
+
16: (v) => v === 't', // BOOL
|
|
31
|
+
21: (v) => parseInt(v, 10), // INT2 (SMALLINT)
|
|
32
|
+
23: (v) => parseInt(v, 10), // INT4 (INTEGER)
|
|
33
|
+
26: (v) => parseInt(v, 10), // OID
|
|
34
|
+
20: (v) => parseInt(v), // INT8 (BIGINT)
|
|
35
|
+
700: (v) => parseFloat(v), // FLOAT4 (REAL)
|
|
36
|
+
701: (v) => parseFloat(v), // FLOAT8 (DOUBLE PRECISION)
|
|
37
|
+
1700: (v) => parseFloat(v), // NUMERIC (DECIMAL)
|
|
38
|
+
18: (v) => v, // CHAR
|
|
39
|
+
19: (v) => v, // NAME
|
|
40
|
+
25: (v) => v, // TEXT
|
|
41
|
+
1042: (v) => v, // BPCHAR (CHAR(N))
|
|
42
|
+
1043: (v) => v, // VARCHAR
|
|
43
|
+
2950: (v) => v, // UUID
|
|
44
|
+
17: (v) => Buffer.from(v.substring(2), 'hex'), // BYTEA
|
|
45
|
+
1082: (v) => new Date(v), // DATE
|
|
46
|
+
1114: (v) => new Date(v + 'Z'), // TIMESTAMP
|
|
47
|
+
1184: (v) => new Date(v), // TIMESTAMPTZ
|
|
48
|
+
1083: (v) => v, // TIME
|
|
49
|
+
1266: (v) => v, // TIMETZ
|
|
50
|
+
1186: (v) => v, // INTERVAL
|
|
51
|
+
114: (v) => JSON.parse(v), // JSON
|
|
52
|
+
3802: (v) => JSON.parse(v), // JSONB
|
|
53
|
+
869: (v) => v, // INET (IP-адреса)
|
|
54
|
+
650: (v) => v, // CIDR
|
|
55
|
+
829: (v) => v, // MACADDR
|
|
56
|
+
600: parsePoint, // POINT
|
|
57
|
+
603: (v) => v.replace(/[()]/g, '') // POLYGON
|
|
58
|
+
.split(',')
|
|
59
|
+
.map(parsePoint),
|
|
60
|
+
1000: (v) => parsePostgresArray(v).map(el => el === 't'),
|
|
61
|
+
1005: (v) => parsePostgresArray(v).map(el => parseInt(el, 10)),
|
|
62
|
+
1007: (v) => parsePostgresArray(v).map(el => parseInt(el, 10)), // int4[]
|
|
63
|
+
1016: (v) => parsePostgresArray(v).map(el => BigInt(el)), // int8[]
|
|
64
|
+
1021: (v) => parsePostgresArray(v).map(el => parseFloat(el)),
|
|
65
|
+
1022: (v) => parsePostgresArray(v).map(el => parseFloat(el)), // float8[]
|
|
66
|
+
1231: (v) => parsePostgresArray(v).map(el => parseFloat(el)), // numeric[]
|
|
67
|
+
1009: (v) => parsePostgresArray(v), // text[]
|
|
68
|
+
1015: (v) => parsePostgresArray(v), // varchar[]
|
|
69
|
+
199: (v) => parsePostgresArray(v).map(el => JSON.parse(el)), // json[]
|
|
70
|
+
3807: (v) => parsePostgresArray(v).map(el => JSON.parse(el)), // jsonb[]
|
|
71
|
+
};
|
|
72
|
+
const defaultParser = (v) => v;
|
|
73
|
+
function parseRowValues(columns, rows) {
|
|
74
|
+
const result = [];
|
|
75
|
+
const columnsLength = columns.length;
|
|
76
|
+
const columnParsers = columns.map(col => Parsers[col.typeOID] || defaultParser);
|
|
77
|
+
for (let r = 0; r < rows.length; r++) {
|
|
78
|
+
const rawRow = rows[r];
|
|
79
|
+
const rowObject = {};
|
|
80
|
+
for (let c = 0; c < columnsLength; c++) {
|
|
81
|
+
const val = rawRow[c];
|
|
82
|
+
const colName = columns[c].name;
|
|
83
|
+
if (val === null) {
|
|
84
|
+
rowObject[colName] = null;
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
try {
|
|
88
|
+
rowObject[colName] = columnParsers[c](val);
|
|
89
|
+
}
|
|
90
|
+
catch {
|
|
91
|
+
rowObject[colName] = val;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
result.push(rowObject);
|
|
95
|
+
}
|
|
96
|
+
return result;
|
|
97
|
+
}
|
|
98
|
+
const setTypeParser = (typeOID, parser) => {
|
|
99
|
+
Parsers[typeOID] = parser;
|
|
100
|
+
};
|
|
101
|
+
exports.setTypeParser = setTypeParser;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m2k-5f/pgtx",
|
|
3
|
-
"version": "
|
|
4
|
-
"description": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"description": "Blazing-fast PostgreSQL driver with pipeline support.",
|
|
5
5
|
"files": [
|
|
6
6
|
"dist",
|
|
7
7
|
"README.md"
|
|
@@ -9,7 +9,8 @@
|
|
|
9
9
|
"scripts": {
|
|
10
10
|
"build": "tsc",
|
|
11
11
|
"prepublishOnly": "npm run build",
|
|
12
|
-
"
|
|
12
|
+
"testGitHub": "node --import tsx --test $(find tests -name '*.test.ts')",
|
|
13
|
+
"test": "node --import tsx --test ./tests/*.test.ts"
|
|
13
14
|
},
|
|
14
15
|
"repository": {
|
|
15
16
|
"type": "git",
|
|
@@ -18,7 +19,8 @@
|
|
|
18
19
|
"keywords": [
|
|
19
20
|
"sql",
|
|
20
21
|
"postgres",
|
|
21
|
-
"
|
|
22
|
+
"driver",
|
|
23
|
+
"pipeline",
|
|
22
24
|
"query-builder",
|
|
23
25
|
"typescript",
|
|
24
26
|
"transactions",
|
|
@@ -37,12 +39,9 @@
|
|
|
37
39
|
"types": "./dist/index.d.ts"
|
|
38
40
|
}
|
|
39
41
|
},
|
|
40
|
-
"dependencies": {
|
|
41
|
-
"pg": "^8.11.0"
|
|
42
|
-
},
|
|
43
42
|
"devDependencies": {
|
|
44
|
-
"@types/pg": "^8.11.0",
|
|
45
43
|
"tsx": "^4.21.0",
|
|
46
|
-
"typescript": "^5.0.0"
|
|
44
|
+
"typescript": "^5.0.0",
|
|
45
|
+
"@types/node": "^26.1.1"
|
|
47
46
|
}
|
|
48
47
|
}
|