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.
- package/.env +6 -5
- package/.vscode/launch.json +51 -12
- package/CHANGELOG.md +48 -0
- package/jest.config.js +31 -21
- package/jest.globalSetup.js +18 -0
- package/jest.globalTeardown.js +6 -0
- package/jest.setup.ts +22 -0
- package/lib/bin/generateInterface.js +40 -45
- package/lib/bin/generateInterface.js.map +1 -1
- package/lib/connectionOptions.d.ts +1 -1
- package/lib/connectionOptions.js +1 -2
- package/lib/index.d.ts +6 -6
- package/lib/index.js +3 -9
- package/lib/index.js.map +1 -1
- package/lib/pgConverters.js +12 -22
- package/lib/pgConverters.js.map +1 -1
- package/lib/pgConverters.test.js +7 -10
- package/lib/pgConverters.test.js.map +1 -1
- package/lib/pgDb.d.ts +7 -7
- package/lib/pgDb.js +551 -596
- package/lib/pgDb.js.map +1 -1
- package/lib/pgDb.test.js +546 -548
- package/lib/pgDb.test.js.map +1 -1
- package/lib/pgDbInterface.d.ts +2 -2
- package/lib/pgDbInterface.js +2 -5
- package/lib/pgDbInterface.js.map +1 -1
- package/lib/pgDbLogger.js +1 -2
- package/lib/pgDbOperators.js +3 -5
- package/lib/pgDbOperators.js.map +1 -1
- package/lib/pgDbOperators.test.js +155 -158
- package/lib/pgDbOperators.test.js.map +1 -1
- package/lib/pgSchema.d.ts +2 -2
- package/lib/pgSchema.js +7 -8
- package/lib/pgSchema.js.map +1 -1
- package/lib/pgTable.d.ts +8 -9
- package/lib/pgTable.js +178 -217
- package/lib/pgTable.js.map +1 -1
- package/lib/pgTableInterface.d.ts +1 -1
- package/lib/pgTableInterface.js +1 -2
- package/lib/pgTableInterface.js.map +1 -1
- package/lib/pgUtils.d.ts +10 -10
- package/lib/pgUtils.js +36 -45
- package/lib/pgUtils.js.map +1 -1
- package/lib/queryAble.d.ts +5 -6
- package/lib/queryAble.js +248 -264
- package/lib/queryAble.js.map +1 -1
- package/lib/queryAbleInterface.d.ts +5 -6
- package/lib/queryAbleInterface.js +1 -2
- package/lib/queryAbleInterface.js.map +1 -1
- package/lib/queryWhere.d.ts +1 -1
- package/lib/queryWhere.js +20 -23
- package/lib/queryWhere.js.map +1 -1
- package/lib/test/pgServiceRestartTest.js +617 -648
- package/lib/test/pgServiceRestartTest.js.map +1 -1
- package/package.json +27 -26
- package/tsconfig.json +6 -12
package/lib/pgDb.js
CHANGED
|
@@ -1,22 +1,18 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
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
|
|
56
|
-
class PgDb extends
|
|
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
|
|
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
|
|
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
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
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
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
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
|
-
|
|
135
|
-
|
|
124
|
+
}
|
|
125
|
+
await new Promise((resolve) => this.pool.end(resolve));
|
|
136
126
|
}
|
|
137
|
-
static connect(config) {
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
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
|
-
|
|
151
|
-
|
|
152
|
-
|
|
138
|
+
}
|
|
139
|
+
let pgdb = new PgDb({ config: config });
|
|
140
|
+
return pgdb.init();
|
|
153
141
|
}
|
|
154
|
-
init() {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
this.
|
|
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
|
-
|
|
169
|
-
|
|
170
|
-
yield this.initFieldTypes();
|
|
171
|
-
});
|
|
153
|
+
async reload() {
|
|
154
|
+
await this.initSchemasAndTables();
|
|
155
|
+
await this.initFieldTypes();
|
|
172
156
|
}
|
|
173
|
-
initSchemasAndTables() {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
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
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
([type2oid['
|
|
233
|
-
([type2oid['
|
|
234
|
-
|
|
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
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
]
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
],
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
]
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
]
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
],
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
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
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
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
|
|
323
|
-
|
|
324
|
-
});
|
|
303
|
+
c.nspname = ANY($1)`, [schemaNames]);
|
|
304
|
+
allUsedTypeFields.forEach(oid => this.knownOids[oid] = true);
|
|
325
305
|
}
|
|
326
|
-
setTypeParser(typeName, parser, schemaName) {
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
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
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
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
|
-
|
|
385
|
-
|
|
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
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
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.
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
});
|
|
354
|
+
this.knownOids[fieldData.oid] = true;
|
|
355
|
+
});
|
|
356
|
+
}
|
|
409
357
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
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
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
367
|
+
async dedicatedConnectionEnd() {
|
|
368
|
+
if (this.connection) {
|
|
369
|
+
this.connection.off('error', QueryAble.connectionErrorListener);
|
|
370
|
+
try {
|
|
371
|
+
await this.connection.release();
|
|
427
372
|
}
|
|
428
|
-
|
|
429
|
-
|
|
373
|
+
catch (err) {
|
|
374
|
+
this.getLogger().error('Error while dedicated connection end.', err);
|
|
430
375
|
}
|
|
431
|
-
|
|
432
|
-
}
|
|
376
|
+
this.connection = null;
|
|
377
|
+
}
|
|
378
|
+
return this;
|
|
433
379
|
}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
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
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
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
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
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
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
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
|
-
|
|
490
|
-
|
|
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
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
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
|
|
542
|
-
|
|
543
|
-
|
|
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
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
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
|
-
|
|
504
|
+
else if (t[0] == '*/') {
|
|
505
|
+
inQuotedString = null;
|
|
568
506
|
}
|
|
569
507
|
}
|
|
570
|
-
if (
|
|
571
|
-
|
|
508
|
+
else if (!inQuotedString && t[0] == '--') {
|
|
509
|
+
line = '';
|
|
572
510
|
}
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
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
|
-
|
|
526
|
+
tmp += t[0];
|
|
590
527
|
}
|
|
591
528
|
}
|
|
592
|
-
if (
|
|
593
|
-
|
|
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
|
-
|
|
608
|
-
|
|
609
|
-
}).then(() => {
|
|
610
|
-
if (error) {
|
|
611
|
-
throw error;
|
|
533
|
+
catch (e) {
|
|
534
|
+
reject(e);
|
|
612
535
|
}
|
|
613
|
-
})
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
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
|
-
|
|
630
|
-
|
|
631
|
-
|
|
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
|
-
|
|
636
|
-
|
|
637
|
-
throw err;
|
|
552
|
+
if (consumer) {
|
|
553
|
+
consumer = consumer.then(resolve, reject);
|
|
638
554
|
}
|
|
639
|
-
|
|
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
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
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
|
-
|
|
653
|
-
if (
|
|
654
|
-
|
|
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.
|
|
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
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
631
|
+
async notify(channel, payload) {
|
|
632
|
+
if (this.needToFixConnectionForListen()) {
|
|
633
|
+
let restartConnectionError = await this.runRestartConnectionForListen();
|
|
634
|
+
if (restartConnectionError) {
|
|
635
|
+
throw restartConnectionError;
|
|
699
636
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
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
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
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
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
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
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
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
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
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
|
-
|
|
763
|
-
exports.default = PgDb;
|
|
718
|
+
export default PgDb;
|
|
764
719
|
//# sourceMappingURL=pgDb.js.map
|