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.
Files changed (82) hide show
  1. package/.vscode/launch.json +35 -0
  2. package/CHANGELOG.md +277 -0
  3. package/LICENSE +21 -0
  4. package/README.md +85 -0
  5. package/docs/API/PgDb.md +218 -0
  6. package/docs/API/PgSchema.md +91 -0
  7. package/docs/API/PgTable.md +365 -0
  8. package/docs/API/QueryOptions.md +77 -0
  9. package/docs/API/condition.md +133 -0
  10. package/docs/connection.md +91 -0
  11. package/docs/css/docs.css +164 -0
  12. package/docs/executingSqlFile.md +44 -0
  13. package/docs/faq.md +15 -0
  14. package/docs/functions.md +19 -0
  15. package/docs/generatingInterfaceForTables.md +35 -0
  16. package/docs/index.md +48 -0
  17. package/docs/logger.md +40 -0
  18. package/docs/mappingDatabaseTypes.md +89 -0
  19. package/docs/notification.md +19 -0
  20. package/docs/pitfalls.md +73 -0
  21. package/docs/streams.md +68 -0
  22. package/docs/transaction.md +65 -0
  23. package/lib/bin/generateInterface.d.ts +1 -0
  24. package/lib/bin/generateInterface.js +53 -0
  25. package/lib/bin/generateInterface.js.map +1 -0
  26. package/lib/connectionOptions.d.ts +25 -0
  27. package/lib/connectionOptions.js +3 -0
  28. package/lib/connectionOptions.js.map +1 -0
  29. package/lib/index.d.ts +6 -0
  30. package/lib/index.js +10 -0
  31. package/lib/index.js.map +1 -0
  32. package/lib/pgConverters.d.ts +10 -0
  33. package/lib/pgConverters.js +66 -0
  34. package/lib/pgConverters.js.map +1 -0
  35. package/lib/pgDb.d.ts +86 -0
  36. package/lib/pgDb.js +745 -0
  37. package/lib/pgDb.js.map +1 -0
  38. package/lib/pgDbLogger.d.ts +5 -0
  39. package/lib/pgDbLogger.js +3 -0
  40. package/lib/pgDbLogger.js.map +1 -0
  41. package/lib/pgDbOperators.d.ts +113 -0
  42. package/lib/pgDbOperators.js +44 -0
  43. package/lib/pgDbOperators.js.map +1 -0
  44. package/lib/pgSchema.d.ts +16 -0
  45. package/lib/pgSchema.js +16 -0
  46. package/lib/pgSchema.js.map +1 -0
  47. package/lib/pgTable.d.ts +131 -0
  48. package/lib/pgTable.js +322 -0
  49. package/lib/pgTable.js.map +1 -0
  50. package/lib/pgUtils.d.ts +31 -0
  51. package/lib/pgUtils.js +157 -0
  52. package/lib/pgUtils.js.map +1 -0
  53. package/lib/queryAble.d.ts +76 -0
  54. package/lib/queryAble.js +330 -0
  55. package/lib/queryAble.js.map +1 -0
  56. package/lib/queryWhere.d.ts +8 -0
  57. package/lib/queryWhere.js +249 -0
  58. package/lib/queryWhere.js.map +1 -0
  59. package/mkdocs.yml +25 -0
  60. package/package.json +65 -0
  61. package/spec/resources/init.sql +122 -0
  62. package/spec/resources/throw_exception.sql +5 -0
  63. package/spec/resources/tricky.sql +13 -0
  64. package/spec/run.js +5 -0
  65. package/spec/support/jasmine.json +9 -0
  66. package/src/bin/generateInterface.ts +54 -0
  67. package/src/connectionOptions.ts +42 -0
  68. package/src/index.ts +6 -0
  69. package/src/pgConverters.ts +55 -0
  70. package/src/pgDb.ts +820 -0
  71. package/src/pgDbLogger.ts +13 -0
  72. package/src/pgDbOperators.ts +62 -0
  73. package/src/pgSchema.ts +15 -0
  74. package/src/pgTable.ts +401 -0
  75. package/src/pgUtils.ts +176 -0
  76. package/src/queryAble.ts +393 -0
  77. package/src/queryWhere.ts +326 -0
  78. package/src/test/pgDbOperatorSpec.ts +492 -0
  79. package/src/test/pgDbSpec.ts +1339 -0
  80. package/src/test/pgServiceRestartTest.ts +1500 -0
  81. package/src/tsconfig.json +33 -0
  82. 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,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=connectionOptions.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connectionOptions.js","sourceRoot":"","sources":["../src/connectionOptions.ts"],"names":[],"mappings":""}
package/lib/index.d.ts ADDED
@@ -0,0 +1,6 @@
1
+ export { PgDb } from './pgDb';
2
+ export { ConnectionOptions } from './connectionOptions';
3
+ export { PgDbLogger } from './pgDbLogger';
4
+ export { PgTable } from './pgTable';
5
+ export { PgSchema } from './pgSchema';
6
+ export { QueryOptions } from './queryAble';
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
@@ -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