prostgles-server 4.2.157 → 4.2.159

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 (159) hide show
  1. package/dist/Auth/AuthHandler.js +2 -2
  2. package/dist/Auth/AuthHandler.js.map +1 -1
  3. package/dist/Auth/AuthTypes.d.ts +4 -8
  4. package/dist/Auth/AuthTypes.d.ts.map +1 -1
  5. package/dist/Auth/setAuthProviders.d.ts +1 -1
  6. package/dist/Auth/setAuthProviders.d.ts.map +1 -1
  7. package/dist/Auth/setAuthProviders.js +6 -7
  8. package/dist/Auth/setAuthProviders.js.map +1 -1
  9. package/dist/Auth/setEmailProvider.d.ts +1 -1
  10. package/dist/Auth/setEmailProvider.d.ts.map +1 -1
  11. package/dist/Auth/setEmailProvider.js +22 -2
  12. package/dist/Auth/setEmailProvider.js.map +1 -1
  13. package/dist/Auth/setupAuthRoutes.js +1 -1
  14. package/dist/Auth/setupAuthRoutes.js.map +1 -1
  15. package/dist/Prostgles.d.ts +1 -0
  16. package/dist/Prostgles.d.ts.map +1 -1
  17. package/dist/Prostgles.js +6 -0
  18. package/dist/Prostgles.js.map +1 -1
  19. package/dist/initProstgles.d.ts.map +1 -1
  20. package/dist/initProstgles.js +2 -6
  21. package/dist/initProstgles.js.map +1 -1
  22. package/package.json +1 -1
  23. package/lib/Auth/AuthHandler.ts +0 -436
  24. package/lib/Auth/AuthTypes.ts +0 -285
  25. package/lib/Auth/getSafeReturnURL.ts +0 -35
  26. package/lib/Auth/sendEmail.ts +0 -83
  27. package/lib/Auth/setAuthProviders.ts +0 -129
  28. package/lib/Auth/setEmailProvider.ts +0 -63
  29. package/lib/Auth/setupAuthRoutes.ts +0 -161
  30. package/lib/DBEventsManager.ts +0 -178
  31. package/lib/DBSchemaBuilder.ts +0 -225
  32. package/lib/DboBuilder/DboBuilder.ts +0 -319
  33. package/lib/DboBuilder/DboBuilderTypes.ts +0 -361
  34. package/lib/DboBuilder/QueryBuilder/Functions.ts +0 -1153
  35. package/lib/DboBuilder/QueryBuilder/QueryBuilder.ts +0 -288
  36. package/lib/DboBuilder/QueryBuilder/getJoinQuery.ts +0 -263
  37. package/lib/DboBuilder/QueryBuilder/getNewQuery.ts +0 -271
  38. package/lib/DboBuilder/QueryBuilder/getSelectQuery.ts +0 -136
  39. package/lib/DboBuilder/QueryBuilder/prepareHaving.ts +0 -22
  40. package/lib/DboBuilder/QueryStreamer.ts +0 -250
  41. package/lib/DboBuilder/TableHandler/DataValidator.ts +0 -428
  42. package/lib/DboBuilder/TableHandler/TableHandler.ts +0 -205
  43. package/lib/DboBuilder/TableHandler/delete.ts +0 -115
  44. package/lib/DboBuilder/TableHandler/insert.ts +0 -183
  45. package/lib/DboBuilder/TableHandler/insertTest.ts +0 -78
  46. package/lib/DboBuilder/TableHandler/onDeleteFromFileTable.ts +0 -62
  47. package/lib/DboBuilder/TableHandler/runInsertUpdateQuery.ts +0 -134
  48. package/lib/DboBuilder/TableHandler/update.ts +0 -126
  49. package/lib/DboBuilder/TableHandler/updateBatch.ts +0 -49
  50. package/lib/DboBuilder/TableHandler/updateFile.ts +0 -48
  51. package/lib/DboBuilder/TableHandler/upsert.ts +0 -34
  52. package/lib/DboBuilder/ViewHandler/ViewHandler.ts +0 -393
  53. package/lib/DboBuilder/ViewHandler/count.ts +0 -38
  54. package/lib/DboBuilder/ViewHandler/find.ts +0 -153
  55. package/lib/DboBuilder/ViewHandler/getExistsCondition.ts +0 -73
  56. package/lib/DboBuilder/ViewHandler/getExistsFilters.ts +0 -74
  57. package/lib/DboBuilder/ViewHandler/getInfo.ts +0 -32
  58. package/lib/DboBuilder/ViewHandler/getTableJoinQuery.ts +0 -84
  59. package/lib/DboBuilder/ViewHandler/parseComplexFilter.ts +0 -96
  60. package/lib/DboBuilder/ViewHandler/parseFieldFilter.ts +0 -105
  61. package/lib/DboBuilder/ViewHandler/parseJoinPath.ts +0 -208
  62. package/lib/DboBuilder/ViewHandler/prepareSortItems.ts +0 -163
  63. package/lib/DboBuilder/ViewHandler/prepareWhere.ts +0 -90
  64. package/lib/DboBuilder/ViewHandler/size.ts +0 -37
  65. package/lib/DboBuilder/ViewHandler/subscribe.ts +0 -118
  66. package/lib/DboBuilder/ViewHandler/validateViewRules.ts +0 -70
  67. package/lib/DboBuilder/dboBuilderUtils.ts +0 -222
  68. package/lib/DboBuilder/getColumns.ts +0 -114
  69. package/lib/DboBuilder/getCondition.ts +0 -201
  70. package/lib/DboBuilder/getSubscribeRelatedTables.ts +0 -190
  71. package/lib/DboBuilder/getTablesForSchemaPostgresSQL.ts +0 -426
  72. package/lib/DboBuilder/insertNestedRecords.ts +0 -355
  73. package/lib/DboBuilder/parseUpdateRules.ts +0 -187
  74. package/lib/DboBuilder/prepareShortestJoinPaths.ts +0 -186
  75. package/lib/DboBuilder/runSQL.ts +0 -182
  76. package/lib/DboBuilder/runTransaction.ts +0 -50
  77. package/lib/DboBuilder/sqlErrCodeToMsg.ts +0 -254
  78. package/lib/DboBuilder/uploadFile.ts +0 -69
  79. package/lib/Event_Trigger_Tags.ts +0 -118
  80. package/lib/FileManager/FileManager.ts +0 -358
  81. package/lib/FileManager/getValidatedFileType.ts +0 -69
  82. package/lib/FileManager/initFileManager.ts +0 -187
  83. package/lib/FileManager/upload.ts +0 -62
  84. package/lib/FileManager/uploadStream.ts +0 -79
  85. package/lib/Filtering.ts +0 -463
  86. package/lib/JSONBValidation/validate_jsonb_schema_sql.ts +0 -502
  87. package/lib/JSONBValidation/validation.ts +0 -143
  88. package/lib/Logging.ts +0 -127
  89. package/lib/PostgresNotifListenManager.ts +0 -143
  90. package/lib/Prostgles.ts +0 -479
  91. package/lib/ProstglesTypes.ts +0 -196
  92. package/lib/PubSubManager/PubSubManager.ts +0 -609
  93. package/lib/PubSubManager/addSub.ts +0 -138
  94. package/lib/PubSubManager/addSync.ts +0 -141
  95. package/lib/PubSubManager/getCreatePubSubManagerError.ts +0 -72
  96. package/lib/PubSubManager/getPubSubManagerInitQuery.ts +0 -662
  97. package/lib/PubSubManager/initPubSubManager.ts +0 -79
  98. package/lib/PubSubManager/notifListener.ts +0 -173
  99. package/lib/PubSubManager/orphanTriggerCheck.ts +0 -70
  100. package/lib/PubSubManager/pushSubData.ts +0 -55
  101. package/lib/PublishParser/PublishParser.ts +0 -162
  102. package/lib/PublishParser/getFileTableRules.ts +0 -124
  103. package/lib/PublishParser/getSchemaFromPublish.ts +0 -141
  104. package/lib/PublishParser/getTableRulesWithoutFileTable.ts +0 -177
  105. package/lib/PublishParser/publishTypesAndUtils.ts +0 -399
  106. package/lib/RestApi.ts +0 -127
  107. package/lib/SchemaWatch/SchemaWatch.ts +0 -90
  108. package/lib/SchemaWatch/createSchemaWatchEventTrigger.ts +0 -3
  109. package/lib/SchemaWatch/getValidatedWatchSchemaType.ts +0 -45
  110. package/lib/SchemaWatch/getWatchSchemaTagList.ts +0 -27
  111. package/lib/SyncReplication.ts +0 -557
  112. package/lib/TableConfig/TableConfig.ts +0 -468
  113. package/lib/TableConfig/getColumnDefinitionQuery.ts +0 -111
  114. package/lib/TableConfig/getConstraintDefinitionQueries.ts +0 -95
  115. package/lib/TableConfig/getFutureTableSchema.ts +0 -64
  116. package/lib/TableConfig/getPGIndexes.ts +0 -53
  117. package/lib/TableConfig/getTableColumnQueries.ts +0 -129
  118. package/lib/TableConfig/initTableConfig.ts +0 -326
  119. package/lib/index.ts +0 -13
  120. package/lib/initProstgles.ts +0 -322
  121. package/lib/onSocketConnected.ts +0 -102
  122. package/lib/runClientRequest.ts +0 -129
  123. package/lib/shortestPath.ts +0 -122
  124. package/lib/typeTests/DBoGenerated.d.ts +0 -320
  125. package/lib/typeTests/dboTypeCheck.ts +0 -81
  126. package/lib/utils.ts +0 -15
  127. package/tests/client/hooks.spec.ts +0 -205
  128. package/tests/client/index.ts +0 -139
  129. package/tests/client/package-lock.json +0 -637
  130. package/tests/client/package.json +0 -26
  131. package/tests/client/renderReactHook.ts +0 -177
  132. package/tests/client/tsconfig.json +0 -15
  133. package/tests/client/useProstgles.spec.ts +0 -120
  134. package/tests/clientFileTests.spec.ts +0 -102
  135. package/tests/clientOnlyQueries.spec.ts +0 -667
  136. package/tests/clientRestApi.spec.ts +0 -82
  137. package/tests/config_test/DBoGenerated.d.ts +0 -407
  138. package/tests/config_test/index.html +0 -109
  139. package/tests/config_test/index.js +0 -86
  140. package/tests/config_test/index.js.map +0 -1
  141. package/tests/config_test/index.ts +0 -91
  142. package/tests/config_test/init.sql +0 -48
  143. package/tests/config_test/package.json +0 -29
  144. package/tests/config_test/tsconfig.json +0 -23
  145. package/tests/config_testDBoGenerated.d.ts +0 -407
  146. package/tests/isomorphicQueries.spec.ts +0 -1493
  147. package/tests/server/DBoGenerated.d.ts +0 -537
  148. package/tests/server/index.html +0 -73
  149. package/tests/server/index.ts +0 -289
  150. package/tests/server/init.sql +0 -224
  151. package/tests/server/package-lock.json +0 -2164
  152. package/tests/server/package.json +0 -25
  153. package/tests/server/publishTypeCheck.ts +0 -136
  154. package/tests/server/server.ts +0 -35
  155. package/tests/server/testPublish.ts +0 -147
  156. package/tests/server/testTableConfig.ts +0 -156
  157. package/tests/server/tsconfig.json +0 -22
  158. package/tests/serverOnlyQueries.spec.ts +0 -32
  159. package/tests/test.sh +0 -20
@@ -1,288 +0,0 @@
1
-
2
- /*---------------------------------------------------------------------------------------------
3
- * Copyright (c) Stefan L. All rights reserved.
4
- * Licensed under the MIT License. See LICENSE in the project root for license information.
5
- *--------------------------------------------------------------------------------------------*/
6
-
7
- import { asName, ColumnInfo, getKeys, isEmpty, isObject, JoinSelect, PG_COLUMN_UDT_DATA_TYPE, Select, ValidatedColumnInfo } from "prostgles-types";
8
- import { isPlainObject, postgresToTsType, SortItem } from "../DboBuilder";
9
-
10
- import { ParsedJoinPath } from "../ViewHandler/parseJoinPath";
11
- import { ViewHandler } from "../ViewHandler/ViewHandler";
12
- import { COMPUTED_FIELDS, FieldSpec, FunctionSpec, parseFunction } from "./Functions";
13
-
14
- export type SelectItem = {
15
- getFields: (args?: any[]) => string[] | "*";
16
- getQuery: (tableAlias?: string) => string;
17
- columnPGDataType?: string;
18
- column_udt_type?: PG_COLUMN_UDT_DATA_TYPE;
19
- tsDataType?: ValidatedColumnInfo["tsDataType"]
20
- alias: string;
21
- selected: boolean;
22
- } & ({
23
- type: "column";
24
- columnName: string;
25
- } | {
26
- type: "function" | "aggregation" | "joinedColumn" | "computed";
27
- columnName?: undefined;
28
- });
29
- export type SelectItemValidated = SelectItem & { fields: string[]; }
30
- export type WhereOptions = Awaited<ReturnType<ViewHandler["prepareWhere"]>>;
31
- export type NewQueryRoot = {
32
- /**
33
- * All fields from the table will be in nested SELECT and GROUP BY to allow order/filter by fields not in select
34
- */
35
- allFields: string[];
36
-
37
- /**
38
- * Contains user selection and all the allowed columns. Allowed columns not selected are marked with selected: false
39
- */
40
- select: SelectItem[];
41
-
42
- table: string;
43
- where: string;
44
- whereOpts: WhereOptions;
45
- orderByItems: SortItem[];
46
- having: string;
47
- limit: number | null;
48
- offset: number;
49
- isLeftJoin: boolean;
50
- tableAlias?: string;
51
- };
52
-
53
- export type NewQueryJoin = (NewQuery & {
54
- joinPath: ParsedJoinPath[];
55
- joinAlias: string;
56
- });
57
- export type NewQuery = NewQueryRoot & {
58
- joins?: NewQueryJoin[];
59
- }
60
-
61
- export const asNameAlias = (field: string, tableAlias?: string) => {
62
- const result = asName(field);
63
- if(tableAlias) return asName(tableAlias) + "." + result;
64
- return result;
65
- }
66
-
67
- export const parseFunctionObject = (funcData: any): { funcName: string; args: any[] } => {
68
- const makeErr = (msg: string) => `Function not specified correctly. Expecting { $funcName: ["columnName" | <value>, ...args] } object but got: ${JSON.stringify(funcData)} \n ${msg}`
69
- if(!isObject(funcData)) throw makeErr("");
70
- const keys = getKeys(funcData);
71
- if(keys.length !== 1) throw makeErr("");
72
- const funcName = keys[0]!;
73
- const args = funcData[funcName];
74
- if(!args || !Array.isArray(args)){
75
- throw makeErr("Arguments missing or invalid");
76
- }
77
-
78
- return { funcName, args };
79
- }
80
-
81
-
82
- export class SelectItemBuilder {
83
-
84
- select: SelectItemValidated[] = [];
85
- private allFields: string[];
86
-
87
- private allowedFields: string[];
88
- private allowedOrderByFields: string[];
89
- private computedFields: FieldSpec[];
90
- private functions: FunctionSpec[];
91
- private allowedFieldsIncludingComputed: string[];
92
- private isView: boolean;
93
- private columns: ColumnInfo[];
94
-
95
- constructor(params: { allowedFields: string[]; allowedOrderByFields: string[]; computedFields: FieldSpec[]; functions: FunctionSpec[]; allFields: string[]; isView: boolean; columns: ColumnInfo[]; }){
96
- this.allFields = params.allFields;
97
- this.allowedFields = params.allowedFields;
98
- this.allowedOrderByFields = params.allowedOrderByFields;
99
- this.computedFields = params.computedFields;
100
- this.isView = params.isView;
101
- this.functions = params.functions;
102
- this.columns = params.columns;
103
- this.allowedFieldsIncludingComputed = this.allowedFields.concat(this.computedFields? this.computedFields.map(cf => cf.name) : []);
104
- if(!this.allowedFields.length){
105
- if(!this.columns.length){
106
- throw "This view/table has no columns. Cannot select anything";
107
- }
108
- throw "allowedFields empty/missing";
109
- }
110
-
111
- /* Check for conflicting computed column names */
112
- const conflictingCol = this.allFields.find(fieldName => this.computedFields.find(cf => cf.name === fieldName));
113
- if(conflictingCol){
114
- throw "INTERNAL ERROR: Cannot have duplicate column names ( " + conflictingCol + " ). One or more computed column names are colliding with table columns ones";
115
- }
116
- }
117
-
118
- private checkField = (f: string, isSelected: boolean) => {
119
- const allowedSelectedFields = this.allowedFieldsIncludingComputed;
120
- const allowedNonSelectedFields = [...this.allowedFieldsIncludingComputed, ...this.allowedOrderByFields];
121
-
122
- /** Not selected items can be part of the orderBy fields */
123
- const allowedFields = isSelected? allowedSelectedFields : allowedNonSelectedFields;
124
- if(!allowedFields.includes(f)){
125
- throw "Field " + f + " is invalid or dissallowed. \nAllowed fields: " + allowedFields.join(", ");
126
- }
127
- return f;
128
- }
129
-
130
- private addItem = (item: SelectItem) => {
131
- let fields = item.getFields();
132
- // console.trace(fields)
133
- if(fields === "*") fields = this.allowedFields.slice(0);
134
- fields.map(f => this.checkField(f, item.selected));
135
-
136
- if(this.select.find(s => s.alias === item.alias)){
137
- throw `Cannot specify duplicate columns ( ${item.alias} ). Perhaps you're using "*" with column names?`;
138
- }
139
- this.select.push({ ...item, fields });
140
- }
141
-
142
- private addFunction = (func: FunctionSpec | string, args: any[], alias: string) => {
143
- const funcDef = parseFunction({
144
- func, args, functions: this.functions,
145
- allowedFields: this.allowedFieldsIncludingComputed,
146
- });
147
-
148
- this.addItem({
149
- type: funcDef.type,
150
- alias,
151
- getFields: () => funcDef.getFields(args),
152
- getQuery: (tableAlias?: string) => funcDef.getQuery({ allColumns: this.columns, allowedFields: this.allowedFields, args, tableAlias,
153
- ctidField: undefined,
154
-
155
- /* CTID not available in AFTER trigger */
156
- // ctidField: this.isView? undefined : "ctid"
157
- }),
158
- selected: true
159
- });
160
- }
161
-
162
- addColumn = (fieldName: string, selected: boolean) => {
163
-
164
- /* Check if computed col */
165
- if(selected){
166
- const compCol = COMPUTED_FIELDS.find(cf => cf.name === fieldName);
167
- if(compCol && !this.select.find(s => s.alias === fieldName)){
168
- const cf: FunctionSpec = {
169
- ...compCol,
170
- type: "computed",
171
- numArgs: 0,
172
- singleColArg: false,
173
- getFields: (_args: any[]) => []
174
- }
175
- this.addFunction(cf, [], compCol.name)
176
- return;
177
- }
178
- }
179
-
180
- const colDef = this.columns.find(c => c.name === fieldName);
181
- const alias = selected? fieldName : ("not_selected_" + fieldName);
182
- this.addItem({
183
- type: "column",
184
- columnName: fieldName,
185
- columnPGDataType: colDef?.data_type,
186
- column_udt_type: colDef?.udt_name,
187
- tsDataType: colDef && postgresToTsType(colDef.udt_name),
188
- alias,
189
- getQuery: (tableAlias) => asNameAlias(fieldName, tableAlias),
190
- getFields: () => [fieldName],
191
- selected
192
- });
193
- }
194
-
195
- parseUserSelect = async (userSelect: Select, joinParse?: (key: string, val: JoinSelect, throwErr: (msg: string) => any) => any) => {
196
-
197
- /* [col1, col2, col3] */
198
- if(Array.isArray(userSelect)){
199
- if(userSelect.find(key => typeof key !== "string")) throw "Invalid array select. Expecting an array of strings";
200
-
201
- userSelect.map(key => this.addColumn(key, true))
202
-
203
- /* Empty select */
204
- } else if(userSelect === ""){
205
- return [];
206
-
207
- } else if(userSelect === "*"){
208
- this.allowedFields.map(key => this.addColumn(key, true) );
209
-
210
- } else if(isPlainObject(userSelect) && !isEmpty(userSelect)){
211
- const selectKeys = Object.keys(userSelect),
212
- selectValues = Object.values(userSelect);
213
-
214
- /* Cannot include and exclude at the same time */
215
- if(
216
- selectValues.filter(v => [0, false].includes(v)).length
217
- ){
218
- if(selectValues.filter(v => ![0, false].includes(v)).length ){
219
- throw "\nCannot include and exclude fields at the same time";
220
- }
221
-
222
- /* Exclude only */
223
- this.allowedFields.filter(f => !selectKeys.includes(f)).map(key => this.addColumn(key, true) )
224
-
225
- } else {
226
- await Promise.all(selectKeys.map(async key => {
227
- const val: any = userSelect[key as keyof typeof userSelect],
228
- throwErr = (extraErr = "") => {
229
- console.trace(extraErr)
230
- throw "Unexpected select -> " + JSON.stringify({ [key]: val }) + "\n" + extraErr;
231
- };
232
-
233
- /* Included fields */
234
- if([1, true].includes(val)){
235
- if(key === "*"){
236
- this.allowedFields.map(key => this.addColumn(key, true) )
237
- } else {
238
- this.addColumn(key, true);
239
- }
240
-
241
- /* Aggs and functions */
242
- } else if(typeof val === "string" || isObject(val)) {
243
-
244
- /* Function shorthand notation
245
- { id: "$max" } === { id: { $max: ["id"] } } === SELECT MAX(id) AS id
246
- */
247
- if(
248
- (typeof val === "string" && val !== "*") ||
249
- isPlainObject(val) && Object.keys(val).length === 1 && Array.isArray(Object.values(val)[0])
250
- ){
251
-
252
- let funcName: string | undefined, args: any[] | undefined;
253
- if(typeof val === "string") {
254
- /* Shorthand notation -> it is expected that the key is the column name used as the only argument */
255
- try {
256
- this.checkField(key, true)
257
- } catch (err){
258
- throwErr(` 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"] } } `)
259
- }
260
- funcName = val;
261
- args = [key];
262
-
263
- /** Function full notation { $funcName: ["colName", ...args] } */
264
- } else {
265
- ({ funcName, args } = parseFunctionObject(val));
266
- }
267
-
268
- this.addFunction(funcName, args, key);
269
-
270
- /* Join */
271
- } else {
272
-
273
- if(!joinParse) {
274
- throw "Joins dissalowed";
275
- }
276
- await joinParse(key, val as JoinSelect, throwErr);
277
-
278
- }
279
-
280
- } else throwErr();
281
-
282
- }));
283
- }
284
- } else throw "Unexpected select -> " + JSON.stringify(userSelect);
285
-
286
- }
287
-
288
- }
@@ -1,263 +0,0 @@
1
- import { isDefined, asName } from "prostgles-types";
2
- import { ParsedJoinPath, parseJoinPath } from "../ViewHandler/parseJoinPath";
3
- import { NewQuery, NewQueryJoin, SelectItem, asNameAlias } from "./QueryBuilder";
4
- import { ROOT_TABLE_ALIAS, ROOT_TABLE_ROW_NUM_ID, indentLines } from "./getSelectQuery";
5
- import { ViewHandler } from "../ViewHandler/ViewHandler";
6
- import { getJoinOnCondition } from "../ViewHandler/getTableJoinQuery";
7
- import { prepareOrderByQuery } from "../DboBuilder";
8
-
9
- type Args = {
10
- q1: NewQuery;
11
- q2: NewQueryJoin;
12
- selectParamsGroupBy: boolean;
13
- }
14
-
15
- /**
16
- * Rename all join columns to prevent name clash
17
- */
18
- export const getJoinCol = (colName: string) => {
19
- const alias = asName("prgl_join_col__" + colName);
20
- return {
21
- alias,
22
- rootSelect: `${asName(colName)} AS ${alias}`,
23
- }
24
- }
25
-
26
- export const JSON_AGG_FIELD_NAME = "prostgles_json_agg_result_field";
27
- /**
28
- * Used for LIMIT and for sorting
29
- */
30
- export const NESTED_ROWID_FIELD_NAME = "prostgles_rowid_field";
31
-
32
- const getJoinTable = (tableName: string, pathIndex: number, isLastTableAlias: string | undefined) => {
33
- const rawAlias = isLastTableAlias ?? `p${pathIndex} ${tableName}`;
34
- return {
35
- // name: asName(tableName), /** table names are already escaped */
36
- name: tableName,
37
- alias: asName(rawAlias),
38
- rawAlias,
39
- }
40
- }
41
-
42
- type GetJoinQueryResult = {
43
- resultAlias: string;
44
- // queryLines: string[];
45
- firstJoinTableJoinFields: string[];
46
- isOrJoin: boolean;
47
- type: "cte";
48
- joinLines: string[];
49
- cteLines: string[];
50
- }
51
-
52
- /**
53
- Returns join query. All inner join tables will be prefixed with path index unless it's the final target table which is aliased using the q2 tableAlias
54
-
55
- LEFT JOIN (
56
- SELECT [target table select + join fields]
57
- FROM first_join/target_table
58
- JOIN ..next_joins ON ...
59
- JOIN target_table
60
- ) target_table
61
- ON ...condition
62
- */
63
- export const getJoinQuery = (viewHandler: ViewHandler, { q1, q2 }: Args): GetJoinQueryResult => {
64
- const paths = parseJoinPath({
65
- rootTable: q1.table,
66
- rawPath: q2.joinPath,
67
- viewHandler: viewHandler,
68
- allowMultiOrJoin: true,
69
- addShortestJoinIfMissing: true,
70
- });
71
-
72
- const targetTableAliasRaw = q2.tableAlias || q2.table;
73
- const targetTableAlias = asName(targetTableAliasRaw);
74
-
75
- const firstJoinTablePath = paths[0]!;
76
- const firstJoinTableJoinFields = firstJoinTablePath.on.flatMap(condObj => Object.entries(condObj).map(([source, target]) => target));
77
- const { rootSelectItems, jsonAggLimit } = getNestedSelectFields({
78
- q: q2,
79
- firstJoinTableAlias: getJoinTable(firstJoinTablePath.table, 0, paths.length === 1? targetTableAliasRaw : undefined).rawAlias,
80
- _joinFields: firstJoinTableJoinFields
81
- });
82
-
83
- const joinType = q2.isLeftJoin? "LEFT" : "INNER";
84
-
85
- const isOrJoin = firstJoinTablePath.on.length > 1;
86
- const joinCondition = getJoinOnCondition({
87
- on: firstJoinTablePath.on,
88
- leftAlias: asName(q1.tableAlias || q1.table),
89
- rightAlias: targetTableAlias,
90
- getRightColName: (col) => getJoinCol(col).alias
91
- });
92
-
93
- const joinFields = rootSelectItems.filter(s => s.isJoinCol).map(s => s.alias);
94
- const selectedFields = rootSelectItems.filter(s => s.selected).map(s => asNameAlias(s.alias, targetTableAliasRaw));
95
- const rootNestedSort = q1.orderByItems.filter(d => d.nested?.joinAlias === q2.joinAlias);
96
- const jsonAggSort = prepareOrderByQuery(q2.orderByItems, targetTableAliasRaw).join(", ");
97
- const jsonAgg = `json_agg((SELECT x FROM (SELECT ${selectedFields}) as x )${jsonAggSort}) ${jsonAggLimit} as ${JSON_AGG_FIELD_NAME}`;
98
-
99
- const { innerQuery } = getInnerJoinQuery({ paths, q1, q2, rootSelectItems, targetTableAliasRaw });
100
-
101
- const requiredJoinFields = joinFields.map(field => getJoinCol(field).alias);
102
- /**
103
- * Used to prevent duplicates in case of OR filters
104
- */
105
- const rootTableIdField = `${ROOT_TABLE_ALIAS}.${ROOT_TABLE_ROW_NUM_ID}`;
106
- const wrappingQuery = [
107
- `SELECT `,
108
- ...indentLines([
109
- ...(isOrJoin? [rootTableIdField]: requiredJoinFields),
110
- jsonAgg,
111
- ...rootNestedSort.map(d => d.nested!.wrapperQuerySortItem)
112
- ], { appendCommas: true }),
113
- `FROM (`,
114
- ...indentLines(innerQuery),
115
- `) ${targetTableAlias}`,
116
- ...(isOrJoin? [
117
- `LEFT JOIN ${q1.table} ${ROOT_TABLE_ALIAS}`,
118
- `ON ${joinCondition}`
119
- ] : []),
120
- `GROUP BY ${isOrJoin? rootTableIdField : requiredJoinFields}`,
121
- ];
122
-
123
- /**
124
- * This is done to prevent join cte names clashing with actual table names
125
- */
126
- const targetTableAliasTempRename = asName(`${targetTableAlias}_prostgles_join_temp_rename`)
127
- const cteLines = [
128
- `${targetTableAliasTempRename} AS (`,
129
- ...indentLines(wrappingQuery),
130
- `)`
131
- ];
132
-
133
- const joinLines = [
134
- `${joinType} JOIN ( SELECT * FROM ${targetTableAliasTempRename} ) as ${targetTableAlias}`,
135
- isOrJoin?
136
- `ON ${targetTableAlias}.${ROOT_TABLE_ROW_NUM_ID} = ${rootTableIdField}` :
137
- `ON ${joinCondition}`
138
- ];
139
-
140
- return {
141
- type: "cte",
142
- resultAlias: JSON_AGG_FIELD_NAME,
143
- // queryLines,
144
- joinLines,
145
- cteLines,
146
- isOrJoin,
147
- firstJoinTableJoinFields,
148
- }
149
- }
150
-
151
-
152
- /**
153
- * prepares the
154
- */
155
- const getInnerJoinQuery = ({ paths, q1, q2, targetTableAliasRaw, rootSelectItems }: {
156
- paths: ParsedJoinPath[];
157
- q1: NewQuery;
158
- q2: NewQueryJoin;
159
- targetTableAliasRaw: string;
160
- rootSelectItems: SelectItemNested[];
161
- }) => {
162
-
163
- const innerQuery = paths.flatMap((path, i) => {
164
-
165
- const isLast = i === paths.length - 1;
166
- const targetQueryExtraQueries: string[] = [];
167
-
168
- const prevTable = getJoinTable(!i? (q1.tableAlias? asName(q1.tableAlias) : q1.table) : paths[i-1]!.table, i-1, undefined);
169
-
170
- const table = getJoinTable(path.table, i, isLast? targetTableAliasRaw : undefined);
171
-
172
- if(isLast){
173
- if(q2.where){
174
- targetQueryExtraQueries.push(q2.where);
175
- }
176
-
177
- /* If aggs exist need to set groupBy add joinFields into select */
178
- const aggs = q2.select.filter(s => s.type === "aggregation")
179
- if (aggs.length) {
180
- const groupByFields = rootSelectItems.map((c, i) => (c.isJoinCol || c.selected && c.type !== "aggregation")? `${i+1}` : undefined ).filter(isDefined);
181
- if(groupByFields.length){
182
- targetQueryExtraQueries.push(`GROUP BY ${groupByFields}`)
183
- }
184
- if(q2.having){
185
- targetQueryExtraQueries.push(`HAVING ${q2.having}`)
186
- }
187
- }
188
- }
189
-
190
- const isFirst = !i;
191
- if(isFirst){
192
- return [
193
- `SELECT `,
194
- ` /* Join fields + select */`,
195
- ...indentLines(rootSelectItems.map(s => s.query), { appendCommas: true }),
196
- `FROM ${table.name} ${table.alias}`,
197
- ...targetQueryExtraQueries
198
- ]
199
- }
200
-
201
- return [
202
- `INNER JOIN ${table.name} ${table.alias}`,
203
- `ON ${getJoinOnCondition({
204
- on: path.on,
205
- leftAlias: prevTable.alias,
206
- rightAlias: table.alias,
207
- })}`,
208
- ...targetQueryExtraQueries
209
- ]
210
- });
211
-
212
- return { innerQuery }
213
- }
214
-
215
-
216
- type GetSelectFieldsArgs = {
217
- q: NewQueryJoin;
218
- firstJoinTableAlias: string;
219
- _joinFields: string[];
220
- }
221
-
222
- export type SelectItemNested = SelectItem & { query: string; isJoinCol: boolean; };
223
- const getNestedSelectFields = ({ q, firstJoinTableAlias, _joinFields }: GetSelectFieldsArgs) => {
224
- const targetTableAlias = (q.tableAlias || q.table);
225
-
226
- const requiredJoinFields = Array.from(new Set(_joinFields))
227
- const selectedFields = q.select.filter(s => s.selected);
228
- const rootSelectItems: SelectItemNested[] = selectedFields
229
- .map(s => ({
230
- ...s,
231
- isJoinCol: false,
232
- query: s.getQuery(targetTableAlias) + " AS " + asName(s.alias)
233
- }))
234
- .concat(requiredJoinFields.map(f => ({
235
- type: "column",
236
- columnName: f,
237
- alias: f,
238
- getFields: () => [f],
239
- getQuery: (tableAlias) => asNameAlias(f, tableAlias),
240
- selected: false,
241
- isJoinCol: true,
242
- query: `${asName(firstJoinTableAlias)}.${getJoinCol(f).rootSelect}`,
243
- })));
244
-
245
- const getQuery = (tableAlias?: string) => {
246
- const partitionBy = `PARTITION BY ${requiredJoinFields.map(f => asNameAlias(f, tableAlias))}`;
247
- return `ROW_NUMBER() OVER(${partitionBy}) AS ${NESTED_ROWID_FIELD_NAME}`
248
- };
249
- rootSelectItems.push({
250
- type: "computed",
251
- selected: false,
252
- alias: NESTED_ROWID_FIELD_NAME,
253
- getFields: () => [],
254
- getQuery,
255
- query: getQuery(firstJoinTableAlias),
256
- isJoinCol: false,
257
- })
258
-
259
- return {
260
- rootSelectItems,
261
- jsonAggLimit: q.limit? `FILTER (WHERE ${NESTED_ROWID_FIELD_NAME} <= ${q.limit})` : ""
262
- };
263
- }