prostgles-server 4.2.624 → 4.2.625

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 (135) hide show
  1. package/dist/Audit/AuditTable.d.ts +2 -1
  2. package/dist/Audit/AuditTable.d.ts.map +1 -1
  3. package/dist/Audit/AuditTable.js +3 -2
  4. package/dist/Audit/AuditTable.js.map +1 -1
  5. package/dist/Audit/getAuditTableRules.d.ts +7 -0
  6. package/dist/Audit/getAuditTableRules.d.ts.map +1 -0
  7. package/dist/Audit/getAuditTableRules.js +191 -0
  8. package/dist/Audit/getAuditTableRules.js.map +1 -0
  9. package/dist/Audit/getAuditTriggerConfig.d.ts.map +1 -1
  10. package/dist/Audit/getAuditTriggerConfig.js +14 -1
  11. package/dist/Audit/getAuditTriggerConfig.js.map +1 -1
  12. package/dist/DBSchemaBuilder/getDBGeneratedSchema.d.ts.map +1 -1
  13. package/dist/DBSchemaBuilder/getDBGeneratedSchema.js +1 -2
  14. package/dist/DBSchemaBuilder/getDBGeneratedSchema.js.map +1 -1
  15. package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts +10 -5
  16. package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
  17. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +90 -71
  18. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
  19. package/dist/DboBuilder/QueryBuilder/getJoinQuery.d.ts.map +1 -1
  20. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js +3 -2
  21. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js.map +1 -1
  22. package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts +2 -2
  23. package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts.map +1 -1
  24. package/dist/DboBuilder/QueryBuilder/getNewQuery.js +53 -116
  25. package/dist/DboBuilder/QueryBuilder/getNewQuery.js.map +1 -1
  26. package/dist/DboBuilder/QueryBuilder/getQuerySource.d.ts +18 -0
  27. package/dist/DboBuilder/QueryBuilder/getQuerySource.d.ts.map +1 -0
  28. package/dist/DboBuilder/QueryBuilder/getQuerySource.js +29 -0
  29. package/dist/DboBuilder/QueryBuilder/getQuerySource.js.map +1 -0
  30. package/dist/DboBuilder/QueryBuilder/getSelectQuery.d.ts.map +1 -1
  31. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js +6 -2
  32. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js.map +1 -1
  33. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.d.ts +13 -0
  34. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.d.ts.map +1 -0
  35. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.js +57 -0
  36. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.js.map +1 -0
  37. package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
  38. package/dist/DboBuilder/TableHandler/TableHandler.js +2 -1
  39. package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
  40. package/dist/DboBuilder/TableHandler/delete.d.ts.map +1 -1
  41. package/dist/DboBuilder/TableHandler/delete.js +2 -1
  42. package/dist/DboBuilder/TableHandler/delete.js.map +1 -1
  43. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.d.ts.map +1 -1
  44. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js +2 -1
  45. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js.map +1 -1
  46. package/dist/DboBuilder/TableHandler/update.d.ts.map +1 -1
  47. package/dist/DboBuilder/TableHandler/update.js +2 -1
  48. package/dist/DboBuilder/TableHandler/update.js.map +1 -1
  49. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +6 -16
  50. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
  51. package/dist/DboBuilder/ViewHandler/ViewHandler.js +2 -7
  52. package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
  53. package/dist/DboBuilder/ViewHandler/find.d.ts.map +1 -1
  54. package/dist/DboBuilder/ViewHandler/find.js +1 -1
  55. package/dist/DboBuilder/ViewHandler/find.js.map +1 -1
  56. package/dist/DboBuilder/ViewHandler/getExistsCondition.d.ts +1 -1
  57. package/dist/DboBuilder/ViewHandler/getExistsCondition.d.ts.map +1 -1
  58. package/dist/DboBuilder/ViewHandler/getExistsCondition.js +24 -13
  59. package/dist/DboBuilder/ViewHandler/getExistsCondition.js.map +1 -1
  60. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts +4 -1
  61. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts.map +1 -1
  62. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js +20 -14
  63. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js.map +1 -1
  64. package/dist/DboBuilder/ViewHandler/prepareWhere.d.ts +7 -3
  65. package/dist/DboBuilder/ViewHandler/prepareWhere.d.ts.map +1 -1
  66. package/dist/DboBuilder/ViewHandler/prepareWhere.js +30 -23
  67. package/dist/DboBuilder/ViewHandler/prepareWhere.js.map +1 -1
  68. package/dist/DboBuilder/getCondition.d.ts +2 -1
  69. package/dist/DboBuilder/getCondition.d.ts.map +1 -1
  70. package/dist/DboBuilder/getCondition.js +9 -8
  71. package/dist/DboBuilder/getCondition.js.map +1 -1
  72. package/dist/DboBuilder/getSubscribeRelatedTables.d.ts.map +1 -1
  73. package/dist/DboBuilder/getSubscribeRelatedTables.js +3 -2
  74. package/dist/DboBuilder/getSubscribeRelatedTables.js.map +1 -1
  75. package/dist/DboBuilder/parseUpdateRules.d.ts.map +1 -1
  76. package/dist/DboBuilder/parseUpdateRules.js +3 -2
  77. package/dist/DboBuilder/parseUpdateRules.js.map +1 -1
  78. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts +2 -2
  79. package/dist/Prostgles.d.ts.map +1 -1
  80. package/dist/Prostgles.js +2 -0
  81. package/dist/Prostgles.js.map +1 -1
  82. package/dist/ProstglesContext.spec.js +25 -0
  83. package/dist/ProstglesContext.spec.js.map +1 -1
  84. package/dist/PubSubManager/PubSubManager.d.ts +1 -1
  85. package/dist/PublishParser/PublishParser.d.ts.map +1 -1
  86. package/dist/PublishParser/PublishParser.js +15 -4
  87. package/dist/PublishParser/PublishParser.js.map +1 -1
  88. package/dist/PublishParser/applyScopeToTableRules.d.ts +0 -1
  89. package/dist/PublishParser/applyScopeToTableRules.d.ts.map +1 -1
  90. package/dist/PublishParser/applyScopeToTableRules.js +3 -7
  91. package/dist/PublishParser/applyScopeToTableRules.js.map +1 -1
  92. package/dist/PublishParser/getPublishedTableNames.d.ts.map +1 -1
  93. package/dist/PublishParser/getPublishedTableNames.js +16 -0
  94. package/dist/PublishParser/getPublishedTableNames.js.map +1 -1
  95. package/dist/PublishParser/publishTypesAndUtils.d.ts +0 -4
  96. package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
  97. package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
  98. package/dist/TableConfig/getColumnSQLDefinitionQuery.d.ts.map +1 -1
  99. package/dist/TableConfig/getColumnSQLDefinitionQuery.js +1 -2
  100. package/dist/TableConfig/getColumnSQLDefinitionQuery.js.map +1 -1
  101. package/dist/index.d.ts +1 -1
  102. package/dist/index.d.ts.map +1 -1
  103. package/dist/index.js +2 -1
  104. package/dist/index.js.map +1 -1
  105. package/lib/Audit/AuditTable.ts +4 -3
  106. package/lib/Audit/getAuditTableRules.ts +288 -0
  107. package/lib/Audit/getAuditTriggerConfig.ts +14 -1
  108. package/lib/DBSchemaBuilder/getDBGeneratedSchema.ts +1 -2
  109. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +118 -90
  110. package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +3 -2
  111. package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +111 -194
  112. package/lib/DboBuilder/QueryBuilder/getQuerySource.ts +55 -0
  113. package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +8 -2
  114. package/lib/DboBuilder/QueryBuilder/parseJoinSelect.ts +73 -0
  115. package/lib/DboBuilder/TableHandler/TableHandler.ts +3 -6
  116. package/lib/DboBuilder/TableHandler/delete.ts +2 -1
  117. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +2 -1
  118. package/lib/DboBuilder/TableHandler/update.ts +2 -1
  119. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +6 -12
  120. package/lib/DboBuilder/ViewHandler/find.ts +0 -1
  121. package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +35 -28
  122. package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +22 -14
  123. package/lib/DboBuilder/ViewHandler/prepareWhere.ts +48 -27
  124. package/lib/DboBuilder/getCondition.ts +11 -10
  125. package/lib/DboBuilder/getSubscribeRelatedTables.ts +3 -2
  126. package/lib/DboBuilder/parseUpdateRules.ts +3 -2
  127. package/lib/Prostgles.ts +1 -0
  128. package/lib/ProstglesContext.spec.ts +30 -0
  129. package/lib/PublishParser/PublishParser.ts +33 -8
  130. package/lib/PublishParser/applyScopeToTableRules.ts +1 -7
  131. package/lib/PublishParser/getPublishedTableNames.ts +22 -0
  132. package/lib/PublishParser/publishTypesAndUtils.ts +0 -5
  133. package/lib/TableConfig/getColumnSQLDefinitionQuery.ts +8 -2
  134. package/lib/index.ts +1 -0
  135. package/package.json +1 -1
@@ -1,255 +1,172 @@
1
- import type {
2
- DetailedJoinSelect,
3
- JoinPath,
4
- JoinSelect,
5
- RawJoinPath,
6
- SelectParams,
7
- SimpleJoinSelect,
8
- } from "prostgles-types";
9
- import { asName, getKeys, includes, isEmpty, omitKeys } from "prostgles-types";
1
+ import type { SelectParams } from "prostgles-types";
2
+ import { asName, isEmpty, omitKeys } from "prostgles-types";
10
3
  import type { ParsedTableRule } from "../../PublishParser/PublishParser";
11
4
  import type { Filter, LocalParams, PGIdentifier, ValidatedTableRules } from "../DboBuilder";
12
5
  import type { ViewHandler } from "../ViewHandler/ViewHandler";
13
6
  import { parseJoinPath } from "../ViewHandler/parseJoinPath";
14
7
  import { prepareSortItems } from "../ViewHandler/prepareSortItems";
15
- import type { PrepareWhereParams } from "../ViewHandler/prepareWhere";
8
+ import { prepareWhere, type PrepareWhereParams } from "../ViewHandler/prepareWhere";
16
9
  import { COMPUTED_FIELDS } from "./Functions/COMPUTED_FIELDS";
17
10
  import { FUNCTIONS } from "./Functions/Functions";
18
11
  import type { NewQuery, NewQueryJoin } from "./QueryBuilder";
19
12
  import { SelectItemBuilder } from "./QueryBuilder";
13
+ import { ROOT_TABLE_ALIAS } from "./getSelectQuery";
20
14
 
21
- const JOIN_KEYS = ["$innerJoin", "$leftJoin"] as const;
22
- const JOIN_PARAM_KEYS = getKeys({
23
- $condition: 1,
24
- filter: 1,
25
- having: 1,
26
- limit: 1,
27
- offset: 1,
28
- orderBy: 1,
29
- select: 1,
30
- } satisfies Record<keyof Omit<DetailedJoinSelect, (typeof JOIN_KEYS)[number]>, 1>);
31
-
32
- type ParsedJoin =
33
- | {
34
- type: "detailed";
35
- params: DetailedJoinSelect & {
36
- table: DetailedJoinSelect["$leftJoin"];
37
- path: RawJoinPath;
38
- };
39
- }
40
- | { type: "simple"; params: SimpleJoinSelect }
41
- | { type?: undefined; error: string };
42
-
43
- const parseJoinSelect = (joinParams: JoinSelect): ParsedJoin => {
44
- if (!(joinParams as string)) {
45
- return {
46
- error: "Empty join params",
47
- };
48
- }
49
- if (typeof joinParams === "string") {
50
- if ((joinParams as string) !== "*") {
51
- throw "Join select can be * or { field: 1 }";
52
- }
53
- return {
54
- type: "simple",
55
- params: joinParams,
56
- };
57
- }
58
- const [joinKey, ...otherKeys] = getKeys(joinParams).filter((k) => includes(JOIN_KEYS, k));
59
- if (otherKeys.length) {
60
- return {
61
- error: "Cannot specify more than one join type ( $innerJoin OR $leftJoin )",
62
- };
63
- } else if (joinKey) {
64
- /* Full option join { field_name: db.innerJoin.table_name(filter, select) } */
65
- const invalidParams = Object.keys(joinParams).filter(
66
- (k) => !includes([...JOIN_PARAM_KEYS, ...JOIN_KEYS], k),
67
- );
68
- if (invalidParams.length) {
69
- throw "Invalid join params: " + invalidParams.join(", ");
70
- }
71
- const path = joinParams[joinKey] as string | JoinPath[];
72
- if (Array.isArray(path) && !path.length) {
73
- throw `Cannot have an empty join path/tableName ${joinKey}`;
74
- }
75
- return {
76
- type: "detailed",
77
- params: {
78
- ...(joinParams as DetailedJoinSelect),
79
- path,
80
- table: typeof path === "string" ? path : path.at(-1)!.table,
81
- },
82
- };
83
- }
84
-
85
- return {
86
- type: "simple",
87
- params: joinParams as SimpleJoinSelect,
88
- };
89
- };
90
-
91
- export async function getNewQuery(
92
- _this: ViewHandler,
15
+ export const getNewQuery = async (
16
+ viewHandler: ViewHandler,
93
17
  filter: Filter,
94
18
  selectParams: SelectParams & { joinExpressionAlias?: PGIdentifier } = {},
95
- param3_unused = null,
96
19
  tableRules: ParsedTableRule | undefined,
97
20
  localParams: LocalParams | undefined,
98
- ): Promise<NewQuery> {
99
- const { columns } = _this;
21
+ ): Promise<NewQuery> => {
22
+ const { columns } = viewHandler;
100
23
 
101
24
  if (localParams?.isRemoteRequest && !tableRules?.select?.fields) {
102
- throw `INTERNAL ERROR: publish.${_this.name}.select.fields rule missing`;
25
+ throw `INTERNAL ERROR: publish.${viewHandler.name}.select.fields rule missing`;
103
26
  }
104
27
 
105
28
  const allowedOrderByFields =
106
29
  !tableRules ?
107
- _this.column_names.slice(0)
108
- : _this.parseFieldFilter(tableRules.select?.orderByFields ?? tableRules.select?.fields);
30
+ viewHandler.column_names.slice(0)
31
+ : viewHandler.parseFieldFilter(tableRules.select?.orderByFields ?? tableRules.select?.fields);
109
32
  const allowedSelectFields =
110
- !tableRules ? _this.column_names.slice(0) : _this.parseFieldFilter(tableRules.select?.fields);
33
+ !tableRules ?
34
+ viewHandler.column_names.slice(0)
35
+ : viewHandler.parseFieldFilter(tableRules.select?.fields);
111
36
 
112
37
  const joinQueries: NewQueryJoin[] = [];
113
38
 
114
- const { select: userSelect = "*" } = selectParams,
115
- sBuilder = new SelectItemBuilder({
116
- allowedFields: allowedSelectFields,
117
- allowedOrderByFields,
118
- computedFields: COMPUTED_FIELDS,
119
- isView: _this.isView,
120
- functions: FUNCTIONS,
121
- allFields: _this.column_names.slice(0),
122
- columns,
123
- });
124
-
125
- await sBuilder.parseUserSelect(userSelect, async (joinColumnName, _joinParams, throwErr) => {
126
- const j_selectParams: SelectParams = {};
127
- let j_filter: Filter = {},
128
- j_isLeftJoin = true;
39
+ const { select: userSelect = "*" } = selectParams;
129
40
 
130
- const parsedJoin = parseJoinSelect(_joinParams);
131
-
132
- if (!parsedJoin.type) {
133
- throwErr(parsedJoin.error);
134
- return;
135
- }
136
- const joinExpressionAlias = { raw: joinColumnName, escaped: asName(joinColumnName) };
137
- const j_path = parseJoinPath({
138
- rawPath: parsedJoin.type === "simple" ? joinColumnName : parsedJoin.params.path,
139
- rootTable: _this.name,
140
- viewHandler: _this,
141
- allowMultiOrJoin: true,
142
- addShortestJoinIfMissing: true,
143
- });
144
-
145
- if (parsedJoin.params === "*") {
146
- j_selectParams.select = "*";
147
- } else if (parsedJoin.type === "detailed") {
148
- const joinParams = parsedJoin.params;
149
-
150
- j_isLeftJoin = !!joinParams.$leftJoin;
151
-
152
- j_selectParams.select = joinParams.select || "*";
153
- j_filter = joinParams.filter || {};
154
- j_selectParams.limit = joinParams.limit;
155
- j_selectParams.offset = joinParams.offset;
156
- j_selectParams.orderBy = joinParams.orderBy;
157
- j_selectParams.having = joinParams.having;
158
- } else {
159
- j_selectParams.select = parsedJoin.params;
160
- }
161
-
162
- const joinTableName =
163
- parsedJoin.type === "simple" ? joinColumnName
164
- : typeof j_path === "string" ? j_path
165
- : j_path.at(-1)?.table;
166
- if (!joinTableName) {
167
- throw "jTable missing";
168
- }
169
- const joinTableHandler = _this.dboBuilder.dbo[joinTableName] as ViewHandler | undefined;
170
- if (!joinTableHandler) {
171
- throw `Joined table ${JSON.stringify(joinTableName)} is disallowed or inexistent \nOr you forgot to put the function arguments into an array`;
172
- }
41
+ const selectItemBuilder = new SelectItemBuilder({
42
+ allowedFields: allowedSelectFields,
43
+ allowedOrderByFields,
44
+ computedFields: COMPUTED_FIELDS,
45
+ isView: viewHandler.isView,
46
+ functions: FUNCTIONS,
47
+ allFields: viewHandler.column_names.slice(0),
48
+ columns,
49
+ });
173
50
 
174
- let joinTableRules: ParsedTableRule | undefined;
175
- let isLocal = true;
176
- if (localParams && localParams.clientReq) {
177
- isLocal = false;
178
- joinTableRules = await _this.dboBuilder.publishParser?.getValidatedRequestRuleWusr(
179
- {
180
- tableName: joinTableName,
181
- command: "find",
182
- clientReq: localParams.clientReq,
183
- },
184
- localParams.scope,
185
- );
186
- }
51
+ await selectItemBuilder.parseUserSelectWithJoins(
52
+ userSelect,
53
+ async (joinColumnName, parsedJoin) => {
54
+ const j_selectParams: SelectParams = {};
55
+ let j_filter: Filter = {},
56
+ j_isLeftJoin = true;
57
+
58
+ const joinExpressionAlias = { raw: joinColumnName, escaped: asName(joinColumnName) };
59
+ const j_path = parseJoinPath({
60
+ rawPath: parsedJoin.type === "simple" ? joinColumnName : parsedJoin.params.path,
61
+ rootTable: viewHandler.name,
62
+ viewHandler: viewHandler,
63
+ allowMultiOrJoin: true,
64
+ addShortestJoinIfMissing: true,
65
+ });
187
66
 
188
- const isAllowedAccessToTable = isLocal || joinTableRules;
189
- if (isAllowedAccessToTable) {
67
+ if (parsedJoin.params === "*") {
68
+ j_selectParams.select = "*";
69
+ } else if (parsedJoin.type === "detailed") {
70
+ const joinParams = parsedJoin.params;
71
+
72
+ j_isLeftJoin = !!joinParams.$leftJoin;
73
+
74
+ j_filter = joinParams.filter || {};
75
+ j_selectParams.select = joinParams.select || "*";
76
+ j_selectParams.limit = joinParams.limit;
77
+ j_selectParams.offset = joinParams.offset;
78
+ j_selectParams.orderBy = joinParams.orderBy;
79
+ j_selectParams.having = joinParams.having;
80
+ } else {
81
+ j_selectParams.select = parsedJoin.params;
82
+ }
83
+
84
+ const joinTableName =
85
+ parsedJoin.type === "simple" ? joinColumnName
86
+ : typeof j_path === "string" ? j_path
87
+ : j_path.at(-1)?.table;
88
+ if (!joinTableName) {
89
+ throw "jTable missing";
90
+ }
91
+ const joinTableHandler = viewHandler.dboBuilder.dboMap.get(joinTableName);
92
+ if (!joinTableHandler) {
93
+ throw `Joined table ${JSON.stringify(joinTableName)} is disallowed or inexistent \nOr you forgot to put the function arguments into an array`;
94
+ }
95
+
96
+ let joinTableRules: ParsedTableRule | undefined;
97
+ let isLocal = true;
98
+ if (localParams && localParams.clientReq) {
99
+ isLocal = false;
100
+ joinTableRules = await viewHandler.dboBuilder.publishParser?.getValidatedRequestRuleWusr(
101
+ {
102
+ tableName: joinTableName,
103
+ command: "find",
104
+ clientReq: localParams.clientReq,
105
+ },
106
+ localParams.scope,
107
+ );
108
+ }
109
+
110
+ const isAllowedAccessToTable = isLocal || joinTableRules?.select;
111
+ if (!isAllowedAccessToTable) {
112
+ throw `Join select for ${JSON.stringify(joinTableName)} is invalid or not allowed`;
113
+ }
190
114
  const joinQuery: NewQuery = await getNewQuery(
191
115
  joinTableHandler,
192
116
  j_filter,
193
117
  { ...j_selectParams, joinExpressionAlias },
194
- param3_unused,
195
118
  joinTableRules,
196
119
  localParams,
197
120
  );
198
121
  joinQuery.isLeftJoin = j_isLeftJoin;
199
- joinQuery.tableAlias = joinExpressionAlias;
200
122
  joinQueries.push({
201
123
  ...joinQuery,
202
124
  joinPath: j_path,
203
125
  joinAlias: joinQuery.tableAlias ?? joinQuery.table,
204
126
  });
205
- }
206
- });
127
+ },
128
+ );
207
129
 
208
- /**
209
- * Is this still needed?!!!
210
- * Add non selected columns
211
- * This ensures all fields are available for orderBy in case of nested select
212
- * */
213
- Array.from(new Set([...allowedSelectFields, ...allowedOrderByFields])).map((key) => {
214
- if (!sBuilder.select.find((s) => s.alias === key && s.type === "column")) {
215
- sBuilder.addColumn(key, false);
216
- }
217
- });
218
-
219
- const select = sBuilder.select;
130
+ const select = selectItemBuilder.select;
220
131
 
221
- const tableAlias = selectParams.joinExpressionAlias;
222
132
  const commonWhereParams: PrepareWhereParams = {
223
133
  filter,
224
134
  select,
225
135
  forcedFilter: tableRules?.select?.forcedFilter,
226
136
  filterFields: tableRules?.select?.filterFields,
227
- tableAlias,
137
+ tableAlias: selectParams.joinExpressionAlias,
228
138
  localParams,
229
139
  tableRule: tableRules,
230
140
  isHaving: false,
141
+ selectParams,
231
142
  };
232
- const filterOpts = await _this.prepareWhere({
143
+ const filterOpts = await prepareWhere(viewHandler, {
233
144
  ...commonWhereParams,
234
145
  isHaving: false,
235
146
  });
147
+ const { source } = filterOpts;
236
148
  const havingOpts =
237
- !isEmpty(selectParams.having) ?
238
- await _this.prepareWhere({
239
- ...omitKeys(commonWhereParams, ["forcedFilter"]),
149
+ isEmpty(selectParams.having) ? undefined : (
150
+ await prepareWhere(viewHandler, {
151
+ ...omitKeys(commonWhereParams, ["forcedFilter", "selectParams"]),
240
152
  filter: selectParams.having,
153
+ tableAlias:
154
+ selectParams.joinExpressionAlias ? source.alias : (
155
+ { raw: ROOT_TABLE_ALIAS, escaped: ROOT_TABLE_ALIAS }
156
+ ),
241
157
  isHaving: true,
242
158
  })
243
- : undefined;
244
- const where = filterOpts.where;
245
- const validatedRules = _this.getValidatedRules(tableRules, localParams);
159
+ );
160
+ const validatedRules = viewHandler.getValidatedRules(tableRules, localParams);
246
161
 
247
- const resQuery: NewQuery = {
248
- allFields: _this.column_names.slice(0),
162
+ const newQuery: NewQuery = {
163
+ allFields: viewHandler.column_names.slice(0),
249
164
  select,
250
- table: { raw: _this.name, escaped: _this.name },
165
+ table: { raw: viewHandler.name, escaped: viewHandler.name },
166
+ tableAlias: selectParams.joinExpressionAlias,
167
+ source,
251
168
  joins: joinQueries,
252
- where,
169
+ where: filterOpts.where,
253
170
  whereOpts: filterOpts,
254
171
  having: havingOpts?.condition ?? "",
255
172
  isLeftJoin: false,
@@ -264,12 +181,12 @@ export async function getNewQuery(
264
181
  offset: prepareOffsetQuery(selectParams.offset),
265
182
  };
266
183
 
267
- if (resQuery.select.some((s) => s.type === "aggregation") && resQuery.joins?.length) {
184
+ if (newQuery.select.some((s) => s.type === "aggregation") && newQuery.joins?.length) {
268
185
  throw new Error(`Root query aggregation AND nested joins not allowed`);
269
186
  }
270
187
 
271
- return resQuery;
272
- }
188
+ return newQuery;
189
+ };
273
190
 
274
191
  const prepareOffsetQuery = (offset?: number) => {
275
192
  if (Number.isInteger(offset)) {
@@ -0,0 +1,55 @@
1
+ import { asName, type SelectParams } from "prostgles-types";
2
+ import type { ParsedTableRule } from "../../PublishParser/PublishParser";
3
+ import type {
4
+ Awaitable,
5
+ SelectRequestData,
6
+ SelectRule,
7
+ } from "../../PublishParser/publishTypesAndUtils";
8
+ import type { PGIdentifier } from "../DboBuilder";
9
+ import type { ViewHandler } from "../ViewHandler/ViewHandler";
10
+
11
+ const GET_TABLE_EXPRESSION = Symbol("getTableExpression");
12
+ const TABLE_EXPRESSION_ALIAS = "prostgles_table_expression";
13
+
14
+ type SelectRuleWithTableExpression = SelectRule & {
15
+ [GET_TABLE_EXPRESSION]?: (request: SelectRequestData) => Awaitable<string | undefined>;
16
+ };
17
+
18
+ export type QuerySource = {
19
+ expression: string;
20
+ alias?: PGIdentifier;
21
+ };
22
+
23
+ export const withTableExpression = <T extends SelectRule>(
24
+ selectRule: T,
25
+ getTableExpression: NonNullable<SelectRuleWithTableExpression[typeof GET_TABLE_EXPRESSION]>,
26
+ ): T => {
27
+ return Object.assign(selectRule, { [GET_TABLE_EXPRESSION]: getTableExpression });
28
+ };
29
+
30
+ export const getQuerySource = async (
31
+ viewHandler: ViewHandler,
32
+ tableRules: ParsedTableRule | undefined,
33
+ filter: SelectRequestData["filter"],
34
+ params: SelectParams,
35
+ preferredAlias?: PGIdentifier,
36
+ ): Promise<QuerySource> => {
37
+ const selectRule = tableRules?.select as SelectRuleWithTableExpression | undefined;
38
+ const getTableExpression = selectRule?.[GET_TABLE_EXPRESSION];
39
+ const tableExpression =
40
+ getTableExpression ? await getTableExpression({ filter, params }) : undefined;
41
+ const alias =
42
+ preferredAlias ??
43
+ (tableExpression ?
44
+ { raw: TABLE_EXPRESSION_ALIAS, escaped: asName(TABLE_EXPRESSION_ALIAS) }
45
+ : undefined);
46
+
47
+ return {
48
+ expression: tableExpression ?? viewHandler.escapedName,
49
+ alias,
50
+ };
51
+ };
52
+
53
+ export const getQuerySourceSQL = ({ expression, alias }: QuerySource) => {
54
+ return `${expression}${alias ? ` ${alias.escaped}` : ""}`;
55
+ };
@@ -3,6 +3,7 @@ import { isDefined, asName } from "prostgles-types";
3
3
  import type { NewQuery } from "./QueryBuilder";
4
4
  import type { ViewHandler } from "../ViewHandler/ViewHandler";
5
5
  import { getJoinQuery } from "./getJoinQuery";
6
+ import { getQuerySourceSQL } from "./getQuerySource";
6
7
 
7
8
  /**
8
9
  * Used to prevent single row nested results in case of OR join conditions
@@ -46,6 +47,7 @@ export function getSelectQuery(
46
47
 
47
48
  /** OR joins cannot be easily aggregated to one-many with the root table. Must group by root table id */
48
49
  const hasOrJoins = parsedJoins.some((j) => j.isOrJoin);
50
+ const tableExpression = getQuerySourceSQL(q.source);
49
51
 
50
52
  const joinCtes: string[][] = parsedJoins
51
53
  .map((j) => {
@@ -58,7 +60,7 @@ export function getSelectQuery(
58
60
  joinCtes.unshift([
59
61
  `${q.table.escaped} AS (`,
60
62
  ` SELECT *, ${pkey ? asName(pkey.name) : "ROW_NUMBER() OVER()"} as ${ROOT_TABLE_ROW_NUM_ID}`,
61
- ` FROM ${q.table.escaped}`,
63
+ ` FROM ${tableExpression}`,
62
64
  `)`,
63
65
  ]);
64
66
  }
@@ -80,7 +82,11 @@ export function getSelectQuery(
80
82
  ...indentLines(selectItems, { appendCommas: true }),
81
83
  `FROM ( `,
82
84
  ` SELECT *`,
83
- ` FROM ${q.table.escaped}`,
85
+ ` FROM ${
86
+ hasOrJoins ?
87
+ getQuerySourceSQL({ expression: q.table.escaped, alias: q.source.alias })
88
+ : tableExpression
89
+ }`,
84
90
  ...(q.where ? [` ${q.where}`] : []),
85
91
  `) ${ROOT_TABLE_ALIAS}`,
86
92
  ...parsedJoins.flatMap((j) => j.joinLines),
@@ -0,0 +1,73 @@
1
+ import type {
2
+ DetailedJoinSelect,
3
+ JoinPath,
4
+ JoinSelect,
5
+ RawJoinPath,
6
+ SimpleJoinSelect,
7
+ } from "prostgles-types";
8
+ import { getKeys, includes } from "prostgles-types";
9
+
10
+ const JOIN_KEYS = ["$innerJoin", "$leftJoin"] as const;
11
+ const JOIN_PARAM_KEYS = getKeys({
12
+ $condition: 1,
13
+ filter: 1,
14
+ having: 1,
15
+ limit: 1,
16
+ offset: 1,
17
+ orderBy: 1,
18
+ select: 1,
19
+ } satisfies Record<keyof Omit<DetailedJoinSelect, (typeof JOIN_KEYS)[number]>, 1>);
20
+
21
+ export type ParsedJoin =
22
+ | {
23
+ type: "detailed";
24
+ params: DetailedJoinSelect & {
25
+ table: DetailedJoinSelect["$leftJoin"];
26
+ path: RawJoinPath;
27
+ };
28
+ }
29
+ | { type: "simple"; params: SimpleJoinSelect };
30
+
31
+ export const parseJoinSelect = (joinParams: JoinSelect): ParsedJoin | string => {
32
+ if (!(joinParams as string)) {
33
+ return "Empty join params";
34
+ }
35
+ if (typeof joinParams === "string") {
36
+ if ((joinParams as string) !== "*") {
37
+ throw "Join select can be * or { field: 1 }";
38
+ }
39
+ return {
40
+ type: "simple",
41
+ params: joinParams,
42
+ };
43
+ }
44
+ const [joinKey, ...otherKeys] = getKeys(joinParams).filter((k) => includes(JOIN_KEYS, k));
45
+ if (otherKeys.length) {
46
+ return "Cannot specify more than one join type ( $innerJoin OR $leftJoin )";
47
+ } else if (joinKey) {
48
+ /* Full option join { field_name: db.innerJoin.table_name(filter, select) } */
49
+ const invalidParams = Object.keys(joinParams).filter(
50
+ (k) => !includes([...JOIN_PARAM_KEYS, ...JOIN_KEYS], k),
51
+ );
52
+ if (invalidParams.length) {
53
+ throw "Invalid join params: " + invalidParams.join(", ");
54
+ }
55
+ const path = joinParams[joinKey] as string | JoinPath[];
56
+ if (Array.isArray(path) && !path.length) {
57
+ throw `Cannot have an empty join path/tableName ${joinKey}`;
58
+ }
59
+ return {
60
+ type: "detailed",
61
+ params: {
62
+ ...(joinParams as DetailedJoinSelect),
63
+ path,
64
+ table: typeof path === "string" ? path : path.at(-1)!.table,
65
+ },
66
+ };
67
+ }
68
+
69
+ return {
70
+ type: "simple",
71
+ params: joinParams as SimpleJoinSelect,
72
+ };
73
+ };
@@ -19,11 +19,7 @@ import type {
19
19
  import { getSyncBatchOptions } from "../../PubSubManager/SyncReplication/getSyncBatchOptions";
20
20
  import type { TableDefinition } from "../../TableConfig/TableConfigTypes";
21
21
  import type { DboBuilder, Filter, LocalParams, TableHandlers } from "../DboBuilder";
22
- import {
23
- getErrorAsObject,
24
- getSerializedClientErrorFromPGError,
25
- withUserRLS,
26
- } from "../DboBuilder";
22
+ import { getErrorAsObject, getSerializedClientErrorFromPGError, withUserRLS } from "../DboBuilder";
27
23
  import type { TableSchema } from "../DboBuilderTypes";
28
24
  import { parseUpdateRules } from "../parseUpdateRules";
29
25
  import { COMPUTED_FIELDS } from "../QueryBuilder/Functions/COMPUTED_FIELDS";
@@ -41,6 +37,7 @@ import { isApplicableHook } from "./isApplicableHook";
41
37
  import type { TableConfigurator } from "../../TableConfig/TableConfigurator";
42
38
  import type { TableHooksDefinition } from "../../TableHooks/TableHooks";
43
39
  import type { TransactionCallbacks } from "../../PublishParser/publishTypesAndUtils";
40
+ import { prepareWhere } from "../ViewHandler/prepareWhere";
44
41
 
45
42
  export type ValidatedParams = {
46
43
  row: AnyObject;
@@ -359,7 +356,7 @@ export class TableHandler extends ViewHandler {
359
356
  ).then(async (data: AnyObject[]) => {
360
357
  const { filterFields, forcedFilter } = table_rules.select || {};
361
358
  const condition = (
362
- await this.prepareWhere({
359
+ await prepareWhere(this, {
363
360
  select: undefined,
364
361
  filter,
365
362
  forcedFilter,
@@ -11,6 +11,7 @@ import {
11
11
  import { getReturnTypeQuery } from "../ViewHandler/getReturnTypeQuery";
12
12
  import type { TableHandler } from "./TableHandler";
13
13
  import { executeAfterHooksCheckAndPostValidation } from "./executeAfterHooksCheckAndPostValidation";
14
+ import { prepareWhere } from "../ViewHandler/prepareWhere";
14
15
 
15
16
  export async function _delete(
16
17
  this: TableHandler,
@@ -86,7 +87,7 @@ export async function _delete(
86
87
 
87
88
  let queryType: keyof pgPromise.ITask<{}> = "none";
88
89
  let queryWithoutRLS = `DELETE FROM ${this.escapedName} `;
89
- const filterOpts = await this.prepareWhere({
90
+ const filterOpts = await prepareWhere(this, {
90
91
  select: undefined,
91
92
  filter,
92
93
  forcedFilter,
@@ -6,6 +6,7 @@ import { rejectWithPGClientError, withUserRLS } from "../DboBuilder";
6
6
  import type { TableHandler } from "./TableHandler";
7
7
  import { getSelectItemQuery } from "./TableHandler";
8
8
  import { executeAfterHooksCheckAndPostValidation } from "./executeAfterHooksCheckAndPostValidation";
9
+ import { prepareWhere } from "../ViewHandler/prepareWhere";
9
10
 
10
11
  type RunInsertUpdateQueryArgs = {
11
12
  tableHandler: TableHandler;
@@ -54,7 +55,7 @@ export const runInsertUpdateQuery = async (args: RunInsertUpdateQueryArgs) => {
54
55
  // let checkCondition = "WHERE FALSE";
55
56
  let checkCondition = "FALSE";
56
57
  if (checkFilter) {
57
- const checkCond = await tableHandler.prepareWhere({
58
+ const checkCond = await prepareWhere(tableHandler, {
58
59
  select: undefined,
59
60
  localParams: undefined,
60
61
  tableRule: undefined,
@@ -9,6 +9,7 @@ import { getReferenceColumnInserts } from "./insert/getReferenceColumnInserts";
9
9
  import { runInsertUpdateQuery } from "./runInsertUpdateQuery";
10
10
  import { lockFileForUpdate } from "./updateFile";
11
11
  import type { TableHandler } from "./TableHandler";
12
+ import { prepareWhere } from "../ViewHandler/prepareWhere";
12
13
 
13
14
  export async function update(
14
15
  this: TableHandler,
@@ -66,7 +67,7 @@ export async function update(
66
67
  );
67
68
  }
68
69
 
69
- const updateFilter = await this.prepareWhere({
70
+ const updateFilter = await prepareWhere(this, {
70
71
  select: undefined,
71
72
  filter,
72
73
  forcedFilter,
@@ -13,26 +13,25 @@ import type { TableEvent } from "../../Logging";
13
13
  import type { DB } from "../../Prostgles";
14
14
  import type { Join } from "../../ProstglesTypes";
15
15
  import type { ParsedTableRule } from "../../PublishParser/PublishParser";
16
- import type { Graph } from "../joins/shortestPath";
16
+ import type { VoidFunction } from "../../SchemaWatch/SchemaWatch";
17
+ import type { TableDefinition } from "../../TableConfig/TableConfigTypes";
18
+ import type { TableHooksDefinition } from "../../TableHooks/TableHooks";
19
+ import { escapeTSNames } from "../../utils/utils";
17
20
  import type { DboBuilder, Filter, LocalParams, TableHandlers } from "../DboBuilder";
18
21
  import { getSerializedClientErrorFromPGError } from "../DboBuilder";
19
22
  import type { TableSchema } from "../DboBuilderTypes";
20
23
  import { getValidatedTableRules } from "../TableRules/getValidatedTableRules";
21
24
  import { getColumns } from "../getColumns";
25
+ import type { Graph } from "../joins/shortestPath";
22
26
  import { count } from "./count";
23
27
  import { find, type Param3 } from "./find";
28
+ import { getDbHandlerWithAbort } from "./getDbHandlerWithAbort";
24
29
  import { getInfo } from "./getInfo";
25
30
  import { parseFieldFilter } from "./parseFieldFilter";
26
- import { prepareWhere } from "./prepareWhere";
27
31
  import { size } from "./size";
28
32
  import type { OnData } from "./subscribe";
29
33
  import { subscribe } from "./subscribe";
30
34
  import { validateViewRules } from "./validateViewRules";
31
- import { escapeTSNames } from "../../utils/utils";
32
- import type { TableDefinition } from "../../TableConfig/TableConfigTypes";
33
- import { getDbHandlerWithAbort } from "./getDbHandlerWithAbort";
34
- import type { VoidFunction } from "../../SchemaWatch/SchemaWatch";
35
- import type { TableHooksDefinition } from "../../TableHooks/TableHooks";
36
35
 
37
36
  export type JoinPaths = {
38
37
  t1: string;
@@ -338,11 +337,6 @@ export class ViewHandler {
338
337
  return col_names;
339
338
  }
340
339
 
341
- /**
342
- * Parses group or simple filter
343
- */
344
- prepareWhere = prepareWhere.bind(this);
345
-
346
340
  intersectColumns(
347
341
  allowedFields: FieldFilter,
348
342
  disallowedFields: FieldFilter,
@@ -101,7 +101,6 @@ export const find = async function (
101
101
  this,
102
102
  filter,
103
103
  selectParamsLimitCheck,
104
- undefined,
105
104
  tableRules,
106
105
  localParams,
107
106
  );