prostgles-server 2.0.178 → 2.0.179

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 (98) hide show
  1. package/dist/AuthHandler.d.ts +4 -4
  2. package/dist/AuthHandler.d.ts.map +1 -1
  3. package/dist/DBSchemaBuilder.d.ts +6 -6
  4. package/dist/DBSchemaBuilder.d.ts.map +1 -1
  5. package/dist/DBSchemaBuilder.js +25 -8
  6. package/dist/DBSchemaBuilder.js.map +1 -1
  7. package/dist/DboBuilder.d.ts +20 -21
  8. package/dist/DboBuilder.d.ts.map +1 -1
  9. package/dist/DboBuilder.js +1 -1
  10. package/dist/DboBuilder.js.map +1 -1
  11. package/dist/Prostgles.d.ts +8 -10
  12. package/dist/Prostgles.d.ts.map +1 -1
  13. package/dist/Prostgles.js.map +1 -1
  14. package/dist/PublishParser.d.ts +37 -37
  15. package/dist/PublishParser.d.ts.map +1 -1
  16. package/dist/PublishParser.js.map +1 -1
  17. package/dist/index.d.ts +2 -3
  18. package/dist/index.d.ts.map +1 -1
  19. package/dist/index.js.map +1 -1
  20. package/lib/AuthHandler.d.ts +148 -0
  21. package/lib/AuthHandler.d.ts.map +1 -0
  22. package/lib/AuthHandler.js +411 -0
  23. package/lib/AuthHandler.ts +3 -3
  24. package/lib/DBEventsManager.d.ts +38 -0
  25. package/lib/DBEventsManager.d.ts.map +1 -0
  26. package/lib/DBEventsManager.js +136 -0
  27. package/lib/DBSchemaBuilder.d.ts +11 -0
  28. package/lib/DBSchemaBuilder.d.ts.map +1 -0
  29. package/lib/DBSchemaBuilder.js +102 -0
  30. package/lib/DBSchemaBuilder.ts +62 -27
  31. package/lib/DboBuilder.d.ts +428 -0
  32. package/lib/DboBuilder.d.ts.map +1 -0
  33. package/lib/DboBuilder.js +3078 -0
  34. package/lib/DboBuilder.ts +25 -25
  35. package/lib/FileManager.d.ts +168 -0
  36. package/lib/FileManager.d.ts.map +1 -0
  37. package/lib/FileManager.js +474 -0
  38. package/lib/Filtering.d.ts +15 -0
  39. package/lib/Filtering.d.ts.map +1 -0
  40. package/lib/Filtering.js +299 -0
  41. package/lib/PostgresNotifListenManager.d.ts +27 -0
  42. package/lib/PostgresNotifListenManager.d.ts.map +1 -0
  43. package/lib/PostgresNotifListenManager.js +122 -0
  44. package/lib/Prostgles.d.ts +193 -0
  45. package/lib/Prostgles.d.ts.map +1 -0
  46. package/lib/Prostgles.js +579 -0
  47. package/lib/Prostgles.ts +6 -6
  48. package/lib/PubSubManager.d.ts +157 -0
  49. package/lib/PubSubManager.d.ts.map +1 -0
  50. package/lib/PubSubManager.js +1400 -0
  51. package/lib/PublishParser.d.ts +262 -0
  52. package/lib/PublishParser.d.ts.map +1 -0
  53. package/lib/PublishParser.js +390 -0
  54. package/lib/PublishParser.ts +39 -38
  55. package/lib/QueryBuilder.d.ts +124 -0
  56. package/lib/QueryBuilder.d.ts.map +1 -0
  57. package/lib/QueryBuilder.js +1349 -0
  58. package/lib/SyncReplication.d.ts +34 -0
  59. package/lib/SyncReplication.d.ts.map +1 -0
  60. package/lib/SyncReplication.js +411 -0
  61. package/lib/TableConfig.d.ts +175 -0
  62. package/lib/TableConfig.d.ts.map +1 -0
  63. package/lib/TableConfig.js +231 -0
  64. package/lib/index.d.ts +10 -0
  65. package/lib/index.d.ts.map +1 -0
  66. package/lib/index.js +45 -0
  67. package/lib/index.ts +3 -4
  68. package/lib/shortestPath.d.ts +10 -0
  69. package/lib/shortestPath.d.ts.map +1 -0
  70. package/lib/shortestPath.js +111 -0
  71. package/lib/utils.d.ts +2 -0
  72. package/lib/utils.d.ts.map +1 -0
  73. package/lib/utils.js +5 -0
  74. package/package.json +3 -3
  75. package/tests/client/PID.txt +1 -1
  76. package/tests/client/index.d.ts +1 -1
  77. package/tests/client/index.d.ts.map +1 -1
  78. package/tests/client_only_queries.d.ts +4 -0
  79. package/tests/client_only_queries.d.ts.map +1 -0
  80. package/tests/isomorphic_queries.d.ts +6 -0
  81. package/tests/isomorphic_queries.d.ts.map +1 -0
  82. package/tests/server/DBoGenerated.d.ts +97 -193
  83. package/tests/server/dboTypeCheck.d.ts +2 -0
  84. package/tests/server/dboTypeCheck.d.ts.map +1 -0
  85. package/tests/server/dboTypeCheck.js +14 -0
  86. package/tests/server/dboTypeCheck.ts +17 -0
  87. package/tests/server/index.d.ts +2 -0
  88. package/tests/server/index.d.ts.map +1 -0
  89. package/tests/server/index.js +11 -11
  90. package/tests/server/index.ts +23 -16
  91. package/tests/server/package-lock.json +5 -5
  92. package/tests/server/publishTypeCheck.d.ts +2 -0
  93. package/tests/server/publishTypeCheck.d.ts.map +1 -0
  94. package/tests/server/publishTypeCheck.js +120 -0
  95. package/tests/server/publishTypeCheck.ts +129 -0
  96. package/tests/server/tsconfig.json +4 -5
  97. package/tests/server_only_queries.d.ts +2 -0
  98. package/tests/server_only_queries.d.ts.map +1 -0
@@ -0,0 +1,299 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseFilterItem = void 0;
4
+ const prostgles_types_1 = require("prostgles-types");
5
+ const DboBuilder_1 = require("./DboBuilder");
6
+ const parseFilterItem = (args) => {
7
+ const { filter: _f, select, tableAlias, pgp } = args;
8
+ if (!_f || (0, prostgles_types_1.isEmpty)(_f))
9
+ return "";
10
+ const mErr = (msg) => {
11
+ throw `${msg}: ${JSON.stringify(_f, null, 2)}`;
12
+ }, asValue = (v) => pgp.as.format("$1", [v]);
13
+ const fKeys = (0, prostgles_types_1.getKeys)(_f);
14
+ if (fKeys.length === 0) {
15
+ return "";
16
+ }
17
+ else if (fKeys.length > 1) {
18
+ return fKeys.map(fk => (0, exports.parseFilterItem)({
19
+ filter: { [fk]: _f[fk] },
20
+ select,
21
+ tableAlias,
22
+ pgp,
23
+ }))
24
+ .sort() /* sorted to ensure duplicate subscription channels are not created due to different condition order */
25
+ .join(" AND ");
26
+ }
27
+ const fKey = fKeys[0];
28
+ /* Exists filter */
29
+ if (prostgles_types_1.EXISTS_KEYS.find(k => k in _f)) {
30
+ // parseExistsFilter()
31
+ }
32
+ let selItem;
33
+ if (select)
34
+ selItem = select.find(s => fKey === s.alias);
35
+ let rightF = _f[fKey];
36
+ const getLeftQ = (selItm) => {
37
+ if (selItm.type === "function")
38
+ return selItm.getQuery();
39
+ return selItm.getQuery(tableAlias);
40
+ };
41
+ /**
42
+ * Parsed left side of the query
43
+ */
44
+ let leftQ; // = asName(selItem.alias);
45
+ /* Check if string notation. Build obj if necessary */
46
+ const dot_notation_delims = ["->", "."];
47
+ if (!selItem) {
48
+ /* See if dot notation. Pick the best matching starting string */
49
+ if (select) {
50
+ selItem = select.find(s => fKey.startsWith(s.alias) &&
51
+ dot_notation_delims.find(dn => fKey.slice(s.alias.length).startsWith(dn)));
52
+ }
53
+ if (!selItem) {
54
+ mErr("Bad filter. Could not match to a column or alias: ");
55
+ throw " ";
56
+ }
57
+ const remainingStr = fKey.slice(selItem.alias.length);
58
+ /* Is json path spec */
59
+ if (remainingStr.startsWith("->")) {
60
+ leftQ = getLeftQ(selItem);
61
+ const getSep = (fromIdx = 0) => {
62
+ const strPart = remainingStr.slice(fromIdx);
63
+ let idx = strPart.indexOf("->");
64
+ let idxx = strPart.indexOf("->>");
65
+ if (idx > -1) {
66
+ /* if -> matches then check if it's the last separator */
67
+ if (idx === idxx)
68
+ return { idx: idx + fromIdx, sep: "->>" };
69
+ return { idx: idx + fromIdx, sep: "->" };
70
+ }
71
+ idx = strPart.indexOf("->>");
72
+ if (idx > -1) {
73
+ return { idx: idx + fromIdx, sep: "->>" };
74
+ }
75
+ return undefined;
76
+ };
77
+ let currSep = getSep();
78
+ while (currSep) {
79
+ let nextSep = getSep(currSep.idx + currSep.sep.length);
80
+ let nextIdx = nextSep ? nextSep.idx : remainingStr.length;
81
+ /* If ending in set then add set as well into key */
82
+ if (nextSep && nextIdx + nextSep.sep.length === remainingStr.length) {
83
+ nextIdx = remainingStr.length;
84
+ nextSep = undefined;
85
+ }
86
+ // console.log({ currSep, nextSep })
87
+ leftQ += currSep.sep + asValue(remainingStr.slice(currSep.idx + currSep.sep.length, nextIdx));
88
+ currSep = nextSep;
89
+ }
90
+ /* Is collapsed filter spec e.g. { "col.$ilike": 'text' } */
91
+ }
92
+ else if (remainingStr.startsWith(".")) {
93
+ leftQ = getLeftQ(selItem);
94
+ let getSep = (fromIdx = 0) => {
95
+ const idx = remainingStr.slice(fromIdx).indexOf(".");
96
+ if (idx > -1)
97
+ return fromIdx + idx;
98
+ return idx;
99
+ };
100
+ let currIdx = getSep();
101
+ let res = {};
102
+ let curObj = res;
103
+ while (currIdx > -1) {
104
+ let nextIdx = getSep(currIdx + 1);
105
+ let nIdx = nextIdx > -1 ? nextIdx : remainingStr.length;
106
+ /* If ending in dot then add dot as well into key */
107
+ if (nextIdx + 1 === remainingStr.length) {
108
+ nIdx = remainingStr.length;
109
+ nextIdx = -1;
110
+ }
111
+ const key = remainingStr.slice(currIdx + 1, nIdx);
112
+ curObj[key] = nextIdx > -1 ? {} : _f[fKey];
113
+ curObj = curObj[key];
114
+ currIdx = nextIdx;
115
+ }
116
+ rightF = res;
117
+ }
118
+ else {
119
+ console.trace(141, select, selItem, remainingStr);
120
+ mErr("Bad filter. Could not find the valid col name or alias or col json path");
121
+ }
122
+ }
123
+ else {
124
+ leftQ = getLeftQ(selItem);
125
+ }
126
+ if (!leftQ)
127
+ mErr("Internal error: leftQ missing?!");
128
+ /* Matching sel item */
129
+ if ((0, DboBuilder_1.isPlainObject)(rightF)) {
130
+ const parseRightVal = (val, expect = null) => {
131
+ const checkIfArr = () => {
132
+ if (!Array.isArray(val))
133
+ return mErr("This type of filter/column expects an Array of items");
134
+ };
135
+ if (expect === "csv") {
136
+ checkIfArr();
137
+ return pgp.as.format("($1:csv)", [val]);
138
+ }
139
+ else if (expect === "array" || selItem && selItem.columnPGDataType && selItem.columnPGDataType === "ARRAY") {
140
+ checkIfArr();
141
+ return pgp.as.format(" ARRAY[$1:csv]", [val]);
142
+ }
143
+ return asValue(val);
144
+ };
145
+ const filterKeys = Object.keys(rightF);
146
+ if (filterKeys.length !== 1)
147
+ mErr("Bad filter. Expecting one key only");
148
+ const fOpType = filterKeys[0];
149
+ const fVal = rightF[fOpType];
150
+ let sOpType;
151
+ let sVal;
152
+ if (fVal && (0, DboBuilder_1.isPlainObject)(fVal)) {
153
+ const keys = Object.keys(fVal);
154
+ if (!keys.length || keys.length !== 1) {
155
+ return mErr("Bad filter. Expecting a nested object with one key only ");
156
+ }
157
+ sOpType = keys[0];
158
+ sVal = fVal[sOpType];
159
+ }
160
+ // console.log({ fOpType, fVal, sOpType })
161
+ /** JSON cannot be compared so we'll cast it to TEXT */
162
+ if (selItem?.column_udt_type === "json" || ["$ilike", "$like", "$nilike", "$nlike"].includes(fOpType)) {
163
+ leftQ += "::TEXT ";
164
+ }
165
+ /** st_makeenvelope */
166
+ if (prostgles_types_1.GeomFilterKeys.includes(fOpType) && sOpType && prostgles_types_1.GeomFilter_Funcs.includes(sOpType)) {
167
+ /** If leftQ is geography then this err can happen: 'Antipodal (180 degrees long) edge detected!' */
168
+ if (sOpType.toLowerCase() === "st_makeenvelope")
169
+ leftQ += "::geometry";
170
+ return leftQ + ` ${fOpType} ` + `${sOpType}${parseRightVal(sVal, "csv")}`;
171
+ }
172
+ else if (["=", "$eq"].includes(fOpType) && !sOpType) {
173
+ if (fVal === null)
174
+ return leftQ + " IS NULL ";
175
+ return leftQ + " = " + parseRightVal(fVal);
176
+ }
177
+ else if (["<>", "$ne"].includes(fOpType)) {
178
+ if (fVal === null)
179
+ return leftQ + " IS NOT NULL ";
180
+ return leftQ + " <> " + parseRightVal(fVal);
181
+ }
182
+ else if ([">", "$gt"].includes(fOpType)) {
183
+ return leftQ + " > " + parseRightVal(fVal);
184
+ }
185
+ else if (["<", "$lt"].includes(fOpType)) {
186
+ return leftQ + " < " + parseRightVal(fVal);
187
+ }
188
+ else if ([">=", "$gte"].includes(fOpType)) {
189
+ return leftQ + " >= " + parseRightVal(fVal);
190
+ }
191
+ else if (["<=", "$lte"].includes(fOpType)) {
192
+ return leftQ + " <= " + parseRightVal(fVal);
193
+ }
194
+ else if (["$in"].includes(fOpType)) {
195
+ if (!fVal?.length) {
196
+ return " FALSE ";
197
+ }
198
+ let _fVal = fVal.filter((v) => v !== null);
199
+ let c1 = "", c2 = "";
200
+ if (_fVal.length)
201
+ c1 = leftQ + " IN " + parseRightVal(_fVal, "csv");
202
+ if (fVal.includes(null))
203
+ c2 = ` ${leftQ} IS NULL `;
204
+ return [c1, c2].filter(c => c).join(" OR ");
205
+ }
206
+ else if (["$nin"].includes(fOpType)) {
207
+ if (!fVal?.length) {
208
+ return " TRUE ";
209
+ }
210
+ let _fVal = fVal.filter((v) => v !== null);
211
+ let c1 = "", c2 = "";
212
+ if (_fVal.length)
213
+ c1 = leftQ + " NOT IN " + parseRightVal(_fVal, "csv");
214
+ if (fVal.includes(null))
215
+ c2 = ` ${leftQ} IS NOT NULL `;
216
+ return [c1, c2].filter(c => c).join(" AND ");
217
+ }
218
+ else if (["$between"].includes(fOpType)) {
219
+ if (!Array.isArray(fVal) || fVal.length !== 2) {
220
+ return mErr("Between filter expects an array of two values");
221
+ }
222
+ return leftQ + " BETWEEN " + asValue(fVal[0]) + " AND " + asValue(fVal[1]);
223
+ }
224
+ else if (["$ilike"].includes(fOpType)) {
225
+ return leftQ + " ILIKE " + asValue(fVal);
226
+ }
227
+ else if (["$like"].includes(fOpType)) {
228
+ return leftQ + " LIKE " + asValue(fVal);
229
+ }
230
+ else if (["$nilike"].includes(fOpType)) {
231
+ return leftQ + " NOT ILIKE " + asValue(fVal);
232
+ }
233
+ else if (["$nlike"].includes(fOpType)) {
234
+ return leftQ + " NOT LIKE " + asValue(fVal);
235
+ /* MAYBE TEXT OR MAYBE ARRAY */
236
+ }
237
+ else if (["@>", "<@", "$contains", "$containedBy", "&&", "@@"].includes(fOpType)) {
238
+ let operand = fOpType === "@@" ? "@@" :
239
+ ["@>", "$contains"].includes(fOpType) ? "@>" :
240
+ ["&&"].includes(fOpType) ? "&&" :
241
+ "<@";
242
+ /* Array for sure */
243
+ if (Array.isArray(fVal)) {
244
+ return leftQ + operand + parseRightVal(fVal, "array");
245
+ /* FTSQuery */
246
+ }
247
+ else if (["@@"].includes(fOpType) && prostgles_types_1.TextFilter_FullTextSearchFilterKeys.includes(sOpType)) {
248
+ let lq = `to_tsvector(${leftQ}::text)`;
249
+ if (selItem && selItem.columnPGDataType === "tsvector")
250
+ lq = leftQ;
251
+ let res = `${lq} ${operand} ` + `${sOpType}${parseRightVal(sVal, "csv")}`;
252
+ return res;
253
+ }
254
+ else {
255
+ return mErr("Unrecognised filter operand: " + fOpType + " ");
256
+ }
257
+ }
258
+ else {
259
+ /** Maybe it's an object key which means it's an equality comparison against a json object */
260
+ if (selItem?.column_udt_type?.startsWith("json")) {
261
+ return leftQ + " = " + parseRightVal(rightF);
262
+ }
263
+ return mErr("Unrecognised filter operand: " + fOpType + " ");
264
+ }
265
+ }
266
+ else {
267
+ /* Is an equal filter */
268
+ if (rightF === null) {
269
+ return leftQ + " IS NULL ";
270
+ }
271
+ else {
272
+ return leftQ + " = " + asValue(rightF);
273
+ }
274
+ }
275
+ };
276
+ exports.parseFilterItem = parseFilterItem;
277
+ // ensure pgp is not NULL!!!
278
+ // const asValue = v => v;// pgp.as.value;
279
+ // const filters: FilterSpec[] = [
280
+ // ...(["ilike", "like"].map(op => ({
281
+ // operands: ["$" + op],
282
+ // tsDataTypes: ["any"] as TSDataType[],
283
+ // tsDefinition: ` { $${op}: string } `,
284
+ // // data_types:
285
+ // getQuery: (leftQuery: string, rightVal: any) => {
286
+ // return `${leftQuery}::text ${op.toUpperCase()} ${asValue(rightVal)}::text`
287
+ // }
288
+ // }))),
289
+ // {
290
+ // operands: ["", "="],
291
+ // tsDataTypes: ["any"],
292
+ // tsDefinition: ` { "=": any } | any `,
293
+ // // data_types:
294
+ // getQuery: (leftQuery: string, rightVal: any) => {
295
+ // if(rightVal === null) return`${leftQuery} IS NULL `;
296
+ // return `${leftQuery} = ${asValue(rightVal)}`;
297
+ // }
298
+ // }
299
+ // ];
@@ -0,0 +1,27 @@
1
+ import { DB } from "./Prostgles";
2
+ import pg from "pg-promise/typescript/pg-subset";
3
+ import pgPromise from "pg-promise";
4
+ export declare type PrglNotifListener = (args: {
5
+ length: number;
6
+ processId: number;
7
+ channel: string;
8
+ payload: string;
9
+ name: string;
10
+ }) => void;
11
+ export declare class PostgresNotifListenManager {
12
+ connection?: pgPromise.IConnected<{}, pg.IClient>;
13
+ db_pg: DB;
14
+ notifListener: PrglNotifListener;
15
+ db_channel_name: string;
16
+ isListening: any;
17
+ client: any;
18
+ static create: (db_pg: DB, notifListener: PrglNotifListener, db_channel_name: string) => Promise<PostgresNotifListenManager>;
19
+ constructor(db_pg: DB, notifListener: PrglNotifListener, db_channel_name: string, noInit?: boolean);
20
+ init(): Promise<PostgresNotifListenManager>;
21
+ isReady(): any;
22
+ startListening(): Promise<unknown>;
23
+ destroy: () => void;
24
+ stopListening: () => void;
25
+ reconnect(delay?: number | undefined, maxAttempts?: number | undefined): Promise<unknown>;
26
+ }
27
+ //# sourceMappingURL=PostgresNotifListenManager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"PostgresNotifListenManager.d.ts","sourceRoot":"","sources":["PostgresNotifListenManager.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,EAAE,EAAE,MAAM,aAAa,CAAC;AACjC,OAAO,EAAE,MAAM,iCAAiC,CAAC;AACjD,OAAO,SAAS,MAAM,YAAY,CAAC;AAEnC,oBAAY,iBAAiB,GAAG,CAAC,IAAI,EAAE;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAC;CAAE,KAAK,IAAI,CAAC;AACvI,qBAAa,0BAA0B;IACnC,UAAU,CAAC,EAAE,SAAS,CAAC,UAAU,CAAC,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC;IAClD,KAAK,EAAE,EAAE,CAAC;IACV,aAAa,EAAE,iBAAiB,CAAC;IACjC,eAAe,EAAE,MAAM,CAAC;IACxB,WAAW,EAAE,GAAG,CAAC;IACjB,MAAM,EAAE,GAAG,CAAC;IAEZ,MAAM,CAAC,MAAM,6BAA8B,iBAAiB,mBAAmB,MAAM,KAAG,QAAQ,0BAA0B,CAAC,CAG1H;gBAEW,KAAK,EAAE,EAAE,EAAE,aAAa,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,EAAE,MAAM,UAAQ;IAS1F,IAAI,IAAI,OAAO,CAAC,0BAA0B,CAAC;IAQjD,OAAO;IAIP,cAAc;IA+Bd,OAAO,aAEN;IAED,aAAa,aAKZ;IAED,SAAS,CAAC,KAAK,GAAE,MAAM,GAAG,SAAa,EAAE,WAAW,GAAE,MAAM,GAAG,SAAa;CAsD/E"}
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ /*---------------------------------------------------------------------------------------------
3
+ * Copyright (c) Stefan L. All rights reserved.
4
+ * Licensed under the MIT License. See LICENSE in the project root for license information.
5
+ *--------------------------------------------------------------------------------------------*/
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.PostgresNotifListenManager = void 0;
8
+ class PostgresNotifListenManager {
9
+ constructor(db_pg, notifListener, db_channel_name, noInit = false) {
10
+ this.destroy = () => {
11
+ if (this.connection)
12
+ this.connection.done();
13
+ };
14
+ this.stopListening = () => {
15
+ if (this.db_channel_name) {
16
+ if (this.connection)
17
+ this.connection.none('UNLISTEN $1~', this.db_channel_name);
18
+ if (this.client)
19
+ this.client.query('UNLISTEN $1~', this.db_channel_name);
20
+ }
21
+ };
22
+ if (!db_pg || !notifListener || !db_channel_name)
23
+ throw "PostgresNotifListenManager: db_pg OR notifListener OR db_channel_name MISSING";
24
+ this.db_pg = db_pg;
25
+ this.notifListener = notifListener;
26
+ this.db_channel_name = db_channel_name;
27
+ if (!noInit)
28
+ this.init();
29
+ }
30
+ async init() {
31
+ this.connection = undefined;
32
+ this.isListening = await this.startListening();
33
+ return this;
34
+ }
35
+ isReady() {
36
+ return this.isListening;
37
+ }
38
+ startListening() {
39
+ if (!this.db_pg || !this.notifListener)
40
+ throw "PostgresNotifListenManager: db_pg OR notifListener missing";
41
+ return this.reconnect() // = same as reconnect(0, 1)
42
+ .then(obj => {
43
+ return obj;
44
+ /* TODO: expose this within onReady */
45
+ // console.log('psqlWS - Successful Initial Connection');
46
+ // obj.done(); - releases the connection
47
+ /* HOW TO SEND NOTIF
48
+ Used for testing in conjunction with
49
+ SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname='db-name';
50
+
51
+ function sendNotifications() {
52
+ if (this.connection) {
53
+ this.connection.none('NOTIFY $1~, $2', [this.db_channel_name, 'my payload string'])
54
+ .catch(error => {
55
+ console.log('psqlWS - Failed to Notify:', error); // unlikely to ever happen
56
+ })
57
+ }
58
+ }
59
+ */
60
+ })
61
+ .catch(error => {
62
+ console.log('PostgresNotifListenManager: Failed Initial Connection:', error);
63
+ });
64
+ }
65
+ reconnect(delay = 0, maxAttempts = 0) {
66
+ if (!this.db_pg || !this.notifListener)
67
+ throw "db_pg OR notifListener missing";
68
+ delay = delay > 0 ? parseInt(delay + "") : 0;
69
+ maxAttempts = maxAttempts > 0 ? parseInt(maxAttempts + "") : 1;
70
+ const setListeners = (client, notifListener, db_channel_name) => {
71
+ client.on('notification', notifListener);
72
+ this.client = client;
73
+ if (!this.connection)
74
+ throw "Connection missing";
75
+ return this.connection.none('LISTEN $1~', db_channel_name)
76
+ .catch(error => {
77
+ console.log("PostgresNotifListenManager: unexpected error: ", error); // unlikely to ever happen
78
+ });
79
+ }, removeListeners = (client) => {
80
+ client.removeListener('notification', this.notifListener);
81
+ }, onConnectionLost = (err, e) => {
82
+ console.log('PostgresNotifListenManager: Connectivity Problem:', err);
83
+ this.connection = undefined; // prevent use of the broken connection
84
+ removeListeners(e.client);
85
+ this.reconnect(5000, 10) // retry 10 times, with 5-second intervals
86
+ .then(() => {
87
+ console.log('PostgresNotifListenManager: Successfully Reconnected');
88
+ })
89
+ .catch(() => {
90
+ // failed after 10 attempts
91
+ console.log('PostgresNotifListenManager: Connection Lost Permanently. TERMINATING NODE PROCESS');
92
+ process.exit(); // exiting the process
93
+ });
94
+ };
95
+ return new Promise((resolve, reject) => {
96
+ setTimeout(() => {
97
+ this.db_pg.connect({ direct: true, onLost: onConnectionLost })
98
+ .then(obj => {
99
+ this.connection = obj; // global connection is now available
100
+ resolve(obj);
101
+ return setListeners(obj.client, this.notifListener, this.db_channel_name);
102
+ })
103
+ .catch(error => {
104
+ console.log('PostgresNotifListenManager: Error Connecting:', error);
105
+ if (--maxAttempts) {
106
+ this.reconnect(delay, maxAttempts)
107
+ .then(resolve)
108
+ .catch(reject);
109
+ }
110
+ else {
111
+ reject(error);
112
+ }
113
+ });
114
+ }, delay);
115
+ });
116
+ }
117
+ }
118
+ exports.PostgresNotifListenManager = PostgresNotifListenManager;
119
+ PostgresNotifListenManager.create = (db_pg, notifListener, db_channel_name) => {
120
+ let res = new PostgresNotifListenManager(db_pg, notifListener, db_channel_name, true);
121
+ return res.init();
122
+ };
@@ -0,0 +1,193 @@
1
+ import * as pgPromise from 'pg-promise';
2
+ import pg = require('pg-promise/typescript/pg-subset');
3
+ import FileManager, { ImageOptions, LocalConfig, S3Config } from "./FileManager";
4
+ import AuthHandler, { Auth } from "./AuthHandler";
5
+ import TableConfigurator, { TableConfig } from "./TableConfig";
6
+ import { DboBuilder, DBHandlerServer, PRGLIOSocket } from "./DboBuilder";
7
+ export { DBHandlerServer };
8
+ export declare type PGP = pgPromise.IMain<{}, pg.IClient>;
9
+ import { AnyObject } from "prostgles-types";
10
+ import { Publish, PublishMethods, PublishParams, PublishParser } from "./PublishParser";
11
+ import { DBEventsManager } from "./DBEventsManager";
12
+ export declare type DB = pgPromise.IDatabase<{}, pg.IClient>;
13
+ declare type DbConnection = string | pg.IConnectionParameters<pg.IClient>;
14
+ declare type DbConnectionOpts = pg.IDefaults;
15
+ export declare const TABLE_METHODS: readonly ["update", "find", "findOne", "insert", "delete", "upsert"];
16
+ export declare const JOIN_TYPES: readonly ["one-many", "many-one", "one-one", "many-many"];
17
+ export declare type Join = {
18
+ tables: [string, string];
19
+ on: {
20
+ [key: string]: string;
21
+ };
22
+ type: typeof JOIN_TYPES[number];
23
+ };
24
+ export declare type Joins = Join[] | "inferred";
25
+ declare type Keywords = {
26
+ $and: string;
27
+ $or: string;
28
+ $not: string;
29
+ };
30
+ export declare type DeepPartial<T> = {
31
+ [P in keyof T]?: DeepPartial<T[P]>;
32
+ };
33
+ declare type ExpressApp = {
34
+ get: (routePath: string, cb: (req: {
35
+ params: {
36
+ name: string;
37
+ };
38
+ cookies: {
39
+ sid: string;
40
+ };
41
+ }, res: {
42
+ redirect: (redirectUrl: string) => any;
43
+ contentType: (type: string) => void;
44
+ sendFile: (fileName: string, opts?: {
45
+ root: string;
46
+ }) => any;
47
+ status: (code: number) => {
48
+ json: (response: AnyObject) => any;
49
+ };
50
+ }) => any) => any;
51
+ };
52
+ /**
53
+ * Allows uploading and downloading files.
54
+ * Currently supports only S3.
55
+ *
56
+ * @description
57
+ * Will create a media table that contains file metadata and urls
58
+ * Inserting a file into this table through prostgles will upload it to S3 and insert the relevant metadata into the media table
59
+ * Requesting a file from HTTP GET {fileUrlPath}/{fileId} will:
60
+ * 1. check auth (if provided)
61
+ * 2. check the permissions in publish (if provided)
62
+ * 3. redirect the request to the signed url (if allowed)
63
+ *
64
+ * Specifying referencedTables will:
65
+ * 1. create a column in that table called media
66
+ * 2. create a lookup table lookup_media_{referencedTable} that joins referencedTable to the media table
67
+ */
68
+ export declare type FileTableConfig = {
69
+ tableName?: string;
70
+ /**
71
+ * GET path used in serving media. defaults to /${tableName}
72
+ */
73
+ fileServeRoute?: string;
74
+ awsS3Config?: S3Config;
75
+ localConfig?: LocalConfig;
76
+ expressApp: ExpressApp;
77
+ referencedTables?: {
78
+ [tableName: string]: "one" | "many";
79
+ };
80
+ imageOptions?: ImageOptions;
81
+ };
82
+ export declare type ProstglesInitOptions<S = void> = {
83
+ dbConnection: DbConnection;
84
+ dbOptions?: DbConnectionOpts;
85
+ tsGeneratedTypesDir?: string;
86
+ io?: any;
87
+ publish?: Publish<S>;
88
+ publishMethods?: PublishMethods<S>;
89
+ publishRawSQL?(params: PublishParams<S>): ((boolean | "*") | Promise<(boolean | "*")>);
90
+ joins?: Joins;
91
+ schema?: string;
92
+ sqlFilePath?: string;
93
+ onReady(dbo: DBOFullyTyped<S>, db: DB): void;
94
+ transactions?: string | boolean;
95
+ wsChannelNamePrefix?: string;
96
+ onSocketConnect?(socket: PRGLIOSocket, dbo: DBOFullyTyped<S>, db?: DB): any;
97
+ onSocketDisconnect?(socket: PRGLIOSocket, dbo: DBOFullyTyped<S>, db?: DB): any;
98
+ auth?: Auth<S>;
99
+ DEBUG_MODE?: boolean;
100
+ watchSchemaType?:
101
+ /**
102
+ * Will check client queries for schema changes
103
+ * Default
104
+ */
105
+ "events"
106
+ /**
107
+ * Will set database event trigger for schema changes. Requires superuser
108
+ */
109
+ | "queries";
110
+ watchSchema?:
111
+ /**
112
+ * If true then DBoGenerated.d.ts will be updated and "onReady" will be called with new schema on both client and server
113
+ */
114
+ boolean
115
+ /**
116
+ * "hotReloadMode" will only rewrite the DBoGenerated.d.ts found in tsGeneratedTypesDir
117
+ * This is meant to be used in development when server restarts on file change
118
+ */
119
+ | "hotReloadMode"
120
+ /**
121
+ * Function called when schema changes. Nothing else triggered
122
+ */
123
+ | ((event: {
124
+ command: string;
125
+ query: string;
126
+ }) => void)
127
+ /**
128
+ * Schema checked for changes every 'checkIntervalMillis" milliseconds
129
+ */
130
+ | {
131
+ checkIntervalMillis: number;
132
+ };
133
+ keywords?: Keywords;
134
+ onNotice?: (notice: AnyObject, message?: string) => void;
135
+ fileTable?: FileTableConfig;
136
+ tableConfig?: TableConfig;
137
+ };
138
+ export declare type OnReady = {
139
+ dbo: DBHandlerServer;
140
+ db: DB;
141
+ };
142
+ import { DBOFullyTyped } from "./DBSchemaBuilder";
143
+ export declare class Prostgles {
144
+ opts: ProstglesInitOptions;
145
+ db?: DB;
146
+ pgp?: PGP;
147
+ dbo?: DBHandlerServer;
148
+ _dboBuilder?: DboBuilder;
149
+ get dboBuilder(): DboBuilder;
150
+ set dboBuilder(d: DboBuilder);
151
+ publishParser?: PublishParser;
152
+ authHandler?: AuthHandler;
153
+ keywords: {
154
+ $filter: string;
155
+ $and: string;
156
+ $or: string;
157
+ $not: string;
158
+ };
159
+ private loaded;
160
+ dbEventsManager?: DBEventsManager;
161
+ fileManager?: FileManager;
162
+ tableConfigurator?: TableConfigurator;
163
+ isMedia(tableName: string): boolean;
164
+ constructor(params: ProstglesInitOptions);
165
+ destroyed: boolean;
166
+ onSchemaChange(event: {
167
+ command: string;
168
+ query: string;
169
+ }): Promise<void>;
170
+ checkDb(): void;
171
+ getTSFileName(): {
172
+ fileName: string;
173
+ fullPath: string;
174
+ };
175
+ private getFileText;
176
+ writeDBSchema(force?: boolean): void;
177
+ refreshDBO: () => Promise<DBHandlerServer>;
178
+ isSuperUser: boolean;
179
+ schema_checkIntervalMillis: any;
180
+ init(onReady: (dbo: DBOFullyTyped, db: DB) => any): Promise<{
181
+ db: DBOFullyTyped;
182
+ _db: DB;
183
+ pgp: PGP;
184
+ io?: any;
185
+ destroy: () => Promise<boolean>;
186
+ }>;
187
+ runSQLFile(filePath: string): Promise<any[][]>;
188
+ connectedSockets: any[];
189
+ setSocketEvents(): Promise<void>;
190
+ pushSocketSchema: (socket: any) => Promise<void>;
191
+ }
192
+ export declare function isSuperUser(db: DB): Promise<boolean>;
193
+ //# sourceMappingURL=Prostgles.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"Prostgles.d.ts","sourceRoot":"","sources":["Prostgles.ts"],"names":[],"mappings":"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"}