pogi 2.11.0 → 3.0.0-beta3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/.env +5 -0
  2. package/.vscode/launch.json +47 -15
  3. package/jest.config.js +23 -0
  4. package/lib/bin/generateInterface.js +3 -3
  5. package/lib/bin/generateInterface.js.map +1 -1
  6. package/lib/connectionOptions.d.ts +7 -0
  7. package/lib/index.d.ts +1 -1
  8. package/lib/pgConverters.d.ts +9 -10
  9. package/lib/pgConverters.js +44 -39
  10. package/lib/pgConverters.js.map +1 -1
  11. package/lib/pgConverters.test.d.ts +1 -0
  12. package/lib/pgConverters.test.js +13 -0
  13. package/lib/pgConverters.test.js.map +1 -0
  14. package/lib/pgDb.d.ts +23 -31
  15. package/lib/pgDb.js +122 -103
  16. package/lib/pgDb.js.map +1 -1
  17. package/lib/pgDb.test.d.ts +1 -0
  18. package/lib/pgDb.test.js +1126 -0
  19. package/lib/pgDb.test.js.map +1 -0
  20. package/lib/pgDbInterface.d.ts +22 -0
  21. package/lib/pgDbInterface.js +11 -0
  22. package/lib/pgDbInterface.js.map +1 -0
  23. package/lib/pgDbOperators.d.ts +3 -3
  24. package/lib/pgDbOperators.js +4 -7
  25. package/lib/pgDbOperators.js.map +1 -1
  26. package/lib/pgDbOperators.test.d.ts +1 -0
  27. package/lib/pgDbOperators.test.js +313 -0
  28. package/lib/pgDbOperators.test.js.map +1 -0
  29. package/lib/pgSchema.d.ts +2 -3
  30. package/lib/pgSchema.js.map +1 -1
  31. package/lib/pgSchemaInterface.d.ts +0 -0
  32. package/lib/pgSchemaInterface.js +2 -0
  33. package/lib/pgSchemaInterface.js.map +1 -0
  34. package/lib/pgTable.d.ts +13 -38
  35. package/lib/pgTable.js +54 -54
  36. package/lib/pgTable.js.map +1 -1
  37. package/lib/pgTableInterface.d.ts +28 -0
  38. package/lib/pgTableInterface.js +4 -0
  39. package/lib/pgTableInterface.js.map +1 -0
  40. package/lib/pgUtils.d.ts +16 -6
  41. package/lib/pgUtils.js +162 -31
  42. package/lib/pgUtils.js.map +1 -1
  43. package/lib/queryAble.d.ts +16 -53
  44. package/lib/queryAble.js +58 -50
  45. package/lib/queryAble.js.map +1 -1
  46. package/lib/queryAbleInterface.d.ts +55 -0
  47. package/lib/queryAbleInterface.js +7 -0
  48. package/lib/queryAbleInterface.js.map +1 -0
  49. package/lib/queryWhere.d.ts +2 -2
  50. package/lib/queryWhere.js +19 -23
  51. package/lib/queryWhere.js.map +1 -1
  52. package/lib/test/pgDbOperatorSpec.d.ts +1 -0
  53. package/lib/test/pgDbOperatorSpec.js +326 -0
  54. package/lib/test/pgDbOperatorSpec.js.map +1 -0
  55. package/lib/test/pgDbSpec.d.ts +1 -0
  56. package/lib/test/pgDbSpec.js +1139 -0
  57. package/lib/test/pgDbSpec.js.map +1 -0
  58. package/lib/test/pgServiceRestartTest.d.ts +1 -0
  59. package/lib/test/pgServiceRestartTest.js +1532 -0
  60. package/lib/test/pgServiceRestartTest.js.map +1 -0
  61. package/package.json +21 -14
  62. package/{src/tsconfig.json → tsconfig.json} +11 -11
  63. package/spec/resources/init.sql +0 -122
  64. package/spec/resources/throw_exception.sql +0 -5
  65. package/spec/resources/tricky.sql +0 -13
  66. package/spec/run.js +0 -5
  67. package/spec/support/jasmine.json +0 -9
  68. package/src/bin/generateInterface.ts +0 -54
  69. package/src/connectionOptions.ts +0 -42
  70. package/src/index.ts +0 -6
  71. package/src/pgConverters.ts +0 -55
  72. package/src/pgDb.ts +0 -820
  73. package/src/pgDbLogger.ts +0 -13
  74. package/src/pgDbOperators.ts +0 -62
  75. package/src/pgSchema.ts +0 -15
  76. package/src/pgTable.ts +0 -401
  77. package/src/pgUtils.ts +0 -176
  78. package/src/queryAble.ts +0 -393
  79. package/src/queryWhere.ts +0 -326
  80. package/src/test/pgDbOperatorSpec.ts +0 -492
  81. package/src/test/pgDbSpec.ts +0 -1339
  82. package/src/test/pgServiceRestartTest.ts +0 -1500
package/src/queryAble.ts DELETED
@@ -1,393 +0,0 @@
1
- import { PgDbLogger } from "./pgDbLogger";
2
- import { pgUtils } from "./pgUtils";
3
- import * as stream from "stream";
4
-
5
- const util = require('util');
6
- const QueryStream = require('pg-query-stream');
7
- const through = require('through');
8
-
9
- export interface QueryOptions {
10
- limit?: number;
11
- offset?: number;
12
- orderBy?: string | string[] | { [fieldName: string]: 'asc' | 'desc' };//free text or column list
13
- groupBy?: string | string[];//free text or column list
14
- fields?: string | string[];//free text or column list
15
- logger?: PgDbLogger;
16
- forUpdate?: boolean;
17
- distinct?: boolean;
18
- skipUndefined?: boolean;
19
- }
20
-
21
- export interface SqlQueryOptions {
22
- logger?: PgDbLogger;
23
- }
24
-
25
- export interface ResultFieldType {
26
- name: string,
27
- tableID: number,
28
- columnID: number,
29
- dataTypeID: number,
30
- dataTypeSize: number,
31
- dataTypeModifier: number,
32
- format: string
33
- }
34
-
35
- export interface ResultType {
36
- command: 'SELECT' | 'UPDATE' | 'DELETE',
37
- rowCount: number,
38
- oid: number,
39
- rows: any[],
40
- fields: ResultFieldType[],
41
- _parsers: Function[][],
42
- RowCtor: Function[],
43
- rowsAsArray: boolean,
44
- _getTypeParser: Function[]
45
- }
46
-
47
- export interface PgRowResult {
48
- columns: string[],
49
- rows: any[]
50
- }
51
-
52
- let defaultLogger = {
53
- log: () => { },
54
- error: () => { }
55
- };
56
-
57
- export class QueryAble {
58
- db;
59
- schema;
60
- protected logger: PgDbLogger;
61
-
62
- constructor() {
63
- }
64
-
65
- setLogger(logger: PgDbLogger) {
66
- this.logger = logger;
67
- }
68
-
69
- getLogger(useConsoleAsDefault = false) {
70
- return this.logger || this.schema && this.schema.logger || this.db.logger || (useConsoleAsDefault ? console : defaultLogger);
71
- }
72
-
73
- /** alias to {@link query} */
74
- async run(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any[]> {
75
- return this.query(sql, params, options);
76
- }
77
-
78
- /**
79
- * Params can be
80
- * 1) array, then sql should have $1 $2 for placeholders
81
- * 2) object, then sql should have:
82
- * :example -> for params in statements (set/where), will be transformed to $1 $2 ...
83
- * :!example -> for DDL names (schema, table, column), will be replaced in the query
84
- * e.g. query('select * from a.b where id=$1;',['the_stage_is_set']);
85
- * e.g. query('select * from :!schema.:!table where id=:id;',{schema:'a',table:'b', id:'the_stage_is_set'});
86
- */
87
- async query(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any[]> {
88
- let connection = this.db.connection;
89
- let logger = (options && options.logger || this.getLogger(false));
90
- return this.internalQuery({ connection, sql, params, logger });
91
- }
92
-
93
- protected async internalQuery(options: { connection, sql: string, params?: any, logger?}): Promise<any[]>;
94
- protected async internalQuery(options: { connection, sql: string, params?: any, logger?, rowMode: true }): Promise<PgRowResult>;
95
- protected async internalQuery(options: { connection, sql: string, params?: any, logger?, rowMode?: boolean }): Promise<any[] | PgRowResult> {
96
- if (this.db.needToFixConnectionForListen()) {
97
- await this.db.runRestartConnectionForListen();
98
- }
99
- let { connection, sql, params, logger } = options;
100
- logger = logger || this.getLogger(false);
101
-
102
- try {
103
- if (params && !Array.isArray(params)) {
104
- let p = pgUtils.processNamedParams(sql, params);
105
- sql = p.sql;
106
- params = p.params;
107
- }
108
-
109
- if (connection) {
110
- logger.log('reused connection', sql, util.inspect(params, false, null), connection.processID);
111
- let res = await connection.query({ text: sql, values: params, rowMode: options?.rowMode ? 'array' : undefined });
112
- await this.checkAndFixOids(connection, res.fields);
113
- this.postProcessFields(res.rows, res.fields, logger);
114
-
115
- return options?.rowMode ? { columns: (res.fields || []).map(f => f.name), rows: res.rows || [] } : res.rows;
116
- } else {
117
- connection = await this.db.pool.connect();
118
- logger.log('new connection', sql, util.inspect(params, false, null), connection.processID);
119
- connection.on('error', (err: Error) => { });
120
- let res = await connection.query({ text: sql, values: params, rowMode: options?.rowMode ? 'array' : undefined });
121
- await this.checkAndFixOids(connection, res.fields);
122
- connection.release();
123
- connection = null;
124
- this.postProcessFields(res.rows, res.fields, logger);
125
-
126
- return options?.rowMode ? { columns: (res.fields || []).map(f => f.name), rows: res.rows || [] } : res.rows;
127
- }
128
- } catch (e) {
129
- pgUtils.logError(logger, { error: e, sql, params, connection });
130
- if (connection) {
131
- try {
132
- //If any problem has happened in a dedicated connection, (wrong sql format or non-accessible postgres server)
133
- //close the connection to be a free connection in the pool,
134
- //but keep the db.connection member non - null to crash in all of the following commands
135
- connection.release();
136
- } catch (e) {
137
- logger.error('connection error', e.message);
138
- }
139
- }
140
- throw e;
141
- }
142
- }
143
-
144
- /**
145
- * Same as query but response is two array: columns and rows and rows are arrays also not objects
146
- * This is useful for queries which have colliding column names
147
- */
148
- async queryAsRows(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<PgRowResult> {
149
- let connection = this.db.connection;
150
- let logger = (options && options.logger || this.getLogger(false));
151
- return this.internalQuery({ connection, sql, params, logger, rowMode: true });
152
- }
153
-
154
- /**
155
- * If the callback function return true, the connection will be closed.
156
- */
157
- async queryWithOnCursorCallback(sql: string, params: any[] | {}, options: SqlQueryOptions, callback: (any) => any): Promise<void> {
158
- if (this.db.needToFixConnectionForListen()) {
159
- await this.db.runRestartConnectionForListen();
160
- }
161
- let connection = this.db.connection;
162
- let logger = this.getLogger(true);
163
-
164
- try {
165
- if (params && !Array.isArray(params)) {
166
- let p = pgUtils.processNamedParams(sql, params);
167
- sql = p.sql;
168
- params = p.params;
169
- }
170
-
171
- let queryInternal = async () => {
172
- this.getLogger(false).log(sql, util.inspect(params, false, null), connection.processID);
173
- let fieldsToFix: ResultFieldType[];
174
- let isFirst = true;
175
-
176
- let query = new QueryStream(sql, params);
177
- let stream = connection.query(query);
178
- await new Promise((resolve, reject) => {
179
- query.handleError = (err: Error, connection) => {
180
- reject(err);
181
- };
182
- stream.on('data', (res) => {
183
- try {
184
- let fields = stream._result && stream._result.fields || stream.cursor._result && stream.cursor._result.fields;
185
- if (isFirst) {
186
- if (this.hasUnknownOids(fields)) {
187
- fieldsToFix = fields;
188
- stream.destroy();
189
- return;
190
- }
191
- isFirst = false;
192
- }
193
- this.postProcessFields([res], fields, this.getLogger(false));
194
-
195
- if (callback(res)) {
196
- stream.destroy();
197
- }
198
- } catch (e) {
199
- reject(e);
200
- }
201
- });
202
-
203
- stream.on('close', resolve);
204
- stream.on('error', reject);
205
- });
206
- if (fieldsToFix) {
207
- await this.checkAndFixOids(connection, fieldsToFix);
208
- query = new QueryStream(sql, params);
209
- stream = connection.query(query);
210
- await new Promise((resolve, reject) => {
211
- query.handleError = (err: Error, connection) => {
212
- reject(err);
213
- };
214
- stream.on('data', (res) => {
215
- try {
216
- let fields = stream._result && stream._result.fields || stream.cursor._result && stream.cursor._result.fields;
217
- this.postProcessFields([res], fields, this.getLogger(false));
218
-
219
- if (callback(res)) {
220
- stream.destroy();
221
- }
222
- } catch (e) {
223
- reject(e);
224
- }
225
- });
226
-
227
- stream.on('close', resolve);
228
- stream.on('error', reject);
229
- });
230
- }
231
- }
232
-
233
- if (connection) {
234
- await queryInternal();
235
- } else {
236
- connection = await this.db.pool.connect();
237
- logger.log('new connection', sql, util.inspect(params, false, null), connection.processID);
238
- connection.on('error', (err: Error) => { });
239
- await queryInternal();
240
- connection.release();
241
- connection = null;
242
- }
243
- } catch (e) {
244
- pgUtils.logError(logger, { error: e, sql, params, connection });
245
- if (connection) {
246
- try {
247
- connection.release();
248
- } catch (e) {
249
- logger.error('connection error', e.message);
250
- }
251
- }
252
- throw e;
253
- }
254
- }
255
-
256
- async queryAsStream(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<stream.Readable> {
257
- if (this.db.needToFixConnectionForListen()) {
258
- await this.db.runRestartConnectionForListen();
259
- }
260
- let connection = this.db.connection;
261
- let logger = (options && options.logger || this.getLogger(false));
262
- let pgStream;
263
- let queriable = this;
264
- let isFirst = true;
265
- let convertTypeFilter = through(function (data) {
266
- try {
267
- let fields = pgStream._result && pgStream._result.fields || pgStream.cursor._result && pgStream.cursor._result.fields;
268
- if (isFirst) {
269
- if (queriable.hasUnknownOids(fields)) {
270
- throw new Error('[337] Query returns fields with unknown oid.');
271
- }
272
- isFirst = false;
273
- }
274
- queriable.postProcessFields([data], fields, queriable.db.pgdbTypeParsers);
275
-
276
- this.emit('data', data);
277
- } catch (err) {
278
- this.emit('error', err);
279
- }
280
- });
281
- convertTypeFilter.on('error', (e) => {
282
- if (connection) {
283
- try {
284
- connection.release();
285
- } catch (e) {
286
- logger.error('connection error', e.message);
287
- }
288
- }
289
- connection = null;
290
- pgUtils.logError(logger, { error: e, sql, params, connection });
291
- });
292
-
293
- try {
294
- if (params && !Array.isArray(params)) {
295
- let p = pgUtils.processNamedParams(sql, params);
296
- sql = p.sql;
297
- params = p.params;
298
- }
299
-
300
- if (connection) {
301
- logger.log(sql, util.inspect(params, false, null), connection.processID);
302
- let query = new QueryStream(sql, params);
303
- query.handleError = (err: Error, connection) => {
304
- convertTypeFilter.emit('error', err);
305
- };
306
- pgStream = connection.query(query);
307
- return pgStream.pipe(convertTypeFilter);
308
- } else {
309
- connection = await this.db.pool.connect();
310
- logger.log('new connection', sql, util.inspect(params, false, null), connection.processID);
311
- connection.on('error', (err: Error) => { });
312
- let query = new QueryStream(sql, params);
313
- query.handleError = (err: Error, connection) => {
314
- convertTypeFilter.emit('error', err);
315
- };
316
- pgStream = connection.query(query);
317
- pgStream.on('close', () => {
318
- if (connection) connection.release();
319
- connection = null;
320
- });
321
- pgStream.on('error', (e) => {
322
- pgUtils.logError(logger, { error: e, sql, params, connection });
323
- if (connection) connection.release();
324
- connection = null;
325
- });
326
- return pgStream.pipe(convertTypeFilter);
327
- }
328
- } catch (e) {
329
- pgUtils.logError(logger, { error: e, sql, params, connection });
330
- throw e;
331
- }
332
- }
333
-
334
- async queryOne(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any> {
335
- let res = await this.query(sql, params, options);
336
- if (res.length > 1) {
337
- let logger = (options && options.logger || this.getLogger(false));
338
- let error = Error('More then one rows exists');
339
- pgUtils.logError(logger, { error, sql, params, connection: this.db.connection });
340
- throw error;
341
- }
342
- return res[0];
343
- }
344
-
345
- async queryFirst(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any> {
346
- let res = await this.query(sql, params, options);
347
- return res[0];
348
- }
349
-
350
- /** @return one record's one field */
351
- async queryOneField(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any> {
352
- let res = await this.query(sql, params, options);
353
- if (!res.length) {
354
- return null;
355
- }
356
- let fieldName = Object.keys(res[0])[0];
357
- if (res.length > 1) {
358
- let logger = (options && options.logger || this.getLogger(false));
359
- let error = Error('More then one field exists!');
360
- pgUtils.logError(logger, { error, sql, params, connection: this.db.connection });
361
- throw error;
362
- }
363
- return res.length == 1 ? res[0][fieldName] : null;
364
- }
365
-
366
- /** @return one column for the matching records */
367
- async queryOneColumn(sql: string, params?: any[] | {}, options?: SqlQueryOptions): Promise<any[]> {
368
- let res = await this.query(sql, params, options);
369
- if (!res.length) {
370
- return [];
371
- }
372
- let fieldName = Object.keys(res[0])[0];
373
- return res.map(r => r[fieldName]);
374
- }
375
-
376
- private postProcessFields(rows: any[], fields: ResultFieldType[], logger) {
377
- pgUtils.postProcessResult(rows, fields, this.db.pgdbTypeParsers);
378
- if (this.db.postProcessResult) this.db.postProcessResult(rows, fields, logger);
379
- }
380
-
381
- private async checkAndFixOids(connection, fields: ResultFieldType[]) {
382
- if (fields) {
383
- let oidList = fields.map(field => field.dataTypeID);
384
- return this.db.resetMissingParsers(connection, oidList);
385
- }
386
- }
387
-
388
- private hasUnknownOids(fields: ResultFieldType[]): boolean {
389
- let oidList = fields.map(field => field.dataTypeID);
390
- let unknownOids = oidList.filter(oid => !this.db.knownOids[oid]);
391
- return !!unknownOids.length;
392
- }
393
- }