pogi 2.10.1 → 3.0.0-beta

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 (108) hide show
  1. package/.vscode/launch.json +47 -15
  2. package/CHANGELOG.md +20 -0
  3. package/docs/API/PgDb.md +25 -0
  4. package/docs/notification.md +19 -0
  5. package/jest.config.js +23 -0
  6. package/lib/bin/generateInterface.js +2 -2
  7. package/lib/bin/generateInterface.js.map +1 -1
  8. package/lib/index.js +1 -0
  9. package/lib/index.js.map +1 -1
  10. package/lib/pgConverters.d.ts +2 -0
  11. package/lib/pgConverters.js +27 -10
  12. package/lib/pgConverters.js.map +1 -1
  13. package/lib/pgDb.d.ts +15 -6
  14. package/lib/pgDb.js +263 -67
  15. package/lib/pgDb.js.map +1 -1
  16. package/lib/pgTable.js +7 -7
  17. package/lib/pgTable.js.map +1 -1
  18. package/lib/pgUtils.d.ts +3 -1
  19. package/lib/pgUtils.js +61 -23
  20. package/lib/pgUtils.js.map +1 -1
  21. package/lib/queryAble.d.ts +16 -1
  22. package/lib/queryAble.js +124 -56
  23. package/lib/queryAble.js.map +1 -1
  24. package/lib/src/bin/generateInterface.d.ts +1 -0
  25. package/lib/src/bin/generateInterface.js +53 -0
  26. package/lib/src/bin/generateInterface.js.map +1 -0
  27. package/lib/src/connectionOptions.d.ts +34 -0
  28. package/lib/src/connectionOptions.js +3 -0
  29. package/lib/src/connectionOptions.js.map +1 -0
  30. package/lib/src/index.d.ts +6 -0
  31. package/lib/src/index.js +12 -0
  32. package/lib/src/index.js.map +1 -0
  33. package/lib/src/pgConverters.d.ts +9 -0
  34. package/lib/src/pgConverters.js +71 -0
  35. package/lib/src/pgConverters.js.map +1 -0
  36. package/lib/src/pgConverters.test.d.ts +1 -0
  37. package/lib/src/pgConverters.test.js +13 -0
  38. package/lib/src/pgConverters.test.js.map +1 -0
  39. package/lib/src/pgDb.d.ts +79 -0
  40. package/lib/src/pgDb.js +764 -0
  41. package/lib/src/pgDb.js.map +1 -0
  42. package/lib/src/pgDb.test.d.ts +1 -0
  43. package/lib/src/pgDb.test.js +1126 -0
  44. package/lib/src/pgDb.test.js.map +1 -0
  45. package/lib/src/pgDbInterface.js +11 -0
  46. package/lib/src/pgDbInterface.js.map +1 -0
  47. package/lib/src/pgDbLogger.d.ts +5 -0
  48. package/lib/src/pgDbLogger.js +3 -0
  49. package/lib/src/pgDbLogger.js.map +1 -0
  50. package/lib/src/pgDbOperators.d.ts +113 -0
  51. package/lib/src/pgDbOperators.js +41 -0
  52. package/lib/src/pgDbOperators.js.map +1 -0
  53. package/lib/src/pgDbOperators.test.d.ts +1 -0
  54. package/lib/src/pgDbOperators.test.js +313 -0
  55. package/lib/src/pgDbOperators.test.js.map +1 -0
  56. package/lib/src/pgSchema.d.ts +17 -0
  57. package/lib/src/pgSchema.js +16 -0
  58. package/lib/src/pgSchema.js.map +1 -0
  59. package/lib/src/pgSchemaInterface.d.ts +12 -0
  60. package/lib/src/pgSchemaInterface.js +3 -0
  61. package/lib/src/pgSchemaInterface.js.map +1 -0
  62. package/lib/src/pgTable.d.ts +105 -0
  63. package/lib/src/pgTable.js +322 -0
  64. package/lib/src/pgTable.js.map +1 -0
  65. package/lib/src/pgTableInterface.d.ts +102 -0
  66. package/lib/src/pgTableInterface.js +4 -0
  67. package/lib/src/pgTableInterface.js.map +1 -0
  68. package/lib/src/pgUtils.d.ts +41 -0
  69. package/lib/src/pgUtils.js +282 -0
  70. package/lib/src/pgUtils.js.map +1 -0
  71. package/lib/src/queryAble.d.ts +40 -0
  72. package/lib/src/queryAble.js +338 -0
  73. package/lib/src/queryAble.js.map +1 -0
  74. package/lib/src/queryAbleInterface.d.ts +59 -0
  75. package/lib/src/queryAbleInterface.js +7 -0
  76. package/lib/src/queryAbleInterface.js.map +1 -0
  77. package/lib/src/queryWhere.d.ts +8 -0
  78. package/lib/src/queryWhere.js +245 -0
  79. package/lib/src/queryWhere.js.map +1 -0
  80. package/mkdocs.yml +1 -0
  81. package/package.json +23 -14
  82. package/src/bin/generateInterface.ts +2 -2
  83. package/src/connectionOptions.ts +46 -13
  84. package/src/index.d.ts +7 -0
  85. package/src/pgConverters.test.ts +10 -0
  86. package/src/pgConverters.ts +34 -22
  87. package/src/pgDb.test.ts +1324 -0
  88. package/src/pgDb.ts +321 -125
  89. package/src/pgDbInterface.ts +57 -0
  90. package/src/pgDbOperators.test.ts +478 -0
  91. package/src/pgDbOperators.ts +45 -22
  92. package/src/pgSchema.ts +10 -9
  93. package/src/pgSchemaInterface.ts +12 -0
  94. package/src/pgTable.ts +65 -97
  95. package/src/pgTableInterface.ts +131 -0
  96. package/src/pgUtils.ts +156 -42
  97. package/src/queryAble.ts +167 -125
  98. package/src/queryAbleInterface.ts +108 -0
  99. package/src/queryWhere.ts +42 -43
  100. package/{spec/resources → src/test}/init.sql +23 -0
  101. package/src/test/pgServiceRestartTest.ts +1500 -0
  102. package/{spec/resources → src/test}/throw_exception.sql +0 -0
  103. package/{spec/resources → src/test}/tricky.sql +0 -0
  104. package/{src/tsconfig.json → tsconfig.json} +9 -6
  105. package/spec/run.js +0 -5
  106. package/spec/support/jasmine.json +0 -9
  107. package/src/test/pgDbOperatorSpec.ts +0 -492
  108. package/src/test/pgDbSpec.ts +0 -994
@@ -0,0 +1,764 @@
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 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, t.typcategory
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
+ const TYPE2OID = `SELECT t.oid, typname FROM pg_catalog.pg_type t WHERE typname in (
43
+ '_bool',
44
+ 'int8','_int2','_int4','_int8','_float4','float8','_float8',
45
+ '_text','_varchar',
46
+ 'json','jsonb', '_json','_jsonb',
47
+ 'date','time','timestamp','timestamptz','timetz','_date','_time','_timestamp','_timestamptz','_timetz',
48
+ 'tsvector')`;
49
+ var FieldType;
50
+ (function (FieldType) {
51
+ FieldType[FieldType["JSON"] = 0] = "JSON";
52
+ FieldType[FieldType["ARRAY"] = 1] = "ARRAY";
53
+ FieldType[FieldType["TIME"] = 2] = "TIME";
54
+ FieldType[FieldType["TSVECTOR"] = 3] = "TSVECTOR";
55
+ })(FieldType = exports.FieldType || (exports.FieldType = {}));
56
+ class PgDb extends queryAble_1.QueryAble {
57
+ constructor(pgdb) {
58
+ 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
+ this.schemas = {};
74
+ this.config = pgdb.config || {};
75
+ this.pool = pgdb.pool;
76
+ this.postProcessResult = pgdb.postProcessResult;
77
+ this.pgdbTypeParsers = pgdb.pgdbTypeParsers || {};
78
+ this.knownOids = pgdb.knownOids || {};
79
+ this.db = this;
80
+ if (pgdb.getLogger) {
81
+ this.setLogger(pgdb.getLogger());
82
+ }
83
+ for (let schemaName in pgdb.schemas) {
84
+ let schema = new pgSchema_1.PgSchema(this, schemaName);
85
+ this.schemas[schemaName] = schema;
86
+ if (!(schemaName in this))
87
+ this[schemaName] = schema;
88
+ 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);
90
+ if (!(tableName in schema))
91
+ schema[tableName] = schema.tables[tableName];
92
+ }
93
+ }
94
+ this.defaultSchemas = pgdb.defaultSchemas || [];
95
+ this.setDefaultTablesAndFunctions();
96
+ }
97
+ setPostProcessResult(f) {
98
+ this.postProcessResult = f;
99
+ }
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];
123
+ }
124
+ });
125
+ }
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
+ }
133
+ }
134
+ yield new Promise((resolve) => this.pool.end(resolve));
135
+ });
136
+ }
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
+ }
149
+ }
150
+ let pgdb = new PgDb({ config: config });
151
+ return pgdb.init();
152
+ });
153
+ }
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;
165
+ });
166
+ }
167
+ reload() {
168
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
169
+ yield this.initSchemasAndTables();
170
+ yield this.initFieldTypes();
171
+ });
172
+ }
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
+ });
200
+ }
201
+ setDefaultTablesAndFunctions() {
202
+ this.tables = {};
203
+ this.fn = {};
204
+ if (!this.defaultSchemas)
205
+ return;
206
+ for (let sc of this.defaultSchemas) {
207
+ let schema = this.schemas[sc];
208
+ if (!schema)
209
+ continue;
210
+ for (let table in schema.tables)
211
+ this.tables[table] = this.tables[table] || schema.tables[table];
212
+ for (let fn in schema.fn)
213
+ this.fn[fn] = this.fn[fn] || schema.fn[fn];
214
+ }
215
+ }
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
+ }
237
+ }
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
+ });
284
+ });
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
+ }
305
+ }
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(`
315
+ SELECT distinct a.atttypid as typid
316
+ FROM pg_attribute a
317
+ JOIN pg_class b ON (a.attrelid = b.oid)
318
+ JOIN pg_type t ON (a.atttypid = t.oid)
319
+ JOIN pg_namespace c ON (b.relnamespace=c.oid)
320
+ WHERE
321
+ reltype>0 AND
322
+ c.nspname in (${schemaNames})`);
323
+ allUsedTypeFields.forEach(oid => this.knownOids[oid] = true);
324
+ });
325
+ }
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 });
331
+ pg.types.setTypeParser(oid, parser);
332
+ delete this.pgdbTypeParsers[oid];
333
+ 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);
346
+ }
347
+ });
348
+ }
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 });
354
+ this.pgdbTypeParsers[oid] = parser;
355
+ 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
+ });
381
+ }
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
+ });
394
+ }
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);
404
+ }
405
+ this.connection = null;
406
+ }
407
+ return this;
408
+ });
409
+ }
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
+ });
421
+ }
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}"`);
427
+ }
428
+ else {
429
+ throw new Error('No active transaction');
430
+ }
431
+ return this;
432
+ });
433
+ }
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
+ });
450
+ }
451
+ transactionCommit() {
452
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
453
+ yield this.query('COMMIT');
454
+ return this.dedicatedConnectionEnd();
455
+ });
456
+ }
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
+ });
469
+ }
470
+ isTransactionActive() {
471
+ return this.connection != null;
472
+ }
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);
483
+ }
484
+ else {
485
+ let statement = statementList[currentStatement++];
486
+ if (statementTransformerFunction) {
487
+ statement = statementTransformerFunction(statement);
488
+ }
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];
522
+ }
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
+ }
539
+ }
540
+ }
541
+ else if (!inQuotedString && t[0] == '/*' || inQuotedString == '/*') {
542
+ if (!inQuotedString) {
543
+ inQuotedString = t[0];
544
+ }
545
+ else if (t[0] == '*/') {
546
+ inQuotedString = null;
547
+ }
548
+ }
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 = '';
565
+ }
566
+ else {
567
+ tmp += t[0];
568
+ }
569
+ }
570
+ if (tmp && line) {
571
+ tmp += '\n';
572
+ }
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);
587
+ }
588
+ else {
589
+ resolve();
590
+ }
591
+ }
592
+ if (consumer) {
593
+ consumer = consumer.then(resolve, reject);
594
+ }
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
+ }
607
+ }).catch((e) => {
608
+ this.getLogger(true).error(e);
609
+ }).then(() => {
610
+ if (error) {
611
+ throw error;
612
+ }
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;
628
+ }
629
+ try {
630
+ if (!this.connectionForListen) {
631
+ yield this.initConnectionForListen();
632
+ }
633
+ yield this.connectionForListen.query(`LISTEN "${channel}"`);
634
+ }
635
+ catch (err) {
636
+ this._needToRestartConnectionForListen = true;
637
+ throw err;
638
+ }
639
+ this.listeners.on(channel, callback);
640
+ }
641
+ });
642
+ }
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);
651
+ }
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;
667
+ }
668
+ this.listeners.removeAllListeners(channel);
669
+ }
670
+ });
671
+ }
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
+ }
679
+ }
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
+ try {
685
+ return this.internalQuery({ connection, sql, params });
686
+ }
687
+ catch (err) {
688
+ if (hasConnectionForListen) {
689
+ this._needToRestartConnectionForListen = true;
690
+ }
691
+ throw err;
692
+ }
693
+ });
694
+ }
695
+ runRestartConnectionForListen() {
696
+ return (0, tslib_1.__awaiter)(this, void 0, void 0, function* () {
697
+ if (!this._needToRestartConnectionForListen) {
698
+ return null;
699
+ }
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;
715
+ }
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;
726
+ }
727
+ }
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
+ });
741
+ }
742
+ needToFixConnectionForListen() {
743
+ return this._needToRestartConnectionForListen;
744
+ }
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
+ });
753
+ }
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
+ });
760
+ }
761
+ }
762
+ exports.PgDb = PgDb;
763
+ exports.default = PgDb;
764
+ //# sourceMappingURL=pgDb.js.map