@quillsql/react 2.13.35 → 2.13.37

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 (196) hide show
  1. package/dist/cjs/Chart.d.ts +0 -1
  2. package/dist/cjs/Chart.d.ts.map +1 -1
  3. package/dist/cjs/Chart.js +17 -14
  4. package/dist/cjs/ChartBuilder.d.ts +1 -0
  5. package/dist/cjs/ChartBuilder.d.ts.map +1 -1
  6. package/dist/cjs/ChartBuilder.js +178 -96
  7. package/dist/cjs/Context.d.ts.map +1 -1
  8. package/dist/cjs/Context.js +6 -8
  9. package/dist/cjs/Dashboard.d.ts +2 -1
  10. package/dist/cjs/Dashboard.d.ts.map +1 -1
  11. package/dist/cjs/Dashboard.js +18 -8
  12. package/dist/cjs/ReportBuilder.d.ts +2 -0
  13. package/dist/cjs/ReportBuilder.d.ts.map +1 -1
  14. package/dist/cjs/ReportBuilder.js +398 -271
  15. package/dist/cjs/SQLEditor.d.ts.map +1 -1
  16. package/dist/cjs/SQLEditor.js +33 -11
  17. package/dist/cjs/Table.d.ts.map +1 -1
  18. package/dist/cjs/Table.js +17 -1
  19. package/dist/cjs/components/Chart/InternalChart.d.ts +0 -1
  20. package/dist/cjs/components/Chart/InternalChart.d.ts.map +1 -1
  21. package/dist/cjs/components/Chart/InternalChart.js +6 -7
  22. package/dist/cjs/components/Dashboard/DataLoader.d.ts.map +1 -1
  23. package/dist/cjs/components/Dashboard/DataLoader.js +75 -30
  24. package/dist/cjs/components/Dashboard/MetricComponent.d.ts +1 -1
  25. package/dist/cjs/components/Dashboard/MetricComponent.d.ts.map +1 -1
  26. package/dist/cjs/components/Dashboard/MetricComponent.js +98 -106
  27. package/dist/cjs/components/QuillMultiSelectSectionList.d.ts.map +1 -1
  28. package/dist/cjs/components/QuillMultiSelectSectionList.js +21 -16
  29. package/dist/cjs/components/QuillMultiSelectWithCombo.js +18 -8
  30. package/dist/cjs/components/QuillSelectWithCombo.js +17 -7
  31. package/dist/cjs/components/ReportBuilder/AddLimitPopover.d.ts +1 -1
  32. package/dist/cjs/components/ReportBuilder/AddLimitPopover.d.ts.map +1 -1
  33. package/dist/cjs/components/ReportBuilder/AddLimitPopover.js +2 -2
  34. package/dist/cjs/components/ReportBuilder/AddSortPopover.d.ts +16 -4
  35. package/dist/cjs/components/ReportBuilder/AddSortPopover.d.ts.map +1 -1
  36. package/dist/cjs/components/ReportBuilder/AddSortPopover.js +9 -18
  37. package/dist/cjs/components/UiComponents.d.ts +2 -1
  38. package/dist/cjs/components/UiComponents.d.ts.map +1 -1
  39. package/dist/cjs/components/UiComponents.js +44 -28
  40. package/dist/cjs/hooks/useAskQuill.d.ts.map +1 -1
  41. package/dist/cjs/hooks/useAskQuill.js +28 -4
  42. package/dist/cjs/hooks/useQuill.d.ts.map +1 -1
  43. package/dist/cjs/hooks/useQuill.js +9 -1
  44. package/dist/cjs/hooks/useVirtualTables.d.ts.map +1 -1
  45. package/dist/cjs/hooks/useVirtualTables.js +11 -35
  46. package/dist/cjs/internals/ReportBuilder/PivotForm.d.ts.map +1 -1
  47. package/dist/cjs/internals/ReportBuilder/PivotForm.js +14 -2
  48. package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts +12 -11
  49. package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
  50. package/dist/cjs/internals/ReportBuilder/PivotModal.js +63 -18
  51. package/dist/cjs/models/Client.d.ts +4 -5
  52. package/dist/cjs/models/Client.d.ts.map +1 -1
  53. package/dist/cjs/models/Pivot.d.ts +10 -0
  54. package/dist/cjs/models/Pivot.d.ts.map +1 -1
  55. package/dist/cjs/models/Report.d.ts +13 -1
  56. package/dist/cjs/models/Report.d.ts.map +1 -1
  57. package/dist/cjs/utils/astFilterProcessing.d.ts +1 -1
  58. package/dist/cjs/utils/astFilterProcessing.d.ts.map +1 -1
  59. package/dist/cjs/utils/astFilterProcessing.js +799 -64
  60. package/dist/cjs/utils/astProcessing.d.ts +4 -1
  61. package/dist/cjs/utils/astProcessing.d.ts.map +1 -1
  62. package/dist/cjs/utils/astProcessing.js +2 -2
  63. package/dist/cjs/utils/client.d.ts.map +1 -1
  64. package/dist/cjs/utils/client.js +6 -3
  65. package/dist/cjs/utils/columnProcessing.d.ts +1 -0
  66. package/dist/cjs/utils/columnProcessing.d.ts.map +1 -1
  67. package/dist/cjs/utils/columnProcessing.js +1 -0
  68. package/dist/cjs/utils/dashboard.d.ts +2 -1
  69. package/dist/cjs/utils/dashboard.d.ts.map +1 -1
  70. package/dist/cjs/utils/dashboard.js +38 -10
  71. package/dist/cjs/utils/filterProcessing.d.ts +1 -1
  72. package/dist/cjs/utils/filterProcessing.d.ts.map +1 -1
  73. package/dist/cjs/utils/merge.d.ts +16 -0
  74. package/dist/cjs/utils/merge.d.ts.map +1 -1
  75. package/dist/cjs/utils/merge.js +210 -0
  76. package/dist/cjs/utils/paginationProcessing.d.ts +1 -1
  77. package/dist/cjs/utils/paginationProcessing.d.ts.map +1 -1
  78. package/dist/cjs/utils/paginationProcessing.js +3 -2
  79. package/dist/cjs/utils/pivotConstructor.d.ts +19 -9
  80. package/dist/cjs/utils/pivotConstructor.d.ts.map +1 -1
  81. package/dist/cjs/utils/pivotConstructor.js +90 -34
  82. package/dist/cjs/utils/queryConstructor.d.ts +8 -1
  83. package/dist/cjs/utils/queryConstructor.d.ts.map +1 -1
  84. package/dist/cjs/utils/queryConstructor.js +276 -310
  85. package/dist/cjs/utils/report.d.ts +25 -12
  86. package/dist/cjs/utils/report.d.ts.map +1 -1
  87. package/dist/cjs/utils/report.js +13 -7
  88. package/dist/cjs/utils/schema.d.ts +1 -1
  89. package/dist/cjs/utils/schema.d.ts.map +1 -1
  90. package/dist/cjs/utils/schema.js +3 -32
  91. package/dist/cjs/utils/tableProcessing.d.ts +43 -13
  92. package/dist/cjs/utils/tableProcessing.d.ts.map +1 -1
  93. package/dist/cjs/utils/tableProcessing.js +140 -75
  94. package/dist/cjs/utils/textProcessing.d.ts.map +1 -1
  95. package/dist/cjs/utils/textProcessing.js +10 -1
  96. package/dist/cjs/utils/valueFormatter.d.ts +2 -1
  97. package/dist/cjs/utils/valueFormatter.d.ts.map +1 -1
  98. package/dist/cjs/utils/valueFormatter.js +18 -14
  99. package/dist/esm/Chart.d.ts +0 -1
  100. package/dist/esm/Chart.d.ts.map +1 -1
  101. package/dist/esm/Chart.js +0 -6
  102. package/dist/esm/ChartBuilder.d.ts +1 -0
  103. package/dist/esm/ChartBuilder.d.ts.map +1 -1
  104. package/dist/esm/ChartBuilder.js +179 -97
  105. package/dist/esm/Context.d.ts.map +1 -1
  106. package/dist/esm/Context.js +7 -9
  107. package/dist/esm/Dashboard.d.ts +2 -1
  108. package/dist/esm/Dashboard.d.ts.map +1 -1
  109. package/dist/esm/Dashboard.js +1 -1
  110. package/dist/esm/ReportBuilder.d.ts +2 -0
  111. package/dist/esm/ReportBuilder.d.ts.map +1 -1
  112. package/dist/esm/ReportBuilder.js +399 -272
  113. package/dist/esm/SQLEditor.d.ts.map +1 -1
  114. package/dist/esm/SQLEditor.js +33 -11
  115. package/dist/esm/Table.d.ts.map +1 -1
  116. package/dist/esm/Table.js +17 -1
  117. package/dist/esm/components/Chart/InternalChart.d.ts +0 -1
  118. package/dist/esm/components/Chart/InternalChart.d.ts.map +1 -1
  119. package/dist/esm/components/Chart/InternalChart.js +6 -6
  120. package/dist/esm/components/Dashboard/DataLoader.d.ts.map +1 -1
  121. package/dist/esm/components/Dashboard/DataLoader.js +75 -30
  122. package/dist/esm/components/Dashboard/MetricComponent.d.ts +1 -1
  123. package/dist/esm/components/Dashboard/MetricComponent.d.ts.map +1 -1
  124. package/dist/esm/components/Dashboard/MetricComponent.js +98 -106
  125. package/dist/esm/components/QuillMultiSelectSectionList.d.ts.map +1 -1
  126. package/dist/esm/components/QuillMultiSelectSectionList.js +5 -12
  127. package/dist/esm/components/QuillMultiSelectWithCombo.js +1 -1
  128. package/dist/esm/components/ReportBuilder/AddLimitPopover.d.ts +1 -1
  129. package/dist/esm/components/ReportBuilder/AddLimitPopover.d.ts.map +1 -1
  130. package/dist/esm/components/ReportBuilder/AddLimitPopover.js +2 -2
  131. package/dist/esm/components/ReportBuilder/AddSortPopover.d.ts +16 -4
  132. package/dist/esm/components/ReportBuilder/AddSortPopover.d.ts.map +1 -1
  133. package/dist/esm/components/ReportBuilder/AddSortPopover.js +9 -18
  134. package/dist/esm/components/UiComponents.d.ts +2 -1
  135. package/dist/esm/components/UiComponents.d.ts.map +1 -1
  136. package/dist/esm/components/UiComponents.js +27 -21
  137. package/dist/esm/hooks/useAskQuill.d.ts.map +1 -1
  138. package/dist/esm/hooks/useAskQuill.js +28 -4
  139. package/dist/esm/hooks/useQuill.d.ts.map +1 -1
  140. package/dist/esm/hooks/useQuill.js +10 -2
  141. package/dist/esm/hooks/useVirtualTables.d.ts.map +1 -1
  142. package/dist/esm/hooks/useVirtualTables.js +12 -36
  143. package/dist/esm/internals/ReportBuilder/PivotForm.d.ts.map +1 -1
  144. package/dist/esm/internals/ReportBuilder/PivotForm.js +14 -2
  145. package/dist/esm/internals/ReportBuilder/PivotModal.d.ts +12 -11
  146. package/dist/esm/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
  147. package/dist/esm/internals/ReportBuilder/PivotModal.js +63 -18
  148. package/dist/esm/models/Client.d.ts +4 -5
  149. package/dist/esm/models/Client.d.ts.map +1 -1
  150. package/dist/esm/models/Pivot.d.ts +10 -0
  151. package/dist/esm/models/Pivot.d.ts.map +1 -1
  152. package/dist/esm/models/Report.d.ts +13 -1
  153. package/dist/esm/models/Report.d.ts.map +1 -1
  154. package/dist/esm/utils/astFilterProcessing.d.ts +1 -1
  155. package/dist/esm/utils/astFilterProcessing.d.ts.map +1 -1
  156. package/dist/esm/utils/astFilterProcessing.js +799 -64
  157. package/dist/esm/utils/astProcessing.d.ts +4 -1
  158. package/dist/esm/utils/astProcessing.d.ts.map +1 -1
  159. package/dist/esm/utils/astProcessing.js +2 -2
  160. package/dist/esm/utils/client.d.ts.map +1 -1
  161. package/dist/esm/utils/client.js +6 -3
  162. package/dist/esm/utils/columnProcessing.d.ts +1 -0
  163. package/dist/esm/utils/columnProcessing.d.ts.map +1 -1
  164. package/dist/esm/utils/columnProcessing.js +1 -1
  165. package/dist/esm/utils/dashboard.d.ts +2 -1
  166. package/dist/esm/utils/dashboard.d.ts.map +1 -1
  167. package/dist/esm/utils/dashboard.js +39 -11
  168. package/dist/esm/utils/filterProcessing.d.ts +1 -1
  169. package/dist/esm/utils/filterProcessing.d.ts.map +1 -1
  170. package/dist/esm/utils/merge.d.ts +16 -0
  171. package/dist/esm/utils/merge.d.ts.map +1 -1
  172. package/dist/esm/utils/merge.js +207 -0
  173. package/dist/esm/utils/paginationProcessing.d.ts +1 -1
  174. package/dist/esm/utils/paginationProcessing.d.ts.map +1 -1
  175. package/dist/esm/utils/paginationProcessing.js +3 -2
  176. package/dist/esm/utils/pivotConstructor.d.ts +19 -9
  177. package/dist/esm/utils/pivotConstructor.d.ts.map +1 -1
  178. package/dist/esm/utils/pivotConstructor.js +91 -35
  179. package/dist/esm/utils/queryConstructor.d.ts +8 -1
  180. package/dist/esm/utils/queryConstructor.d.ts.map +1 -1
  181. package/dist/esm/utils/queryConstructor.js +274 -314
  182. package/dist/esm/utils/report.d.ts +25 -12
  183. package/dist/esm/utils/report.d.ts.map +1 -1
  184. package/dist/esm/utils/report.js +13 -7
  185. package/dist/esm/utils/schema.d.ts +1 -1
  186. package/dist/esm/utils/schema.d.ts.map +1 -1
  187. package/dist/esm/utils/schema.js +1 -30
  188. package/dist/esm/utils/tableProcessing.d.ts +43 -13
  189. package/dist/esm/utils/tableProcessing.d.ts.map +1 -1
  190. package/dist/esm/utils/tableProcessing.js +140 -75
  191. package/dist/esm/utils/textProcessing.d.ts.map +1 -1
  192. package/dist/esm/utils/textProcessing.js +10 -1
  193. package/dist/esm/utils/valueFormatter.d.ts +2 -1
  194. package/dist/esm/utils/valueFormatter.d.ts.map +1 -1
  195. package/dist/esm/utils/valueFormatter.js +18 -14
  196. package/package.json +1 -1
@@ -1,11 +1,17 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.processSingleQuotes = processSingleQuotes;
4
+ exports.processAggType = processAggType;
3
5
  exports.processColumnReference = processColumnReference;
4
6
  exports.replaceSpacesWithUnderscores = replaceSpacesWithUnderscores;
7
+ exports.processDateTrunc = processDateTrunc;
8
+ exports.processValueField = processValueField;
5
9
  exports.generateCountQuery = generateCountQuery;
6
10
  exports.generateDistinctQuery = generateDistinctQuery;
7
11
  exports.generateMinMaxDateRangeQueries = generateMinMaxDateRangeQueries;
8
12
  exports.generatePivotQuery = generatePivotQuery;
13
+ exports.additionalProcessingOnPivotQuery = additionalProcessingOnPivotQuery;
14
+ exports.generateRowCountQuery = generateRowCountQuery;
9
15
  const columnProcessing_1 = require("./columnProcessing");
10
16
  const constants_1 = require("./constants");
11
17
  const pivotProcessing_1 = require("./pivotProcessing");
@@ -92,6 +98,23 @@ isPivotColumnFieldAlias, isPivotValueFieldAlias) {
92
98
  }
93
99
  return `\`${replaceBigQuerySpecialCharacters(column.replaceAll('`', ''))}\``;
94
100
  }
101
+ case 'mssql': {
102
+ if (column === '') {
103
+ return fallbackOnNull ? `[${fallbackOnNull}]` : `[_]`;
104
+ }
105
+ if (isPivotColumnFieldAlias) {
106
+ return `[${column.replaceAll(']', '').replaceAll('[', '')}]`;
107
+ }
108
+ const columnParts = column.split('.');
109
+ if (columnParts.length > 1) {
110
+ return (`[` +
111
+ columnParts
112
+ .map((part) => part.replaceAll(']', '').replaceAll('[', ''))
113
+ .join('].[`') +
114
+ `]`);
115
+ }
116
+ return `[${column.replaceAll(']', '').replaceAll('[', '')}]`;
117
+ }
95
118
  default:
96
119
  return column;
97
120
  }
@@ -109,27 +132,33 @@ function processInterval(interval, rowField, databaseType) {
109
132
  return `TIMESTAMP_ADD(${processColumnReference(rowField, databaseType)}, INTERVAL ${interval} )`;
110
133
  }
111
134
  function processDateTrunc(dateBucket, rowField, databaseType, comparisonInterval) {
135
+ const dateField = comparisonInterval
136
+ ? processInterval(comparisonInterval, rowField, databaseType)
137
+ : processColumnReference(rowField, databaseType);
112
138
  if (['postgresql', 'snowflake'].includes(databaseType.toLowerCase())) {
113
- const dateField = comparisonInterval
114
- ? processInterval(comparisonInterval, rowField, databaseType)
115
- : processColumnReference(rowField, databaseType);
116
139
  return `date_trunc('${dateBucket}', ${dateField})`;
117
140
  }
118
141
  if (['clickhouse'].includes(databaseType.toLowerCase())) {
119
- const dateField = comparisonInterval
120
- ? processInterval(comparisonInterval, rowField, databaseType)
121
- : processColumnReference(rowField, databaseType);
122
142
  return `dateTrunc('${dateBucket}', ${dateField})`;
123
143
  }
124
144
  if (['mysql'].includes(databaseType.toLowerCase())) {
125
- const dateField = comparisonInterval
126
- ? processInterval(comparisonInterval, rowField, databaseType)
127
- : processColumnReference(rowField, databaseType);
128
- return `extract(${dateBucket} from ${dateField})`;
145
+ switch (dateBucket.toLowerCase()) {
146
+ case 'year':
147
+ return `DATE_FORMAT(${dateField}, '%Y-01-01 00:00:00')`;
148
+ case 'month':
149
+ return `DATE_FORMAT(${dateField}, '%Y-%m-01 00:00:00')`;
150
+ case 'week':
151
+ return `DATE_FORMAT(${dateField}, '%Y-%U-1 00:00:00')`;
152
+ case 'day':
153
+ default:
154
+ return `DATE(${dateField})`;
155
+ }
156
+ }
157
+ if (['mssql'].includes(databaseType.toLowerCase())) {
158
+ // note DATETRUNC is for mssql >= 2022
159
+ return `DATETRUNC(${dateBucket}, ${dateField})`;
160
+ // return `FORMAT(${dateField}, '${mssqlDateBucketFormat(dateBucket)}')`;
129
161
  }
130
- const dateField = comparisonInterval
131
- ? processInterval(comparisonInterval, rowField, databaseType)
132
- : processColumnReference(rowField, databaseType);
133
162
  return `TIMESTAMP_TRUNC(${dateField}, ${dateBucket})`;
134
163
  }
135
164
  function processValueField(aggType, databaseType, valueField) {
@@ -172,6 +201,8 @@ function generateDistinctQuery(stringFields, query, databaseType) {
172
201
  return generateDistinctQueryPostgres(stringFields, query);
173
202
  case 'snowflake':
174
203
  return generateDistinctQuerySnowflake(stringFields, query);
204
+ case 'mssql':
205
+ return generateDistinctQueryMSSQL(stringFields, query);
175
206
  default:
176
207
  return generateDistinctQueryDefault(stringFields, query, databaseType);
177
208
  }
@@ -207,44 +238,73 @@ function generateDistinctQuerySnowflake(stringFields, query) {
207
238
  const distinctQuery = distinctQueries.join(' UNION ALL ');
208
239
  return `WITH querytable AS (${query.replace(';', '')}) ` + distinctQuery;
209
240
  }
241
+ // Not the ideal way to do things, but node-sql-parser doesn't support
242
+ // DISTINCT or JSON PATH for transactsql at the moment
243
+ // Note, this does not return an array like the other functions, so we need to keep that in mind
244
+ // for mssql distinct values when we attempt to parse them
245
+ function generateDistinctQueryMSSQL(stringFields, query) {
246
+ const escapeFieldName = (field) => field.replace(/'/g, "''");
247
+ const distinctQueries = stringFields.map((field) => {
248
+ return `
249
+ SELECT
250
+ '${escapeFieldName(field)}' AS field,
251
+ STRING_AGG(${field}, ',') AS string_values
252
+ FROM (
253
+ SELECT ${field}
254
+ FROM querytable
255
+ WHERE ${field} IS NOT NULL
256
+ GROUP BY ${field}
257
+ ) AS grouped
258
+ `
259
+ .replace(/\s+/g, ' ')
260
+ .trim();
261
+ });
262
+ const distinctQuery = distinctQueries.join(' UNION ALL ');
263
+ return `
264
+ WITH querytable AS (
265
+ ${query.replace(';', '')}
266
+ )
267
+ ${distinctQuery}`
268
+ .replace(/\s+/g, ' ')
269
+ .trim();
270
+ }
210
271
  function generateMinMaxDateRangeQueries(columnFields, query, databaseType) {
211
272
  const max = 'MAX';
212
273
  const min = 'MIN';
274
+ const cast = databaseType.toLowerCase() === 'snowflake' ? '::TIMESTAMP_TZ' : '';
213
275
  const distinctQueries = columnFields.map((field) => {
214
276
  const wrappedField = ['postgresql', 'clickhouse'].includes(databaseType.toLowerCase())
215
277
  ? `"${field}"`
216
278
  : field;
217
- return `SELECT '${field}' AS field, ${min}(${wrappedField}) AS min_range, ${max}(${wrappedField}) AS max_range FROM querytable`;
279
+ return `SELECT '${field}' AS field, ${min}(${wrappedField})${cast} AS min_range, ${max}(${wrappedField})${cast} AS max_range FROM querytable`;
218
280
  });
219
281
  const distinctQuery = distinctQueries.join(' UNION ALL ');
220
282
  return `WITH querytable AS (${query.replace(';', '')}) ` + distinctQuery;
221
283
  }
222
- function generatePivotQuery(pivot, itemQueries, databaseType, comparisonInterval, distinctStrings, dateBucket, rowLimit) {
284
+ function generatePivotQuery(pivot, itemQuery, databaseType, distinctStrings, dateBucket) {
223
285
  if (!(0, pivotProcessing_1.isValidPivot)(pivot).valid) {
224
286
  return undefined;
225
287
  }
226
- if (pivot.columnField) {
227
- return create2DPivotQuery(pivot, itemQueries, databaseType, dateBucket, comparisonInterval, distinctStrings, rowLimit);
288
+ if (pivot.columnField && distinctStrings && distinctStrings.length > 0) {
289
+ return create2DPivotQuery(pivot, itemQuery, databaseType, distinctStrings, dateBucket);
228
290
  }
229
291
  if (pivot.rowField) {
230
- return create1DPivotQuery(pivot, itemQueries, dateBucket, databaseType, comparisonInterval, rowLimit);
292
+ return create1DPivotQuery(pivot, itemQuery, dateBucket, databaseType);
231
293
  }
232
- return createAggregationValuePivot(pivot, itemQueries, databaseType, rowLimit);
294
+ return createAggregationValuePivot(pivot, itemQuery, databaseType);
233
295
  }
234
- function create2DPivotQuery(pivot, itemQueries, databaseType, dateBucket, comparisonInterval, columnFieldValues, rowLimit) {
296
+ function create2DPivotQuery(pivot, itemQuery, databaseType, columnFieldValues, dateBucket) {
235
297
  if (!pivot || !pivot.columnField) {
236
298
  return undefined;
237
299
  }
238
- if (!columnFieldValues) {
239
- return undefined;
240
- }
241
300
  if ((0, columnProcessing_1.isStringType)(pivot.rowFieldType || '') || !pivot.rowFieldType) {
242
- return create2DStringPivotQuery(pivot, itemQueries, columnFieldValues, databaseType, rowLimit);
301
+ return create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType);
243
302
  }
244
- return create2DDatePivotQuery(pivot, itemQueries, columnFieldValues, databaseType, dateBucket, comparisonInterval, rowLimit);
303
+ return create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseType, dateBucket);
245
304
  }
246
- function create2DStringPivotQuery(pivot, itemQueries, columnFieldValues, databaseType, rowLimit) {
247
- if (!pivot.columnField || !pivot.rowField) {
305
+ function create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType) {
306
+ const isValidBaseQuery = itemQuery.match(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/);
307
+ if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField) {
248
308
  return undefined;
249
309
  }
250
310
  const rowField = pivot.rowField;
@@ -253,97 +313,44 @@ function create2DStringPivotQuery(pivot, itemQueries, columnFieldValues, databas
253
313
  const rowFieldAlias = processColumnReference(rowField, databaseType, undefined, false, true);
254
314
  const valueFieldAlias = processColumnReference(valueField ?? rowField, databaseType, undefined, false, true);
255
315
  const columnFieldAlias = processColumnReference(columnField, databaseType, undefined, false, true);
256
- const max = 'GREATEST';
257
316
  const valueAliasSubstring = valueField
258
317
  ? `${processColumnReference(valueField, databaseType, undefined, true)} AS ${valueFieldAlias},`
259
318
  : '';
319
+ let value2AliasSubstring = '';
320
+ let caseWhens = columnFieldValues.map((column) => {
321
+ return `${processAggType(pivot.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) AS ${processColumnReference(column, databaseType, '_', true)}`;
322
+ });
260
323
  if (pivot.aggregationType === 'percentage' && pivot.valueField2) {
261
324
  const valueField2Alias = processColumnReference(pivot.valueField2, databaseType, undefined, false, true);
262
- const value2AliasSubstring = `${processColumnReference(pivot.valueField2, databaseType, undefined, true)} AS ${valueField2Alias},`;
263
325
  if (pivot.valueField === pivot.valueField2) {
264
- const caseWhens = columnFieldValues.map((column) => {
265
- return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / ${max}(sum(${processColumnReference(pivot.valueField2, databaseType)}), 1) AS ${processColumnReference(column, databaseType, '_', true)}`;
326
+ caseWhens = columnFieldValues.map((column) => {
327
+ return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / GREATEST(sum(${processColumnReference(pivot.valueField2, databaseType)}), 1) AS ${processColumnReference(column, databaseType, '_', true)}`;
266
328
  });
267
- const caseWhensCompare = columnFieldValues.map((column) => {
268
- return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)}) / ${max}(sum(${processColumnReference(pivot.valueField2, databaseType)}), 1) AS ${processColumnReference(`comparison_${column}`, databaseType, '_', true)}`;
329
+ }
330
+ else {
331
+ value2AliasSubstring = `${processColumnReference(pivot.valueField2, databaseType, undefined, true)} AS ${valueField2Alias},`;
332
+ caseWhens = columnFieldValues.map((column) => {
333
+ return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueField2Alias)} END), 1) AS ${processColumnReference(column, databaseType, '_', true)}`;
269
334
  });
270
- const compareCTE = itemQueries[1]
271
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
272
- : '';
273
- const aliasCTE = itemQueries[1]
274
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring}
275
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_ct)`
276
- : '';
277
- const compareCaseWhenCTE = itemQueries[1]
278
- ? `, quill_ct_cw as (SELECT ${rowFieldAlias} as ${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)}${caseWhensCompare.length > 0 ? `, ${caseWhensCompare.join(', ')}` : ''} FROM quill_c_alias GROUP BY ${rowFieldAlias})`
279
- : '';
280
- const joinQuery = itemQueries[1]
281
- ? `JOIN quill_ct_cw ct ON ct.${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)} = qt.${rowFieldAlias}`
282
- : '';
283
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}),
284
- quill_alias AS (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring}
285
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_qt),
286
- quill_qt_cw AS (SELECT ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''} FROM quill_alias GROUP BY ${rowFieldAlias})
287
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
288
- SELECT * FROM quill_qt_cw qt
289
- ${joinQuery}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
290
335
  }
291
- const caseWhens = columnFieldValues.map((column) => {
292
- return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / ${max}(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueField2Alias)} END), 1) AS ${processColumnReference(column, databaseType, '_', true)}`;
293
- });
294
- const caseWhensCompare = columnFieldValues.map((column) => {
295
- return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / ${max}(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueField2Alias)} END), 1) AS ${processColumnReference(`comparison_${column}`, databaseType, '_', true)}`;
296
- });
297
- const compareCTE = itemQueries[1]
298
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
299
- : '';
300
- const aliasCTE = itemQueries[1]
301
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring} ${value2AliasSubstring}
302
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_ct)`
303
- : '';
304
- const compareCaseWhenCTE = itemQueries[1]
305
- ? `, quill_ct_cw as (SELECT ${rowFieldAlias} as ${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)}${caseWhensCompare.length > 0 ? `, ${caseWhensCompare.join(', ')}` : ''} FROM quill_c_alias GROUP BY ${rowFieldAlias})`
306
- : '';
307
- const joinQuery = itemQueries[1]
308
- ? `JOIN quill_ct_cw ct ON ct.${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)} = qt.${rowFieldAlias}`
309
- : '';
310
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}),
311
- quill_alias AS (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring} ${value2AliasSubstring}
312
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_qt),
313
- quill_qt_cw AS (SELECT ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''} FROM quill_alias GROUP BY ${rowFieldAlias})
314
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
315
- SELECT * FROM quill_qt_cw qt
316
- ${joinQuery}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
317
336
  }
318
- const caseWhens = columnFieldValues.map((column) => {
319
- return `${processAggType(pivot.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) AS ${processColumnReference(column, databaseType, '_', true)}`;
320
- });
321
- const caseWhensCompare = columnFieldValues.map((column) => {
322
- return `${processAggType(pivot.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) AS ${processColumnReference(`comparison_${column}`, databaseType, '_', true)}`;
323
- });
324
- const compareCTE = itemQueries[1]
325
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
326
- : '';
327
- const aliasCTE = itemQueries[1]
328
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring}
329
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_ct)`
330
- : '';
331
- const compareCaseWhenCTE = itemQueries[1]
332
- ? `, quill_ct_cw as (SELECT ${rowFieldAlias} as ${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)}${caseWhensCompare.length > 0 ? `, ${caseWhensCompare.join(', ')}` : ''} FROM quill_c_alias GROUP BY ${rowFieldAlias})`
333
- : '';
334
- const joinQuery = itemQueries[1]
335
- ? `JOIN quill_ct_cw ct ON ct.${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)} = qt.${rowFieldAlias}`
336
- : '';
337
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}),
338
- quill_alias AS (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring}
339
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_qt),
340
- quill_qt_cw AS (SELECT ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''} FROM quill_alias GROUP BY ${rowFieldAlias})
341
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
342
- SELECT * FROM quill_qt_cw qt
343
- ${joinQuery}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
337
+ // pivot sort matters in the base query when there is a rowLimit. In mssql, an orderby must be accompanied by a limit in a subquery and not allowed in a cte
338
+ const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} ` : ''}`;
339
+ const pivotQuery = `
340
+ ,quill_alias AS (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring} ${value2AliasSubstring}
341
+ ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_base_table),
342
+ quill_qt_cw AS (SELECT ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''} FROM quill_alias GROUP BY ${rowFieldAlias}),
343
+ quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} * FROM quill_qt_cw qt
344
+ ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''})
345
+ SELECT * FROM quill_base_pivot
346
+ `
347
+ .replace(/\s+/g, ' ')
348
+ .trim();
349
+ return itemQuery.replace(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/, pivotQuery);
344
350
  }
345
- function create2DDatePivotQuery(pivot, itemQueries, columnFieldValues, databaseType, dateBucket = 'month', comparisonInterval, rowLimit) {
346
- if (!pivot.columnField || !pivot.rowField) {
351
+ function create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseType, dateBucket = 'month') {
352
+ const isValidBaseQuery = itemQuery.match(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/);
353
+ if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField) {
347
354
  return undefined;
348
355
  }
349
356
  const rowField = pivot.rowField;
@@ -354,246 +361,205 @@ function create2DDatePivotQuery(pivot, itemQueries, columnFieldValues, databaseT
354
361
  const valueAliasSubstring = pivot.valueField
355
362
  ? `${processColumnReference(pivot.valueField, databaseType, undefined, true)} AS ${valueFieldAlias},`
356
363
  : '';
357
- const max = 'GREATEST';
364
+ let value2AliasSubstring = '';
365
+ let caseWhens = columnFieldValues.map((column) => {
366
+ return `${processAggType(pivot.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) AS ${processColumnReference(column, databaseType, '_', true)}`;
367
+ });
358
368
  if (pivot.aggregationType === 'percentage' && pivot.valueField2) {
359
369
  const valueField2Alias = processColumnReference(pivot.valueField2, databaseType, undefined, false, true);
360
- const value2AliasSubstring = `${processColumnReference(pivot.valueField2, databaseType, undefined, true)} AS ${valueField2Alias},`;
361
370
  // edge case. if the user picks amount and amount, we assume they want a pie chart like breakdown of amount. so the summation of valueField2 has to be moved outside of the case when
362
371
  if (pivot.valueField === pivot.valueField2) {
363
- const caseWhens = columnFieldValues.map((column) => {
364
- return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / ${max}(sum(${processColumnReference(valueField2Alias, databaseType)}), 1) AS ${processColumnReference(column, databaseType, '_', true)}`;
372
+ caseWhens = columnFieldValues.map((column) => {
373
+ return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / GREATEST(sum(${processColumnReference(valueField2Alias, databaseType)}), 1) AS ${processColumnReference(column, databaseType, '_', true)}`;
365
374
  });
366
- const caseWhensCompare = columnFieldValues.map((column) => {
367
- return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / ${max}(sum(${processColumnReference(valueField2Alias, databaseType)}), 1) AS ${processColumnReference(`comparison_${column}`, databaseType, '_', true)}`;
375
+ }
376
+ else {
377
+ value2AliasSubstring = `${processColumnReference(pivot.valueField2, databaseType, undefined, true)} AS ${valueField2Alias},`;
378
+ caseWhens = columnFieldValues.map((column) => {
379
+ return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueField2Alias)} END), 1) AS ${processColumnReference(column, databaseType, '_', true)}`;
368
380
  });
369
- const compareCTE = itemQueries[1] && comparisonInterval
370
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
371
- : '';
372
- const aliasCTE = itemQueries[1] && comparisonInterval
373
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring}
374
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_ct)`
375
- : '';
376
- const compareCaseWhenCTE = itemQueries[1] && comparisonInterval
377
- ? `, quill_ct_cw as (SELECT ${processDateTrunc(dateBucket, rowField, databaseType)} as ${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)}${caseWhensCompare.length > 0 ? `, ${caseWhensCompare.join(', ')}` : ''} FROM quill_c_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})`
378
- : '';
379
- const joinQuery = itemQueries[1] && comparisonInterval
380
- ? `LEFT JOIN quill_ct_cw ${processColumnReference(`ct`, databaseType)} ON qt.${rowFieldAlias} = ${processDateTrunc(dateBucket, `ct.comparison_${rowFieldAlias}`, databaseType, comparisonInterval)}`
381
- : '';
382
- return `WITH quill_query_table AS (${itemQueries[0]?.replaceAll(';', '')}),
383
- quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring}
384
- ${processColumnReference(columnField, databaseType, undefined, true, true)} AS ${columnFieldAlias} FROM quill_query_table),
385
- quill_qt_agg as (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})
386
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
387
- SELECT * FROM quill_qt_agg qt
388
- ${joinQuery} ORDER BY qt.${rowFieldAlias}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
389
381
  }
390
- const caseWhens = columnFieldValues.map((column) => {
391
- return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / ${max}(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueField2Alias)} END), 1) AS ${processColumnReference(column, databaseType, '_', true)}`;
392
- });
393
- const caseWhensCompare = columnFieldValues.map((column) => {
394
- return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) / ${max}(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueField2Alias)} END), 1) AS ${processColumnReference(`comparison_${column}`, databaseType, '_', true)}`;
395
- });
396
- const compareCTE = itemQueries[1] && comparisonInterval
397
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
398
- : '';
399
- const aliasCTE = itemQueries[1] && comparisonInterval
400
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring} ${value2AliasSubstring}
401
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_ct)`
402
- : '';
403
- const compareCaseWhenCTE = itemQueries[1] && comparisonInterval
404
- ? `, quill_ct_cw as (SELECT ${processDateTrunc(dateBucket, rowField, databaseType)} as ${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)}${caseWhensCompare.length > 0 ? `, ${caseWhensCompare.join(', ')}` : ''} FROM quill_c_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})`
405
- : '';
406
- const joinQuery = itemQueries[1] && comparisonInterval
407
- ? `LEFT JOIN quill_ct_cw ${processColumnReference(`ct`, databaseType)} ON qt.${rowFieldAlias} = ${processDateTrunc(dateBucket, `ct.comparison_${rowFieldAlias}`, databaseType, comparisonInterval)}`
408
- : '';
409
- return `WITH quill_query_table AS (${itemQueries[0]?.replaceAll(';', '')}),
410
- quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring} ${value2AliasSubstring}
411
- ${processColumnReference(columnField, databaseType, undefined, true, true)} AS ${columnFieldAlias} FROM quill_query_table),
412
- quill_qt_agg as (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})
413
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
414
- SELECT * FROM quill_qt_agg qt
415
- ${joinQuery} ORDER BY qt.${rowFieldAlias}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
416
382
  }
417
- const caseWhens = columnFieldValues.map((column) => {
418
- return `${processAggType(pivot.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) AS ${processColumnReference(column, databaseType, '_', true)}`;
419
- });
420
- const caseWhensCompare = columnFieldValues.map((column) => {
421
- return `${processAggType(pivot.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${processValueField(pivot.aggregationType, databaseType, valueFieldAlias)} END) AS ${processColumnReference(`comparison_${column}`, databaseType, '_', true)}`;
422
- });
423
- const compareCTE = itemQueries[1] && comparisonInterval
424
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
425
- : '';
426
- const aliasCTE = itemQueries[1] && comparisonInterval
427
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring}
428
- ${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias} FROM quill_ct)`
429
- : '';
430
- const compareCaseWhenCTE = itemQueries[1] && comparisonInterval
431
- ? `, quill_ct_cw as (SELECT ${processDateTrunc(dateBucket, rowField, databaseType)} as ${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)}${caseWhensCompare.length > 0 ? `, ${caseWhensCompare.join(', ')}` : ''} FROM quill_c_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})`
432
- : '';
433
- const joinQuery = itemQueries[1] && comparisonInterval
434
- ? `LEFT JOIN quill_ct_cw ${processColumnReference(`ct`, databaseType)} ON qt.${rowFieldAlias} = ${processDateTrunc(dateBucket, `ct.comparison_${rowFieldAlias}`, databaseType, comparisonInterval)}`
435
- : '';
436
- return `WITH quill_query_table AS (${itemQueries[0]?.replaceAll(';', '')}),
437
- quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring}
438
- ${processColumnReference(columnField, databaseType, undefined, true, true)} AS ${columnFieldAlias} FROM quill_query_table),
439
- quill_qt_agg as (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})
440
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
441
- SELECT * FROM quill_qt_agg qt
442
- ${joinQuery} ORDER BY qt.${rowFieldAlias}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
383
+ // pivot sort matters in the base query when there is a rowLimit. In mssql, an orderby must be accompanied by a limit in a subquery and not allowed in a cte
384
+ const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} ` : ''}`;
385
+ const pivotQuery = `
386
+ , quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowFieldAlias}, ${valueAliasSubstring} ${value2AliasSubstring}
387
+ ${processColumnReference(columnField, databaseType, undefined, true, true)} AS ${columnFieldAlias} FROM quill_base_table),
388
+ quill_qt_agg AS (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
389
+ quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} * FROM quill_qt_agg qt
390
+ ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''})
391
+ SELECT * FROM quill_base_pivot
392
+ `
393
+ .replace(/\s+/g, ' ')
394
+ .trim();
395
+ return itemQuery.replace(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/, pivotQuery);
443
396
  }
444
- function create1DPivotQuery(pivot, itemQueries, dateBucket = 'month', databaseType, comparisonInterval, rowLimit) {
397
+ function create1DPivotQuery(pivot, itemQuery, dateBucket = 'month', databaseType) {
445
398
  if ((0, columnProcessing_1.isStringType)(pivot.rowFieldType || '') || !pivot.rowFieldType) {
446
- return create1DStringPivotQuery(pivot, itemQueries, databaseType, rowLimit);
399
+ return create1DStringPivotQuery(pivot, itemQuery, databaseType);
447
400
  }
448
- return create1DDatePivotQuery(pivot, itemQueries, dateBucket, databaseType, comparisonInterval, rowLimit);
401
+ return create1DDatePivotQuery(pivot, itemQuery, dateBucket, databaseType);
449
402
  }
450
- function create1DStringPivotQuery(pivot, itemQueries, databaseType, rowLimit) {
403
+ // we have an item query that is guaranteed to end in SELECT * FROM [quill_base_table]
404
+ // also, stop fetching the comparison rows in the same query, since we're no longer wrapping everything in
405
+ // their own with statements and withs with the same name will conflict
406
+ function create1DStringPivotQuery(pivot, itemQuery, databaseType) {
407
+ const isValidBaseQuery = itemQuery.match(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/);
408
+ if (!isValidBaseQuery) {
409
+ return undefined;
410
+ }
451
411
  const rowField = pivot.rowField;
452
412
  const valueField = pivot.valueField;
453
413
  const rowAlias = processColumnReference(rowField, databaseType, undefined, false, true);
454
414
  const valueAlias = processColumnReference(valueField ?? rowField, databaseType, undefined, false, true);
455
415
  const countAlias = processColumnReference('count', databaseType);
456
- const max = 'GREATEST';
457
416
  const valueAliasSubstring = valueField
458
417
  ? `, ${processColumnReference(`${valueField}`, databaseType, undefined, true)} AS ${valueAlias}`
459
418
  : ``;
419
+ let value2AliasSubstring = '';
420
+ let quillSelectSubstring = `${rowAlias}, ${processAggType(pivot.aggregationType)}(${valueField ? valueAlias : '*'}) as ${valueField ? valueAlias : countAlias}`;
460
421
  if (pivot.aggregationType === 'percentage' && pivot.valueField2) {
461
422
  const value2Alias = processColumnReference(pivot.valueField2, databaseType, undefined, false, true);
462
- const value2AliasSubstring = valueField && valueField !== pivot.valueField2
463
- ? `, ${processColumnReference(`${pivot.valueField2}`, databaseType, undefined, true)} AS ${value2Alias}`
464
- : ``;
465
- const compareCTE = itemQueries[1]
466
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
467
- : '';
468
- const aliasCTE = itemQueries[1]
469
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowAlias}${valueAliasSubstring}${value2AliasSubstring} FROM quill_ct)`
470
- : '';
471
- const compareCaseWhenCTE = itemQueries[1]
472
- ? `, quill_ct_cw as (SELECT ${rowAlias} as ${processColumnReference(`comparison_${rowAlias}`, databaseType)}, ${processAggType(pivot.aggregationType)}(${valueField ? valueAlias : '*'}) as ${processColumnReference(`comparison_${valueField ? valueAlias : countAlias}`, databaseType)} FROM quill_c_alias GROUP BY ${rowAlias})`
473
- : '';
474
- const joinQuery = itemQueries[1]
475
- ? `JOIN quill_ct_cw ct ON ct.${processColumnReference(`comparison_${rowField}`, databaseType)} = qt.${processColumnReference(`${rowField}`, databaseType)}`
476
- : '';
477
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}),
478
- quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowAlias}${valueAliasSubstring}${value2AliasSubstring} FROM quill_qt),
479
- quill_qt_cw AS (SELECT ${rowAlias}, sum(${valueAlias}) / ${max}(sum(${value2Alias}), 1) as ${processColumnReference(`${valueField ?? ''}_${(0, textProcessing_1.matchCasing)('percentage', valueField)}`, databaseType, undefined, false, true)} FROM quill_alias GROUP BY ${rowAlias})
480
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
481
- SELECT * FROM quill_qt_cw qt
482
- ${joinQuery}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
423
+ if (pivot.valueField !== pivot.valueField2) {
424
+ value2AliasSubstring =
425
+ valueField && valueField !== pivot.valueField2
426
+ ? `, ${processColumnReference(`${pivot.valueField2}`, databaseType, undefined, true)} AS ${value2Alias}`
427
+ : '';
428
+ }
429
+ quillSelectSubstring = `${rowAlias}, sum(${valueAlias}) / GREATEST(sum(${value2Alias}), 1) as ${processColumnReference(`${valueField ?? ''}_${(0, textProcessing_1.matchCasing)('percentage', valueField)}`, databaseType, undefined, false, true)}`;
483
430
  }
484
- const compareCTE = itemQueries[1]
485
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
486
- : '';
487
- const aliasCTE = itemQueries[1]
488
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowAlias}${valueAliasSubstring} FROM quill_ct)`
489
- : '';
490
- const compareCaseWhenCTE = itemQueries[1]
491
- ? `, quill_ct_cw as (SELECT ${rowAlias} as ${processColumnReference(`comparison_${rowAlias}`, databaseType)}, ${processAggType(pivot.aggregationType)}(${valueField ? valueAlias : '*'}) as ${processColumnReference(`comparison_${valueField ? valueAlias : countAlias}`, databaseType)} FROM quill_c_alias GROUP BY ${rowAlias})`
492
- : '';
493
- const joinQuery = itemQueries[1]
494
- ? `JOIN quill_ct_cw ct ON ct.${processColumnReference(`comparison_${rowField}`, databaseType)} = qt.${processColumnReference(`${rowField}`, databaseType)}`
495
- : '';
496
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}),
497
- quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowAlias}${valueAliasSubstring} FROM quill_qt),
498
- quill_qt_cw AS (SELECT ${rowAlias}, ${processAggType(pivot.aggregationType)}(${valueField ? valueAlias : '*'}) as ${valueField ? valueAlias : countAlias} FROM quill_alias GROUP BY ${rowAlias})
499
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
500
- SELECT * FROM quill_qt_cw qt
501
- ${joinQuery}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
431
+ // pivot sort matters in the base query when there is a rowLimit. In mssql, an orderby must be accompanied by a limit in a subquery and not allowed in a cte
432
+ const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} ` : ''}`;
433
+ const pivotQuery = `, quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowAlias}${valueAliasSubstring}${value2AliasSubstring} FROM quill_base_table),
434
+ quill_qt_cw AS (SELECT ${quillSelectSubstring} FROM quill_alias GROUP BY ${rowAlias}),
435
+ quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} * FROM quill_qt_cw qt
436
+ ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''})
437
+ SELECT * FROM quill_base_pivot
438
+ `
439
+ .replace(/\s+/g, ' ')
440
+ .trim();
441
+ return itemQuery.replace(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/, pivotQuery);
502
442
  }
503
- function create1DDatePivotQuery(pivot, itemQueries, dateBucket = 'month', databaseType, comparisonInterval, rowLimit) {
443
+ function create1DDatePivotQuery(pivot, itemQuery, dateBucket = 'month', databaseType) {
444
+ const isValidBaseQuery = itemQuery.match(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/);
445
+ if (!isValidBaseQuery) {
446
+ return undefined;
447
+ }
504
448
  const rowField = pivot.rowField || '';
505
449
  const valueField = pivot.valueField;
506
450
  const rowFieldAlias = processColumnReference(rowField, databaseType, undefined);
507
451
  const valueFieldAlias = processColumnReference(valueField ?? rowField, databaseType, undefined, false, true);
508
- const countAlias = processColumnReference('count', databaseType);
509
- const valueAliasSubstring = valueField
510
- ? `, ${processColumnReference(`${valueField}`, databaseType, undefined, true)} AS ${valueFieldAlias}`
511
- : ``;
512
- const max = 'GREATEST';
452
+ const comparisonValueFieldAlias = processColumnReference(valueField ?? rowField, databaseType, undefined, false, true);
453
+ const countAlias = processColumnReference(`count`, databaseType);
454
+ const valueAliasSubstring = valueField ? `, ${valueFieldAlias}` : ``;
455
+ let value2AliasSubstring = '';
456
+ let quillAggSubstring = `
457
+ ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(`${rowField}`, databaseType)}
458
+ , ${processAggType(pivot.aggregationType)}(${valueField ? valueFieldAlias : rowFieldAlias}) as ${valueField ? comparisonValueFieldAlias : countAlias}
459
+ `;
513
460
  // this "and" is for typescript. in reality, pivot.valueField2 must exist if pivot.aggregationType === 'percentage'
514
461
  if (pivot.aggregationType === 'percentage' && pivot.valueField2) {
515
462
  const valueField2Alias = processColumnReference(pivot.valueField2, databaseType, undefined, false, true);
516
- const value2AliasSubstring = valueField !== pivot.valueField2
517
- ? `, ${processColumnReference(`${pivot.valueField2}`, databaseType, undefined, true)} AS ${valueField2Alias}`
518
- : '';
519
- const compareCTE = itemQueries[1] && comparisonInterval
520
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
521
- : '';
522
- const aliasCTE = itemQueries[1] && comparisonInterval
523
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}${valueAliasSubstring}${value2AliasSubstring} FROM quill_ct)`
524
- : '';
525
- const compareCaseWhenCTE = itemQueries[1] && comparisonInterval
526
- ? `, quill_ct_cw as (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)},
527
- sum(${processColumnReference(`${valueFieldAlias}`, databaseType, undefined, true)}) / ${max}(sum(${processColumnReference(`${valueField2Alias}`, databaseType, undefined, true)}), 1) as ${processColumnReference(`comparison_${valueField ? valueFieldAlias : 'count'}_${(0, textProcessing_1.matchCasing)('percentage', valueField)}`, databaseType, undefined, false, true)} FROM quill_c_alias GROUP BY ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)})`
528
- : '';
529
- const joinQuery = itemQueries[1] && comparisonInterval
530
- ? `LEFT JOIN quill_ct_cw ${processColumnReference(`ct`, databaseType)} ON qt.${processColumnReference(rowField, databaseType)} = ${processDateTrunc(dateBucket, `ct.comparison_${rowField}`, databaseType, comparisonInterval)}`
531
- : '';
532
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}),
533
- quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowFieldAlias}${valueAliasSubstring}${value2AliasSubstring} FROM quill_qt),
534
- quill_qt_agg AS (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(`${rowField}`, databaseType)}, sum(${valueFieldAlias}) / ${max}(sum(${valueField2Alias}), 1) as ${processColumnReference(`${valueField ?? ''}_${(0, textProcessing_1.matchCasing)('percentage', valueField)}`, databaseType, undefined, false, true)} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})
535
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
536
- SELECT * FROM quill_qt_agg qt
537
- ${joinQuery} ORDER BY qt.${processColumnReference(`${rowField}`, databaseType)}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
463
+ value2AliasSubstring =
464
+ valueField !== pivot.valueField2 ? `, ${valueField2Alias}` : '';
465
+ quillAggSubstring = `
466
+ ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(rowField, databaseType)}
467
+ , sum(${valueFieldAlias}) / GREATEST(sum(${valueField2Alias}), 1) as ${processColumnReference(`${valueField ?? ''}_${(0, textProcessing_1.matchCasing)('percentage', valueField)}`, databaseType, undefined, false, true)}
468
+ `;
538
469
  }
539
- const compareCTE = itemQueries[1] && comparisonInterval
540
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
541
- : '';
542
- const aliasCTE = itemQueries[1] && comparisonInterval
543
- ? `, quill_c_alias as (SELECT ${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}${valueAliasSubstring} FROM quill_ct)`
544
- : '';
545
- const compareCaseWhenCTE = itemQueries[1] && comparisonInterval
546
- ? `, quill_ct_cw as (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(`comparison_${rowFieldAlias}`, databaseType)},
547
- ${processAggType(pivot.aggregationType)}(${valueFieldAlias}) as ${processColumnReference(`comparison_${valueField ? valueFieldAlias : 'count'}`, databaseType)} FROM quill_c_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})`
548
- : '';
549
- const joinQuery = itemQueries[1] && comparisonInterval
550
- ? `LEFT JOIN quill_ct_cw ${processColumnReference(`ct`, databaseType)} ON qt.${processColumnReference(rowField, databaseType)} = ${processDateTrunc(dateBucket, `ct.comparison_${rowField}`, databaseType, comparisonInterval)}`
551
- : '';
552
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}),
553
- quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowFieldAlias}${valueAliasSubstring} FROM quill_qt),
554
- quill_qt_agg AS (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(`${rowField}`, databaseType)}, ${processAggType(pivot.aggregationType)}(${valueField ? valueFieldAlias : rowFieldAlias}) as ${valueField ? valueFieldAlias : countAlias} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)})
555
- ${compareCTE} ${aliasCTE} ${compareCaseWhenCTE}
556
- SELECT * FROM quill_qt_agg qt
557
- ${joinQuery} ORDER BY qt.${processColumnReference(`${rowField}`, databaseType)}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
470
+ // pivot sort matters in the base query when there is a rowLimit. In mssql, an orderby must be accompanied by a limit in a subquery and not allowed in a cte
471
+ const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} ` : ''}`;
472
+ const pivotQuery = `, quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowFieldAlias}${valueAliasSubstring}
473
+ ${value2AliasSubstring}
474
+ FROM quill_base_table),
475
+ quill_qt_agg AS (SELECT ${quillAggSubstring}
476
+ FROM quill_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
477
+ quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} * FROM quill_qt_agg qt
478
+ ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''})
479
+ SELECT * FROM quill_base_pivot
480
+ `
481
+ .replace(/\s+/g, ' ')
482
+ .trim();
483
+ return itemQuery.replace(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/, pivotQuery);
558
484
  }
559
- function createAggregationValuePivot(pivot, itemQueries, databaseType, rowLimit) {
485
+ function createAggregationValuePivot(pivot, itemQuery, databaseType) {
486
+ const isValidBaseQuery = itemQuery.match(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/);
487
+ if (!isValidBaseQuery || !pivot.valueField) {
488
+ return undefined;
489
+ }
560
490
  const valueField = pivot.valueField;
561
491
  const aggregationType = processAggType(pivot.aggregationType);
562
- if (!pivot.valueField)
563
- return undefined;
564
492
  const valueAlias = processColumnReference(valueField, databaseType, undefined, false, true);
493
+ let value2AliasSubstring = '';
494
+ let quillAggSubstring = `SELECT ${aggregationType}(${valueAlias}) as ${processColumnReference(valueField, databaseType)}`;
565
495
  if (aggregationType === 'percentage' && pivot.valueField2) {
566
496
  const value2Alias = processColumnReference(pivot.valueField2, databaseType, undefined, false, true);
567
- const max = 'GREATEST';
568
- const compareCTE = itemQueries[1]
569
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
570
- : '';
571
- const aliasCTE = itemQueries[1]
572
- ? `, quill_c_alias as (SELECT ${processColumnReference(valueField, databaseType, undefined, true)} AS ${valueAlias}, ${processColumnReference(pivot.valueField2, databaseType, undefined, true)} AS ${value2Alias} FROM quill_ct)`
573
- : '';
574
- const compareAggregation = itemQueries[1]
575
- ? `, quill_ct_cw as (SELECT sum(${processColumnReference(`${valueField}`, databaseType)}) / ${max}(sum(${processColumnReference(`${pivot.valueField2}`, databaseType)}), 1) as ${processColumnReference(`comparison_${valueField}_${(0, textProcessing_1.matchCasing)('percentage', valueField)}`, databaseType, undefined, false, true)} FROM quill_c_alias)`
576
- : '';
577
- const joinQuery = itemQueries[1] ? `CROSS JOIN quill_ct_cw ct` : '';
578
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}), quill_alias AS (SELECT ${processColumnReference(`${valueField}`, databaseType, undefined, true)} AS ${valueAlias}, ${processColumnReference(`${pivot.valueField2}`, databaseType, undefined, true)} AS ${value2Alias} FROM quill_qt),
579
- quill_qt_agg AS (SELECT sum(${valueAlias}) / ${max}(sum(${value2Alias}), 1) as ${processColumnReference(`${valueField}_${(0, textProcessing_1.matchCasing)('percentage', valueField)}`, databaseType)} FROM quill_alias)
580
- ${compareCTE} ${aliasCTE} ${compareAggregation}
581
- SELECT * FROM quill_qt_agg qt
582
- ${joinQuery}${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
497
+ value2AliasSubstring = `, ${value2Alias}`;
498
+ quillAggSubstring = `SELECT sum(${valueAlias}) / GREATEST(sum(${value2Alias}), 1) as ${processColumnReference(`${valueField}_${(0, textProcessing_1.matchCasing)('percentage', valueField)}`, databaseType, undefined, false, true)}`;
583
499
  }
584
- const compareCTE = itemQueries[1]
585
- ? `, quill_ct as (${itemQueries[1]?.replaceAll(';', '')})`
586
- : '';
587
- const aliasCTE = itemQueries[1]
588
- ? `, quill_c_alias as (SELECT ${processColumnReference(valueField, databaseType, undefined, true)} AS ${valueAlias} FROM quill_ct)`
589
- : '';
590
- const compareAggregation = itemQueries[1]
591
- ? `, quill_ct_cw as (SELECT ${aggregationType}(${processColumnReference(`${valueField}`, databaseType)}) as ${processColumnReference(`comparison_${valueField}`, databaseType)} FROM quill_c_alias)`
592
- : '';
593
- const joinQuery = itemQueries[1] ? `CROSS JOIN quill_ct_cw ct` : '';
594
- return `WITH quill_qt AS (${itemQueries[0]?.replaceAll(';', '')}), quill_alias AS (SELECT ${processColumnReference(`${valueField}`, databaseType, undefined, true)} AS ${valueAlias} FROM quill_qt),
595
- quill_qt_agg AS (SELECT ${aggregationType}(${valueAlias}) as ${processColumnReference(`${valueField}`, databaseType)} FROM quill_alias)
596
- ${compareCTE} ${aliasCTE} ${compareAggregation}
597
- SELECT * FROM quill_qt_agg qt
598
- ${joinQuery} ${rowLimit ? ` LIMIT ${rowLimit}` : ''}`;
500
+ // pivot sort matters in the base query when there is a rowLimit. In mssql, an orderby must be accompanied by a limit in a subquery and not allowed in a cte
501
+ const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} ` : ''}`;
502
+ const pivotQuery = `, quill_alias AS (SELECT ${valueAlias}${value2AliasSubstring} FROM quill_base_table),
503
+ quill_qt_agg AS (${quillAggSubstring} FROM quill_alias),
504
+ quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} * FROM quill_qt_agg qt
505
+ ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''})
506
+ SELECT * FROM quill_base_pivot
507
+ `
508
+ .replace(/\s+/g, ' ')
509
+ .trim();
510
+ return itemQuery.replace(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/, pivotQuery);
511
+ }
512
+ function additionalProcessingOnPivotQuery(pivot, query, additionalProcessing, databaseType = 'postgresql') {
513
+ if (!additionalProcessing || !query)
514
+ return query;
515
+ const isValidBaseQuery = query.match(/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/);
516
+ if (!isValidBaseQuery) {
517
+ return undefined;
518
+ }
519
+ let rowsPerPage = 0;
520
+ let currentInterval = 0;
521
+ let offset = 0;
522
+ let limit = 1000;
523
+ let sortQuery = `${pivot.sort && pivot.sortField
524
+ ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, undefined, true)} ${pivot.sortDirection || ''}`
525
+ : pivot.rowField
526
+ ? `ORDER BY ${processColumnReference(`${pivot.rowField}`, databaseType)}`
527
+ : pivot.valueField
528
+ ? pivot.aggregationType === 'percentage'
529
+ ? `ORDER BY ${processColumnReference(`${pivot.valueField}_${(0, textProcessing_1.matchCasing)('percentage', pivot.valueField)}`, databaseType, undefined, false, true)}`
530
+ : `ORDER BY ${processColumnReference(pivot.valueField, databaseType, undefined, false, true)}`
531
+ : ''}`;
532
+ if (additionalProcessing.page) {
533
+ const page = additionalProcessing.page.page || 0;
534
+ if (additionalProcessing.page.rowsPerRequest) {
535
+ limit = additionalProcessing.page.rowsPerRequest;
536
+ }
537
+ rowsPerPage = additionalProcessing.page.rowsPerPage || 0;
538
+ currentInterval = page ? Math.floor(page / (limit / rowsPerPage)) : 0;
539
+ offset = currentInterval * limit;
540
+ }
541
+ if (additionalProcessing.sort) {
542
+ sortQuery = `ORDER BY ${processColumnReference(additionalProcessing.sort.field, databaseType)} ${additionalProcessing.sort.direction || ''}`;
543
+ }
544
+ const additionalProcessingQuery = `
545
+ SELECT *
546
+ FROM quill_base_pivot ${sortQuery}${databaseType === 'mssql' ? ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY` : ` LIMIT ${limit} OFFSET ${offset}`}
547
+ `
548
+ .replace(/\s+/g, ' ')
549
+ .trim();
550
+ return query.replace(/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/, additionalProcessingQuery);
551
+ }
552
+ function generateRowCountQuery(query, databaseType) {
553
+ if (!query)
554
+ return query;
555
+ const isValidBaseQuery = query.match(/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/);
556
+ if (!isValidBaseQuery) {
557
+ return undefined;
558
+ }
559
+ const rowCountQuery = `, subview_row_count_cte AS (SELECT * FROM quill_base_pivot)
560
+ SELECT count(*) as ${processColumnReference('row_count', databaseType || 'postgresql', undefined, true)} FROM subview_row_count_cte
561
+ `
562
+ .replace(/\s+/g, ' ')
563
+ .trim();
564
+ return query.replace(/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/, rowCountQuery);
599
565
  }