pogi 2.11.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/.vscode/launch.json +35 -0
- package/CHANGELOG.md +277 -0
- package/LICENSE +21 -0
- package/README.md +85 -0
- package/docs/API/PgDb.md +218 -0
- package/docs/API/PgSchema.md +91 -0
- package/docs/API/PgTable.md +365 -0
- package/docs/API/QueryOptions.md +77 -0
- package/docs/API/condition.md +133 -0
- package/docs/connection.md +91 -0
- package/docs/css/docs.css +164 -0
- package/docs/executingSqlFile.md +44 -0
- package/docs/faq.md +15 -0
- package/docs/functions.md +19 -0
- package/docs/generatingInterfaceForTables.md +35 -0
- package/docs/index.md +48 -0
- package/docs/logger.md +40 -0
- package/docs/mappingDatabaseTypes.md +89 -0
- package/docs/notification.md +19 -0
- package/docs/pitfalls.md +73 -0
- package/docs/streams.md +68 -0
- package/docs/transaction.md +65 -0
- package/lib/bin/generateInterface.d.ts +1 -0
- package/lib/bin/generateInterface.js +53 -0
- package/lib/bin/generateInterface.js.map +1 -0
- package/lib/connectionOptions.d.ts +25 -0
- package/lib/connectionOptions.js +3 -0
- package/lib/connectionOptions.js.map +1 -0
- package/lib/index.d.ts +6 -0
- package/lib/index.js +10 -0
- package/lib/index.js.map +1 -0
- package/lib/pgConverters.d.ts +10 -0
- package/lib/pgConverters.js +66 -0
- package/lib/pgConverters.js.map +1 -0
- package/lib/pgDb.d.ts +86 -0
- package/lib/pgDb.js +745 -0
- package/lib/pgDb.js.map +1 -0
- package/lib/pgDbLogger.d.ts +5 -0
- package/lib/pgDbLogger.js +3 -0
- package/lib/pgDbLogger.js.map +1 -0
- package/lib/pgDbOperators.d.ts +113 -0
- package/lib/pgDbOperators.js +44 -0
- package/lib/pgDbOperators.js.map +1 -0
- package/lib/pgSchema.d.ts +16 -0
- package/lib/pgSchema.js +16 -0
- package/lib/pgSchema.js.map +1 -0
- package/lib/pgTable.d.ts +131 -0
- package/lib/pgTable.js +322 -0
- package/lib/pgTable.js.map +1 -0
- package/lib/pgUtils.d.ts +31 -0
- package/lib/pgUtils.js +157 -0
- package/lib/pgUtils.js.map +1 -0
- package/lib/queryAble.d.ts +76 -0
- package/lib/queryAble.js +330 -0
- package/lib/queryAble.js.map +1 -0
- package/lib/queryWhere.d.ts +8 -0
- package/lib/queryWhere.js +249 -0
- package/lib/queryWhere.js.map +1 -0
- package/mkdocs.yml +25 -0
- package/package.json +65 -0
- package/spec/resources/init.sql +122 -0
- package/spec/resources/throw_exception.sql +5 -0
- package/spec/resources/tricky.sql +13 -0
- package/spec/run.js +5 -0
- package/spec/support/jasmine.json +9 -0
- package/src/bin/generateInterface.ts +54 -0
- package/src/connectionOptions.ts +42 -0
- package/src/index.ts +6 -0
- package/src/pgConverters.ts +55 -0
- package/src/pgDb.ts +820 -0
- package/src/pgDbLogger.ts +13 -0
- package/src/pgDbOperators.ts +62 -0
- package/src/pgSchema.ts +15 -0
- package/src/pgTable.ts +401 -0
- package/src/pgUtils.ts +176 -0
- package/src/queryAble.ts +393 -0
- package/src/queryWhere.ts +326 -0
- package/src/test/pgDbOperatorSpec.ts +492 -0
- package/src/test/pgDbSpec.ts +1339 -0
- package/src/test/pgServiceRestartTest.ts +1500 -0
- package/src/tsconfig.json +33 -0
- package/utils_sql/lower.sql +4 -0
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
## Transaction
|
|
2
|
+
as simple as:
|
|
3
|
+
```js
|
|
4
|
+
let pgdb_nt; //no transaction (using the pool)
|
|
5
|
+
let pgdb_wt; //with transaction
|
|
6
|
+
|
|
7
|
+
pgdb_nt = await PgDb.connect(..);
|
|
8
|
+
pgdb_wt = await pgdb_nt.transactionBegin();
|
|
9
|
+
try {
|
|
10
|
+
//look busy
|
|
11
|
+
|
|
12
|
+
await pgdb_nt.query(..) //executed outside of the transaction
|
|
13
|
+
await pgdb_wt.query(..) //executed inside of the transaction
|
|
14
|
+
|
|
15
|
+
await pgdb_wt.transactionCommit();
|
|
16
|
+
} catch(e) {
|
|
17
|
+
await pgdb_wt.transactionRollback();
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
active transaction can be tested with
|
|
22
|
+
```js
|
|
23
|
+
if (pgdb.isTransactionActive()) {
|
|
24
|
+
//...
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
## Savepoint transaction like a subtransaction
|
|
28
|
+
|
|
29
|
+
```js
|
|
30
|
+
//connection with transaction
|
|
31
|
+
let pgdb_wt = await pgdb.transactionBegin();
|
|
32
|
+
// ... do some work
|
|
33
|
+
pgdb_wt = await pgdb.savePoint('import');
|
|
34
|
+
try {
|
|
35
|
+
//... do import
|
|
36
|
+
await pgdb_wt.transactionCommit();
|
|
37
|
+
} catch(e) {
|
|
38
|
+
// rollback to "import" savepoint
|
|
39
|
+
await pgdb_wt.transactionRollback({savepoint:'import'});
|
|
40
|
+
}
|
|
41
|
+
// transaction continue from "import" savepoint
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
See [Postgresql documentation](https://www.postgresql.org/docs/current/sql-savepoint.html)
|
|
45
|
+
|
|
46
|
+
## Dedicated connection
|
|
47
|
+
PgDb use connection pool, so it run every query in a random connection from the pool. Connection pool size can be set at connection time with "poolSize" attribute, see [connection](/connection).
|
|
48
|
+
Sometimes single connection mode is desired (ex: execute an SQL file), or if you want to use variables, or set the `search_path`.
|
|
49
|
+
It is posibble and its usage very similar to transactions. `dedicatedConnectionBegin()` will create a new PgDb instance which is now in a dedicated connection mode.
|
|
50
|
+
All further query will be run in the same connection, no pool is used. Programmer responsible to close dedicated connection with `dedicatedConnectionEnd()` to avoid leaking.
|
|
51
|
+
If closed, connection will get back to the pool and pgdb instance will work in pool mode.
|
|
52
|
+
|
|
53
|
+
```js
|
|
54
|
+
pgdb = await PgDb.connect(..);
|
|
55
|
+
pgdb_1con = await pgdb.dedicatedConnectionBegin();
|
|
56
|
+
try {
|
|
57
|
+
//do magic
|
|
58
|
+
await pgdb_1con.query(..);
|
|
59
|
+
await pgdb_1con.schema.table.find(..);
|
|
60
|
+
|
|
61
|
+
} finally {
|
|
62
|
+
//lets release it
|
|
63
|
+
await pgdb_1con.dedicatedConnectionEnd();
|
|
64
|
+
}
|
|
65
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const tslib_1 = require("tslib");
|
|
4
|
+
const pgDb_1 = require("../pgDb");
|
|
5
|
+
const pgSchema_1 = require("../pgSchema");
|
|
6
|
+
const pgTable_1 = require("../pgTable");
|
|
7
|
+
(function () {
|
|
8
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
9
|
+
try {
|
|
10
|
+
let pgdb = yield pgDb_1.PgDb.connect({
|
|
11
|
+
logger: {
|
|
12
|
+
log: () => {
|
|
13
|
+
}, error: console.error
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
console.log('import {PgDb, PgSchema, PgTable} from "pogi";\n');
|
|
17
|
+
console.log('export interface PgDbType extends PgDb {');
|
|
18
|
+
for (let schemaName in pgdb.schemas) {
|
|
19
|
+
if (!(pgdb[schemaName] instanceof pgSchema_1.PgSchema)) {
|
|
20
|
+
throw Error('Already existing property: ' + schemaName + '!');
|
|
21
|
+
}
|
|
22
|
+
console.log(` '${schemaName}': PgSchema_${schemaName};`);
|
|
23
|
+
}
|
|
24
|
+
console.log(` 'schemas': {`);
|
|
25
|
+
for (let schemaName in pgdb.schemas) {
|
|
26
|
+
console.log(` '${schemaName}': PgSchema_${schemaName};`);
|
|
27
|
+
}
|
|
28
|
+
console.log(' }');
|
|
29
|
+
console.log('}');
|
|
30
|
+
for (let schemaName in pgdb.schemas) {
|
|
31
|
+
console.log(`export interface PgSchema_${schemaName} extends PgSchema {`);
|
|
32
|
+
for (let tableName in pgdb.schemas[schemaName].tables) {
|
|
33
|
+
if (!(pgdb[schemaName][tableName] instanceof pgTable_1.PgTable)) {
|
|
34
|
+
throw Error('Already existing property: ' + tableName + ' on schema:' + schemaName + '!');
|
|
35
|
+
}
|
|
36
|
+
console.log(` '${tableName}': PgTable<any>;`);
|
|
37
|
+
}
|
|
38
|
+
console.log(` tables: {`);
|
|
39
|
+
for (let tableName in pgdb.schemas[schemaName].tables) {
|
|
40
|
+
console.log(` '${tableName}': PgTable<any>;`);
|
|
41
|
+
}
|
|
42
|
+
console.log(' }');
|
|
43
|
+
console.log('}');
|
|
44
|
+
}
|
|
45
|
+
pgdb.close();
|
|
46
|
+
}
|
|
47
|
+
catch (e) {
|
|
48
|
+
console.error(e);
|
|
49
|
+
}
|
|
50
|
+
return Promise.resolve();
|
|
51
|
+
});
|
|
52
|
+
})();
|
|
53
|
+
//# sourceMappingURL=generateInterface.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateInterface.js","sourceRoot":"","sources":["../../src/bin/generateInterface.ts"],"names":[],"mappings":";;;AAAA,kCAA6B;AAC7B,0CAAqC;AACrC,wCAAmC;AAEnC,CAAC;;QACG,IAAI;YACA,IAAI,IAAI,GAAG,MAAM,WAAI,CAAC,OAAO,CAAC;gBAC1B,MAAM,EAAE;oBACJ,GAAG,EAAE,GAAG,EAAE;oBACV,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK;iBAC1B;aACJ,CAAC,CAAC;YAEH,OAAO,CAAC,GAAG,CAAC,iDAAiD,CAAC,CAAC;YAC/D,OAAO,CAAC,GAAG,CAAC,0CAA0C,CAAC,CAAC;YAExD,KAAK,IAAI,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE;gBACjC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,YAAY,mBAAQ,CAAC,EAAE;oBACzC,MAAM,KAAK,CAAC,6BAA6B,GAAG,UAAU,GAAG,GAAG,CAAC,CAAC;iBACjE;gBACD,OAAO,CAAC,GAAG,CAAC,QAAQ,UAAU,eAAe,UAAU,GAAG,CAAC,CAAC;aAC/D;YAED,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAC;YAChC,KAAK,IAAI,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE;gBACjC,OAAO,CAAC,GAAG,CAAC,YAAY,UAAU,eAAe,UAAU,GAAG,CAAC,CAAC;aACnE;YACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;YACrB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;YAEjB,KAAK,IAAI,UAAU,IAAI,IAAI,CAAC,OAAO,EAAE;gBACjC,OAAO,CAAC,GAAG,CAAC,6BAA6B,UAAU,qBAAqB,CAAC,CAAC;gBAC1E,KAAK,IAAI,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE;oBACnD,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,YAAY,iBAAO,CAAC,EAAE;wBACnD,MAAM,KAAK,CAAC,6BAA6B,GAAG,SAAS,GAAG,aAAa,GAAG,UAAU,GAAG,GAAG,CAAC,CAAC;qBAC7F;oBACD,OAAO,CAAC,GAAG,CAAC,QAAQ,SAAS,kBAAkB,CAAC,CAAC;iBACpD;gBACD,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;gBAC7B,KAAK,IAAI,SAAS,IAAI,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,EAAE;oBACnD,OAAO,CAAC,GAAG,CAAC,YAAY,SAAS,kBAAkB,CAAC,CAAC;iBACxD;gBACD,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBAErB,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;aACpB;YAGD,IAAI,CAAC,KAAK,EAAE,CAAC;SAChB;QAAC,OAAO,CAAC,EAAE;YACR,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACpB;QACD,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;IAC7B,CAAC;CAAA,CAAC,EAAE,CAAC"}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { PgDbLogger } from './pgDbLogger';
|
|
2
|
+
export interface ConnectionOptions {
|
|
3
|
+
host?: string;
|
|
4
|
+
user?: string;
|
|
5
|
+
database?: string;
|
|
6
|
+
password?: string;
|
|
7
|
+
port?: number;
|
|
8
|
+
poolSize?: number;
|
|
9
|
+
rows?: number;
|
|
10
|
+
min?: number;
|
|
11
|
+
max?: number;
|
|
12
|
+
binary?: boolean;
|
|
13
|
+
poolIdleTimeout?: number;
|
|
14
|
+
reapIntervalMillis?: number;
|
|
15
|
+
poolLog?: boolean;
|
|
16
|
+
client_encoding?: string;
|
|
17
|
+
ssl?: boolean | any;
|
|
18
|
+
application_name?: string;
|
|
19
|
+
fallback_application_name?: string;
|
|
20
|
+
parseInputDatesAsUTC?: boolean;
|
|
21
|
+
connectionString?: string;
|
|
22
|
+
idleTimeoutMillis?: number;
|
|
23
|
+
logger?: PgDbLogger;
|
|
24
|
+
skipUndefined?: 'all' | 'select' | 'none';
|
|
25
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"connectionOptions.js","sourceRoot":"","sources":["../src/connectionOptions.ts"],"names":[],"mappings":""}
|
package/lib/index.d.ts
ADDED
package/lib/index.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PgSchema = exports.PgTable = exports.PgDb = void 0;
|
|
4
|
+
var pgDb_1 = require("./pgDb");
|
|
5
|
+
Object.defineProperty(exports, "PgDb", { enumerable: true, get: function () { return pgDb_1.PgDb; } });
|
|
6
|
+
var pgTable_1 = require("./pgTable");
|
|
7
|
+
Object.defineProperty(exports, "PgTable", { enumerable: true, get: function () { return pgTable_1.PgTable; } });
|
|
8
|
+
var pgSchema_1 = require("./pgSchema");
|
|
9
|
+
Object.defineProperty(exports, "PgSchema", { enumerable: true, get: function () { return pgSchema_1.PgSchema; } });
|
|
10
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";;;AAAA,+BAA8B;AAArB,4FAAA,IAAI,OAAA;AAGb,qCAAoC;AAA3B,kGAAA,OAAO,OAAA;AAChB,uCAAsC;AAA7B,oGAAA,QAAQ,OAAA"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare let arraySplit: (str: any) => any[];
|
|
2
|
+
export declare let numWithValidation: (val: any) => number;
|
|
3
|
+
export declare let numberOrNull: (val: any) => number;
|
|
4
|
+
export declare let boolOrNull: (val: any) => boolean;
|
|
5
|
+
export declare let arraySplitToBool: (val: any) => any;
|
|
6
|
+
export declare let arraySplitToNum: (val: any) => any;
|
|
7
|
+
export declare let arraySplitToNumWithValidation: (val: any) => any;
|
|
8
|
+
export declare let stringArrayToNumWithValidation: (val: any) => any;
|
|
9
|
+
export declare let arraySplitToDate: (val: any) => any;
|
|
10
|
+
export declare let arraySplitToJson: (str: any) => any[];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.arraySplitToJson = exports.arraySplitToDate = exports.stringArrayToNumWithValidation = exports.arraySplitToNumWithValidation = exports.arraySplitToNum = exports.arraySplitToBool = exports.boolOrNull = exports.numberOrNull = exports.numWithValidation = exports.arraySplit = void 0;
|
|
4
|
+
const moment = require("moment");
|
|
5
|
+
let arraySplit = (str) => {
|
|
6
|
+
if (str == "{}")
|
|
7
|
+
return [];
|
|
8
|
+
str = str.substring(1, str.length - 1);
|
|
9
|
+
let e = /(?:("(?:[^"\\]|\\.)*")|([^,"]*))(?:,|$)/g;
|
|
10
|
+
let valList = [];
|
|
11
|
+
let parsingResult;
|
|
12
|
+
do {
|
|
13
|
+
parsingResult = e.exec(str);
|
|
14
|
+
let valStr = (parsingResult[2] == 'NULL') ? null :
|
|
15
|
+
(parsingResult[1] == null ? parsingResult[2] : unescapeString(parsingResult[1]));
|
|
16
|
+
valList.push(valStr);
|
|
17
|
+
} while (e.lastIndex < str.length);
|
|
18
|
+
return valList;
|
|
19
|
+
};
|
|
20
|
+
exports.arraySplit = arraySplit;
|
|
21
|
+
let numWithValidation = val => {
|
|
22
|
+
if (val === 'NULL') {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
let v = +val;
|
|
26
|
+
if (v > Number.MAX_SAFE_INTEGER || v < Number.MIN_SAFE_INTEGER) {
|
|
27
|
+
throw Error("Number can't be represented in javascript precisely: " + val);
|
|
28
|
+
}
|
|
29
|
+
return v;
|
|
30
|
+
};
|
|
31
|
+
exports.numWithValidation = numWithValidation;
|
|
32
|
+
let numberOrNull = val => {
|
|
33
|
+
if (val === 'NULL') {
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
return +val;
|
|
37
|
+
};
|
|
38
|
+
exports.numberOrNull = numberOrNull;
|
|
39
|
+
let boolOrNull = val => {
|
|
40
|
+
if (val === 'NULL') {
|
|
41
|
+
return null;
|
|
42
|
+
}
|
|
43
|
+
return val == 't';
|
|
44
|
+
};
|
|
45
|
+
exports.boolOrNull = boolOrNull;
|
|
46
|
+
let arraySplitToBool = val => val == "{}" ? [] : val.substring(1, val.length - 1).split(',').map(exports.boolOrNull);
|
|
47
|
+
exports.arraySplitToBool = arraySplitToBool;
|
|
48
|
+
let arraySplitToNum = val => val == "{}" ? [] : val.substring(1, val.length - 1).split(',').map(exports.numberOrNull);
|
|
49
|
+
exports.arraySplitToNum = arraySplitToNum;
|
|
50
|
+
let arraySplitToNumWithValidation = val => val == "{}" ? [] : val.substring(1, val.length - 1).split(',').map(exports.numWithValidation);
|
|
51
|
+
exports.arraySplitToNumWithValidation = arraySplitToNumWithValidation;
|
|
52
|
+
let stringArrayToNumWithValidation = val => val.map(exports.numWithValidation);
|
|
53
|
+
exports.stringArrayToNumWithValidation = stringArrayToNumWithValidation;
|
|
54
|
+
let arraySplitToDate = val => val == "{}" ? [] : val.substring(1, val.length - 1).split(',').map(d => d == 'NULL' ? null : moment(d.substring(1, d.length - 1)).toDate());
|
|
55
|
+
exports.arraySplitToDate = arraySplitToDate;
|
|
56
|
+
let arraySplitToJson = (str) => {
|
|
57
|
+
let vals = exports.arraySplit(str);
|
|
58
|
+
return vals.map(s => typeof s === 'string' ? JSON.parse(s) : s);
|
|
59
|
+
};
|
|
60
|
+
exports.arraySplitToJson = arraySplitToJson;
|
|
61
|
+
function unescapeString(s) {
|
|
62
|
+
return s.slice(1, s.length - 1)
|
|
63
|
+
.replace(/\\"/g, '"')
|
|
64
|
+
.replace(/\\\\/g, '\\');
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=pgConverters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pgConverters.js","sourceRoot":"","sources":["../src/pgConverters.ts"],"names":[],"mappings":"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"}
|
package/lib/pgDb.d.ts
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { QueryAble, ResultFieldType } from "./queryAble";
|
|
2
|
+
import { PgTable } from "./pgTable";
|
|
3
|
+
import { PgSchema } from "./pgSchema";
|
|
4
|
+
import { PgDbLogger } from './pgDbLogger';
|
|
5
|
+
import { ConnectionOptions } from './connectionOptions';
|
|
6
|
+
export declare enum FieldType {
|
|
7
|
+
JSON = 0,
|
|
8
|
+
ARRAY = 1,
|
|
9
|
+
TIME = 2,
|
|
10
|
+
TSVECTOR = 3
|
|
11
|
+
}
|
|
12
|
+
export declare enum TranzactionIsolationLevel {
|
|
13
|
+
serializable = "SERIALIZABLE",
|
|
14
|
+
repeatableRead = "REPEATABLE READ",
|
|
15
|
+
readCommitted = "READ COMMITTED",
|
|
16
|
+
readUncommitted = "READ UNCOMMITTED"
|
|
17
|
+
}
|
|
18
|
+
export declare type PostProcessResultFunc = (res: any[], fields: ResultFieldType[], logger: PgDbLogger) => void;
|
|
19
|
+
export interface Notification {
|
|
20
|
+
processId: number;
|
|
21
|
+
channel: string;
|
|
22
|
+
payload?: string;
|
|
23
|
+
}
|
|
24
|
+
export declare class PgDb extends QueryAble {
|
|
25
|
+
protected static instances: {
|
|
26
|
+
[index: string]: Promise<PgDb>;
|
|
27
|
+
};
|
|
28
|
+
pool: any;
|
|
29
|
+
connection: any;
|
|
30
|
+
config: ConnectionOptions;
|
|
31
|
+
defaultSchemas: any;
|
|
32
|
+
db: any;
|
|
33
|
+
schemas: {
|
|
34
|
+
[name: string]: PgSchema;
|
|
35
|
+
};
|
|
36
|
+
tables: {
|
|
37
|
+
[name: string]: PgTable<any>;
|
|
38
|
+
};
|
|
39
|
+
fn: {
|
|
40
|
+
[name: string]: (...any: any[]) => any;
|
|
41
|
+
};
|
|
42
|
+
[name: string]: any | PgSchema;
|
|
43
|
+
pgdbTypeParsers: {};
|
|
44
|
+
knownOids: Record<number, boolean>;
|
|
45
|
+
postProcessResult: PostProcessResultFunc;
|
|
46
|
+
private constructor();
|
|
47
|
+
setPostProcessResult(f: (res: any[], fields: ResultFieldType[], logger: PgDbLogger) => void): void;
|
|
48
|
+
static getInstance(config: ConnectionOptions): Promise<PgDb>;
|
|
49
|
+
close(): Promise<void>;
|
|
50
|
+
static connect(config: ConnectionOptions): Promise<PgDb>;
|
|
51
|
+
private init;
|
|
52
|
+
reload(): Promise<void>;
|
|
53
|
+
private initSchemasAndTables;
|
|
54
|
+
private setDefaultTablesAndFunctions;
|
|
55
|
+
private initFieldTypes;
|
|
56
|
+
setTypeParser(typeName: string, parser: (string: any) => any, schemaName?: string): Promise<void>;
|
|
57
|
+
setPgDbTypeParser(typeName: string, parser: (string: any) => any, schemaName?: string): Promise<void>;
|
|
58
|
+
resetMissingParsers(connection: any, oidList: number[]): Promise<void>;
|
|
59
|
+
dedicatedConnectionBegin(): Promise<PgDb>;
|
|
60
|
+
dedicatedConnectionEnd(): Promise<PgDb>;
|
|
61
|
+
savePoint(name: string): Promise<PgDb>;
|
|
62
|
+
savePointRelease(name: string): Promise<PgDb>;
|
|
63
|
+
transactionBegin(options?: {
|
|
64
|
+
isolationLevel?: TranzactionIsolationLevel;
|
|
65
|
+
deferrable?: boolean;
|
|
66
|
+
readOnly?: boolean;
|
|
67
|
+
}): Promise<PgDb>;
|
|
68
|
+
transactionCommit(): Promise<PgDb>;
|
|
69
|
+
transactionRollback(options?: {
|
|
70
|
+
savePoint?: string;
|
|
71
|
+
}): Promise<PgDb>;
|
|
72
|
+
isTransactionActive(): boolean;
|
|
73
|
+
execute(fileName: string, statementTransformerFunction?: (string: any) => string): Promise<void>;
|
|
74
|
+
private listeners;
|
|
75
|
+
private connectionForListen;
|
|
76
|
+
private _needToRestartConnectionForListen;
|
|
77
|
+
private restartConnectionForListen;
|
|
78
|
+
listen(channel: string, callback: (notification: Notification) => void): Promise<void>;
|
|
79
|
+
unlisten(channel: string, callback?: (Notification: any) => void): Promise<void>;
|
|
80
|
+
notify(channel: string, payload?: string): Promise<any[]>;
|
|
81
|
+
runRestartConnectionForListen(): Promise<Error>;
|
|
82
|
+
needToFixConnectionForListen(): boolean;
|
|
83
|
+
private tryToFixConnectionForListenActively;
|
|
84
|
+
private initConnectionForListen;
|
|
85
|
+
}
|
|
86
|
+
export default PgDb;
|
package/lib/pgDb.js
ADDED
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PgDb = exports.TranzactionIsolationLevel = exports.FieldType = void 0;
|
|
4
|
+
const tslib_1 = require("tslib");
|
|
5
|
+
const queryAble_1 = require("./queryAble");
|
|
6
|
+
const pgTable_1 = require("./pgTable");
|
|
7
|
+
const pgSchema_1 = require("./pgSchema");
|
|
8
|
+
const PgConverters = require("./pgConverters");
|
|
9
|
+
const pgUtils_1 = require("./pgUtils");
|
|
10
|
+
const _ = require("lodash");
|
|
11
|
+
const pg = require("pg");
|
|
12
|
+
const readline = require("readline");
|
|
13
|
+
const fs = require("fs");
|
|
14
|
+
const EventEmitter = require("events");
|
|
15
|
+
const CONNECTION_URL_REGEXP = /^postgres:\/\/(?:([^:]+)(?::([^@]*))?@)?([^\/:]+)?(?::([^\/]+))?\/(.*)$/;
|
|
16
|
+
const SQL_TOKENIZER_REGEXP = /''|'|""|"|;|\$|--|\/\*|\*\/|(.+?)/g;
|
|
17
|
+
const SQL_$_ESCAPE_REGEXP = /\$[^$]*\$/g;
|
|
18
|
+
const LIST_SCHEMAS_TABLES = `SELECT table_schema as schema, table_name as name
|
|
19
|
+
FROM information_schema.tables
|
|
20
|
+
WHERE table_schema NOT IN ('pg_catalog', 'pg_constraint', 'information_schema')`;
|
|
21
|
+
const GET_OID_FOR_COLUMN_TYPE_FOR_SCHEMA = "SELECT t.oid FROM pg_catalog.pg_type t, pg_namespace n WHERE typname=:typeName and n.oid=t.typnamespace and n.nspname=:schemaName;";
|
|
22
|
+
const GET_OID_FOR_COLUMN_TYPE = "SELECT t.oid FROM pg_catalog.pg_type t WHERE typname=:typeName";
|
|
23
|
+
const GET_SCHEMAS_PROCEDURES = `SELECT
|
|
24
|
+
n.nspname as "schema",
|
|
25
|
+
p.proname as "name",
|
|
26
|
+
(not p.proretset) as "return_single_row",
|
|
27
|
+
(t.typtype in ('b', 'd', 'e', 'r')) as "return_single_value"
|
|
28
|
+
FROM pg_proc p
|
|
29
|
+
inner join pg_namespace n on (p.pronamespace = n.oid)
|
|
30
|
+
inner join pg_type t on (p.prorettype = t.oid)
|
|
31
|
+
left outer join pg_trigger tr on (tr.tgfoid = p.oid)
|
|
32
|
+
WHERE n.nspname NOT IN ('pg_catalog', 'pg_constraint', 'information_schema')
|
|
33
|
+
AND tr.oid is null;`;
|
|
34
|
+
const GET_CURRENT_SCHEMAS = "SELECT current_schemas(false)";
|
|
35
|
+
const LIST_SPECIAL_TYPE_FIELDS = `SELECT c.nspname as schema_name, b.relname as table_name, a.attname as column_name, a.atttypid as typid
|
|
36
|
+
FROM pg_attribute a
|
|
37
|
+
JOIN pg_class b ON (a.attrelid = b.oid)
|
|
38
|
+
JOIN pg_type t ON (a.atttypid = t.oid)
|
|
39
|
+
JOIN pg_namespace c ON (b.relnamespace=c.oid)
|
|
40
|
+
WHERE (a.atttypid in (114, 3802, 1082, 1083, 1114, 1184, 1266, 3614) or t.typcategory='A')
|
|
41
|
+
AND reltype>0 `;
|
|
42
|
+
var FieldType;
|
|
43
|
+
(function (FieldType) {
|
|
44
|
+
FieldType[FieldType["JSON"] = 0] = "JSON";
|
|
45
|
+
FieldType[FieldType["ARRAY"] = 1] = "ARRAY";
|
|
46
|
+
FieldType[FieldType["TIME"] = 2] = "TIME";
|
|
47
|
+
FieldType[FieldType["TSVECTOR"] = 3] = "TSVECTOR";
|
|
48
|
+
})(FieldType = exports.FieldType || (exports.FieldType = {}));
|
|
49
|
+
var TranzactionIsolationLevel;
|
|
50
|
+
(function (TranzactionIsolationLevel) {
|
|
51
|
+
TranzactionIsolationLevel["serializable"] = "SERIALIZABLE";
|
|
52
|
+
TranzactionIsolationLevel["repeatableRead"] = "REPEATABLE READ";
|
|
53
|
+
TranzactionIsolationLevel["readCommitted"] = "READ COMMITTED";
|
|
54
|
+
TranzactionIsolationLevel["readUncommitted"] = "READ UNCOMMITTED";
|
|
55
|
+
})(TranzactionIsolationLevel = exports.TranzactionIsolationLevel || (exports.TranzactionIsolationLevel = {}));
|
|
56
|
+
class PgDb extends queryAble_1.QueryAble {
|
|
57
|
+
constructor(pgdb = {}) {
|
|
58
|
+
super();
|
|
59
|
+
this.tables = {};
|
|
60
|
+
this.fn = {};
|
|
61
|
+
this.pgdbTypeParsers = {};
|
|
62
|
+
this.knownOids = {};
|
|
63
|
+
this.listeners = new EventEmitter();
|
|
64
|
+
this._needToRestartConnectionForListen = false;
|
|
65
|
+
this.restartConnectionForListen = null;
|
|
66
|
+
this.schemas = {};
|
|
67
|
+
this.config = pgdb.config;
|
|
68
|
+
this.pool = pgdb.pool;
|
|
69
|
+
this.postProcessResult = pgdb.postProcessResult;
|
|
70
|
+
this.pgdbTypeParsers = pgdb.pgdbTypeParsers || {};
|
|
71
|
+
this.knownOids = pgdb.knownOids || {};
|
|
72
|
+
this.db = this;
|
|
73
|
+
if (pgdb.getLogger) {
|
|
74
|
+
this.setLogger(pgdb.getLogger());
|
|
75
|
+
}
|
|
76
|
+
for (let schemaName in pgdb.schemas) {
|
|
77
|
+
let schema = new pgSchema_1.PgSchema(this, schemaName);
|
|
78
|
+
this.schemas[schemaName] = schema;
|
|
79
|
+
if (!(schemaName in this))
|
|
80
|
+
this[schemaName] = schema;
|
|
81
|
+
for (let tableName in pgdb.schemas[schemaName].tables) {
|
|
82
|
+
schema.tables[tableName] = new pgTable_1.PgTable(schema, pgdb.schemas[schemaName][tableName].desc, pgdb.schemas[schemaName][tableName].fieldTypes);
|
|
83
|
+
if (!(tableName in schema))
|
|
84
|
+
schema[tableName] = schema.tables[tableName];
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
this.defaultSchemas = pgdb.defaultSchemas;
|
|
88
|
+
this.setDefaultTablesAndFunctions();
|
|
89
|
+
}
|
|
90
|
+
setPostProcessResult(f) {
|
|
91
|
+
this.postProcessResult = f;
|
|
92
|
+
}
|
|
93
|
+
static getInstance(config) {
|
|
94
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
95
|
+
if (config.connectionString) {
|
|
96
|
+
let res = CONNECTION_URL_REGEXP.exec(config.connectionString);
|
|
97
|
+
if (res) {
|
|
98
|
+
config.user = res[1];
|
|
99
|
+
config.password = res[2] ? res[2] : '';
|
|
100
|
+
config.host = res[3] ? res[3] : 'localhost';
|
|
101
|
+
config.port = res[4] ? +res[4] : 5432;
|
|
102
|
+
config.database = res[5];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
let connectionString = `postgres://${config.user}@${config.host}:${config.port}/${config.database}`;
|
|
106
|
+
if (!PgDb.instances) {
|
|
107
|
+
PgDb.instances = {};
|
|
108
|
+
}
|
|
109
|
+
if (PgDb.instances[connectionString]) {
|
|
110
|
+
return PgDb.instances[connectionString];
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
let pgdb = new PgDb({ config: config });
|
|
114
|
+
PgDb.instances[connectionString] = pgdb.init();
|
|
115
|
+
return PgDb.instances[connectionString];
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
close() {
|
|
120
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
121
|
+
for (let cs in PgDb.instances) {
|
|
122
|
+
let db = yield PgDb.instances[cs];
|
|
123
|
+
if (db.pool == this.pool) {
|
|
124
|
+
delete PgDb.instances[cs];
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
yield this.pool.end((err) => { });
|
|
128
|
+
});
|
|
129
|
+
}
|
|
130
|
+
static connect(config) {
|
|
131
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
132
|
+
if (config.connectionString) {
|
|
133
|
+
let res = CONNECTION_URL_REGEXP.exec(config.connectionString);
|
|
134
|
+
if (res) {
|
|
135
|
+
config.user = res[1];
|
|
136
|
+
if (res[2])
|
|
137
|
+
config.password = res[2];
|
|
138
|
+
config.host = res[3] ? res[3] : 'localhost';
|
|
139
|
+
config.port = res[4] ? +res[4] : 5432;
|
|
140
|
+
config.database = res[5];
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
let pgdb = new PgDb({ config: config });
|
|
144
|
+
return pgdb.init();
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
init() {
|
|
148
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
149
|
+
this.pool = new pg.Pool(_.omit(this.config, ['logger', 'skipUndefined']));
|
|
150
|
+
if (this.config.logger)
|
|
151
|
+
this.setLogger(this.config.logger);
|
|
152
|
+
this.pool.on('error', (e, client) => {
|
|
153
|
+
this.getLogger(true).error('pool error', e);
|
|
154
|
+
});
|
|
155
|
+
yield this.reload();
|
|
156
|
+
this.getLogger().log('Successfully connected to Db');
|
|
157
|
+
return this;
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
reload() {
|
|
161
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
162
|
+
yield this.initSchemasAndTables();
|
|
163
|
+
yield this.initFieldTypes();
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
initSchemasAndTables() {
|
|
167
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
168
|
+
let schemasAndTables = yield this.query(LIST_SCHEMAS_TABLES);
|
|
169
|
+
let functions = yield this.query(GET_SCHEMAS_PROCEDURES);
|
|
170
|
+
this.defaultSchemas = yield this.queryOneField(GET_CURRENT_SCHEMAS);
|
|
171
|
+
let oldSchemaNames = Object.keys(this.schemas);
|
|
172
|
+
for (let sc of oldSchemaNames) {
|
|
173
|
+
if (this[sc] === this.schemas[sc])
|
|
174
|
+
delete this[sc];
|
|
175
|
+
}
|
|
176
|
+
this.schemas = {};
|
|
177
|
+
for (let r of schemasAndTables) {
|
|
178
|
+
let schema = this.schemas[r.schema] = this.schemas[r.schema] || new pgSchema_1.PgSchema(this, r.schema);
|
|
179
|
+
if (!(r.schema in this))
|
|
180
|
+
this[r.schema] = schema;
|
|
181
|
+
schema.tables[r.name] = new pgTable_1.PgTable(schema, r);
|
|
182
|
+
if (!(r.name in schema))
|
|
183
|
+
schema[r.name] = schema.tables[r.name];
|
|
184
|
+
}
|
|
185
|
+
for (let r of functions) {
|
|
186
|
+
let schema = this.schemas[r.schema] = this.schemas[r.schema] || new pgSchema_1.PgSchema(this, r.schema);
|
|
187
|
+
if (!(r.schema in this))
|
|
188
|
+
this[r.schema] = schema;
|
|
189
|
+
schema.fn[r.name] = pgUtils_1.pgUtils.createFunctionCaller(schema, r);
|
|
190
|
+
}
|
|
191
|
+
this.setDefaultTablesAndFunctions();
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
setDefaultTablesAndFunctions() {
|
|
195
|
+
this.tables = {};
|
|
196
|
+
this.fn = {};
|
|
197
|
+
if (!this.defaultSchemas)
|
|
198
|
+
return;
|
|
199
|
+
for (let sc of this.defaultSchemas) {
|
|
200
|
+
let schema = this.schemas[sc];
|
|
201
|
+
if (!schema)
|
|
202
|
+
continue;
|
|
203
|
+
for (let table in schema.tables)
|
|
204
|
+
this.tables[table] = this.tables[table] || schema.tables[table];
|
|
205
|
+
for (let fn in schema.fn)
|
|
206
|
+
this.fn[fn] = this.fn[fn] || schema.fn[fn];
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
initFieldTypes() {
|
|
210
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
211
|
+
let schemaNames = "'" + Object.keys(this.schemas).join("', '") + "'";
|
|
212
|
+
if (schemaNames == "''") {
|
|
213
|
+
this.getLogger(true).error("No readable schema found!");
|
|
214
|
+
return;
|
|
215
|
+
}
|
|
216
|
+
let specialTypeFields = yield this.query(LIST_SPECIAL_TYPE_FIELDS + ' AND c.nspname in (' + schemaNames + ')');
|
|
217
|
+
for (let r of specialTypeFields) {
|
|
218
|
+
if (this.schemas[r.schema_name][r.table_name]) {
|
|
219
|
+
this.schemas[r.schema_name][r.table_name].fieldTypes[r.column_name] =
|
|
220
|
+
([3802, 114].indexOf(r.typid) > -1) ? FieldType.JSON :
|
|
221
|
+
([3614].indexOf(r.typid) > -1) ? FieldType.TSVECTOR :
|
|
222
|
+
([1082, 1083, 1114, 1184, 1266].indexOf(r.typid) > -1) ? FieldType.TIME :
|
|
223
|
+
FieldType.ARRAY;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
let builtInArrayTypeParsers = [
|
|
227
|
+
{
|
|
228
|
+
oidList: [
|
|
229
|
+
1000
|
|
230
|
+
],
|
|
231
|
+
parser: PgConverters.arraySplitToBool
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
oidList: [
|
|
235
|
+
1005,
|
|
236
|
+
1007,
|
|
237
|
+
1021
|
|
238
|
+
],
|
|
239
|
+
parser: PgConverters.arraySplitToNum
|
|
240
|
+
},
|
|
241
|
+
{
|
|
242
|
+
oidList: [
|
|
243
|
+
1009,
|
|
244
|
+
1015
|
|
245
|
+
],
|
|
246
|
+
parser: PgConverters.arraySplit
|
|
247
|
+
},
|
|
248
|
+
{
|
|
249
|
+
oidList: [
|
|
250
|
+
199,
|
|
251
|
+
3807
|
|
252
|
+
],
|
|
253
|
+
parser: PgConverters.arraySplitToJson
|
|
254
|
+
},
|
|
255
|
+
{
|
|
256
|
+
oidList: [
|
|
257
|
+
1115,
|
|
258
|
+
1182,
|
|
259
|
+
1183,
|
|
260
|
+
1185,
|
|
261
|
+
1270
|
|
262
|
+
],
|
|
263
|
+
parser: PgConverters.arraySplitToDate
|
|
264
|
+
}
|
|
265
|
+
];
|
|
266
|
+
builtInArrayTypeParsers.forEach(parserObj => {
|
|
267
|
+
parserObj.oidList.forEach(oid => {
|
|
268
|
+
pg.types.setTypeParser(oid, parserObj.parser);
|
|
269
|
+
delete this.pgdbTypeParsers[oid];
|
|
270
|
+
this.knownOids[oid] = true;
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
for (let r of specialTypeFields) {
|
|
274
|
+
if (this.knownOids[r.typid] && !this.pgdbTypeParsers[r.typid]) {
|
|
275
|
+
continue;
|
|
276
|
+
}
|
|
277
|
+
switch (r.typid) {
|
|
278
|
+
case 114:
|
|
279
|
+
case 3802:
|
|
280
|
+
case 1082:
|
|
281
|
+
case 1083:
|
|
282
|
+
case 1114:
|
|
283
|
+
case 1184:
|
|
284
|
+
case 1266:
|
|
285
|
+
case 3614:
|
|
286
|
+
break;
|
|
287
|
+
case 1016:
|
|
288
|
+
case 1022:
|
|
289
|
+
break;
|
|
290
|
+
default:
|
|
291
|
+
pg.types.setTypeParser(r.typid, PgConverters.arraySplit);
|
|
292
|
+
delete this.pgdbTypeParsers[r.typid];
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
yield this.setPgDbTypeParser('int8', PgConverters.numWithValidation);
|
|
296
|
+
yield this.setPgDbTypeParser('float8', PgConverters.numWithValidation);
|
|
297
|
+
yield this.setPgDbTypeParser('_int8', PgConverters.stringArrayToNumWithValidation);
|
|
298
|
+
yield this.setPgDbTypeParser('_float8', PgConverters.stringArrayToNumWithValidation);
|
|
299
|
+
let allUsedTypeFields = yield this.queryOneColumn(`
|
|
300
|
+
SELECT a.atttypid as typid
|
|
301
|
+
FROM pg_attribute a
|
|
302
|
+
JOIN pg_class b ON (a.attrelid = b.oid)
|
|
303
|
+
JOIN pg_type t ON (a.atttypid = t.oid)
|
|
304
|
+
JOIN pg_namespace c ON (b.relnamespace=c.oid)
|
|
305
|
+
WHERE
|
|
306
|
+
reltype>0 AND
|
|
307
|
+
c.nspname in (${schemaNames})`);
|
|
308
|
+
allUsedTypeFields.forEach(oid => this.knownOids[oid] = true);
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
setTypeParser(typeName, parser, schemaName) {
|
|
312
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
313
|
+
try {
|
|
314
|
+
if (schemaName) {
|
|
315
|
+
let oid = yield this.queryOneField(GET_OID_FOR_COLUMN_TYPE_FOR_SCHEMA, { typeName, schemaName });
|
|
316
|
+
pg.types.setTypeParser(oid, parser);
|
|
317
|
+
delete this.pgdbTypeParsers[oid];
|
|
318
|
+
this.knownOids[oid] = true;
|
|
319
|
+
}
|
|
320
|
+
else {
|
|
321
|
+
let list = yield this.queryOneColumn(GET_OID_FOR_COLUMN_TYPE, { typeName });
|
|
322
|
+
list.forEach(oid => {
|
|
323
|
+
pg.types.setTypeParser(oid, parser);
|
|
324
|
+
delete this.pgdbTypeParsers[oid];
|
|
325
|
+
this.knownOids[oid] = true;
|
|
326
|
+
});
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
catch (e) {
|
|
330
|
+
throw Error('Not existing type: ' + typeName);
|
|
331
|
+
}
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
setPgDbTypeParser(typeName, parser, schemaName) {
|
|
335
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
336
|
+
try {
|
|
337
|
+
if (schemaName) {
|
|
338
|
+
let oid = yield this.queryOneField(GET_OID_FOR_COLUMN_TYPE_FOR_SCHEMA, { typeName, schemaName });
|
|
339
|
+
this.pgdbTypeParsers[oid] = parser;
|
|
340
|
+
this.knownOids[oid] = true;
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
let list = yield this.queryOneColumn(GET_OID_FOR_COLUMN_TYPE, { typeName });
|
|
344
|
+
list.forEach(oid => {
|
|
345
|
+
this.pgdbTypeParsers[oid] = parser;
|
|
346
|
+
this.knownOids[oid] = true;
|
|
347
|
+
});
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
catch (e) {
|
|
351
|
+
throw Error('Not existing type: ' + typeName);
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
resetMissingParsers(connection, oidList) {
|
|
356
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
357
|
+
let unknownOids = oidList.filter(oid => !this.knownOids[oid]);
|
|
358
|
+
if (unknownOids.length) {
|
|
359
|
+
let fieldsData = yield connection.query(`select oid, typcategory from pg_type where oid = ANY($1)`, [unknownOids]);
|
|
360
|
+
fieldsData.rows.forEach(fieldData => {
|
|
361
|
+
if (fieldData.typcategory == 'A') {
|
|
362
|
+
this.pgdbTypeParsers[fieldData.oid] = PgConverters.arraySplit;
|
|
363
|
+
}
|
|
364
|
+
this.knownOids[fieldData.oid] = true;
|
|
365
|
+
});
|
|
366
|
+
}
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
dedicatedConnectionBegin() {
|
|
370
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
371
|
+
if (this.needToFixConnectionForListen()) {
|
|
372
|
+
yield this.runRestartConnectionForListen();
|
|
373
|
+
}
|
|
374
|
+
let pgDb = new PgDb(this);
|
|
375
|
+
pgDb.connection = yield this.pool.connect();
|
|
376
|
+
pgDb.connection.on('error', () => { });
|
|
377
|
+
return pgDb;
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
dedicatedConnectionEnd() {
|
|
381
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
382
|
+
if (this.connection) {
|
|
383
|
+
try {
|
|
384
|
+
yield this.connection.release();
|
|
385
|
+
}
|
|
386
|
+
catch (err) {
|
|
387
|
+
this.getLogger().error('Error while dedicated connection end.', err);
|
|
388
|
+
}
|
|
389
|
+
this.connection = null;
|
|
390
|
+
}
|
|
391
|
+
return this;
|
|
392
|
+
});
|
|
393
|
+
}
|
|
394
|
+
savePoint(name) {
|
|
395
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
396
|
+
if (this.isTransactionActive()) {
|
|
397
|
+
name = (name || '').replace(/"/g, '');
|
|
398
|
+
yield this.query(`SAVEPOINT "${name}"`);
|
|
399
|
+
}
|
|
400
|
+
else {
|
|
401
|
+
throw Error('No active transaction');
|
|
402
|
+
}
|
|
403
|
+
return this;
|
|
404
|
+
});
|
|
405
|
+
}
|
|
406
|
+
savePointRelease(name) {
|
|
407
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
408
|
+
if (this.isTransactionActive()) {
|
|
409
|
+
name = (name || '').replace(/"/g, '');
|
|
410
|
+
yield this.query(`RELEASE SAVEPOINT "${name}"`);
|
|
411
|
+
}
|
|
412
|
+
else {
|
|
413
|
+
throw Error('No active transaction');
|
|
414
|
+
}
|
|
415
|
+
return this;
|
|
416
|
+
});
|
|
417
|
+
}
|
|
418
|
+
transactionBegin(options) {
|
|
419
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
420
|
+
let pgDb = this.connection ? this : yield this.dedicatedConnectionBegin();
|
|
421
|
+
let q = 'BEGIN';
|
|
422
|
+
if (options === null || options === void 0 ? void 0 : options.isolationLevel) {
|
|
423
|
+
q += ' ISOLATION LEVEL ' + options.isolationLevel;
|
|
424
|
+
}
|
|
425
|
+
if (options === null || options === void 0 ? void 0 : options.readOnly) {
|
|
426
|
+
q += ' READ ONLY';
|
|
427
|
+
}
|
|
428
|
+
if (options === null || options === void 0 ? void 0 : options.deferrable) {
|
|
429
|
+
q += ' DEFERRABLE ';
|
|
430
|
+
}
|
|
431
|
+
yield pgDb.query(q);
|
|
432
|
+
return pgDb;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
transactionCommit() {
|
|
436
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
437
|
+
yield this.query('COMMIT');
|
|
438
|
+
return this.dedicatedConnectionEnd();
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
transactionRollback(options) {
|
|
442
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
443
|
+
if (options === null || options === void 0 ? void 0 : options.savePoint) {
|
|
444
|
+
let name = (options.savePoint || '').replace(/"/g, '');
|
|
445
|
+
yield this.query(`ROLLBACK TO SAVEPOINT "${name}"`);
|
|
446
|
+
return this;
|
|
447
|
+
}
|
|
448
|
+
else {
|
|
449
|
+
yield this.query('ROLLBACK');
|
|
450
|
+
return this.dedicatedConnectionEnd();
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
}
|
|
454
|
+
isTransactionActive() {
|
|
455
|
+
return this.connection != null;
|
|
456
|
+
}
|
|
457
|
+
execute(fileName, statementTransformerFunction) {
|
|
458
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
459
|
+
let isTransactionInPlace = this.isTransactionActive();
|
|
460
|
+
let pgdb = isTransactionInPlace ? this : yield this.dedicatedConnectionBegin();
|
|
461
|
+
let runStatementList = (statementList) => {
|
|
462
|
+
return new Promise((resolve, reject) => {
|
|
463
|
+
let currentStatement = 0;
|
|
464
|
+
let runStatement = () => {
|
|
465
|
+
if (statementList.length == currentStatement) {
|
|
466
|
+
resolve(undefined);
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
let statement = statementList[currentStatement++];
|
|
470
|
+
if (statementTransformerFunction) {
|
|
471
|
+
statement = statementTransformerFunction(statement);
|
|
472
|
+
}
|
|
473
|
+
this.getLogger(true).log('run', statementList[currentStatement - 1]);
|
|
474
|
+
pgdb.query(statement)
|
|
475
|
+
.then(() => runStatement(), reject)
|
|
476
|
+
.catch(reject);
|
|
477
|
+
}
|
|
478
|
+
};
|
|
479
|
+
runStatement();
|
|
480
|
+
}).catch((e) => {
|
|
481
|
+
this.getLogger(true).error(e);
|
|
482
|
+
throw e;
|
|
483
|
+
});
|
|
484
|
+
};
|
|
485
|
+
let lineCounter = 0;
|
|
486
|
+
let promise = new Promise((resolve, reject) => {
|
|
487
|
+
let statementList = [];
|
|
488
|
+
let tmp = '', t;
|
|
489
|
+
let consumer;
|
|
490
|
+
let inQuotedString;
|
|
491
|
+
let rl = readline.createInterface({
|
|
492
|
+
input: fs.createReadStream(fileName),
|
|
493
|
+
terminal: false
|
|
494
|
+
}).on('line', (line) => {
|
|
495
|
+
lineCounter++;
|
|
496
|
+
try {
|
|
497
|
+
while (t = SQL_TOKENIZER_REGEXP.exec(line)) {
|
|
498
|
+
if (!inQuotedString && (t[0] == '"' || t[0] == "'") || inQuotedString == '"' || inQuotedString == "'") {
|
|
499
|
+
if (!inQuotedString) {
|
|
500
|
+
inQuotedString = t[0];
|
|
501
|
+
}
|
|
502
|
+
else if (inQuotedString == t[0]) {
|
|
503
|
+
inQuotedString = null;
|
|
504
|
+
}
|
|
505
|
+
tmp += t[0];
|
|
506
|
+
}
|
|
507
|
+
else if (!inQuotedString && t[0] == '$' || inQuotedString && inQuotedString[0] == '$') {
|
|
508
|
+
if (!inQuotedString) {
|
|
509
|
+
let s = line.slice(SQL_TOKENIZER_REGEXP.lastIndex - 1);
|
|
510
|
+
let token = s.match(SQL_$_ESCAPE_REGEXP);
|
|
511
|
+
if (!token) {
|
|
512
|
+
throw Error('Invalid sql in line: ' + line);
|
|
513
|
+
}
|
|
514
|
+
inQuotedString = token[0];
|
|
515
|
+
SQL_TOKENIZER_REGEXP.lastIndex += inQuotedString.length - 1;
|
|
516
|
+
tmp += inQuotedString;
|
|
517
|
+
}
|
|
518
|
+
else {
|
|
519
|
+
tmp += t[0];
|
|
520
|
+
if (tmp.endsWith(inQuotedString)) {
|
|
521
|
+
inQuotedString = null;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
else if (!inQuotedString && t[0] == '/*' || inQuotedString == '/*') {
|
|
526
|
+
if (!inQuotedString) {
|
|
527
|
+
inQuotedString = t[0];
|
|
528
|
+
}
|
|
529
|
+
else if (t[0] == '*/') {
|
|
530
|
+
inQuotedString = null;
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
else if (!inQuotedString && t[0] == '--') {
|
|
534
|
+
line = '';
|
|
535
|
+
}
|
|
536
|
+
else if (!inQuotedString && t[0] == ';') {
|
|
537
|
+
if (tmp.trim() != '') {
|
|
538
|
+
statementList.push(tmp);
|
|
539
|
+
if (!consumer) {
|
|
540
|
+
consumer = runStatementList(statementList).then(() => {
|
|
541
|
+
consumer = null;
|
|
542
|
+
statementList.length = 0;
|
|
543
|
+
rl.resume();
|
|
544
|
+
}, reject);
|
|
545
|
+
rl.pause();
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
tmp = '';
|
|
549
|
+
}
|
|
550
|
+
else {
|
|
551
|
+
tmp += t[0];
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
if (tmp && line) {
|
|
555
|
+
tmp += '\n';
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
catch (e) {
|
|
559
|
+
reject(e);
|
|
560
|
+
}
|
|
561
|
+
}).on('close', () => {
|
|
562
|
+
if (inQuotedString) {
|
|
563
|
+
reject(Error('Invalid SQL, unterminated string'));
|
|
564
|
+
}
|
|
565
|
+
if (tmp.trim() != '') {
|
|
566
|
+
statementList.push(tmp);
|
|
567
|
+
}
|
|
568
|
+
if (!consumer) {
|
|
569
|
+
if (statementList.length) {
|
|
570
|
+
consumer = runStatementList(statementList).catch(reject);
|
|
571
|
+
}
|
|
572
|
+
else {
|
|
573
|
+
resolve();
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (consumer) {
|
|
577
|
+
consumer = consumer.then(resolve, reject);
|
|
578
|
+
}
|
|
579
|
+
});
|
|
580
|
+
});
|
|
581
|
+
let error;
|
|
582
|
+
return promise
|
|
583
|
+
.catch((e) => {
|
|
584
|
+
error = e;
|
|
585
|
+
this.getLogger(true).error('Error at line ' + lineCounter + ' in ' + fileName + '. ' + e);
|
|
586
|
+
})
|
|
587
|
+
.then(() => {
|
|
588
|
+
if (!isTransactionInPlace) {
|
|
589
|
+
return pgdb.dedicatedConnectionEnd();
|
|
590
|
+
}
|
|
591
|
+
}).catch((e) => {
|
|
592
|
+
this.getLogger(true).error(e);
|
|
593
|
+
}).then(() => {
|
|
594
|
+
if (error) {
|
|
595
|
+
throw error;
|
|
596
|
+
}
|
|
597
|
+
});
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
listen(channel, callback) {
|
|
601
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
602
|
+
let restartConnectionError = null;
|
|
603
|
+
if (this.needToFixConnectionForListen()) {
|
|
604
|
+
restartConnectionError = yield this.runRestartConnectionForListen();
|
|
605
|
+
}
|
|
606
|
+
if (this.listeners.listenerCount(channel)) {
|
|
607
|
+
this.listeners.on(channel, callback);
|
|
608
|
+
}
|
|
609
|
+
else {
|
|
610
|
+
if (restartConnectionError) {
|
|
611
|
+
throw restartConnectionError;
|
|
612
|
+
}
|
|
613
|
+
try {
|
|
614
|
+
if (!this.connectionForListen) {
|
|
615
|
+
yield this.initConnectionForListen();
|
|
616
|
+
}
|
|
617
|
+
yield this.connectionForListen.query(`LISTEN "${channel}"`);
|
|
618
|
+
}
|
|
619
|
+
catch (err) {
|
|
620
|
+
this._needToRestartConnectionForListen = true;
|
|
621
|
+
throw err;
|
|
622
|
+
}
|
|
623
|
+
this.listeners.on(channel, callback);
|
|
624
|
+
}
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
unlisten(channel, callback) {
|
|
628
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
629
|
+
let restartConnectionError = null;
|
|
630
|
+
if (this.needToFixConnectionForListen()) {
|
|
631
|
+
restartConnectionError = yield this.runRestartConnectionForListen();
|
|
632
|
+
}
|
|
633
|
+
if (callback && this.listeners.listenerCount(channel) > 1) {
|
|
634
|
+
this.listeners.removeListener(channel, callback);
|
|
635
|
+
}
|
|
636
|
+
else {
|
|
637
|
+
if (restartConnectionError) {
|
|
638
|
+
throw restartConnectionError;
|
|
639
|
+
}
|
|
640
|
+
try {
|
|
641
|
+
yield this.internalQuery({ connection: this.connectionForListen, sql: `UNLISTEN "${channel}"` });
|
|
642
|
+
if (this.listeners.eventNames().length == 1) {
|
|
643
|
+
this.connectionForListen.removeAllListeners('notification');
|
|
644
|
+
this.connectionForListen.release();
|
|
645
|
+
this.connectionForListen = null;
|
|
646
|
+
}
|
|
647
|
+
}
|
|
648
|
+
catch (err) {
|
|
649
|
+
this._needToRestartConnectionForListen = true;
|
|
650
|
+
throw err;
|
|
651
|
+
}
|
|
652
|
+
this.listeners.removeAllListeners(channel);
|
|
653
|
+
}
|
|
654
|
+
});
|
|
655
|
+
}
|
|
656
|
+
notify(channel, payload) {
|
|
657
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
658
|
+
if (this.needToFixConnectionForListen()) {
|
|
659
|
+
let restartConnectionError = yield this.runRestartConnectionForListen();
|
|
660
|
+
if (restartConnectionError) {
|
|
661
|
+
throw restartConnectionError;
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
let hasConnectionForListen = !!this.connectionForListen;
|
|
665
|
+
let connection = this.connectionForListen || this.connection;
|
|
666
|
+
let sql = 'SELECT pg_notify(:channel, :payload)';
|
|
667
|
+
let params = { channel, payload };
|
|
668
|
+
try {
|
|
669
|
+
return this.internalQuery({ connection, sql, params });
|
|
670
|
+
}
|
|
671
|
+
catch (err) {
|
|
672
|
+
if (hasConnectionForListen) {
|
|
673
|
+
this._needToRestartConnectionForListen = true;
|
|
674
|
+
}
|
|
675
|
+
throw err;
|
|
676
|
+
}
|
|
677
|
+
});
|
|
678
|
+
}
|
|
679
|
+
runRestartConnectionForListen() {
|
|
680
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
681
|
+
if (!this._needToRestartConnectionForListen) {
|
|
682
|
+
return null;
|
|
683
|
+
}
|
|
684
|
+
let errorResult = null;
|
|
685
|
+
if (!this.restartConnectionForListen) {
|
|
686
|
+
this.restartConnectionForListen = (() => tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
687
|
+
let eventNames = this.listeners.eventNames();
|
|
688
|
+
try {
|
|
689
|
+
yield this.connectionForListen.release();
|
|
690
|
+
}
|
|
691
|
+
catch (e) {
|
|
692
|
+
}
|
|
693
|
+
this.connectionForListen = null;
|
|
694
|
+
let error;
|
|
695
|
+
if (eventNames.length) {
|
|
696
|
+
try {
|
|
697
|
+
yield this.initConnectionForListen();
|
|
698
|
+
for (let channel of eventNames) {
|
|
699
|
+
yield this.connectionForListen.query(`LISTEN "${channel}"`);
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
catch (err) {
|
|
703
|
+
error = err;
|
|
704
|
+
}
|
|
705
|
+
}
|
|
706
|
+
return error;
|
|
707
|
+
}))();
|
|
708
|
+
errorResult = yield this.restartConnectionForListen;
|
|
709
|
+
this.restartConnectionForListen = null;
|
|
710
|
+
}
|
|
711
|
+
else {
|
|
712
|
+
errorResult = yield this.restartConnectionForListen;
|
|
713
|
+
}
|
|
714
|
+
if (!errorResult) {
|
|
715
|
+
this._needToRestartConnectionForListen = false;
|
|
716
|
+
}
|
|
717
|
+
return errorResult;
|
|
718
|
+
});
|
|
719
|
+
}
|
|
720
|
+
needToFixConnectionForListen() {
|
|
721
|
+
return this._needToRestartConnectionForListen;
|
|
722
|
+
}
|
|
723
|
+
tryToFixConnectionForListenActively() {
|
|
724
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
725
|
+
yield new Promise(r => setTimeout(r, 1000));
|
|
726
|
+
let error = yield this.runRestartConnectionForListen();
|
|
727
|
+
if (error) {
|
|
728
|
+
yield this.tryToFixConnectionForListenActively();
|
|
729
|
+
}
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
initConnectionForListen() {
|
|
733
|
+
return tslib_1.__awaiter(this, void 0, void 0, function* () {
|
|
734
|
+
this.connectionForListen = yield this.pool.connect();
|
|
735
|
+
this.connectionForListen.on('notification', (notification) => this.listeners.emit(notification.channel, notification));
|
|
736
|
+
this.connectionForListen.on('error', (e) => {
|
|
737
|
+
this._needToRestartConnectionForListen = true;
|
|
738
|
+
this.tryToFixConnectionForListenActively();
|
|
739
|
+
});
|
|
740
|
+
});
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
exports.PgDb = PgDb;
|
|
744
|
+
exports.default = PgDb;
|
|
745
|
+
//# sourceMappingURL=pgDb.js.map
|