prostgles-server 4.2.296 → 4.2.297

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 (76) hide show
  1. package/dist/DboBuilder/DboBuilder.d.ts.map +1 -1
  2. package/dist/DboBuilder/DboBuilder.js +5 -3
  3. package/dist/DboBuilder/DboBuilder.js.map +1 -1
  4. package/dist/DboBuilder/TableHandler/update.d.ts.map +1 -1
  5. package/dist/DboBuilder/TableHandler/update.js +2 -2
  6. package/dist/DboBuilder/TableHandler/update.js.map +1 -1
  7. package/dist/DboBuilder/ViewHandler/getValidatedSubscribeOptions.d.ts.map +1 -1
  8. package/dist/DboBuilder/ViewHandler/getValidatedSubscribeOptions.js +3 -1
  9. package/dist/DboBuilder/ViewHandler/getValidatedSubscribeOptions.js.map +1 -1
  10. package/dist/DboBuilder/ViewHandler/subscribe.d.ts.map +1 -1
  11. package/dist/DboBuilder/ViewHandler/subscribe.js +4 -3
  12. package/dist/DboBuilder/ViewHandler/subscribe.js.map +1 -1
  13. package/dist/DboBuilder/getSubscribeRelatedTables.d.ts.map +1 -1
  14. package/dist/DboBuilder/getSubscribeRelatedTables.js +5 -5
  15. package/dist/DboBuilder/getSubscribeRelatedTables.js.map +1 -1
  16. package/dist/PubSubManager/PubSubManager.d.ts +6 -13
  17. package/dist/PubSubManager/PubSubManager.d.ts.map +1 -1
  18. package/dist/PubSubManager/PubSubManager.js +2 -2
  19. package/dist/PubSubManager/PubSubManager.js.map +1 -1
  20. package/dist/PubSubManager/addSub.d.ts.map +1 -1
  21. package/dist/PubSubManager/addSub.js +7 -7
  22. package/dist/PubSubManager/addSub.js.map +1 -1
  23. package/dist/PubSubManager/addSync.d.ts.map +1 -1
  24. package/dist/PubSubManager/addSync.js +1 -1
  25. package/dist/PubSubManager/addSync.js.map +1 -1
  26. package/dist/PubSubManager/addTrigger.d.ts +4 -2
  27. package/dist/PubSubManager/addTrigger.d.ts.map +1 -1
  28. package/dist/PubSubManager/addTrigger.js +55 -3
  29. package/dist/PubSubManager/addTrigger.js.map +1 -1
  30. package/dist/PubSubManager/getCreatePubSubManagerError.js +1 -1
  31. package/dist/PubSubManager/getCreatePubSubManagerError.js.map +1 -1
  32. package/dist/PubSubManager/init/getDataWatchFunctionQuery.d.ts +5 -0
  33. package/dist/PubSubManager/init/getDataWatchFunctionQuery.d.ts.map +1 -1
  34. package/dist/PubSubManager/init/getDataWatchFunctionQuery.js +80 -51
  35. package/dist/PubSubManager/init/getDataWatchFunctionQuery.js.map +1 -1
  36. package/dist/PubSubManager/{getPubSubManagerInitQuery.d.ts → init/getPubSubManagerInitQuery.d.ts} +1 -1
  37. package/dist/PubSubManager/init/getPubSubManagerInitQuery.d.ts.map +1 -0
  38. package/dist/PubSubManager/{getPubSubManagerInitQuery.js → init/getPubSubManagerInitQuery.js} +22 -19
  39. package/dist/PubSubManager/init/getPubSubManagerInitQuery.js.map +1 -0
  40. package/dist/PubSubManager/{initPubSubManager.d.ts → init/initPubSubManager.d.ts} +1 -1
  41. package/dist/PubSubManager/init/initPubSubManager.d.ts.map +1 -0
  42. package/dist/PubSubManager/{initPubSubManager.js → init/initPubSubManager.js} +3 -3
  43. package/dist/PubSubManager/init/initPubSubManager.js.map +1 -0
  44. package/dist/PubSubManager/initialiseEventTriggers.js +1 -1
  45. package/dist/PubSubManager/initialiseEventTriggers.js.map +1 -1
  46. package/dist/PubSubManager/notifListener.d.ts.map +1 -1
  47. package/dist/PubSubManager/notifListener.js +15 -15
  48. package/dist/PubSubManager/notifListener.js.map +1 -1
  49. package/dist/PubSubManager/orphanTriggerCheck.js +1 -1
  50. package/dist/PubSubManager/orphanTriggerCheck.js.map +1 -1
  51. package/dist/TableConfig/runSQLFile.d.ts +3 -0
  52. package/dist/TableConfig/runSQLFile.d.ts.map +1 -1
  53. package/dist/TableConfig/runSQLFile.js +11 -1
  54. package/dist/TableConfig/runSQLFile.js.map +1 -1
  55. package/lib/DboBuilder/DboBuilder.ts +13 -3
  56. package/lib/DboBuilder/TableHandler/update.ts +2 -3
  57. package/lib/DboBuilder/ViewHandler/getValidatedSubscribeOptions.ts +9 -1
  58. package/lib/DboBuilder/ViewHandler/subscribe.ts +5 -3
  59. package/lib/DboBuilder/getSubscribeRelatedTables.ts +8 -5
  60. package/lib/PubSubManager/PubSubManager.ts +7 -12
  61. package/lib/PubSubManager/addSub.ts +10 -9
  62. package/lib/PubSubManager/addSync.ts +5 -1
  63. package/lib/PubSubManager/addTrigger.ts +77 -6
  64. package/lib/PubSubManager/getCreatePubSubManagerError.ts +1 -1
  65. package/lib/PubSubManager/init/getDataWatchFunctionQuery.ts +80 -50
  66. package/lib/PubSubManager/{getPubSubManagerInitQuery.ts → init/getPubSubManagerInitQuery.ts} +23 -20
  67. package/lib/PubSubManager/{initPubSubManager.ts → init/initPubSubManager.ts} +4 -4
  68. package/lib/PubSubManager/initialiseEventTriggers.ts +1 -1
  69. package/lib/PubSubManager/notifListener.ts +19 -28
  70. package/lib/PubSubManager/orphanTriggerCheck.ts +1 -1
  71. package/lib/TableConfig/runSQLFile.ts +19 -2
  72. package/package.json +2 -2
  73. package/dist/PubSubManager/getPubSubManagerInitQuery.d.ts.map +0 -1
  74. package/dist/PubSubManager/getPubSubManagerInitQuery.js.map +0 -1
  75. package/dist/PubSubManager/initPubSubManager.d.ts.map +0 -1
  76. package/dist/PubSubManager/initPubSubManager.js.map +0 -1
@@ -1,4 +1,7 @@
1
1
  import { type Prostgles } from "../Prostgles";
2
2
  export declare const runSQLFile: (prostgles: Prostgles) => Promise<number | undefined>;
3
+ /**
4
+ * Given an sql error, return the lines of the query that caused the error.
5
+ */
3
6
  export declare const getQueryErrorPositionInfo: (err: any, _fileContent?: string) => string | undefined;
4
7
  //# sourceMappingURL=runSQLFile.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"runSQLFile.d.ts","sourceRoot":"","sources":["../../lib/TableConfig/runSQLFile.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,eAAO,MAAM,UAAU,cAAqB,SAAS,gCAyBpD,CAAC;AAEF,eAAO,MAAM,yBAAyB,QAAS,GAAG,iBAAiB,MAAM,uBAcxE,CAAC"}
1
+ {"version":3,"file":"runSQLFile.d.ts","sourceRoot":"","sources":["../../lib/TableConfig/runSQLFile.ts"],"names":[],"mappings":"AACA,OAAO,EAAe,KAAK,SAAS,EAAE,MAAM,cAAc,CAAC;AAE3D,eAAO,MAAM,UAAU,cAAqB,SAAS,gCAyBpD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAS,GAAG,iBAAiB,MAAM,KAAG,MAAM,GAAG,SA4BpF,CAAC"}
@@ -28,8 +28,11 @@ const runSQLFile = async (prostgles) => {
28
28
  return res.data?.success;
29
29
  };
30
30
  exports.runSQLFile = runSQLFile;
31
+ /**
32
+ * Given an sql error, return the lines of the query that caused the error.
33
+ */
31
34
  const getQueryErrorPositionInfo = (err, _fileContent) => {
32
- const { position, length, query } = err, fileContent = _fileContent || query, lines = fileContent.split("\n");
35
+ const { position, length, query, internalPosition, internalQuery } = err, fileContent = _fileContent || query, lines = fileContent.split("\n");
33
36
  if (position && length && fileContent) {
34
37
  const startLine = Math.max(0, fileContent.substring(0, position).split("\n").length - 2), endLine = startLine + 3;
35
38
  return lines
@@ -37,6 +40,13 @@ const getQueryErrorPositionInfo = (err, _fileContent) => {
37
40
  .map((txt, i) => `${startLine + i + 1} ${i === 1 ? "->" : " "} ${txt}`)
38
41
  .join("\n");
39
42
  }
43
+ if (internalPosition && internalQuery) {
44
+ return (0, exports.getQueryErrorPositionInfo)({
45
+ query: internalQuery,
46
+ position: parseInt(internalPosition),
47
+ length: internalQuery.length,
48
+ });
49
+ }
40
50
  };
41
51
  exports.getQueryErrorPositionInfo = getQueryErrorPositionInfo;
42
52
  //# sourceMappingURL=runSQLFile.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"runSQLFile.js","sourceRoot":"","sources":["../../lib/TableConfig/runSQLFile.ts"],"names":[],"mappings":";;;AAAA,qDAA6C;AAC7C,4CAA2D;AAEpD,MAAM,UAAU,GAAG,KAAK,EAAE,SAAoB,EAAE,EAAE;IACvD,MAAM,EACJ,EAAE,EACF,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,GAC7B,GAAG,SAAS,CAAC;IACd,IAAI,CAAC,WAAW;QAAE,OAAO;IACzB,IAAI,CAAC,EAAE;QAAE,MAAM,YAAY,CAAC;IAC5B,MAAM,GAAG,GAAG,MAAM,IAAA,4BAAU,EAAC,KAAK,IAAI,EAAE;QACtC,MAAM,WAAW,GAAG,MAAM,IAAA,uBAAW,EAAC,WAAW,CAAC,CAAC;QAEnD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACvD,MAAM,OAAO,GAAG,IAAA,iCAAyB,EAAC,GAAG,EAAE,WAAW,CAAC,CAAC;YAC5D,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;YAC1E,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;IAChE,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,GAAG,CAAC,KAAK,CAAC;IAClB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,WAAW,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC;AAC3B,CAAC,CAAC;AAzBW,QAAA,UAAU,cAyBrB;AAEK,MAAM,yBAAyB,GAAG,CAAC,GAAQ,EAAE,YAAqB,EAAE,EAAE;IAC3E,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,GAA0D,EAC5F,WAAW,GAAG,YAAY,IAAI,KAAK,EACnC,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,IAAI,QAAQ,IAAI,MAAM,IAAI,WAAW,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,EACtF,OAAO,GAAG,SAAS,GAAG,CAAC,CAAC;QAE1B,OAAO,KAAK;aACT,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC;aACzB,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;aACvE,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;AACH,CAAC,CAAC;AAdW,QAAA,yBAAyB,6BAcpC"}
1
+ {"version":3,"file":"runSQLFile.js","sourceRoot":"","sources":["../../lib/TableConfig/runSQLFile.ts"],"names":[],"mappings":";;;AAAA,qDAA6C;AAC7C,4CAA2D;AAEpD,MAAM,UAAU,GAAG,KAAK,EAAE,SAAoB,EAAE,EAAE;IACvD,MAAM,EACJ,EAAE,EACF,IAAI,EAAE,EAAE,WAAW,EAAE,KAAK,EAAE,GAC7B,GAAG,SAAS,CAAC;IACd,IAAI,CAAC,WAAW;QAAE,OAAO;IACzB,IAAI,CAAC,EAAE;QAAE,MAAM,YAAY,CAAC;IAC5B,MAAM,GAAG,GAAG,MAAM,IAAA,4BAAU,EAAC,KAAK,IAAI,EAAE;QACtC,MAAM,WAAW,GAAG,MAAM,IAAA,uBAAW,EAAC,WAAW,CAAC,CAAC;QAEnD,MAAM,MAAM,GAAG,MAAM,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE;YACvD,MAAM,OAAO,GAAG,IAAA,iCAAyB,EAAC,GAAG,EAAE,WAAW,CAAC,CAAC;YAC5D,OAAO,CAAC,KAAK,CAAC,oCAAoC,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;YAC1E,OAAO,OAAO,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;QAC7B,CAAC,CAAC,CAAC;QACH,OAAO,EAAE,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC;IACpC,CAAC,CAAC,CAAC;IAEH,MAAM,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;IAChE,IAAI,GAAG,CAAC,KAAK,KAAK,SAAS,EAAE,CAAC;QAC5B,MAAM,GAAG,CAAC,KAAK,CAAC;IAClB,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,2CAA2C,EAAE,WAAW,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC;AAC3B,CAAC,CAAC;AAzBW,QAAA,UAAU,cAyBrB;AAEF;;GAEG;AACI,MAAM,yBAAyB,GAAG,CAAC,GAAQ,EAAE,YAAqB,EAAsB,EAAE;IAC/F,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,gBAAgB,EAAE,aAAa,EAAE,GAAG,GAMlE,EACD,WAAW,GAAG,YAAY,IAAI,KAAK,EACnC,KAAK,GAAG,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAElC,IAAI,QAAQ,IAAI,MAAM,IAAI,WAAW,EAAE,CAAC;QACtC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,WAAW,CAAC,SAAS,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,EACtF,OAAO,GAAG,SAAS,GAAG,CAAC,CAAC;QAE1B,OAAO,KAAK;aACT,KAAK,CAAC,SAAS,EAAE,OAAO,CAAC;aACzB,GAAG,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,EAAE,CAAC,GAAG,SAAS,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,IAAI,GAAG,EAAE,CAAC;aACvE,IAAI,CAAC,IAAI,CAAC,CAAC;IAChB,CAAC;IAED,IAAI,gBAAgB,IAAI,aAAa,EAAE,CAAC;QACtC,OAAO,IAAA,iCAAyB,EAAC;YAC/B,KAAK,EAAE,aAAa;YACpB,QAAQ,EAAE,QAAQ,CAAC,gBAAgB,CAAC;YACpC,MAAM,EAAE,aAAa,CAAC,MAAM;SAC7B,CAAC,CAAC;IACL,CAAC;AACH,CAAC,CAAC;AA5BW,QAAA,yBAAyB,6BA4BpC"}
@@ -7,8 +7,12 @@ import {
7
7
  PG_COLUMN_UDT_DATA_TYPE,
8
8
  SQLOptions,
9
9
  getJoinHandlers,
10
+ getSerialisableError,
10
11
  isDefined,
12
+ omitKeys,
11
13
  tryCatch,
14
+ tryCatchV2,
15
+ type AnyObject,
12
16
  } from "prostgles-types";
13
17
  import { getDBSchema } from "../DBSchemaBuilder";
14
18
  import { DB, Prostgles } from "../Prostgles";
@@ -40,6 +44,7 @@ import {
40
44
  import { getTablesForSchemaPostgresSQL } from "./getTablesForSchemaPostgresSQL";
41
45
  import { prepareShortestJoinPaths } from "./prepareShortestJoinPaths";
42
46
  import { cacheDBTypes, runSQL } from "./runSQL";
47
+ import { getQueryErrorPositionInfo } from "../TableConfig/runSQLFile";
43
48
 
44
49
  export * from "./DboBuilderTypes";
45
50
  export * from "./dboBuilderUtils";
@@ -109,9 +114,13 @@ export class DboBuilder {
109
114
  if (!canExecute)
110
115
  throw "PubSubManager based subscriptions not possible: Cannot run EXECUTE statements on this connection";
111
116
 
112
- const { pubSubManager, error, hasError } = await tryCatch(async () => {
117
+ const {
118
+ data: pubSubManager,
119
+ error,
120
+ hasError,
121
+ } = await tryCatchV2(async () => {
113
122
  const pubSubManager = await PubSubManager.create(this);
114
- return { pubSubManager };
123
+ return pubSubManager;
115
124
  });
116
125
  this._pubSubManager = pubSubManager;
117
126
  if (hasError || !this._pubSubManager) {
@@ -119,8 +128,9 @@ export class DboBuilder {
119
128
  type: "debug",
120
129
  command: "PubSubManager.create",
121
130
  duration: 0,
122
- error: getErrorAsObject(error),
131
+ error: getSerialisableError(error),
123
132
  });
133
+ console.error("Could not create PubSubManager", getQueryErrorPositionInfo(error));
124
134
  throw "Could not create this._pubSubManager check logs";
125
135
  }
126
136
  }
@@ -6,10 +6,9 @@ import {
6
6
  getErrorAsObject,
7
7
  getSerializedClientErrorFromPGError,
8
8
  withUserRLS,
9
- type TableHandlers,
10
9
  } from "../DboBuilder";
11
- import { getInsertTableRules, getReferenceColumnInserts } from "./insert/insertNestedRecords";
12
10
  import { prepareNewData } from "./DataValidator";
11
+ import { getInsertTableRules, getReferenceColumnInserts } from "./insert/insertNestedRecords";
13
12
  import { runInsertUpdateQuery } from "./runInsertUpdateQuery";
14
13
  import { TableHandler } from "./TableHandler";
15
14
  import { updateFile } from "./updateFile";
@@ -82,7 +81,7 @@ export async function update(
82
81
  );
83
82
  }
84
83
 
85
- const { data, allowedCols } = await prepareNewData({
84
+ const { data, allowedCols } = prepareNewData({
86
85
  row: newData,
87
86
  forcedData,
88
87
  allowedFields: fields,
@@ -16,6 +16,7 @@ export const getValidatedSubscribeOptions = (
16
16
  optional: true,
17
17
  },
18
18
  skipFirst: { type: "boolean", optional: true },
19
+ skipChangedColumnsCheck: { type: "boolean", optional: true },
19
20
  actions: {
20
21
  oneOf: [
21
22
  {
@@ -48,7 +49,13 @@ export const getValidatedSubscribeOptions = (
48
49
  }
49
50
 
50
51
  const publishedThrottle = subscribeRule?.throttle || 0;
51
- const { actions, throttleOpts, skipFirst, throttle = publishedThrottle } = data;
52
+ const {
53
+ actions,
54
+ throttleOpts,
55
+ skipFirst,
56
+ throttle = publishedThrottle,
57
+ skipChangedColumnsCheck,
58
+ } = data;
52
59
  if (actions && isEmpty(actions)) {
53
60
  throw `addSub: actions cannot be empty`;
54
61
  }
@@ -68,5 +75,6 @@ export const getValidatedSubscribeOptions = (
68
75
  skipFirst,
69
76
  throttle,
70
77
  throttleOpts,
78
+ skipChangedColumnsCheck,
71
79
  };
72
80
  };
@@ -81,7 +81,8 @@ async function subscribe(
81
81
  throw " Cannot have localFunc AND socket ";
82
82
  }
83
83
 
84
- const { throttle, throttleOpts, skipFirst, actions, ...selectParams } = params;
84
+ const { throttle, throttleOpts, skipFirst, actions, skipChangedColumnsCheck, ...selectParams } =
85
+ params;
85
86
 
86
87
  /** Ensure request is valid */
87
88
  await this.find(filter, { ...selectParams, limit: 0 }, undefined, table_rules, localParams);
@@ -101,6 +102,7 @@ async function subscribe(
101
102
  newQuery,
102
103
  });
103
104
 
105
+ const tracked_columns = newQuery.select.filter((s) => s.selected).flatMap((c) => c.fields);
104
106
  const commonSubOpts = {
105
107
  table_info: this.tableOrViewInfo,
106
108
  viewOptions,
@@ -110,11 +112,11 @@ async function subscribe(
110
112
  filter: { ...filter },
111
113
  selectParams: { ...selectParams },
112
114
  subscribeOptions: getValidatedSubscribeOptions(
113
- { actions, skipFirst, throttle, throttleOpts },
115
+ { actions, skipFirst, throttle, throttleOpts, skipChangedColumnsCheck },
114
116
  table_rules?.subscribe
115
117
  ),
116
118
  lastPushed: 0,
117
- newQuery,
119
+ tracked_columns,
118
120
  } as const;
119
121
 
120
122
  const pubSubManager = await this.dboBuilder.getPubSubManager();
@@ -34,12 +34,14 @@ export async function getSubscribeRelatedTables(
34
34
  /** TODO: this needs to be memoized on schema fetch */
35
35
  const viewName = this.name;
36
36
  const viewNameEscaped = this.escapedName;
37
- const { current_schema } = await this.db.oneOrNone("SELECT current_schema");
37
+ const { current_schema } = await this.db.one<{ current_schema: string }>(
38
+ "SELECT current_schema"
39
+ );
38
40
 
39
41
  /** Get list of used columns and their parent tables */
40
- let { def } = (await this.db.oneOrNone("SELECT pg_get_viewdef(${viewName}) as def", {
42
+ let { def } = await this.db.one<{ def: string }>("SELECT pg_get_viewdef(${viewName}) as def", {
41
43
  viewName,
42
- })) as { def: string };
44
+ });
43
45
  def = def.trim();
44
46
  if (def.endsWith(";")) {
45
47
  def = def.slice(0, -1);
@@ -53,7 +55,8 @@ export async function getSubscribeRelatedTables(
53
55
  }
54
56
  const { fields } = await this.dboBuilder.dbo.sql!(
55
57
  `SELECT * FROM ( \n ${def} \n ) prostgles_subscribe_view_definition LIMIT 0`,
56
- {}
58
+ {},
59
+ { returnType: "default-with-rollback" }
57
60
  );
58
61
  const tableColumns = fields.filter((f) => f.tableName && f.columnName);
59
62
 
@@ -96,7 +99,7 @@ export async function getSubscribeRelatedTables(
96
99
  )`;
97
100
 
98
101
  try {
99
- const { count } = await this.db.oneOrNone(`
102
+ const { count } = await this.db.one<{ count: number }>(`
100
103
  WITH ${asName(tableName)} AS (
101
104
  SELECT *
102
105
  FROM ${asName(tableName)}
@@ -13,10 +13,10 @@ import {
13
13
  import { PostgresNotifListenManager } from "../PostgresNotifListenManager";
14
14
  import { DB } from "../Prostgles";
15
15
  import { addSync } from "./addSync";
16
- import { addTrigger } from "./addTrigger";
16
+ import { addTrigger, type AddTriggerParams } from "./addTrigger";
17
17
  import { deleteOrphanedTriggers } from "./deleteOrphanedTriggers";
18
+ import { initPubSubManager } from "./init/initPubSubManager";
18
19
  import { initialiseEventTriggers } from "./initialiseEventTriggers";
19
- import { initPubSubManager } from "./initPubSubManager";
20
20
  import { refreshTriggers } from "./refreshTriggers";
21
21
 
22
22
  import {
@@ -35,9 +35,8 @@ import { ParsedTableRule } from "../PublishParser/PublishParser";
35
35
  import { syncData } from "../SyncReplication";
36
36
  import { addSub } from "./addSub";
37
37
  import { notifListener } from "./notifListener";
38
- import { pushSubData } from "./pushSubData";
39
38
  import { log } from "./PubSubManagerUtils";
40
- import type { NewQuery } from "../DboBuilder/QueryBuilder/QueryBuilder";
39
+ import { pushSubData } from "./pushSubData";
41
40
 
42
41
  export type BasicCallback = (err?: any, res?: any) => void;
43
42
 
@@ -101,7 +100,7 @@ export type SubscriptionParams = {
101
100
  channel_name: string;
102
101
 
103
102
  /**
104
- * If this is a view then an array with all related tables will be
103
+ * If this is a view then all related tables will be added triggers
105
104
  * */
106
105
  viewOptions?: ViewSubscriptionOptions;
107
106
  parentSubParams: Omit<SubscriptionParams, "parentSubParams"> | undefined;
@@ -113,7 +112,7 @@ export type SubscriptionParams = {
113
112
  filter: object;
114
113
  selectParams: SelectParams;
115
114
  subscribeOptions: SubscribeOptions;
116
- newQuery: NewQuery;
115
+ tracked_columns: string[] | undefined;
117
116
 
118
117
  localFuncs?: LocalFuncs;
119
118
  socket: PRGLIOSocket | undefined;
@@ -137,13 +136,9 @@ export type Subscription = Pick<
137
136
  | "table_info"
138
137
  | "filter"
139
138
  | "table_rules"
140
- | "newQuery"
139
+ | "tracked_columns"
141
140
  > & {
142
- triggers: {
143
- table_name: string;
144
- condition: string;
145
- is_related: boolean;
146
- }[];
141
+ triggers: AddTriggerParams[];
147
142
  };
148
143
 
149
144
  export type PubSubManagerTriggers = Record<string, { condition: string; hash: string }[]>;
@@ -1,8 +1,9 @@
1
1
  import { SubscriptionChannels } from "prostgles-types";
2
2
  import { VoidFunction } from "../SchemaWatch/SchemaWatch";
3
- import { tout } from "./initPubSubManager";
3
+ import { tout } from "./init/initPubSubManager";
4
4
  import { BasicCallback, PubSubManager, Subscription, SubscriptionParams } from "./PubSubManager";
5
5
  import { parseCondition } from "./PubSubManagerUtils";
6
+ import type { AddTriggerParams } from "./addTrigger";
6
7
 
7
8
  type AddSubscriptionParams = SubscriptionParams & {
8
9
  condition: string;
@@ -28,7 +29,7 @@ export async function addSub(
28
29
  viewOptions,
29
30
  table_info,
30
31
  subscribeOptions,
31
- newQuery,
32
+ tracked_columns,
32
33
  } = subscriptionParams;
33
34
  const table_name = table_info.name;
34
35
 
@@ -39,12 +40,12 @@ export async function addSub(
39
40
  throw "addSub: cannot have socket AND func";
40
41
  }
41
42
 
42
- const channel_name = `${this.socketChannelPreffix}.${table_name}.${JSON.stringify(filter)}.${JSON.stringify(selectParams)}.${"m"}.sub`;
43
+ const channel_name = `${this.socketChannelPreffix}.${table_name}.${JSON.stringify(filter)}.${JSON.stringify(selectParams)}.m.sub`;
43
44
  const mainTrigger = {
44
45
  table_name: table_name,
45
46
  condition: parseCondition(condition),
46
- is_related: false,
47
- } as const;
47
+ tracked_columns,
48
+ } satisfies AddTriggerParams;
48
49
 
49
50
  const newSub: Subscription = {
50
51
  channel_name,
@@ -59,7 +60,7 @@ export async function addSub(
59
60
  is_throttling: false,
60
61
  socket_id: socket?.id,
61
62
  table_rules,
62
- newQuery,
63
+ tracked_columns,
63
64
  triggers: [mainTrigger],
64
65
  };
65
66
 
@@ -85,8 +86,8 @@ export async function addSub(
85
86
  const relatedSub = {
86
87
  table_name: relatedTable.tableName,
87
88
  condition: parseCondition(relatedTable.condition),
88
- is_related: true,
89
- } as const;
89
+ tracked_columns: undefined,
90
+ } satisfies AddTriggerParams;
90
91
 
91
92
  newSub.triggers.push(relatedSub);
92
93
 
@@ -142,7 +143,7 @@ export async function addSub(
142
143
 
143
144
  this.subs.push(newSub);
144
145
 
145
- /** A view does not have triggers. Only related triggers */
146
+ /** A view will not have triggers. Related tables are added triggers instead */
146
147
  if (table_info.is_view) {
147
148
  if (!viewOptions?.relatedTables.length) {
148
149
  throw "PubSubManager: view parent_tables missing";
@@ -122,7 +122,11 @@ export async function addSync(
122
122
 
123
123
  upsertSync();
124
124
 
125
- await this.addTrigger({ table_name, condition: conditionParsed }, undefined, socket);
125
+ await this.addTrigger(
126
+ { table_name, condition: conditionParsed, tracked_columns: undefined },
127
+ undefined,
128
+ socket
129
+ );
126
130
 
127
131
  return { channelName };
128
132
  });
@@ -1,12 +1,19 @@
1
- import { tryCatchV2 } from "prostgles-types";
1
+ import { asName, pickKeys, tryCatchV2 } from "prostgles-types";
2
2
  import { type PubSubManager, ViewSubscriptionOptions } from "./PubSubManager";
3
3
  import * as crypto from "crypto";
4
4
  import { PRGLIOSocket } from "../DboBuilder/DboBuilderTypes";
5
5
  import { asValue, EXCLUDE_QUERY_FROM_SCHEMA_WATCH_ID } from "./PubSubManagerUtils";
6
+ import { udtNamesWithoutEqualityComparison } from "./init/getDataWatchFunctionQuery";
7
+ import type { TableHandler } from "../DboBuilder/TableHandler/TableHandler";
6
8
 
9
+ export type AddTriggerParams = {
10
+ table_name: string;
11
+ condition: string;
12
+ tracked_columns: string[] | undefined;
13
+ };
7
14
  export async function addTrigger(
8
15
  this: PubSubManager,
9
- params: { table_name: string; condition: string },
16
+ params: AddTriggerParams,
10
17
  viewOptions: ViewSubscriptionOptions | undefined,
11
18
  socket: PRGLIOSocket | undefined
12
19
  ) {
@@ -14,7 +21,6 @@ export async function addTrigger(
14
21
  const { table_name } = { ...params };
15
22
  let { condition } = { ...params };
16
23
  if (!table_name) throw "MISSING table_name";
17
-
18
24
  if (!condition || !condition.trim().length) {
19
25
  condition = "TRUE";
20
26
  }
@@ -29,6 +35,11 @@ export async function addTrigger(
29
35
  condHash: asValue(crypto.createHash("md5").update(condition).digest("hex")),
30
36
  };
31
37
 
38
+ const tableHandler = this.dbo[table_name];
39
+ if (!tableHandler) {
40
+ throw `Cannot add trigger. Tablehandler for ${table_name} not found`;
41
+ }
42
+
32
43
  await this.db.tx((t) =>
33
44
  t.any(`
34
45
  BEGIN WORK;
@@ -52,7 +63,8 @@ export async function addTrigger(
52
63
  condition_hash,
53
64
  app_id,
54
65
  related_view_name,
55
- related_view_def
66
+ related_view_def,
67
+ columns_info
56
68
  )
57
69
  VALUES (
58
70
  ${trgVals.tbl},
@@ -60,9 +72,20 @@ export async function addTrigger(
60
72
  ${trgVals.condHash},
61
73
  ${asValue(this.appId)},
62
74
  ${asValue(viewOptions?.viewName ?? null)},
63
- ${asValue(viewOptions?.definition ?? null)}
75
+ ${asValue(viewOptions?.definition ?? null)},
76
+ ${asValue(getColumnsInfo(params, tableHandler))}
64
77
  )
65
- ON CONFLICT DO NOTHING;
78
+ ON CONFLICT (app_id, table_name, condition_hash)
79
+ DO UPDATE /* upsert tracked_columns where necessary */
80
+ SET columns_info = CASE WHEN EXCLUDED.columns_info IS NOT NULL THEN
81
+ jsonb_set(
82
+ prostgles.app_triggers.columns_info,
83
+ '{tracked_columns}',
84
+ prostgles.app_triggers.columns_info->'tracked_columns' || EXCLUDED.columns_info->'tracked_columns'
85
+ )
86
+ END
87
+ WHERE prostgles.app_triggers.columns_info IS NOT NULL
88
+ ;
66
89
 
67
90
  COMMIT WORK;
68
91
  `)
@@ -93,3 +116,51 @@ export async function addTrigger(
93
116
 
94
117
  return addedTrigger;
95
118
  }
119
+
120
+ const getColumnsInfo = (
121
+ { tracked_columns, table_name }: AddTriggerParams,
122
+ tableHandler: Partial<TableHandler>
123
+ ) => {
124
+ if (tracked_columns && !tracked_columns.length) {
125
+ throw "tracked_columns cannot be defined and empty";
126
+ }
127
+
128
+ let hasPkey = false as boolean;
129
+ const cols = tableHandler.columns?.map((c) => {
130
+ hasPkey = hasPkey || c.is_pkey;
131
+ return {
132
+ ...pickKeys(c, ["name", "is_pkey"]),
133
+ cast_to: udtNamesWithoutEqualityComparison.includes(c.udt_name) ? "::TEXT" : "",
134
+ };
135
+ });
136
+ tracked_columns?.forEach((colName) => {
137
+ if (!cols?.some((c) => c.name === colName)) {
138
+ throw `tracked_columns ${colName} not found in table ${table_name}`;
139
+ }
140
+ });
141
+ const columns_info =
142
+ !hasPkey || !cols || !tracked_columns?.length || tracked_columns.length === cols.length ?
143
+ null
144
+ : {
145
+ join_condition: cols
146
+ .filter((c) => c.is_pkey)
147
+ .map((c) => `n.${asName(c.name)} = o.${asName(c.name)}`)
148
+ .join(" AND "),
149
+ tracked_columns: tracked_columns.reduce(
150
+ (acc, colName) => ({
151
+ ...acc,
152
+ [colName]: 1,
153
+ }),
154
+ {} as Record<string, number>
155
+ ),
156
+ where_statement: cols
157
+ .filter((c) => !c.is_pkey && tracked_columns.includes(c.name))
158
+ .map(
159
+ (c) =>
160
+ `column_name = ${asValue(c.name)} AND n.${asName(c.name)}${c.cast_to} IS DISTINCT FROM o.${asName(c.name)}${c.cast_to}`
161
+ )
162
+ .join(" OR \n"),
163
+ };
164
+
165
+ return columns_info;
166
+ };
@@ -1,5 +1,5 @@
1
1
  import { tryCatch, tryCatchV2 } from "prostgles-types";
2
- import { getPubSubManagerInitQuery } from "./getPubSubManagerInitQuery";
2
+ import { getPubSubManagerInitQuery } from "./init/getPubSubManagerInitQuery";
3
3
  import { getCanExecute } from "../DboBuilder/dboBuilderUtils";
4
4
  import { DboBuilder } from "../DboBuilder/DboBuilder";
5
5