pogi 3.0.1 → 3.2.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 (56) hide show
  1. package/.env +6 -5
  2. package/.vscode/launch.json +51 -12
  3. package/CHANGELOG.md +48 -0
  4. package/jest.config.js +31 -21
  5. package/jest.globalSetup.js +18 -0
  6. package/jest.globalTeardown.js +6 -0
  7. package/jest.setup.ts +22 -0
  8. package/lib/bin/generateInterface.js +40 -45
  9. package/lib/bin/generateInterface.js.map +1 -1
  10. package/lib/connectionOptions.d.ts +1 -1
  11. package/lib/connectionOptions.js +1 -2
  12. package/lib/index.d.ts +6 -6
  13. package/lib/index.js +3 -9
  14. package/lib/index.js.map +1 -1
  15. package/lib/pgConverters.js +12 -22
  16. package/lib/pgConverters.js.map +1 -1
  17. package/lib/pgConverters.test.js +7 -10
  18. package/lib/pgConverters.test.js.map +1 -1
  19. package/lib/pgDb.d.ts +7 -7
  20. package/lib/pgDb.js +551 -596
  21. package/lib/pgDb.js.map +1 -1
  22. package/lib/pgDb.test.js +546 -548
  23. package/lib/pgDb.test.js.map +1 -1
  24. package/lib/pgDbInterface.d.ts +2 -2
  25. package/lib/pgDbInterface.js +2 -5
  26. package/lib/pgDbInterface.js.map +1 -1
  27. package/lib/pgDbLogger.js +1 -2
  28. package/lib/pgDbOperators.js +3 -5
  29. package/lib/pgDbOperators.js.map +1 -1
  30. package/lib/pgDbOperators.test.js +155 -158
  31. package/lib/pgDbOperators.test.js.map +1 -1
  32. package/lib/pgSchema.d.ts +2 -2
  33. package/lib/pgSchema.js +7 -8
  34. package/lib/pgSchema.js.map +1 -1
  35. package/lib/pgTable.d.ts +8 -9
  36. package/lib/pgTable.js +178 -217
  37. package/lib/pgTable.js.map +1 -1
  38. package/lib/pgTableInterface.d.ts +1 -1
  39. package/lib/pgTableInterface.js +1 -2
  40. package/lib/pgTableInterface.js.map +1 -1
  41. package/lib/pgUtils.d.ts +10 -10
  42. package/lib/pgUtils.js +36 -45
  43. package/lib/pgUtils.js.map +1 -1
  44. package/lib/queryAble.d.ts +5 -6
  45. package/lib/queryAble.js +248 -264
  46. package/lib/queryAble.js.map +1 -1
  47. package/lib/queryAbleInterface.d.ts +5 -6
  48. package/lib/queryAbleInterface.js +1 -2
  49. package/lib/queryAbleInterface.js.map +1 -1
  50. package/lib/queryWhere.d.ts +1 -1
  51. package/lib/queryWhere.js +20 -23
  52. package/lib/queryWhere.js.map +1 -1
  53. package/lib/test/pgServiceRestartTest.js +617 -648
  54. package/lib/test/pgServiceRestartTest.js.map +1 -1
  55. package/package.json +27 -26
  56. package/tsconfig.json +6 -12
package/lib/pgDb.js CHANGED
@@ -1,22 +1,18 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.PgDb = exports.FieldType = void 0;
4
- const tslib_1 = require("tslib");
5
- const EventEmitter = require("events");
6
- const fs = require("fs");
7
- const _ = require("lodash");
8
- const pg = require("pg");
9
- const readline = require("readline");
10
- const PgConverters = require("./pgConverters");
11
- const pgSchema_1 = require("./pgSchema");
12
- const pgTable_1 = require("./pgTable");
13
- const pgUtils_1 = require("./pgUtils");
14
- const queryAble_1 = require("./queryAble");
1
+ import EventEmitter from 'events';
2
+ import fs from 'fs';
3
+ import _ from 'lodash';
4
+ import pg from 'pg';
5
+ import readline from 'readline';
6
+ import * as PgConverters from "./pgConverters.js";
7
+ import { PgSchema } from "./pgSchema.js";
8
+ import { PgTable } from "./pgTable.js";
9
+ import { pgUtils } from "./pgUtils.js";
10
+ import { QueryAble } from "./queryAble.js";
15
11
  const CONNECTION_URL_REGEXP = /^postgres:\/\/(?:([^:]+)(?::([^@]*))?@)?([^\/:]+)?(?::([^\/]+))?\/(.*)$/;
16
12
  const SQL_TOKENIZER_REGEXP = /''|'|""|"|;|\$|--|\/\*|\*\/|(.+?)/g;
17
13
  const SQL_$_ESCAPE_REGEXP = /\$[^$]*\$/g;
18
- const LIST_SCHEMAS_TABLES = `SELECT table_schema as schema, table_name as name
19
- FROM information_schema.tables
14
+ const LIST_SCHEMAS_TABLES = `SELECT table_schema as schema, table_name as name
15
+ FROM information_schema.tables
20
16
  WHERE table_schema NOT IN ('pg_catalog', 'pg_constraint', 'information_schema')`;
21
17
  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
18
  const GET_OID_FOR_COLUMN_TYPE = "SELECT t.oid FROM pg_catalog.pg_type t WHERE typname=:typeName";
@@ -33,10 +29,10 @@ WHERE n.nspname NOT IN ('pg_catalog', 'pg_constraint', 'information_schema')
33
29
  AND tr.oid is null;`;
34
30
  const GET_CURRENT_SCHEMAS = "SELECT current_schemas(false)";
35
31
  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, t.typcategory
36
- FROM pg_attribute a
32
+ FROM pg_attribute a
37
33
  JOIN pg_class b ON (a.attrelid = b.oid)
38
34
  JOIN pg_type t ON (a.atttypid = t.oid)
39
- JOIN pg_namespace c ON (b.relnamespace=c.oid)
35
+ JOIN pg_namespace c ON (b.relnamespace=c.oid)
40
36
  WHERE (a.atttypid in (114, 3802, 1082, 1083, 1114, 1184, 1266, 3614) or t.typcategory='A')
41
37
  AND reltype>0 `;
42
38
  const TYPE2OID = `SELECT t.oid, typname FROM pg_catalog.pg_type t WHERE typname in (
@@ -44,32 +40,30 @@ const TYPE2OID = `SELECT t.oid, typname FROM pg_catalog.pg_type t WHERE typname
44
40
  'int8','_int2','_int4','_int8','_float4','float8','_float8',
45
41
  '_text','_varchar',
46
42
  'json','jsonb', '_json','_jsonb',
47
- 'date','time','timestamp','timestamptz','timetz','_date','_time','_timestamp','_timestamptz','_timetz',
43
+ 'date','time','timestamp','timestamptz','timetz','_date','_time','_timestamp','_timestamptz','_timetz',
48
44
  'tsvector')`;
49
- var FieldType;
45
+ export var FieldType;
50
46
  (function (FieldType) {
51
47
  FieldType[FieldType["JSON"] = 0] = "JSON";
52
48
  FieldType[FieldType["ARRAY"] = 1] = "ARRAY";
53
49
  FieldType[FieldType["TIME"] = 2] = "TIME";
54
50
  FieldType[FieldType["TSVECTOR"] = 3] = "TSVECTOR";
55
- })(FieldType = exports.FieldType || (exports.FieldType = {}));
56
- class PgDb extends queryAble_1.QueryAble {
51
+ })(FieldType || (FieldType = {}));
52
+ export class PgDb extends QueryAble {
53
+ static instances;
54
+ pool;
55
+ connection = null;
56
+ config;
57
+ defaultSchemas;
58
+ db;
59
+ schemas;
60
+ tables = {};
61
+ fn = {};
62
+ pgdbTypeParsers = {};
63
+ knownOids = {};
64
+ postProcessResult;
57
65
  constructor(pgdb) {
58
66
  super();
59
- this.connection = null;
60
- this.tables = {};
61
- this.fn = {};
62
- this.pgdbTypeParsers = {};
63
- this.knownOids = {};
64
- this.listeners = new EventEmitter();
65
- this.connectionForListen = null;
66
- this._needToRestartConnectionForListen = false;
67
- this.restartConnectionForListen = null;
68
- this.notificationListener = (notification) => this.listeners.emit(notification.channel, notification);
69
- this.errorListener = (e) => {
70
- this._needToRestartConnectionForListen = true;
71
- this.tryToFixConnectionForListenActively();
72
- };
73
67
  this.schemas = {};
74
68
  this.config = pgdb.config || {};
75
69
  this.pool = pgdb.pool;
@@ -81,12 +75,12 @@ class PgDb extends queryAble_1.QueryAble {
81
75
  this.setLogger(pgdb.getLogger());
82
76
  }
83
77
  for (let schemaName in pgdb.schemas) {
84
- let schema = new pgSchema_1.PgSchema(this, schemaName);
78
+ let schema = new PgSchema(this, schemaName);
85
79
  this.schemas[schemaName] = schema;
86
80
  if (!(schemaName in this))
87
81
  this[schemaName] = schema;
88
82
  for (let tableName in pgdb.schemas[schemaName].tables) {
89
- schema.tables[tableName] = new pgTable_1.PgTable(schema, pgdb.schemas[schemaName][tableName].desc, pgdb.schemas[schemaName][tableName].fieldTypes);
83
+ schema.tables[tableName] = new PgTable(schema, pgdb.schemas[schemaName][tableName].desc, pgdb.schemas[schemaName][tableName].fieldTypes);
90
84
  if (!(tableName in schema))
91
85
  schema[tableName] = schema.tables[tableName];
92
86
  }
@@ -97,106 +91,94 @@ class PgDb extends queryAble_1.QueryAble {
97
91
  setPostProcessResult(f) {
98
92
  this.postProcessResult = f;
99
93
  }
100
- static getInstance(config) {
101
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
102
- if (config.connectionString) {
103
- let res = CONNECTION_URL_REGEXP.exec(config.connectionString);
104
- if (res) {
105
- config.user = res[1];
106
- config.password = res[2] ? res[2] : '';
107
- config.host = res[3] ? res[3] : 'localhost';
108
- config.port = res[4] ? +res[4] : 5432;
109
- config.database = res[5];
110
- }
111
- }
112
- let connectionString = `postgres://${config.user}@${config.host}:${config.port}/${config.database}`;
113
- if (!PgDb.instances) {
114
- PgDb.instances = {};
115
- }
116
- if (PgDb.instances[connectionString] != null) {
117
- return PgDb.instances[connectionString];
118
- }
119
- else {
120
- let pgdb = new PgDb({ config: config });
121
- PgDb.instances[connectionString] = pgdb.init();
122
- return PgDb.instances[connectionString];
94
+ static async getInstance(config) {
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];
123
103
  }
124
- });
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] != null) {
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
+ }
125
117
  }
126
- close() {
127
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
128
- for (let cs in PgDb.instances) {
129
- let db = yield PgDb.instances[cs];
130
- if (db.pool == this.pool) {
131
- delete PgDb.instances[cs];
132
- }
118
+ async close() {
119
+ for (let cs in PgDb.instances) {
120
+ let db = await PgDb.instances[cs];
121
+ if (db.pool == this.pool) {
122
+ delete PgDb.instances[cs];
133
123
  }
134
- yield new Promise((resolve) => this.pool.end(resolve));
135
- });
124
+ }
125
+ await new Promise((resolve) => this.pool.end(resolve));
136
126
  }
137
- static connect(config) {
138
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
139
- if (config.connectionString) {
140
- let res = CONNECTION_URL_REGEXP.exec(config.connectionString);
141
- if (res) {
142
- config.user = res[1];
143
- if (res[2])
144
- config.password = res[2];
145
- config.host = res[3] ? res[3] : 'localhost';
146
- config.port = res[4] ? +res[4] : 5432;
147
- config.database = res[5];
148
- }
127
+ static async connect(config) {
128
+ if (config.connectionString) {
129
+ let res = CONNECTION_URL_REGEXP.exec(config.connectionString);
130
+ if (res) {
131
+ config.user = res[1];
132
+ if (res[2])
133
+ config.password = res[2];
134
+ config.host = res[3] ? res[3] : 'localhost';
135
+ config.port = res[4] ? +res[4] : 5432;
136
+ config.database = res[5];
149
137
  }
150
- let pgdb = new PgDb({ config: config });
151
- return pgdb.init();
152
- });
138
+ }
139
+ let pgdb = new PgDb({ config: config });
140
+ return pgdb.init();
153
141
  }
154
- init() {
155
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
156
- this.pool = new pg.Pool(_.omit(this.config, ['logger', 'skipUndefined']));
157
- if (this.config.logger)
158
- this.setLogger(this.config.logger);
159
- this.pool.on('error', (e, client) => {
160
- this.getLogger(true).error('pool error', e);
161
- });
162
- yield this.reload();
163
- this.getLogger().log('Successfully connected to Db');
164
- return this;
142
+ async init() {
143
+ this.pool = new pg.Pool(_.omit(this.config, ['logger', 'skipUndefined']));
144
+ if (this.config.logger)
145
+ this.setLogger(this.config.logger);
146
+ this.pool.on('error', (e, client) => {
147
+ this.getLogger(true).error('pool error', e);
165
148
  });
149
+ await this.reload();
150
+ this.getLogger().log('Successfully connected to Db');
151
+ return this;
166
152
  }
167
- reload() {
168
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
169
- yield this.initSchemasAndTables();
170
- yield this.initFieldTypes();
171
- });
153
+ async reload() {
154
+ await this.initSchemasAndTables();
155
+ await this.initFieldTypes();
172
156
  }
173
- initSchemasAndTables() {
174
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
175
- let schemasAndTables = yield this.query(LIST_SCHEMAS_TABLES);
176
- let functions = yield this.query(GET_SCHEMAS_PROCEDURES);
177
- this.defaultSchemas = yield this.queryOneField(GET_CURRENT_SCHEMAS);
178
- let oldSchemaNames = Object.keys(this.schemas);
179
- for (let sc of oldSchemaNames) {
180
- if (this[sc] === this.schemas[sc])
181
- delete this[sc];
182
- }
183
- this.schemas = {};
184
- for (let r of schemasAndTables) {
185
- let schema = this.schemas[r.schema] = this.schemas[r.schema] || new pgSchema_1.PgSchema(this, r.schema);
186
- if (!(r.schema in this))
187
- this[r.schema] = schema;
188
- schema.tables[r.name] = new pgTable_1.PgTable(schema, r);
189
- if (!(r.name in schema))
190
- schema[r.name] = schema.tables[r.name];
191
- }
192
- for (let r of functions) {
193
- let schema = this.schemas[r.schema] = this.schemas[r.schema] || new pgSchema_1.PgSchema(this, r.schema);
194
- if (!(r.schema in this))
195
- this[r.schema] = schema;
196
- schema.fn[r.name] = pgUtils_1.pgUtils.createFunctionCaller(schema, r);
197
- }
198
- this.setDefaultTablesAndFunctions();
199
- });
157
+ async initSchemasAndTables() {
158
+ let schemasAndTables = await this.query(LIST_SCHEMAS_TABLES);
159
+ let functions = await this.query(GET_SCHEMAS_PROCEDURES);
160
+ this.defaultSchemas = await this.queryOneField(GET_CURRENT_SCHEMAS);
161
+ let oldSchemaNames = Object.keys(this.schemas);
162
+ for (let sc of oldSchemaNames) {
163
+ if (this[sc] === this.schemas[sc])
164
+ delete this[sc];
165
+ }
166
+ this.schemas = {};
167
+ for (let r of schemasAndTables) {
168
+ let schema = this.schemas[r.schema] = this.schemas[r.schema] || new PgSchema(this, r.schema);
169
+ if (!(r.schema in this))
170
+ this[r.schema] = schema;
171
+ schema.tables[r.name] = new PgTable(schema, r);
172
+ if (!(r.name in schema))
173
+ schema[r.name] = schema.tables[r.name];
174
+ }
175
+ for (let r of functions) {
176
+ let schema = this.schemas[r.schema] = this.schemas[r.schema] || new PgSchema(this, r.schema);
177
+ if (!(r.schema in this))
178
+ this[r.schema] = schema;
179
+ schema.fn[r.name] = pgUtils.createFunctionCaller(schema, r);
180
+ }
181
+ this.setDefaultTablesAndFunctions();
200
182
  }
201
183
  setDefaultTablesAndFunctions() {
202
184
  this.tables = {};
@@ -213,105 +195,104 @@ class PgDb extends queryAble_1.QueryAble {
213
195
  this.fn[fn] = this.fn[fn] || schema.fn[fn];
214
196
  }
215
197
  }
216
- initFieldTypes() {
217
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
218
- let schemaNames = "'" + Object.keys(this.schemas).join("', '") + "'";
219
- if (schemaNames == "''") {
220
- this.getLogger(true).error("No readable schema found!");
221
- return;
222
- }
223
- let type2oid = {};
224
- let res = yield this.query(TYPE2OID);
225
- for (let tt of res || []) {
226
- type2oid[tt.typname] = +tt.oid;
227
- }
228
- let specialTypeFields = yield this.query(LIST_SPECIAL_TYPE_FIELDS + ' AND c.nspname in (' + schemaNames + ')');
229
- for (let r of specialTypeFields) {
230
- if (this.schemas[r.schema_name][r.table_name]) {
231
- this.schemas[r.schema_name][r.table_name].fieldTypes[r.column_name] =
232
- ([type2oid['json'], type2oid['jsonb']].indexOf(r.typid) > -1) ? FieldType.JSON :
233
- ([type2oid['tsvector']].indexOf(r.typid) > -1) ? FieldType.TSVECTOR :
234
- ([type2oid['date'], type2oid['time'], type2oid['timestamp'], type2oid['timestamptz'], type2oid['timetz']].indexOf(r.typid) > -1) ? FieldType.TIME :
235
- FieldType.ARRAY;
236
- }
198
+ async initFieldTypes() {
199
+ let schemaNames = Object.keys(this.schemas);
200
+ if (!schemaNames.length) {
201
+ this.getLogger(true).error("No readable schema found!");
202
+ return;
203
+ }
204
+ let type2oid = {};
205
+ let res = await this.query(TYPE2OID);
206
+ for (let tt of res || []) {
207
+ type2oid[tt.typname] = +tt.oid;
208
+ }
209
+ let specialTypeFields = await this.query(LIST_SPECIAL_TYPE_FIELDS + ' AND c.nspname = ANY($1)', [schemaNames]);
210
+ for (let r of specialTypeFields) {
211
+ if (this.schemas[r.schema_name][r.table_name]) {
212
+ this.schemas[r.schema_name][r.table_name].fieldTypes[r.column_name] =
213
+ ([type2oid['json'], type2oid['jsonb']].indexOf(r.typid) > -1) ? FieldType.JSON :
214
+ ([type2oid['tsvector']].indexOf(r.typid) > -1) ? FieldType.TSVECTOR :
215
+ ([type2oid['date'], type2oid['time'], type2oid['timestamp'], type2oid['timestamptz'], type2oid['timetz']].indexOf(r.typid) > -1) ? FieldType.TIME :
216
+ FieldType.ARRAY;
237
217
  }
238
- let builtInArrayTypeParsers = [
239
- {
240
- oidList: [
241
- type2oid['_bool']
242
- ],
243
- parser: PgConverters.parseBooleanArray
244
- },
245
- {
246
- oidList: [
247
- type2oid['_int2'],
248
- type2oid['_int4'],
249
- type2oid['_float4'],
250
- ],
251
- parser: PgConverters.parseNumberArray
252
- },
253
- {
254
- oidList: [
255
- type2oid['_text'],
256
- type2oid['_varchar']
257
- ],
258
- parser: PgConverters.parseArray
259
- },
260
- {
261
- oidList: [
262
- type2oid['_json'],
263
- type2oid['_jsonb']
264
- ],
265
- parser: PgConverters.parseJsonArray
266
- },
267
- {
268
- oidList: [
269
- type2oid['_date'],
270
- type2oid['_time'],
271
- type2oid['_timetz'],
272
- type2oid['_timestamp'],
273
- type2oid['_timestamptz'],
274
- ],
275
- parser: PgConverters.parseDateArray
276
- }
277
- ];
278
- builtInArrayTypeParsers.forEach(parserObj => {
279
- parserObj.oidList.forEach(oid => {
280
- pg.types.setTypeParser(oid, parserObj.parser);
281
- delete this.pgdbTypeParsers[oid];
282
- this.knownOids[oid] = true;
283
- });
218
+ }
219
+ let builtInArrayTypeParsers = [
220
+ {
221
+ oidList: [
222
+ type2oid['_bool']
223
+ ],
224
+ parser: PgConverters.parseBooleanArray
225
+ },
226
+ {
227
+ oidList: [
228
+ type2oid['_int2'],
229
+ type2oid['_int4'],
230
+ type2oid['_float4'],
231
+ ],
232
+ parser: PgConverters.parseNumberArray
233
+ },
234
+ {
235
+ oidList: [
236
+ type2oid['_text'],
237
+ type2oid['_varchar']
238
+ ],
239
+ parser: PgConverters.parseArray
240
+ },
241
+ {
242
+ oidList: [
243
+ type2oid['_json'],
244
+ type2oid['_jsonb']
245
+ ],
246
+ parser: PgConverters.parseJsonArray
247
+ },
248
+ {
249
+ oidList: [
250
+ type2oid['_date'],
251
+ type2oid['_time'],
252
+ type2oid['_timetz'],
253
+ type2oid['_timestamp'],
254
+ type2oid['_timestamptz'],
255
+ ],
256
+ parser: PgConverters.parseDateArray
257
+ }
258
+ ];
259
+ builtInArrayTypeParsers.forEach(parserObj => {
260
+ parserObj.oidList.forEach(oid => {
261
+ pg.types.setTypeParser(oid, parserObj.parser);
262
+ delete this.pgdbTypeParsers[oid];
263
+ this.knownOids[oid] = true;
284
264
  });
285
- for (let r of specialTypeFields) {
286
- if (this.knownOids[r.typid] && !this.pgdbTypeParsers[r.typid]) {
287
- continue;
288
- }
289
- switch (r.typid) {
290
- case type2oid['json']:
291
- case type2oid['jsonb']:
292
- case type2oid['date']:
293
- case type2oid['time']:
294
- case type2oid['timetz']:
295
- case type2oid['timestamp']:
296
- case type2oid['timestamptz']:
297
- case type2oid['tsvector']:
298
- case type2oid['_int8']:
299
- case type2oid['_float8']:
300
- break;
301
- default:
302
- pg.types.setTypeParser(r.typid, PgConverters.parseArray);
303
- delete this.pgdbTypeParsers[r.typid];
304
- }
265
+ });
266
+ for (let r of specialTypeFields) {
267
+ if (this.knownOids[r.typid] && !this.pgdbTypeParsers[r.typid]) {
268
+ continue;
269
+ }
270
+ switch (r.typid) {
271
+ case type2oid['json']:
272
+ case type2oid['jsonb']:
273
+ case type2oid['date']:
274
+ case type2oid['time']:
275
+ case type2oid['timetz']:
276
+ case type2oid['timestamp']:
277
+ case type2oid['timestamptz']:
278
+ case type2oid['tsvector']:
279
+ case type2oid['_int8']:
280
+ case type2oid['_float8']:
281
+ break;
282
+ default:
283
+ pg.types.setTypeParser(r.typid, PgConverters.parseArray);
284
+ delete this.pgdbTypeParsers[r.typid];
305
285
  }
306
- this.pgdbTypeParsers[type2oid['int8']] = PgConverters.parseNumberWithValidation;
307
- this.pgdbTypeParsers[type2oid['float8']] = PgConverters.parseNumberWithValidation;
308
- this.pgdbTypeParsers[type2oid['_int8']] = PgConverters.parseNumberArrayWithValidation;
309
- this.pgdbTypeParsers[type2oid['_float8']] = PgConverters.parseNumberArrayWithValidation;
310
- this.knownOids[type2oid['int8']] = true;
311
- this.knownOids[type2oid['float8']] = true;
312
- this.knownOids[type2oid['_int8']] = true;
313
- this.knownOids[type2oid['_float8']] = true;
314
- let allUsedTypeFields = yield this.queryOneColumn(`
286
+ }
287
+ this.pgdbTypeParsers[type2oid['int8']] = PgConverters.parseNumberWithValidation;
288
+ this.pgdbTypeParsers[type2oid['float8']] = PgConverters.parseNumberWithValidation;
289
+ this.pgdbTypeParsers[type2oid['_int8']] = PgConverters.parseNumberArrayWithValidation;
290
+ this.pgdbTypeParsers[type2oid['_float8']] = PgConverters.parseNumberArrayWithValidation;
291
+ this.knownOids[type2oid['int8']] = true;
292
+ this.knownOids[type2oid['float8']] = true;
293
+ this.knownOids[type2oid['_int8']] = true;
294
+ this.knownOids[type2oid['_float8']] = true;
295
+ let allUsedTypeFields = await this.queryOneColumn(`
315
296
  SELECT distinct a.atttypid as typid
316
297
  FROM pg_attribute a
317
298
  JOIN pg_class b ON (a.attrelid = b.oid)
@@ -319,446 +300,420 @@ class PgDb extends queryAble_1.QueryAble {
319
300
  JOIN pg_namespace c ON (b.relnamespace=c.oid)
320
301
  WHERE
321
302
  reltype>0 AND
322
- c.nspname in (${schemaNames})`);
323
- allUsedTypeFields.forEach(oid => this.knownOids[oid] = true);
324
- });
303
+ c.nspname = ANY($1)`, [schemaNames]);
304
+ allUsedTypeFields.forEach(oid => this.knownOids[oid] = true);
325
305
  }
326
- setTypeParser(typeName, parser, schemaName) {
327
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
328
- try {
329
- if (schemaName) {
330
- let oid = yield this.queryOneField(GET_OID_FOR_COLUMN_TYPE_FOR_SCHEMA, { typeName, schemaName });
306
+ async setTypeParser(typeName, parser, schemaName) {
307
+ try {
308
+ if (schemaName) {
309
+ let oid = await this.queryOneField(GET_OID_FOR_COLUMN_TYPE_FOR_SCHEMA, { typeName, schemaName });
310
+ pg.types.setTypeParser(oid, parser);
311
+ delete this.pgdbTypeParsers[oid];
312
+ this.knownOids[oid] = true;
313
+ }
314
+ else {
315
+ let list = await this.queryOneColumn(GET_OID_FOR_COLUMN_TYPE, { typeName });
316
+ list.forEach(oid => {
331
317
  pg.types.setTypeParser(oid, parser);
332
318
  delete this.pgdbTypeParsers[oid];
333
319
  this.knownOids[oid] = true;
334
- }
335
- else {
336
- let list = yield this.queryOneColumn(GET_OID_FOR_COLUMN_TYPE, { typeName });
337
- list.forEach(oid => {
338
- pg.types.setTypeParser(oid, parser);
339
- delete this.pgdbTypeParsers[oid];
340
- this.knownOids[oid] = true;
341
- });
342
- }
343
- }
344
- catch (e) {
345
- throw new Error('Not existing type: ' + typeName);
320
+ });
346
321
  }
347
- });
322
+ }
323
+ catch (e) {
324
+ throw new Error('Not existing type: ' + typeName);
325
+ }
348
326
  }
349
- setPgDbTypeParser(typeName, parser, schemaName) {
350
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
351
- try {
352
- if (schemaName) {
353
- let oid = yield this.queryOneField(GET_OID_FOR_COLUMN_TYPE_FOR_SCHEMA, { typeName, schemaName });
327
+ async setPgDbTypeParser(typeName, parser, schemaName) {
328
+ try {
329
+ if (schemaName) {
330
+ let oid = await this.queryOneField(GET_OID_FOR_COLUMN_TYPE_FOR_SCHEMA, { typeName, schemaName });
331
+ this.pgdbTypeParsers[oid] = parser;
332
+ this.knownOids[oid] = true;
333
+ }
334
+ else {
335
+ let list = await this.queryOneColumn(GET_OID_FOR_COLUMN_TYPE, { typeName });
336
+ list.forEach(oid => {
354
337
  this.pgdbTypeParsers[oid] = parser;
355
338
  this.knownOids[oid] = true;
356
- }
357
- else {
358
- let list = yield this.queryOneColumn(GET_OID_FOR_COLUMN_TYPE, { typeName });
359
- list.forEach(oid => {
360
- this.pgdbTypeParsers[oid] = parser;
361
- this.knownOids[oid] = true;
362
- });
363
- }
364
- }
365
- catch (e) {
366
- throw new Error('Not existing type: ' + typeName);
367
- }
368
- });
369
- }
370
- resetMissingParsers(connection, oidList) {
371
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
372
- let unknownOids = oidList.filter(oid => !this.knownOids[oid]);
373
- if (unknownOids.length) {
374
- let fieldsData = yield connection.query(`select oid, typcategory from pg_type where oid = ANY($1)`, [unknownOids]);
375
- fieldsData.rows.forEach(fieldData => {
376
- if (fieldData.typcategory == 'A') {
377
- this.pgdbTypeParsers[fieldData.oid] = PgConverters.parseArray;
378
- }
379
- this.knownOids[fieldData.oid] = true;
380
339
  });
381
340
  }
382
- });
383
- }
384
- dedicatedConnectionBegin() {
385
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
386
- if (this.needToFixConnectionForListen()) {
387
- yield this.runRestartConnectionForListen();
388
- }
389
- let pgDb = new PgDb(this);
390
- pgDb.connection = yield this.pool.connect();
391
- pgDb.connection.on('error', queryAble_1.QueryAble.connectionErrorListener);
392
- return pgDb;
393
- });
341
+ }
342
+ catch (e) {
343
+ throw new Error('Not existing type: ' + typeName);
344
+ }
394
345
  }
395
- dedicatedConnectionEnd() {
396
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
397
- if (this.connection) {
398
- this.connection.off('error', queryAble_1.QueryAble.connectionErrorListener);
399
- try {
400
- yield this.connection.release();
401
- }
402
- catch (err) {
403
- this.getLogger().error('Error while dedicated connection end.', err);
346
+ async resetMissingParsers(connection, oidList) {
347
+ let unknownOids = _.uniq(oidList.filter(oid => !this.knownOids[oid]));
348
+ if (unknownOids.length) {
349
+ let fieldsData = await connection.query(`select oid, typcategory from pg_type where oid = ANY($1)`, [unknownOids]);
350
+ fieldsData.rows.forEach(fieldData => {
351
+ if (fieldData.typcategory == 'A') {
352
+ this.pgdbTypeParsers[fieldData.oid] = PgConverters.parseArray;
404
353
  }
405
- this.connection = null;
406
- }
407
- return this;
408
- });
354
+ this.knownOids[fieldData.oid] = true;
355
+ });
356
+ }
409
357
  }
410
- savePoint(name) {
411
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
412
- if (this.isTransactionActive()) {
413
- name = (name || '').replace(/"/g, '');
414
- yield this.query(`SAVEPOINT "${name}"`);
415
- }
416
- else {
417
- throw new Error('No active transaction');
418
- }
419
- return this;
420
- });
358
+ async dedicatedConnectionBegin() {
359
+ if (this.needToFixConnectionForListen()) {
360
+ await this.runRestartConnectionForListen();
361
+ }
362
+ let pgDb = new PgDb(this);
363
+ pgDb.connection = await this.pool.connect();
364
+ pgDb.connection.on('error', QueryAble.connectionErrorListener);
365
+ return pgDb;
421
366
  }
422
- savePointRelease(name) {
423
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
424
- if (this.isTransactionActive()) {
425
- name = (name || '').replace(/"/g, '');
426
- yield this.query(`RELEASE SAVEPOINT "${name}"`);
367
+ async dedicatedConnectionEnd() {
368
+ if (this.connection) {
369
+ this.connection.off('error', QueryAble.connectionErrorListener);
370
+ try {
371
+ await this.connection.release();
427
372
  }
428
- else {
429
- throw new Error('No active transaction');
373
+ catch (err) {
374
+ this.getLogger().error('Error while dedicated connection end.', err);
430
375
  }
431
- return this;
432
- });
376
+ this.connection = null;
377
+ }
378
+ return this;
433
379
  }
434
- transactionBegin(options) {
435
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
436
- let pgDb = this.connection ? this : yield this.dedicatedConnectionBegin();
437
- let q = 'BEGIN';
438
- if (options === null || options === void 0 ? void 0 : options.isolationLevel) {
439
- q += ' ISOLATION LEVEL ' + options.isolationLevel;
440
- }
441
- if (options === null || options === void 0 ? void 0 : options.readOnly) {
442
- q += ' READ ONLY';
443
- }
444
- if (options === null || options === void 0 ? void 0 : options.deferrable) {
445
- q += ' DEFERRABLE ';
446
- }
447
- yield pgDb.query(q);
448
- return pgDb;
449
- });
380
+ async savePoint(name) {
381
+ if (this.isTransactionActive()) {
382
+ name = (name || '').replace(/"/g, '');
383
+ await this.query(`SAVEPOINT "${name}"`);
384
+ }
385
+ else {
386
+ throw new Error('No active transaction');
387
+ }
388
+ return this;
450
389
  }
451
- transactionCommit() {
452
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
453
- yield this.query('COMMIT');
454
- return this.dedicatedConnectionEnd();
455
- });
390
+ async savePointRelease(name) {
391
+ if (this.isTransactionActive()) {
392
+ name = (name || '').replace(/"/g, '');
393
+ await this.query(`RELEASE SAVEPOINT "${name}"`);
394
+ }
395
+ else {
396
+ throw new Error('No active transaction');
397
+ }
398
+ return this;
456
399
  }
457
- transactionRollback(options) {
458
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
459
- if (options === null || options === void 0 ? void 0 : options.savePoint) {
460
- let name = (options.savePoint || '').replace(/"/g, '');
461
- yield this.query(`ROLLBACK TO SAVEPOINT "${name}"`);
462
- return this;
463
- }
464
- else {
465
- yield this.query('ROLLBACK');
466
- return this.dedicatedConnectionEnd();
467
- }
468
- });
400
+ async transactionBegin(options) {
401
+ let pgDb = this.connection ? this : await this.dedicatedConnectionBegin();
402
+ let q = 'BEGIN';
403
+ if (options?.isolationLevel) {
404
+ q += ' ISOLATION LEVEL ' + options.isolationLevel;
405
+ }
406
+ if (options?.readOnly) {
407
+ q += ' READ ONLY';
408
+ }
409
+ if (options?.deferrable) {
410
+ q += ' DEFERRABLE ';
411
+ }
412
+ await pgDb.query(q);
413
+ return pgDb;
414
+ }
415
+ async transactionCommit() {
416
+ await this.query('COMMIT');
417
+ return this.dedicatedConnectionEnd();
418
+ }
419
+ async transactionRollback(options) {
420
+ if (options?.savePoint) {
421
+ let name = (options.savePoint || '').replace(/"/g, '');
422
+ await this.query(`ROLLBACK TO SAVEPOINT "${name}"`);
423
+ return this;
424
+ }
425
+ else {
426
+ await this.query('ROLLBACK');
427
+ return this.dedicatedConnectionEnd();
428
+ }
469
429
  }
470
430
  isTransactionActive() {
471
431
  return this.connection != null;
472
432
  }
473
- execute(fileName, statementTransformerFunction) {
474
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
475
- let isTransactionInPlace = this.isTransactionActive();
476
- let pgdb = isTransactionInPlace ? this : yield this.dedicatedConnectionBegin();
477
- let runStatementList = (statementList) => {
478
- return new Promise((resolve, reject) => {
479
- let currentStatement = 0;
480
- let runStatement = () => {
481
- if (statementList.length == currentStatement) {
482
- resolve(undefined);
433
+ async execute(fileName, statementTransformerFunction) {
434
+ let isTransactionInPlace = this.isTransactionActive();
435
+ let pgdb = isTransactionInPlace ? this : await this.dedicatedConnectionBegin();
436
+ let runStatementList = (statementList) => {
437
+ return new Promise((resolve, reject) => {
438
+ let currentStatement = 0;
439
+ let runStatement = () => {
440
+ if (statementList.length == currentStatement) {
441
+ resolve(undefined);
442
+ }
443
+ else {
444
+ let statement = statementList[currentStatement++];
445
+ if (statementTransformerFunction) {
446
+ statement = statementTransformerFunction(statement);
483
447
  }
484
- else {
485
- let statement = statementList[currentStatement++];
486
- if (statementTransformerFunction) {
487
- statement = statementTransformerFunction(statement);
448
+ this.getLogger(true).log('run', statementList[currentStatement - 1]);
449
+ pgdb.query(statement)
450
+ .then(() => runStatement(), reject)
451
+ .catch(reject);
452
+ }
453
+ };
454
+ runStatement();
455
+ }).catch((e) => {
456
+ this.getLogger(true).error(e);
457
+ throw e;
458
+ });
459
+ };
460
+ let lineCounter = 0;
461
+ let promise = new Promise((resolve, reject) => {
462
+ let statementList = [];
463
+ let tmp = '', t;
464
+ let consumer;
465
+ let inQuotedString;
466
+ let rl = readline.createInterface({
467
+ input: fs.createReadStream(fileName),
468
+ terminal: false
469
+ }).on('line', (line) => {
470
+ lineCounter++;
471
+ try {
472
+ while (t = SQL_TOKENIZER_REGEXP.exec(line)) {
473
+ if (!inQuotedString && (t[0] == '"' || t[0] == "'") || inQuotedString == '"' || inQuotedString == "'") {
474
+ if (!inQuotedString) {
475
+ inQuotedString = t[0];
488
476
  }
489
- this.getLogger(true).log('run', statementList[currentStatement - 1]);
490
- pgdb.query(statement)
491
- .then(() => runStatement(), reject)
492
- .catch(reject);
493
- }
494
- };
495
- runStatement();
496
- }).catch((e) => {
497
- this.getLogger(true).error(e);
498
- throw e;
499
- });
500
- };
501
- let lineCounter = 0;
502
- let promise = new Promise((resolve, reject) => {
503
- let statementList = [];
504
- let tmp = '', t;
505
- let consumer;
506
- let inQuotedString;
507
- let rl = readline.createInterface({
508
- input: fs.createReadStream(fileName),
509
- terminal: false
510
- }).on('line', (line) => {
511
- lineCounter++;
512
- try {
513
- while (t = SQL_TOKENIZER_REGEXP.exec(line)) {
514
- if (!inQuotedString && (t[0] == '"' || t[0] == "'") || inQuotedString == '"' || inQuotedString == "'") {
515
- if (!inQuotedString) {
516
- inQuotedString = t[0];
517
- }
518
- else if (inQuotedString == t[0]) {
519
- inQuotedString = null;
520
- }
521
- tmp += t[0];
477
+ else if (inQuotedString == t[0]) {
478
+ inQuotedString = null;
522
479
  }
523
- else if (!inQuotedString && t[0] == '$' || inQuotedString && inQuotedString[0] == '$') {
524
- if (!inQuotedString) {
525
- let s = line.slice(SQL_TOKENIZER_REGEXP.lastIndex - 1);
526
- let token = s.match(SQL_$_ESCAPE_REGEXP);
527
- if (!token) {
528
- throw new Error('Invalid sql in line: ' + line);
529
- }
530
- inQuotedString = token[0];
531
- SQL_TOKENIZER_REGEXP.lastIndex += inQuotedString.length - 1;
532
- tmp += inQuotedString;
533
- }
534
- else {
535
- tmp += t[0];
536
- if (tmp.endsWith(inQuotedString)) {
537
- inQuotedString = null;
538
- }
480
+ tmp += t[0];
481
+ }
482
+ else if (!inQuotedString && t[0] == '$' || inQuotedString && inQuotedString[0] == '$') {
483
+ if (!inQuotedString) {
484
+ let s = line.slice(SQL_TOKENIZER_REGEXP.lastIndex - 1);
485
+ let token = s.match(SQL_$_ESCAPE_REGEXP);
486
+ if (!token) {
487
+ throw new Error('Invalid sql in line: ' + line);
539
488
  }
489
+ inQuotedString = token[0];
490
+ SQL_TOKENIZER_REGEXP.lastIndex += inQuotedString.length - 1;
491
+ tmp += inQuotedString;
540
492
  }
541
- else if (!inQuotedString && t[0] == '/*' || inQuotedString == '/*') {
542
- if (!inQuotedString) {
543
- inQuotedString = t[0];
544
- }
545
- else if (t[0] == '*/') {
493
+ else {
494
+ tmp += t[0];
495
+ if (tmp.endsWith(inQuotedString)) {
546
496
  inQuotedString = null;
547
497
  }
548
498
  }
549
- else if (!inQuotedString && t[0] == '--') {
550
- line = '';
551
- }
552
- else if (!inQuotedString && t[0] == ';') {
553
- if (tmp.trim() != '') {
554
- statementList.push(tmp);
555
- if (!consumer) {
556
- consumer = runStatementList(statementList).then(() => {
557
- consumer = null;
558
- statementList.length = 0;
559
- rl.resume();
560
- }, reject);
561
- rl.pause();
562
- }
563
- }
564
- tmp = '';
499
+ }
500
+ else if (!inQuotedString && t[0] == '/*' || inQuotedString == '/*') {
501
+ if (!inQuotedString) {
502
+ inQuotedString = t[0];
565
503
  }
566
- else {
567
- tmp += t[0];
504
+ else if (t[0] == '*/') {
505
+ inQuotedString = null;
568
506
  }
569
507
  }
570
- if (tmp && line) {
571
- tmp += '\n';
508
+ else if (!inQuotedString && t[0] == '--') {
509
+ line = '';
572
510
  }
573
- }
574
- catch (e) {
575
- reject(e);
576
- }
577
- }).on('close', () => {
578
- if (inQuotedString) {
579
- reject(Error('Invalid SQL, unterminated string'));
580
- }
581
- if (tmp.trim() != '') {
582
- statementList.push(tmp);
583
- }
584
- if (!consumer) {
585
- if (statementList.length) {
586
- consumer = runStatementList(statementList).catch(reject);
511
+ else if (!inQuotedString && t[0] == ';') {
512
+ if (tmp.trim() != '') {
513
+ statementList.push(tmp);
514
+ if (!consumer) {
515
+ consumer = runStatementList(statementList).then(() => {
516
+ consumer = null;
517
+ statementList.length = 0;
518
+ rl?.resume();
519
+ }, reject);
520
+ rl?.pause();
521
+ }
522
+ }
523
+ tmp = '';
587
524
  }
588
525
  else {
589
- resolve();
526
+ tmp += t[0];
590
527
  }
591
528
  }
592
- if (consumer) {
593
- consumer = consumer.then(resolve, reject);
529
+ if (tmp && line) {
530
+ tmp += '\n';
594
531
  }
595
- });
596
- });
597
- let error;
598
- return promise
599
- .catch((e) => {
600
- error = e;
601
- this.getLogger(true).error('Error at line ' + lineCounter + ' in ' + fileName + '. ' + e);
602
- })
603
- .then(() => {
604
- if (!isTransactionInPlace) {
605
- return pgdb.dedicatedConnectionEnd();
606
532
  }
607
- }).catch((e) => {
608
- this.getLogger(true).error(e);
609
- }).then(() => {
610
- if (error) {
611
- throw error;
533
+ catch (e) {
534
+ reject(e);
612
535
  }
613
- });
614
- });
615
- }
616
- listen(channel, callback) {
617
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
618
- let restartConnectionError = null;
619
- if (this.needToFixConnectionForListen()) {
620
- restartConnectionError = yield this.runRestartConnectionForListen();
621
- }
622
- if (this.listeners.listenerCount(channel)) {
623
- this.listeners.on(channel, callback);
624
- }
625
- else {
626
- if (restartConnectionError) {
627
- throw restartConnectionError;
536
+ }).on('close', () => {
537
+ rl = null;
538
+ if (inQuotedString) {
539
+ reject(Error('Invalid SQL, unterminated string'));
628
540
  }
629
- try {
630
- if (!this.connectionForListen) {
631
- yield this.initConnectionForListen();
541
+ if (tmp.trim() != '') {
542
+ statementList.push(tmp);
543
+ }
544
+ if (!consumer) {
545
+ if (statementList.length) {
546
+ consumer = runStatementList(statementList).catch(reject);
547
+ }
548
+ else {
549
+ resolve();
632
550
  }
633
- yield this.connectionForListen.query(`LISTEN "${channel}"`);
634
551
  }
635
- catch (err) {
636
- this._needToRestartConnectionForListen = true;
637
- throw err;
552
+ if (consumer) {
553
+ consumer = consumer.then(resolve, reject);
638
554
  }
639
- this.listeners.on(channel, callback);
555
+ });
556
+ });
557
+ let error;
558
+ return promise
559
+ .catch((e) => {
560
+ error = e;
561
+ this.getLogger(true).error('Error at line ' + lineCounter + ' in ' + fileName + '. ' + e);
562
+ })
563
+ .then(() => {
564
+ if (!isTransactionInPlace) {
565
+ return pgdb.dedicatedConnectionEnd();
566
+ }
567
+ }).catch((e) => {
568
+ this.getLogger(true).error(e);
569
+ }).then(() => {
570
+ if (error) {
571
+ throw error;
640
572
  }
641
573
  });
642
574
  }
643
- unlisten(channel, callback) {
644
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
645
- let restartConnectionError = null;
646
- if (this.needToFixConnectionForListen()) {
647
- restartConnectionError = yield this.runRestartConnectionForListen();
648
- }
649
- if (callback && this.listeners.listenerCount(channel) > 1) {
650
- this.listeners.removeListener(channel, callback);
575
+ listeners = new EventEmitter();
576
+ connectionForListen = null;
577
+ _needToRestartConnectionForListen = false;
578
+ restartConnectionForListen = null;
579
+ async listen(channel, callback) {
580
+ let restartConnectionError = null;
581
+ if (this.needToFixConnectionForListen()) {
582
+ restartConnectionError = await this.runRestartConnectionForListen();
583
+ }
584
+ if (this.listeners.listenerCount(channel)) {
585
+ this.listeners.on(channel, callback);
586
+ }
587
+ else {
588
+ if (restartConnectionError) {
589
+ throw restartConnectionError;
651
590
  }
652
- else {
653
- if (restartConnectionError) {
654
- throw restartConnectionError;
655
- }
656
- try {
657
- yield this.internalQuery({ connection: this.connectionForListen, sql: `UNLISTEN "${channel}"` });
658
- if (this.connectionForListen && this.listeners.eventNames().length == 1) {
659
- this.connectionForListen.removeAllListeners('notification');
660
- this.connectionForListen.release();
661
- this.connectionForListen = null;
662
- }
663
- }
664
- catch (err) {
665
- this._needToRestartConnectionForListen = true;
666
- throw err;
591
+ try {
592
+ if (!this.connectionForListen) {
593
+ await this.initConnectionForListen();
667
594
  }
668
- this.listeners.removeAllListeners(channel);
595
+ await this.connectionForListen.query(`LISTEN "${channel}"`);
669
596
  }
670
- });
597
+ catch (err) {
598
+ this._needToRestartConnectionForListen = true;
599
+ throw err;
600
+ }
601
+ this.listeners.on(channel, callback);
602
+ }
671
603
  }
672
- notify(channel, payload) {
673
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
674
- if (this.needToFixConnectionForListen()) {
675
- let restartConnectionError = yield this.runRestartConnectionForListen();
676
- if (restartConnectionError) {
677
- throw restartConnectionError;
678
- }
604
+ async unlisten(channel, callback) {
605
+ let restartConnectionError = null;
606
+ if (this.needToFixConnectionForListen()) {
607
+ restartConnectionError = await this.runRestartConnectionForListen();
608
+ }
609
+ if (callback && this.listeners.listenerCount(channel) > 1) {
610
+ this.listeners.removeListener(channel, callback);
611
+ }
612
+ else {
613
+ if (restartConnectionError) {
614
+ throw restartConnectionError;
679
615
  }
680
- let hasConnectionForListen = !!this.connectionForListen;
681
- let connection = this.connectionForListen || this.connection;
682
- let sql = 'SELECT pg_notify(:channel, :payload)';
683
- let params = { channel, payload };
684
616
  try {
685
- return this.internalQuery({ connection, sql, params });
617
+ await this.internalQuery({ connection: this.connectionForListen, sql: `UNLISTEN "${channel}"` });
618
+ if (this.connectionForListen && this.listeners.eventNames().length == 1) {
619
+ this.connectionForListen.removeAllListeners('notification');
620
+ this.connectionForListen.release();
621
+ this.connectionForListen = null;
622
+ }
686
623
  }
687
624
  catch (err) {
688
- if (hasConnectionForListen) {
689
- this._needToRestartConnectionForListen = true;
690
- }
625
+ this._needToRestartConnectionForListen = true;
691
626
  throw err;
692
627
  }
693
- });
628
+ this.listeners.removeAllListeners(channel);
629
+ }
694
630
  }
695
- runRestartConnectionForListen() {
696
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
697
- if (!this._needToRestartConnectionForListen) {
698
- return null;
631
+ async notify(channel, payload) {
632
+ if (this.needToFixConnectionForListen()) {
633
+ let restartConnectionError = await this.runRestartConnectionForListen();
634
+ if (restartConnectionError) {
635
+ throw restartConnectionError;
699
636
  }
700
- let errorResult = null;
701
- if (!this.restartConnectionForListen) {
702
- this.restartConnectionForListen = (() => (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
703
- let eventNames = this.listeners.eventNames();
704
- if (this.connectionForListen) {
705
- try {
706
- this.connectionForListen.on('notification', this.notificationListener);
707
- this.connectionForListen.on('error', this.errorListener);
708
- }
709
- catch (e) { }
710
- try {
711
- yield this.connectionForListen.release();
712
- }
713
- catch (e) { }
714
- this.connectionForListen = null;
637
+ }
638
+ let hasConnectionForListen = !!this.connectionForListen;
639
+ let connection = this.connectionForListen || this.connection;
640
+ let sql = 'SELECT pg_notify(:channel, :payload)';
641
+ let params = { channel, payload };
642
+ try {
643
+ return this.internalQuery({ connection, sql, params });
644
+ }
645
+ catch (err) {
646
+ if (hasConnectionForListen) {
647
+ this._needToRestartConnectionForListen = true;
648
+ }
649
+ throw err;
650
+ }
651
+ }
652
+ async runRestartConnectionForListen() {
653
+ if (!this._needToRestartConnectionForListen) {
654
+ return null;
655
+ }
656
+ let errorResult = null;
657
+ if (!this.restartConnectionForListen) {
658
+ this.restartConnectionForListen = (async () => {
659
+ let eventNames = this.listeners.eventNames();
660
+ if (this.connectionForListen) {
661
+ try {
662
+ this.connectionForListen.on('notification', this.notificationListener);
663
+ this.connectionForListen.on('error', this.errorListener);
715
664
  }
716
- let error = null;
717
- if (eventNames.length) {
718
- try {
719
- yield this.initConnectionForListen();
720
- for (let channel of eventNames) {
721
- yield this.connectionForListen.query(`LISTEN "${channel}"`);
722
- }
723
- }
724
- catch (err) {
725
- error = err;
665
+ catch (e) { }
666
+ try {
667
+ await this.connectionForListen.release();
668
+ }
669
+ catch (e) { }
670
+ this.connectionForListen = null;
671
+ }
672
+ let error = null;
673
+ if (eventNames.length) {
674
+ try {
675
+ await this.initConnectionForListen();
676
+ for (let channel of eventNames) {
677
+ await this.connectionForListen.query(`LISTEN "${channel}"`);
726
678
  }
727
679
  }
728
- return error;
729
- }))();
730
- errorResult = yield this.restartConnectionForListen;
731
- this.restartConnectionForListen = null;
732
- }
733
- else {
734
- errorResult = yield this.restartConnectionForListen;
735
- }
736
- if (!errorResult) {
737
- this._needToRestartConnectionForListen = false;
738
- }
739
- return errorResult;
740
- });
680
+ catch (err) {
681
+ error = err;
682
+ }
683
+ }
684
+ return error;
685
+ })();
686
+ errorResult = await this.restartConnectionForListen;
687
+ this.restartConnectionForListen = null;
688
+ }
689
+ else {
690
+ errorResult = await this.restartConnectionForListen;
691
+ }
692
+ if (!errorResult) {
693
+ this._needToRestartConnectionForListen = false;
694
+ }
695
+ return errorResult;
741
696
  }
742
697
  needToFixConnectionForListen() {
743
698
  return this._needToRestartConnectionForListen;
744
699
  }
745
- tryToFixConnectionForListenActively() {
746
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
747
- yield new Promise(r => setTimeout(r, 1000));
748
- let error = yield this.runRestartConnectionForListen();
749
- if (error) {
750
- yield this.tryToFixConnectionForListenActively();
751
- }
752
- });
700
+ async tryToFixConnectionForListenActively() {
701
+ await new Promise(r => setTimeout(r, 1000));
702
+ let error = await this.runRestartConnectionForListen();
703
+ if (error) {
704
+ await this.tryToFixConnectionForListenActively();
705
+ }
753
706
  }
754
- initConnectionForListen() {
755
- return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
756
- this.connectionForListen = yield this.pool.connect();
757
- this.connectionForListen.on('notification', this.notificationListener);
758
- this.connectionForListen.on('error', this.errorListener);
759
- });
707
+ notificationListener = (notification) => this.listeners.emit(notification.channel, notification);
708
+ errorListener = (e) => {
709
+ this._needToRestartConnectionForListen = true;
710
+ this.tryToFixConnectionForListenActively();
711
+ };
712
+ async initConnectionForListen() {
713
+ this.connectionForListen = await this.pool.connect();
714
+ this.connectionForListen.on('notification', this.notificationListener);
715
+ this.connectionForListen.on('error', this.errorListener);
760
716
  }
761
717
  }
762
- exports.PgDb = PgDb;
763
- exports.default = PgDb;
718
+ export default PgDb;
764
719
  //# sourceMappingURL=pgDb.js.map