prostgles-server 4.2.623 → 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 (181) hide show
  1. package/debug/client-schema-types/DBGeneratedSchema.ts +13 -1
  2. package/dist/Audit/AuditTable.d.ts +2 -1
  3. package/dist/Audit/AuditTable.d.ts.map +1 -1
  4. package/dist/Audit/AuditTable.js +3 -2
  5. package/dist/Audit/AuditTable.js.map +1 -1
  6. package/dist/Audit/getAuditTableRules.d.ts +7 -0
  7. package/dist/Audit/getAuditTableRules.d.ts.map +1 -0
  8. package/dist/Audit/getAuditTableRules.js +191 -0
  9. package/dist/Audit/getAuditTableRules.js.map +1 -0
  10. package/dist/Audit/getAuditTriggerConfig.d.ts.map +1 -1
  11. package/dist/Audit/getAuditTriggerConfig.js +14 -1
  12. package/dist/Audit/getAuditTriggerConfig.js.map +1 -1
  13. package/dist/DBSchemaBuilder/getDBGeneratedSchema.d.ts.map +1 -1
  14. package/dist/DBSchemaBuilder/getDBGeneratedSchema.js +1 -2
  15. package/dist/DBSchemaBuilder/getDBGeneratedSchema.js.map +1 -1
  16. package/dist/DboBuilder/DboBuilder.js +1 -1
  17. package/dist/DboBuilder/DboBuilder.js.map +1 -1
  18. package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts +10 -5
  19. package/dist/DboBuilder/QueryBuilder/QueryBuilder.d.ts.map +1 -1
  20. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js +90 -71
  21. package/dist/DboBuilder/QueryBuilder/QueryBuilder.js.map +1 -1
  22. package/dist/DboBuilder/QueryBuilder/getJoinQuery.d.ts.map +1 -1
  23. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js +3 -2
  24. package/dist/DboBuilder/QueryBuilder/getJoinQuery.js.map +1 -1
  25. package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts +2 -2
  26. package/dist/DboBuilder/QueryBuilder/getNewQuery.d.ts.map +1 -1
  27. package/dist/DboBuilder/QueryBuilder/getNewQuery.js +53 -116
  28. package/dist/DboBuilder/QueryBuilder/getNewQuery.js.map +1 -1
  29. package/dist/DboBuilder/QueryBuilder/getQuerySource.d.ts +18 -0
  30. package/dist/DboBuilder/QueryBuilder/getQuerySource.d.ts.map +1 -0
  31. package/dist/DboBuilder/QueryBuilder/getQuerySource.js +29 -0
  32. package/dist/DboBuilder/QueryBuilder/getQuerySource.js.map +1 -0
  33. package/dist/DboBuilder/QueryBuilder/getSelectQuery.d.ts.map +1 -1
  34. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js +6 -2
  35. package/dist/DboBuilder/QueryBuilder/getSelectQuery.js.map +1 -1
  36. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.d.ts +13 -0
  37. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.d.ts.map +1 -0
  38. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.js +57 -0
  39. package/dist/DboBuilder/QueryBuilder/parseJoinSelect.js.map +1 -0
  40. package/dist/DboBuilder/TableHandler/TableHandler.d.ts.map +1 -1
  41. package/dist/DboBuilder/TableHandler/TableHandler.js +2 -1
  42. package/dist/DboBuilder/TableHandler/TableHandler.js.map +1 -1
  43. package/dist/DboBuilder/TableHandler/delete.d.ts.map +1 -1
  44. package/dist/DboBuilder/TableHandler/delete.js +2 -1
  45. package/dist/DboBuilder/TableHandler/delete.js.map +1 -1
  46. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.d.ts.map +1 -1
  47. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js +2 -1
  48. package/dist/DboBuilder/TableHandler/runInsertUpdateQuery.js.map +1 -1
  49. package/dist/DboBuilder/TableHandler/update.d.ts.map +1 -1
  50. package/dist/DboBuilder/TableHandler/update.js +2 -1
  51. package/dist/DboBuilder/TableHandler/update.js.map +1 -1
  52. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts +6 -16
  53. package/dist/DboBuilder/ViewHandler/ViewHandler.d.ts.map +1 -1
  54. package/dist/DboBuilder/ViewHandler/ViewHandler.js +2 -7
  55. package/dist/DboBuilder/ViewHandler/ViewHandler.js.map +1 -1
  56. package/dist/DboBuilder/ViewHandler/find.d.ts.map +1 -1
  57. package/dist/DboBuilder/ViewHandler/find.js +1 -1
  58. package/dist/DboBuilder/ViewHandler/find.js.map +1 -1
  59. package/dist/DboBuilder/ViewHandler/getExistsCondition.d.ts +1 -1
  60. package/dist/DboBuilder/ViewHandler/getExistsCondition.d.ts.map +1 -1
  61. package/dist/DboBuilder/ViewHandler/getExistsCondition.js +24 -13
  62. package/dist/DboBuilder/ViewHandler/getExistsCondition.js.map +1 -1
  63. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts +4 -1
  64. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.d.ts.map +1 -1
  65. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js +20 -14
  66. package/dist/DboBuilder/ViewHandler/getTableJoinQuery.js.map +1 -1
  67. package/dist/DboBuilder/ViewHandler/prepareWhere.d.ts +7 -3
  68. package/dist/DboBuilder/ViewHandler/prepareWhere.d.ts.map +1 -1
  69. package/dist/DboBuilder/ViewHandler/prepareWhere.js +30 -23
  70. package/dist/DboBuilder/ViewHandler/prepareWhere.js.map +1 -1
  71. package/dist/DboBuilder/getCondition.d.ts +2 -1
  72. package/dist/DboBuilder/getCondition.d.ts.map +1 -1
  73. package/dist/DboBuilder/getCondition.js +9 -8
  74. package/dist/DboBuilder/getCondition.js.map +1 -1
  75. package/dist/DboBuilder/getSubscribeRelatedTables.d.ts.map +1 -1
  76. package/dist/DboBuilder/getSubscribeRelatedTables.js +3 -2
  77. package/dist/DboBuilder/getSubscribeRelatedTables.js.map +1 -1
  78. package/dist/DboBuilder/parseUpdateRules.d.ts.map +1 -1
  79. package/dist/DboBuilder/parseUpdateRules.js +3 -2
  80. package/dist/DboBuilder/parseUpdateRules.js.map +1 -1
  81. package/dist/DboBuilder/schema/getTablesForSchemaPostgresSQL.d.ts +2 -2
  82. package/dist/Prostgles.d.ts.map +1 -1
  83. package/dist/Prostgles.js +2 -0
  84. package/dist/Prostgles.js.map +1 -1
  85. package/dist/ProstglesContext.spec.js +25 -0
  86. package/dist/ProstglesContext.spec.js.map +1 -1
  87. package/dist/PubSubManager/PubSubManager.d.ts +1 -1
  88. package/dist/PublishParser/PublishParser.d.ts +17 -8
  89. package/dist/PublishParser/PublishParser.d.ts.map +1 -1
  90. package/dist/PublishParser/PublishParser.js +59 -28
  91. package/dist/PublishParser/PublishParser.js.map +1 -1
  92. package/dist/PublishParser/applyScopeToTableRules.d.ts +0 -1
  93. package/dist/PublishParser/applyScopeToTableRules.d.ts.map +1 -1
  94. package/dist/PublishParser/applyScopeToTableRules.js +3 -7
  95. package/dist/PublishParser/applyScopeToTableRules.js.map +1 -1
  96. package/dist/PublishParser/getFileTableRules.d.ts +1 -1
  97. package/dist/PublishParser/getFileTableRules.d.ts.map +1 -1
  98. package/dist/PublishParser/getFileTableRules.js +52 -41
  99. package/dist/PublishParser/getFileTableRules.js.map +1 -1
  100. package/dist/PublishParser/getParsedPublishTable.d.ts +4 -0
  101. package/dist/PublishParser/getParsedPublishTable.d.ts.map +1 -0
  102. package/dist/PublishParser/{getTableRulesWithoutFileTable.js → getParsedPublishTable.js} +13 -7
  103. package/dist/PublishParser/getParsedPublishTable.js.map +1 -0
  104. package/dist/PublishParser/getPublishSchemas.d.ts +4 -0
  105. package/dist/PublishParser/getPublishSchemas.d.ts.map +1 -0
  106. package/dist/PublishParser/getPublishSchemas.js +42 -0
  107. package/dist/PublishParser/getPublishSchemas.js.map +1 -0
  108. package/dist/PublishParser/getPublishedObjectFromResult.d.ts +4 -0
  109. package/dist/PublishParser/getPublishedObjectFromResult.d.ts.map +1 -0
  110. package/dist/PublishParser/getPublishedObjectFromResult.js +77 -0
  111. package/dist/PublishParser/getPublishedObjectFromResult.js.map +1 -0
  112. package/dist/PublishParser/getPublishedTableNames.d.ts.map +1 -1
  113. package/dist/PublishParser/getPublishedTableNames.js +20 -1
  114. package/dist/PublishParser/getPublishedTableNames.js.map +1 -1
  115. package/dist/PublishParser/getSchemaFromPublish.d.ts.map +1 -1
  116. package/dist/PublishParser/getSchemaFromPublish.js +11 -5
  117. package/dist/PublishParser/getSchemaFromPublish.js.map +1 -1
  118. package/dist/PublishParser/publishTypesAndUtils.d.ts +28 -7
  119. package/dist/PublishParser/publishTypesAndUtils.d.ts.map +1 -1
  120. package/dist/PublishParser/publishTypesAndUtils.js +6 -1
  121. package/dist/PublishParser/publishTypesAndUtils.js.map +1 -1
  122. package/dist/PublishParser/validatePublishProfiles.d.ts +2 -2
  123. package/dist/PublishParser/validatePublishProfiles.d.ts.map +1 -1
  124. package/dist/PublishParser/validatePublishProfiles.js.map +1 -1
  125. package/dist/TableConfig/getColumnSQLDefinitionQuery.d.ts.map +1 -1
  126. package/dist/TableConfig/getColumnSQLDefinitionQuery.js +1 -2
  127. package/dist/TableConfig/getColumnSQLDefinitionQuery.js.map +1 -1
  128. package/dist/index.d.ts +2 -2
  129. package/dist/index.d.ts.map +1 -1
  130. package/dist/index.js +2 -1
  131. package/dist/index.js.map +1 -1
  132. package/dist/runClientRequest.d.ts.map +1 -1
  133. package/dist/runClientRequest.js +6 -1
  134. package/dist/runClientRequest.js.map +1 -1
  135. package/lib/Audit/AuditTable.ts +4 -3
  136. package/lib/Audit/getAuditTableRules.ts +288 -0
  137. package/lib/Audit/getAuditTriggerConfig.ts +14 -1
  138. package/lib/DBSchemaBuilder/getDBGeneratedSchema.ts +1 -2
  139. package/lib/DboBuilder/DboBuilder.ts +1 -1
  140. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +118 -90
  141. package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +3 -2
  142. package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +111 -194
  143. package/lib/DboBuilder/QueryBuilder/getQuerySource.ts +55 -0
  144. package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +8 -2
  145. package/lib/DboBuilder/QueryBuilder/parseJoinSelect.ts +73 -0
  146. package/lib/DboBuilder/TableHandler/TableHandler.ts +3 -6
  147. package/lib/DboBuilder/TableHandler/delete.ts +2 -1
  148. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +2 -1
  149. package/lib/DboBuilder/TableHandler/update.ts +2 -1
  150. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +6 -12
  151. package/lib/DboBuilder/ViewHandler/find.ts +0 -1
  152. package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +35 -28
  153. package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +22 -14
  154. package/lib/DboBuilder/ViewHandler/prepareWhere.ts +48 -27
  155. package/lib/DboBuilder/getCondition.ts +11 -10
  156. package/lib/DboBuilder/getSubscribeRelatedTables.ts +3 -2
  157. package/lib/DboBuilder/parseUpdateRules.ts +3 -2
  158. package/lib/Prostgles.ts +1 -0
  159. package/lib/ProstglesContext.spec.ts +30 -0
  160. package/lib/PublishParser/PublishParser.ts +108 -51
  161. package/lib/PublishParser/applyScopeToTableRules.ts +1 -7
  162. package/lib/PublishParser/getFileTableRules.ts +52 -45
  163. package/lib/PublishParser/{getTableRulesWithoutFileTable.ts → getParsedPublishTable.ts} +16 -12
  164. package/lib/PublishParser/getPublishSchemas.ts +49 -0
  165. package/lib/PublishParser/getPublishedObjectFromResult.ts +104 -0
  166. package/lib/PublishParser/getPublishedTableNames.ts +28 -1
  167. package/lib/PublishParser/getSchemaFromPublish.ts +9 -7
  168. package/lib/PublishParser/publishTypesAndUtils.ts +31 -11
  169. package/lib/PublishParser/validatePublishProfiles.ts +1 -1
  170. package/lib/TableConfig/getColumnSQLDefinitionQuery.ts +8 -2
  171. package/lib/index.ts +14 -1
  172. package/lib/runClientRequest.ts +4 -3
  173. package/package.json +1 -1
  174. package/dist/DBSchemaBuilder/getPublishSchemas.d.ts +0 -4
  175. package/dist/DBSchemaBuilder/getPublishSchemas.d.ts.map +0 -1
  176. package/dist/DBSchemaBuilder/getPublishSchemas.js +0 -34
  177. package/dist/DBSchemaBuilder/getPublishSchemas.js.map +0 -1
  178. package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts +0 -6
  179. package/dist/PublishParser/getTableRulesWithoutFileTable.d.ts.map +0 -1
  180. package/dist/PublishParser/getTableRulesWithoutFileTable.js.map +0 -1
  181. package/lib/DBSchemaBuilder/getPublishSchemas.ts +0 -41
@@ -5,7 +5,6 @@
5
5
 
6
6
  import type {
7
7
  ColumnInfo,
8
- JoinSelect,
9
8
  PG_COLUMN_UDT_DATA_TYPE,
10
9
  Select,
11
10
  ValidatedColumnInfo,
@@ -13,12 +12,15 @@ import type {
13
12
  import { getKeys, isEmpty, isObject, postgresToTsType } from "prostgles-types";
14
13
  import type { PGIdentifier, SortItem } from "../DboBuilder";
15
14
 
15
+ import type { Awaitable } from "../../PublishParser/publishTypesAndUtils";
16
+ import { asNameAlias } from "../../utils/asNameAlias";
16
17
  import type { ParsedJoinPath } from "../ViewHandler/parseJoinPath";
17
- import type { ViewHandler } from "../ViewHandler/ViewHandler";
18
- import type { FieldSpec, FunctionSpec } from "./Functions/Functions";
18
+ import type { WhereOptions } from "../ViewHandler/prepareWhere";
19
19
  import { COMPUTED_FIELDS } from "./Functions/COMPUTED_FIELDS";
20
+ import type { FieldSpec, FunctionSpec } from "./Functions/Functions";
20
21
  import { parseFunction } from "./Functions/parseFunction";
21
- import { asNameAlias } from "../../utils/asNameAlias";
22
+ import { parseJoinSelect, type ParsedJoin } from "./parseJoinSelect";
23
+ import type { QuerySource } from "./getQuerySource";
22
24
 
23
25
  export type SelectItem = {
24
26
  getFields: (args: any[]) => string[] | "*";
@@ -36,13 +38,9 @@ export type SelectItem = {
36
38
  | {
37
39
  type: "function" | "aggregation" | "joinedColumn" | "computed";
38
40
  columnName?: undefined;
39
- // args: any[];
40
- // getFields: (args: any[]) => string[] | "*";
41
- // columnNames: string[];
42
41
  }
43
42
  );
44
43
  export type SelectItemValidated = Omit<SelectItem, "getFields"> & { fields: string[] };
45
- export type WhereOptions = Awaited<ReturnType<ViewHandler["prepareWhere"]>>;
46
44
  export type NewQueryRoot = {
47
45
  /**
48
46
  * All fields from the table will be in nested SELECT and GROUP BY to allow order/filter by fields not in select
@@ -55,6 +53,7 @@ export type NewQueryRoot = {
55
53
  select: SelectItemValidated[];
56
54
 
57
55
  table: PGIdentifier;
56
+ source: QuerySource;
58
57
  where: string;
59
58
  whereOpts: WhereOptions;
60
59
  orderByItems: SortItem[];
@@ -148,7 +147,7 @@ export class SelectItemBuilder {
148
147
  const allowedFields = isSelected ? allowedSelectedFields : allowedNonSelectedFields;
149
148
  if (!allowedFields.includes(f)) {
150
149
  throw (
151
- "Field " + f + " is invalid or dissallowed. \nAllowed fields: " + allowedFields.join(", ")
150
+ "Field " + f + " is invalid or disallowed. \nAllowed fields: " + allowedFields.join(", ")
152
151
  );
153
152
  }
154
153
  return f;
@@ -193,7 +192,7 @@ export class SelectItemBuilder {
193
192
  });
194
193
  };
195
194
 
196
- addColumn = (fieldName: string, selected: boolean) => {
195
+ private addColumn = (fieldName: string, selected: boolean) => {
197
196
  /* Check if computed col */
198
197
  if (selected) {
199
198
  const compCol = COMPUTED_FIELDS.find((cf) => cf.name === fieldName);
@@ -225,10 +224,19 @@ export class SelectItemBuilder {
225
224
  });
226
225
  };
227
226
 
228
- parseUserSelect = async (
227
+ parse = async (
229
228
  userSelect: Select,
230
- joinParse?: (key: string, val: JoinSelect, throwErr: (msg: string) => any) => any,
231
- ) => {
229
+ joinParse?: (key: string, parsedJoin: ParsedJoin) => Awaitable<void>,
230
+ ): Promise<void> => {
231
+ if (userSelect === "") {
232
+ return;
233
+ }
234
+
235
+ if (userSelect === "*") {
236
+ this.allowedFields.map((key) => this.addColumn(key, true));
237
+ return;
238
+ }
239
+
232
240
  /* [col1, col2, col3] */
233
241
  if (Array.isArray(userSelect)) {
234
242
  if (userSelect.find((key) => typeof (key as unknown) !== "string")) {
@@ -236,90 +244,110 @@ export class SelectItemBuilder {
236
244
  }
237
245
 
238
246
  userSelect.map((key) => this.addColumn(key, true));
247
+ return;
248
+ }
239
249
 
240
- /* Empty select */
241
- } else if (userSelect === "") {
242
- return [];
243
- } else if (userSelect === "*") {
244
- this.allowedFields.map((key) => this.addColumn(key, true));
245
- } else if (isObject(userSelect) && !isEmpty(userSelect)) {
246
- const selectKeys = Object.keys(userSelect),
247
- selectValues = Object.values(userSelect);
248
-
249
- /* Cannot include and exclude at the same time */
250
- if (selectValues.filter((v) => [0, false].includes(v as number)).length) {
251
- if (selectValues.filter((v) => ![0, false].includes(v as number)).length) {
252
- throw "\nCannot include and exclude fields at the same time";
253
- }
254
-
255
- /* Exclude only */
256
- this.allowedFields
257
- .filter((f) => !selectKeys.includes(f))
258
- .map((key) => this.addColumn(key, true));
259
- } else {
260
- await Promise.all(
261
- selectKeys.map(async (key) => {
262
- const val: unknown = userSelect[key as keyof typeof userSelect];
263
- const throwErr = (extraErr = "") => {
264
- console.trace(extraErr);
265
- throw "Unexpected select -> " + JSON.stringify({ [key]: val }) + "\n" + extraErr;
266
- };
267
-
268
- /* Included fields */
269
- if ([1, true].includes(val as number | boolean)) {
270
- if (key === "*") {
271
- this.allowedFields.map((key) => this.addColumn(key, true));
272
- } else {
273
- this.addColumn(key, true);
274
- }
250
+ if (!isObject(userSelect)) {
251
+ throw "Unexpected select -> " + JSON.stringify(userSelect);
252
+ }
253
+
254
+ if (isEmpty(userSelect)) {
255
+ throw "Unexpected empty object select";
256
+ }
257
+
258
+ const selectKeys = Object.keys(userSelect),
259
+ selectValues = Object.values(userSelect);
260
+
261
+ /* Cannot include and exclude at the same time */
262
+ if (selectValues.filter((v) => [0, false].includes(v as number)).length) {
263
+ if (selectValues.filter((v) => ![0, false].includes(v as number)).length) {
264
+ throw "\nCannot include and exclude fields at the same time";
265
+ }
275
266
 
276
- /* Aggs and functions */
277
- } else if (typeof val === "string" || isObject(val)) {
278
- /* Function shorthand notation
267
+ /* Exclude only */
268
+ this.allowedFields
269
+ .filter((f) => !selectKeys.includes(f))
270
+ .map((key) => this.addColumn(key, true));
271
+ } else {
272
+ await Promise.all(
273
+ selectKeys.map(async (key) => {
274
+ const val: unknown = userSelect[key as keyof typeof userSelect];
275
+ const throwErr: (message: string) => never = (message) => {
276
+ console.trace(message);
277
+ throw "Unexpected select -> " + JSON.stringify({ [key]: val }) + "\n" + message;
278
+ };
279
+
280
+ /* Included fields */
281
+ if ([1, true].includes(val as number | boolean)) {
282
+ if (key === "*") {
283
+ this.allowedFields.map((key) => this.addColumn(key, true));
284
+ } else {
285
+ this.addColumn(key, true);
286
+ }
287
+
288
+ /* Aggregations and functions */
289
+ } else if (typeof val === "string" || isObject(val)) {
290
+ /* Function shorthand notation
279
291
  { id: "$max" } === { id: { $max: ["id"] } } === SELECT MAX(id) AS id
280
- */
281
- if (
282
- (typeof val === "string" && val !== "*") ||
283
- (isObject(val) &&
284
- Object.keys(val).length === 1 &&
285
- Array.isArray(Object.values(val)[0]))
286
- ) {
287
- let funcName: string | undefined, args: any[] | undefined;
288
- if (typeof val === "string") {
289
- /* Shorthand notation -> it is expected that the key is the column name used as the only argument */
290
- try {
291
- this.checkField(key, true);
292
- } catch {
293
- throwErr(
294
- ` Shorthand function notation error: the specifield column ( ${key} ) is invalid or dissallowed. \n Use correct column name or full aliased function notation, e.g.: -> { alias: { $func_name: ["column_name"] } } `,
295
- );
296
- }
297
- funcName = val;
298
- args = [key];
299
-
300
- /** Function full notation { $funcName: ["colName", ...args] } */
301
- } else {
302
- ({ funcName, args } = parseFunctionObject(val));
292
+ */
293
+ if (
294
+ (typeof val === "string" && val !== "*") ||
295
+ (isObject(val) &&
296
+ Object.keys(val).length === 1 &&
297
+ Array.isArray(Object.values(val)[0]))
298
+ ) {
299
+ let funcName: string | undefined, args: any[] | undefined;
300
+ if (typeof val === "string") {
301
+ /* Shorthand notation -> it is expected that the key is the column name used as the only argument */
302
+ try {
303
+ this.checkField(key, true);
304
+ } catch {
305
+ throwErr(
306
+ ` Shorthand function notation error: the specified column ( ${key} ) is invalid or disallowed. \n Use correct column name or full aliased function notation, e.g.: -> { alias: { $func_name: ["column_name"] } } `,
307
+ );
303
308
  }
309
+ funcName = val;
310
+ args = [key];
304
311
 
305
- this.addFunction(funcName, args, key);
306
-
307
- /* Join */
312
+ /** Function full notation { $funcName: ["colName", ...args] } */
308
313
  } else {
309
- if (!joinParse) {
310
- throw "Joins disallowed";
311
- }
312
- await joinParse(key, val as JoinSelect, throwErr);
314
+ ({ funcName, args } = parseFunctionObject(val));
313
315
  }
314
- } else throwErr();
315
- }),
316
- );
317
- }
318
- } else {
319
- if (isEmpty(userSelect)) {
320
- throw "Unexpected empty object select";
321
- }
322
- throw "Unexpected select -> " + JSON.stringify(userSelect);
316
+
317
+ this.addFunction(funcName, args, key);
318
+
319
+ /* Join */
320
+ } else {
321
+ if (!joinParse) {
322
+ throw "Joins disallowed";
323
+ }
324
+ const joinSelect = val;
325
+
326
+ const parsedJoin = parseJoinSelect(joinSelect);
327
+
328
+ if (typeof parsedJoin === "string") {
329
+ throwErr(parsedJoin);
330
+ }
331
+ await joinParse(key, parsedJoin);
332
+ }
333
+ } else throwErr("Invalid select value");
334
+ }),
335
+ );
323
336
  }
337
+
338
+ if (!joinParse) return;
339
+ /**
340
+ * Is this still needed?!!!
341
+ * Add non selected columns
342
+ * This ensures all fields are available for orderBy in case of nested select
343
+ * */
344
+ Array.from(new Set([...this.allowedFields, ...this.allowedOrderByFields])).map((columnName) => {
345
+ if (!this.select.find((s) => s.alias === columnName && s.type === "column")) {
346
+ this.addColumn(columnName, false);
347
+ }
348
+ });
324
349
  };
350
+
351
+ parseUserSelect = (userSelect: Select) => this.parse(userSelect);
352
+ parseUserSelectWithJoins = this.parse;
325
353
  }
@@ -255,6 +255,7 @@ const getInnerJoinQuery = ({
255
255
 
256
256
  const isFirst = !i;
257
257
  if (isFirst) {
258
+ const tableExpression = isLast ? q2.source.expression : table.name;
258
259
  return [
259
260
  `SELECT `,
260
261
  ` /* Join fields + select */`,
@@ -262,13 +263,13 @@ const getInnerJoinQuery = ({
262
263
  rootSelectItems.map((s) => s.query),
263
264
  { appendCommas: true },
264
265
  ),
265
- `FROM ${table.name} ${table.alias}`,
266
+ `FROM ${tableExpression} ${table.alias}`,
266
267
  ...targetQueryExtraQueries,
267
268
  ];
268
269
  }
269
270
 
270
271
  return [
271
- `INNER JOIN ${table.name} ${table.alias}`,
272
+ `INNER JOIN ${isLast ? q2.source.expression : table.name} ${table.alias}`,
272
273
  `ON ${getJoinOnCondition({
273
274
  on: path.on,
274
275
  leftAlias: prevTable.alias,
@@ -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)) {