@quillsql/react 2.13.38 → 2.13.40
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.
- package/dist/cjs/Chart.d.ts.map +1 -1
- package/dist/cjs/Chart.js +0 -1
- package/dist/cjs/ChartBuilder.d.ts.map +1 -1
- package/dist/cjs/ChartBuilder.js +73 -66
- package/dist/cjs/ReportBuilder.d.ts.map +1 -1
- package/dist/cjs/ReportBuilder.js +69 -51
- package/dist/cjs/components/Chart/ChartTooltip.d.ts +1 -1
- package/dist/cjs/components/Chart/ChartTooltip.d.ts.map +1 -1
- package/dist/cjs/components/Chart/ChartTooltip.js +3 -3
- package/dist/cjs/components/Chart/LineChart.d.ts.map +1 -1
- package/dist/cjs/components/Chart/LineChart.js +4 -4
- package/dist/cjs/components/QuillMultiSelectSectionList.js +5 -5
- package/dist/cjs/components/ReportBuilder/convert.d.ts +1 -1
- package/dist/cjs/components/ReportBuilder/convert.d.ts.map +1 -1
- package/dist/cjs/components/ReportBuilder/convert.js +73 -21
- package/dist/cjs/components/UiComponents.d.ts +2 -1
- package/dist/cjs/components/UiComponents.d.ts.map +1 -1
- package/dist/cjs/components/UiComponents.js +11 -4
- package/dist/cjs/hooks/useExport.d.ts.map +1 -1
- package/dist/cjs/hooks/useExport.js +4 -5
- package/dist/cjs/internals/ReportBuilder/PivotForm.d.ts +19 -11
- package/dist/cjs/internals/ReportBuilder/PivotForm.d.ts.map +1 -1
- package/dist/cjs/internals/ReportBuilder/PivotForm.js +62 -48
- package/dist/cjs/internals/ReportBuilder/PivotList.js +5 -4
- package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts +28 -31
- package/dist/cjs/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
- package/dist/cjs/internals/ReportBuilder/PivotModal.js +315 -633
- package/dist/cjs/models/Pivot.d.ts +27 -7
- package/dist/cjs/models/Pivot.d.ts.map +1 -1
- package/dist/cjs/utils/dashboard.d.ts.map +1 -1
- package/dist/cjs/utils/dashboard.js +36 -11
- package/dist/cjs/utils/merge.d.ts.map +1 -1
- package/dist/cjs/utils/merge.js +2 -1
- package/dist/cjs/utils/pivotConstructor.d.ts +1 -0
- package/dist/cjs/utils/pivotConstructor.d.ts.map +1 -1
- package/dist/cjs/utils/pivotConstructor.js +39 -8
- package/dist/cjs/utils/pivotProcessing.d.ts.map +1 -1
- package/dist/cjs/utils/pivotProcessing.js +10 -14
- package/dist/cjs/utils/queryConstructor.d.ts.map +1 -1
- package/dist/cjs/utils/queryConstructor.js +421 -134
- package/dist/cjs/utils/report.d.ts.map +1 -1
- package/dist/cjs/utils/report.js +2 -2
- package/dist/cjs/utils/textProcessing.d.ts +1 -1
- package/dist/cjs/utils/textProcessing.d.ts.map +1 -1
- package/dist/cjs/utils/textProcessing.js +3 -0
- package/dist/esm/Chart.d.ts.map +1 -1
- package/dist/esm/Chart.js +0 -1
- package/dist/esm/ChartBuilder.d.ts.map +1 -1
- package/dist/esm/ChartBuilder.js +73 -66
- package/dist/esm/ReportBuilder.d.ts.map +1 -1
- package/dist/esm/ReportBuilder.js +69 -51
- package/dist/esm/components/Chart/ChartTooltip.d.ts +1 -1
- package/dist/esm/components/Chart/ChartTooltip.d.ts.map +1 -1
- package/dist/esm/components/Chart/ChartTooltip.js +3 -3
- package/dist/esm/components/Chart/LineChart.d.ts.map +1 -1
- package/dist/esm/components/Chart/LineChart.js +4 -4
- package/dist/esm/components/QuillMultiSelectSectionList.js +5 -5
- package/dist/esm/components/ReportBuilder/convert.d.ts +1 -1
- package/dist/esm/components/ReportBuilder/convert.d.ts.map +1 -1
- package/dist/esm/components/ReportBuilder/convert.js +74 -22
- package/dist/esm/components/UiComponents.d.ts +2 -1
- package/dist/esm/components/UiComponents.d.ts.map +1 -1
- package/dist/esm/components/UiComponents.js +11 -4
- package/dist/esm/hooks/useExport.d.ts.map +1 -1
- package/dist/esm/hooks/useExport.js +4 -5
- package/dist/esm/internals/ReportBuilder/PivotForm.d.ts +19 -11
- package/dist/esm/internals/ReportBuilder/PivotForm.d.ts.map +1 -1
- package/dist/esm/internals/ReportBuilder/PivotForm.js +63 -49
- package/dist/esm/internals/ReportBuilder/PivotList.js +5 -4
- package/dist/esm/internals/ReportBuilder/PivotModal.d.ts +28 -31
- package/dist/esm/internals/ReportBuilder/PivotModal.d.ts.map +1 -1
- package/dist/esm/internals/ReportBuilder/PivotModal.js +327 -635
- package/dist/esm/models/Pivot.d.ts +27 -7
- package/dist/esm/models/Pivot.d.ts.map +1 -1
- package/dist/esm/utils/dashboard.d.ts.map +1 -1
- package/dist/esm/utils/dashboard.js +36 -11
- package/dist/esm/utils/merge.d.ts.map +1 -1
- package/dist/esm/utils/merge.js +2 -1
- package/dist/esm/utils/pivotConstructor.d.ts +1 -0
- package/dist/esm/utils/pivotConstructor.d.ts.map +1 -1
- package/dist/esm/utils/pivotConstructor.js +39 -9
- package/dist/esm/utils/pivotProcessing.d.ts.map +1 -1
- package/dist/esm/utils/pivotProcessing.js +10 -14
- package/dist/esm/utils/queryConstructor.d.ts.map +1 -1
- package/dist/esm/utils/queryConstructor.js +421 -134
- package/dist/esm/utils/report.d.ts.map +1 -1
- package/dist/esm/utils/report.js +2 -2
- package/dist/esm/utils/textProcessing.d.ts +1 -1
- package/dist/esm/utils/textProcessing.d.ts.map +1 -1
- package/dist/esm/utils/textProcessing.js +3 -0
- package/package.json +1 -1
|
@@ -226,7 +226,7 @@ function generateDistinctQueryMySQL(stringFields, query) {
|
|
|
226
226
|
}
|
|
227
227
|
function generateDistinctQueryPostgres(stringFields, query) {
|
|
228
228
|
const distinctQueries = stringFields.map((field) => {
|
|
229
|
-
return `SELECT '${field}' AS ${processColumnReference('field', 'postgresql')}, to_json(ARRAY_AGG(DISTINCT ${field})) AS ${processColumnReference('string_values', 'postgresql')} FROM querytable`;
|
|
229
|
+
return `SELECT '${field}' AS ${processColumnReference('field', 'postgresql')}, to_json(ARRAY_AGG(DISTINCT "${field}")) AS ${processColumnReference('string_values', 'postgresql')} FROM querytable`;
|
|
230
230
|
});
|
|
231
231
|
const distinctQuery = distinctQueries.join(' UNION ALL ');
|
|
232
232
|
return `WITH querytable AS (${query.replace(';', '')}) ` + distinctQuery;
|
|
@@ -297,53 +297,115 @@ function create2DPivotQuery(pivot, itemQuery, databaseType, columnFieldValues, d
|
|
|
297
297
|
if (!pivot || !pivot.columnField) {
|
|
298
298
|
return undefined;
|
|
299
299
|
}
|
|
300
|
-
if ((0, columnProcessing_1.isStringType)(pivot.rowFieldType
|
|
300
|
+
if ((0, columnProcessing_1.isStringType)(pivot.rowFieldType ?? '') || !pivot.rowFieldType) {
|
|
301
301
|
return create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType);
|
|
302
302
|
}
|
|
303
303
|
return create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseType, dateBucket);
|
|
304
304
|
}
|
|
305
305
|
function create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType) {
|
|
306
306
|
const isValidBaseQuery = itemQuery.match(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/);
|
|
307
|
-
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField)
|
|
307
|
+
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField)
|
|
308
308
|
return undefined;
|
|
309
|
-
}
|
|
310
309
|
const rowField = pivot.rowField;
|
|
311
|
-
|
|
310
|
+
if (!pivot.aggregations?.[0]?.valueField && !pivot.valueField)
|
|
311
|
+
throw new Error('No value field provided for pivot');
|
|
312
|
+
if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
|
|
313
|
+
throw new Error('No aggregation type provided for pivot');
|
|
312
314
|
const columnField = pivot.columnField;
|
|
313
315
|
const rowFieldAlias = processColumnReference(rowField, databaseType, undefined, false, true);
|
|
314
|
-
const valueFieldAlias = processColumnReference(valueField ?? rowField, databaseType, undefined, false, true);
|
|
315
316
|
const columnFieldAlias = processColumnReference(columnField, databaseType, undefined, false, true);
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (pivot.aggregationType === 'percentage' && pivot.valueField2) {
|
|
324
|
-
const valueField2Alias = processColumnReference(pivot.valueField2, databaseType, undefined, false, true);
|
|
325
|
-
if (pivot.valueField === pivot.valueField2) {
|
|
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)}`;
|
|
328
|
-
});
|
|
317
|
+
let caseWhens = [];
|
|
318
|
+
let valueAliases = [];
|
|
319
|
+
const seenAggs = {};
|
|
320
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
321
|
+
// Track duplicate aggregation combos for disambiguation.
|
|
322
|
+
if (seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']) {
|
|
323
|
+
seenAggs[currentAgg.aggregationType ?? ''][currentAgg.valueField ?? ''] += 1;
|
|
329
324
|
}
|
|
330
325
|
else {
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
}
|
|
326
|
+
seenAggs[currentAgg.aggregationType ?? ''] = {
|
|
327
|
+
...seenAggs[currentAgg.aggregationType ?? ''],
|
|
328
|
+
[currentAgg.valueField ?? '']: 1,
|
|
329
|
+
};
|
|
335
330
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
331
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']?.toString();
|
|
332
|
+
if (disambiguationIndex === '1')
|
|
333
|
+
disambiguationIndex = '';
|
|
334
|
+
const valueFieldAlias = processColumnReference((currentAgg.valueField || rowField || 'count'), databaseType, undefined, false, true);
|
|
335
|
+
const valueAliasSubstring = currentAgg.valueField
|
|
336
|
+
? `${processColumnReference(currentAgg.valueField, databaseType, undefined, true)} AS ${valueFieldAlias}`
|
|
337
|
+
: '';
|
|
338
|
+
let value2AliasSubstring = '';
|
|
339
|
+
const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ''] ?? {}).reduce((acc, v) => acc + v) > 1
|
|
340
|
+
? `_${currentAgg.valueField}${disambiguationIndex}`
|
|
341
|
+
: '';
|
|
342
|
+
const disambiguation = pivot.aggregations?.length > 1
|
|
343
|
+
? `${disambiguationField}_${disambiguationField ? (0, textProcessing_1.matchCasing)(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}`
|
|
344
|
+
: '';
|
|
345
|
+
// Wrap the value field in CASE WHEN if its type is bool.
|
|
346
|
+
const valueExpr = currentAgg.valueFieldType === 'bool'
|
|
347
|
+
? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`
|
|
348
|
+
: processValueField(currentAgg.aggregationType, databaseType, valueFieldAlias);
|
|
349
|
+
if (currentAgg.aggregationType === 'percentage') {
|
|
350
|
+
if (!currentAgg.valueField)
|
|
351
|
+
throw new Error('No value field provided for pivot');
|
|
352
|
+
const valueField2Alias = processColumnReference(currentAgg.valueField2 ?? currentAgg.valueField, databaseType, undefined, false, true);
|
|
353
|
+
// Wrap the second value field if its type is bool.
|
|
354
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === 'bool'
|
|
355
|
+
? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`
|
|
356
|
+
: valueField2Alias;
|
|
357
|
+
if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
|
|
358
|
+
caseWhens = columnFieldValues.map((column) => {
|
|
359
|
+
return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${valueExpr} END) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(column + disambiguation, databaseType, '_', true)}`;
|
|
360
|
+
});
|
|
361
|
+
}
|
|
362
|
+
else {
|
|
363
|
+
value2AliasSubstring = `${processColumnReference(currentAgg.valueField2 ?? currentAgg.valueField, databaseType, undefined, true)} AS ${valueField2Alias}`;
|
|
364
|
+
caseWhens = columnFieldValues.map((column) => {
|
|
365
|
+
return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${valueExpr} END) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${value2Expr} END), 1) AS ${processColumnReference(column + disambiguation, databaseType, '_', true)}`;
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
else {
|
|
370
|
+
caseWhens = [
|
|
371
|
+
...caseWhens,
|
|
372
|
+
...columnFieldValues.map((column) => {
|
|
373
|
+
return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, '_', true)}`;
|
|
374
|
+
}),
|
|
375
|
+
];
|
|
376
|
+
}
|
|
377
|
+
if (valueAliasSubstring)
|
|
378
|
+
valueAliases.push(valueAliasSubstring);
|
|
379
|
+
if (value2AliasSubstring)
|
|
380
|
+
valueAliases.push(value2AliasSubstring);
|
|
381
|
+
});
|
|
382
|
+
valueAliases = [
|
|
383
|
+
`${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}`,
|
|
384
|
+
...valueAliases,
|
|
385
|
+
`${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias}`,
|
|
386
|
+
];
|
|
387
|
+
valueAliases = Array.from(new Set(valueAliases));
|
|
388
|
+
const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit
|
|
389
|
+
? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} `
|
|
390
|
+
: '';
|
|
339
391
|
const pivotQuery = `
|
|
340
|
-
,quill_alias AS (
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
392
|
+
,quill_alias AS (
|
|
393
|
+
SELECT ${valueAliases.length > 0 ? `${valueAliases.join(', ')}` : ''}
|
|
394
|
+
FROM quill_base_table
|
|
395
|
+
),
|
|
396
|
+
quill_qt_cw AS (
|
|
397
|
+
SELECT ${rowFieldAlias}
|
|
398
|
+
${caseWhens.length > 0 ? `, ${caseWhens.join(', ')}` : ''}
|
|
399
|
+
FROM quill_alias
|
|
400
|
+
GROUP BY ${rowFieldAlias}
|
|
401
|
+
),
|
|
402
|
+
quill_base_pivot AS (
|
|
403
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} *
|
|
404
|
+
FROM quill_qt_cw qt
|
|
405
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''}
|
|
406
|
+
)
|
|
345
407
|
SELECT * FROM quill_base_pivot
|
|
346
|
-
|
|
408
|
+
`
|
|
347
409
|
.replace(/\s+/g, ' ')
|
|
348
410
|
.trim();
|
|
349
411
|
return itemQuery.replace(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/, pivotQuery);
|
|
@@ -353,38 +415,95 @@ function create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseTyp
|
|
|
353
415
|
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField) {
|
|
354
416
|
return undefined;
|
|
355
417
|
}
|
|
418
|
+
if (!pivot.aggregations?.[0]?.valueField && !pivot.valueField)
|
|
419
|
+
throw new Error('No value field provided for pivot');
|
|
420
|
+
if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
|
|
421
|
+
throw new Error('No aggregation type provided for pivot');
|
|
422
|
+
// const aggregationType = (pivot.aggregations?.[0]?.aggregationType ?? pivot.aggregationType) as any;
|
|
356
423
|
const rowField = pivot.rowField;
|
|
357
424
|
const columnField = pivot.columnField;
|
|
358
425
|
const rowFieldAlias = processColumnReference(rowField, databaseType, undefined, false, true);
|
|
359
|
-
const valueFieldAlias = processColumnReference(pivot.valueField ?? rowField, databaseType, undefined, false, true);
|
|
360
426
|
const columnFieldAlias = processColumnReference(columnField, databaseType, undefined, false, true);
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
if (pivot.aggregationType === 'percentage' && pivot.valueField2) {
|
|
369
|
-
const valueField2Alias = processColumnReference(pivot.valueField2, databaseType, undefined, false, true);
|
|
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
|
|
371
|
-
if (pivot.valueField === pivot.valueField2) {
|
|
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)}`;
|
|
374
|
-
});
|
|
427
|
+
let caseWhens = [];
|
|
428
|
+
let valueFieldAliases = [];
|
|
429
|
+
const seenAggs = {};
|
|
430
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
431
|
+
// if the aggregation combo has been seen before, increment the count, else add it to the seenAggs array
|
|
432
|
+
if (seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']) {
|
|
433
|
+
seenAggs[currentAgg.aggregationType ?? ''][currentAgg.valueField ?? ''] += 1;
|
|
375
434
|
}
|
|
376
435
|
else {
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
}
|
|
436
|
+
seenAggs[currentAgg.aggregationType ?? ''] = {
|
|
437
|
+
...seenAggs[currentAgg.aggregationType ?? ''],
|
|
438
|
+
[currentAgg.valueField ?? '']: 1,
|
|
439
|
+
};
|
|
381
440
|
}
|
|
382
|
-
|
|
441
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']?.toString();
|
|
442
|
+
if (disambiguationIndex === '1')
|
|
443
|
+
disambiguationIndex = '';
|
|
444
|
+
const valueFieldAlias = processColumnReference((currentAgg.valueField ?? rowField), databaseType, undefined, false, true);
|
|
445
|
+
const valueAliasSubstring = currentAgg.valueField
|
|
446
|
+
? `${processColumnReference(currentAgg.valueField, databaseType, undefined, true)} AS ${valueFieldAlias}`
|
|
447
|
+
: '';
|
|
448
|
+
let value2AliasSubstring = '';
|
|
449
|
+
const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ''] ?? {}).reduce((acc, v) => acc + v) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : '';
|
|
450
|
+
const disambiguation = pivot.aggregations?.length > 1
|
|
451
|
+
? `${disambiguationField}_${disambiguationField ? (0, textProcessing_1.matchCasing)(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}`
|
|
452
|
+
: '';
|
|
453
|
+
// Wrap the value field in CASE WHEN if its type is bool.
|
|
454
|
+
const valueExpr = currentAgg.valueFieldType === 'bool'
|
|
455
|
+
? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`
|
|
456
|
+
: processValueField(currentAgg.aggregationType, databaseType, valueFieldAlias);
|
|
457
|
+
if (currentAgg.aggregationType === 'percentage') {
|
|
458
|
+
if (!currentAgg.valueField)
|
|
459
|
+
throw new Error('No value field provided for pivot');
|
|
460
|
+
const valueField2Alias = processColumnReference(currentAgg.valueField2 ?? currentAgg.valueField, databaseType, undefined, false, true);
|
|
461
|
+
// Wrap the second value field if its type is bool.
|
|
462
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === 'bool'
|
|
463
|
+
? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`
|
|
464
|
+
: valueField2Alias;
|
|
465
|
+
// 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 whe
|
|
466
|
+
if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
|
|
467
|
+
caseWhens = [
|
|
468
|
+
...caseWhens,
|
|
469
|
+
...columnFieldValues.map((column) => {
|
|
470
|
+
return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${valueExpr} END) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(column + disambiguation, databaseType, '_', true)}`;
|
|
471
|
+
}),
|
|
472
|
+
];
|
|
473
|
+
}
|
|
474
|
+
else {
|
|
475
|
+
value2AliasSubstring = `${processColumnReference(currentAgg.valueField2 ?? currentAgg.valueField, databaseType, undefined, true)} AS ${valueField2Alias}`;
|
|
476
|
+
caseWhens = [
|
|
477
|
+
...caseWhens,
|
|
478
|
+
...columnFieldValues.map((column) => {
|
|
479
|
+
return `sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${valueExpr} END) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${value2Expr} END), 1) AS ${processColumnReference(column + disambiguation, databaseType, '_', true)}`;
|
|
480
|
+
}),
|
|
481
|
+
];
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
caseWhens = [
|
|
486
|
+
...caseWhens,
|
|
487
|
+
...columnFieldValues.map((column) => {
|
|
488
|
+
return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(column, databaseType)}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, '_', true)}`;
|
|
489
|
+
}),
|
|
490
|
+
];
|
|
491
|
+
}
|
|
492
|
+
if (valueAliasSubstring)
|
|
493
|
+
valueFieldAliases.push(valueAliasSubstring);
|
|
494
|
+
if (value2AliasSubstring)
|
|
495
|
+
valueFieldAliases.push(value2AliasSubstring);
|
|
496
|
+
});
|
|
497
|
+
valueFieldAliases = [
|
|
498
|
+
`${processColumnReference(rowField, databaseType, undefined, true)} AS ${rowFieldAlias}`,
|
|
499
|
+
...valueFieldAliases,
|
|
500
|
+
`${processColumnReference(columnField, databaseType, undefined, true)} AS ${columnFieldAlias}`,
|
|
501
|
+
];
|
|
502
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
383
503
|
// 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
504
|
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} ` : ''}`;
|
|
385
505
|
const pivotQuery = `
|
|
386
|
-
, quill_alias AS (SELECT ${
|
|
387
|
-
${processColumnReference(columnField, databaseType, undefined, true, true)} AS ${columnFieldAlias} FROM quill_base_table),
|
|
506
|
+
, quill_alias AS (SELECT ${valueFieldAliases.length > 0 ? `${valueFieldAliases.join(', ')}` : ''} FROM quill_base_table),
|
|
388
507
|
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
508
|
quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} * FROM quill_qt_agg qt
|
|
390
509
|
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''})
|
|
@@ -405,37 +524,91 @@ function create1DPivotQuery(pivot, itemQuery, dateBucket = 'month', databaseType
|
|
|
405
524
|
// their own with statements and withs with the same name will conflict
|
|
406
525
|
function create1DStringPivotQuery(pivot, itemQuery, databaseType) {
|
|
407
526
|
const isValidBaseQuery = itemQuery.match(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/);
|
|
408
|
-
if (!isValidBaseQuery)
|
|
527
|
+
if (!isValidBaseQuery)
|
|
409
528
|
return undefined;
|
|
410
|
-
}
|
|
411
529
|
const rowField = pivot.rowField;
|
|
412
|
-
const
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
const
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
const value2Alias = processColumnReference(pivot.valueField2, databaseType, undefined, false, true);
|
|
423
|
-
if (pivot.valueField !== pivot.valueField2) {
|
|
424
|
-
value2AliasSubstring =
|
|
425
|
-
valueField && valueField !== pivot.valueField2
|
|
426
|
-
? `, ${processColumnReference(`${pivot.valueField2}`, databaseType, undefined, true)} AS ${value2Alias}`
|
|
427
|
-
: '';
|
|
530
|
+
const rowAlias = processColumnReference(rowField, databaseType, undefined, true);
|
|
531
|
+
let quillAggSelects = [rowAlias];
|
|
532
|
+
let valueFieldAliases = [];
|
|
533
|
+
const seenAggs = {};
|
|
534
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
535
|
+
if (!currentAgg.valueField)
|
|
536
|
+
currentAgg.valueField = undefined;
|
|
537
|
+
// Track duplicates to disambiguate names
|
|
538
|
+
if (seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']) {
|
|
539
|
+
seenAggs[currentAgg.aggregationType ?? ''][currentAgg.valueField ?? ''] += 1;
|
|
428
540
|
}
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
541
|
+
else {
|
|
542
|
+
seenAggs[currentAgg.aggregationType ?? ''] = {
|
|
543
|
+
...seenAggs[currentAgg.aggregationType ?? ''],
|
|
544
|
+
[currentAgg.valueField ?? '']: 1,
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']?.toString() ?? '';
|
|
548
|
+
if (disambiguationIndex === '1')
|
|
549
|
+
disambiguationIndex = '';
|
|
550
|
+
// This is the alias (from quill_alias CTE) for the field
|
|
551
|
+
const valueFieldAlias = processColumnReference((currentAgg.valueField || rowField || 'count'), databaseType, undefined, false, true);
|
|
552
|
+
// In the base query, we select the raw column.
|
|
553
|
+
const valueAliasSubstring = currentAgg.valueField
|
|
554
|
+
? `${processColumnReference(currentAgg.valueField, databaseType, undefined, true)} AS ${valueFieldAlias}`
|
|
555
|
+
: '';
|
|
556
|
+
let value2AliasSubstring = '';
|
|
557
|
+
const disambiguation = pivot.aggregations?.length > 1
|
|
558
|
+
? `${disambiguationIndex}_${currentAgg.aggregationType}`
|
|
559
|
+
: '';
|
|
560
|
+
// Wrap the field in a CASE WHEN if it's boolean
|
|
561
|
+
let valueExpr = !currentAgg.valueField ? '*' : valueFieldAlias;
|
|
562
|
+
if (currentAgg.valueFieldType === 'bool') {
|
|
563
|
+
valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
|
|
564
|
+
}
|
|
565
|
+
if (currentAgg.aggregationType === 'percentage') {
|
|
566
|
+
if (!currentAgg.valueField) {
|
|
567
|
+
throw new Error('No value field provided for percentage aggregation');
|
|
568
|
+
}
|
|
569
|
+
const valueField2Alias = processColumnReference(currentAgg.valueField2 ?? currentAgg.valueField, databaseType, undefined, false, true);
|
|
570
|
+
let value2Expr = valueField2Alias;
|
|
571
|
+
if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === 'bool') {
|
|
572
|
+
value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
|
|
573
|
+
}
|
|
574
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2
|
|
575
|
+
? `${processColumnReference(currentAgg.valueField2, databaseType, undefined, true)} AS ${valueField2Alias}`
|
|
576
|
+
: '';
|
|
577
|
+
const percentageExpr = currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2
|
|
578
|
+
? `sum(${valueExpr}) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === 'bool' ? 'COUNT(*)' : 'SUM(sum(' + valueExpr + ')) OVER ()'}`
|
|
579
|
+
: `sum(${valueExpr}) / GREATEST(sum(${value2Expr}), 1)`;
|
|
580
|
+
quillAggSelects = [
|
|
581
|
+
...quillAggSelects,
|
|
582
|
+
`${percentageExpr} as ${processColumnReference(`${currentAgg.valueField ?? ''}${disambiguation}`, databaseType, undefined, false, true)}`,
|
|
583
|
+
];
|
|
584
|
+
}
|
|
585
|
+
else {
|
|
586
|
+
quillAggSelects = [
|
|
587
|
+
...quillAggSelects,
|
|
588
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference((currentAgg.valueField || 'count') + disambiguation, databaseType)}`,
|
|
589
|
+
];
|
|
590
|
+
}
|
|
591
|
+
if (valueAliasSubstring)
|
|
592
|
+
valueFieldAliases.push(valueAliasSubstring);
|
|
593
|
+
if (value2AliasSubstring)
|
|
594
|
+
valueFieldAliases.push(value2AliasSubstring);
|
|
595
|
+
});
|
|
596
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
597
|
+
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit
|
|
598
|
+
? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} `
|
|
599
|
+
: ''}`;
|
|
600
|
+
const pivotQuery = `, quill_alias AS (
|
|
601
|
+
SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(', ')}` : ''}
|
|
602
|
+
FROM quill_base_table
|
|
603
|
+
),
|
|
604
|
+
quill_qt_cw AS (
|
|
605
|
+
SELECT ${quillAggSelects.join(', ')} FROM quill_alias GROUP BY ${rowAlias}
|
|
606
|
+
),
|
|
607
|
+
quill_base_pivot AS (
|
|
608
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} *
|
|
609
|
+
FROM quill_qt_cw qt ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''}
|
|
610
|
+
)
|
|
611
|
+
SELECT * FROM quill_base_pivot`
|
|
439
612
|
.replace(/\s+/g, ' ')
|
|
440
613
|
.trim();
|
|
441
614
|
return itemQuery.replace(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/, pivotQuery);
|
|
@@ -446,33 +619,76 @@ function create1DDatePivotQuery(pivot, itemQuery, dateBucket = 'month', database
|
|
|
446
619
|
return undefined;
|
|
447
620
|
}
|
|
448
621
|
const rowField = pivot.rowField || '';
|
|
449
|
-
const valueField = pivot.valueField;
|
|
450
622
|
const rowFieldAlias = processColumnReference(rowField, databaseType, undefined);
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
const
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
623
|
+
let quillAggSelects = [`${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(rowField, databaseType)}`];
|
|
624
|
+
let valueFieldAliases = [];
|
|
625
|
+
const seenAggs = {};
|
|
626
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
627
|
+
if (!currentAgg.valueField)
|
|
628
|
+
currentAgg.valueField = undefined;
|
|
629
|
+
// if the aggregation combo has been seen before, increment the count, else add it to the seenAggs array
|
|
630
|
+
if (seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']) {
|
|
631
|
+
seenAggs[currentAgg.aggregationType ?? ''][currentAgg.valueField ?? ''] += 1;
|
|
632
|
+
}
|
|
633
|
+
else {
|
|
634
|
+
seenAggs[currentAgg.aggregationType ?? ''] = {
|
|
635
|
+
...seenAggs[currentAgg.aggregationType ?? ''],
|
|
636
|
+
[currentAgg.valueField ?? '']: 1,
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']?.toString() ?? '';
|
|
640
|
+
if (disambiguationIndex === '1')
|
|
641
|
+
disambiguationIndex = '';
|
|
642
|
+
const valueFieldAlias = processColumnReference((currentAgg.valueField || rowField || 'count'), databaseType, undefined, false, true);
|
|
643
|
+
const valueAliasSubstring = currentAgg.valueField
|
|
644
|
+
? `${processColumnReference(currentAgg.valueField, databaseType, undefined, true)} AS ${valueFieldAlias}`
|
|
645
|
+
: '';
|
|
646
|
+
let value2AliasSubstring = '';
|
|
647
|
+
const disambiguation = pivot.aggregations?.length > 1
|
|
648
|
+
? `${disambiguationIndex}_${currentAgg.aggregationType}`
|
|
649
|
+
: '';
|
|
650
|
+
// Wrap the field in a CASE WHEN if it's boolean
|
|
651
|
+
let valueExpr = !currentAgg.valueField ? '*' : valueFieldAlias;
|
|
652
|
+
if (currentAgg.valueFieldType === 'bool') {
|
|
653
|
+
valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
|
|
654
|
+
}
|
|
655
|
+
if (currentAgg.aggregationType === 'percentage') {
|
|
656
|
+
if (!currentAgg.valueField) {
|
|
657
|
+
throw new Error('No value field provided for percentage aggregation');
|
|
658
|
+
}
|
|
659
|
+
const valueField2Alias = processColumnReference(currentAgg.valueField2 ?? currentAgg.valueField, databaseType, undefined, false, true);
|
|
660
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2
|
|
661
|
+
? `${processColumnReference(currentAgg.valueField2, databaseType, undefined, true)} AS ${valueField2Alias}`
|
|
662
|
+
: '';
|
|
663
|
+
let value2Expr = valueField2Alias;
|
|
664
|
+
if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === 'bool') {
|
|
665
|
+
value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
|
|
666
|
+
}
|
|
667
|
+
const percentageExpr = currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2
|
|
668
|
+
? `sum(${valueExpr}) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === 'bool' ? 'COUNT(*)' : 'SUM(sum(' + valueExpr + ')) OVER ()'}`
|
|
669
|
+
: `sum(${valueExpr}) / GREATEST(sum(${value2Expr}), 1)`;
|
|
670
|
+
quillAggSelects = [
|
|
671
|
+
...quillAggSelects,
|
|
672
|
+
`${percentageExpr} as ${processColumnReference(`${currentAgg.valueField}${disambiguation}`, databaseType, undefined, false, true)}`,
|
|
673
|
+
];
|
|
674
|
+
}
|
|
675
|
+
else {
|
|
676
|
+
quillAggSelects = [
|
|
677
|
+
...quillAggSelects,
|
|
678
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference((currentAgg.valueField || 'count') + disambiguation, databaseType)}`,
|
|
679
|
+
];
|
|
680
|
+
}
|
|
681
|
+
if (valueAliasSubstring)
|
|
682
|
+
valueFieldAliases.push(valueAliasSubstring);
|
|
683
|
+
if (value2AliasSubstring)
|
|
684
|
+
valueFieldAliases.push(value2AliasSubstring);
|
|
685
|
+
});
|
|
686
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
470
687
|
// 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
688
|
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}${
|
|
473
|
-
${value2AliasSubstring}
|
|
689
|
+
const pivotQuery = `, quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, undefined, true)} AS ${rowFieldAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(', ')}` : ''}
|
|
474
690
|
FROM quill_base_table),
|
|
475
|
-
quill_qt_agg AS (SELECT ${
|
|
691
|
+
quill_qt_agg AS (SELECT ${quillAggSelects.join(', ')}
|
|
476
692
|
FROM quill_alias GROUP BY ${databaseType.toLowerCase() === 'clickhouse' ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
|
|
477
693
|
quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql' ? `TOP ${pivot.rowLimit}` : ''} * FROM quill_qt_agg qt
|
|
478
694
|
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql' ? ` LIMIT ${pivot.rowLimit}` : ''})
|
|
@@ -484,27 +700,89 @@ function create1DDatePivotQuery(pivot, itemQuery, dateBucket = 'month', database
|
|
|
484
700
|
}
|
|
485
701
|
function createAggregationValuePivot(pivot, itemQuery, databaseType) {
|
|
486
702
|
const isValidBaseQuery = itemQuery.match(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/);
|
|
487
|
-
if (!isValidBaseQuery
|
|
703
|
+
if (!isValidBaseQuery)
|
|
488
704
|
return undefined;
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
705
|
+
let quillAggSelects = [];
|
|
706
|
+
let valueFieldAliases = [];
|
|
707
|
+
const seenAggs = {};
|
|
708
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
709
|
+
if (!currentAgg.valueField)
|
|
710
|
+
currentAgg.valueField = undefined;
|
|
711
|
+
// Track duplicate aggregation combos for disambiguation.
|
|
712
|
+
if (seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']) {
|
|
713
|
+
seenAggs[currentAgg.aggregationType ?? ''][currentAgg.valueField ?? ''] += 1;
|
|
714
|
+
}
|
|
715
|
+
else {
|
|
716
|
+
seenAggs[currentAgg.aggregationType ?? ''] = {
|
|
717
|
+
...seenAggs[currentAgg.aggregationType ?? ''],
|
|
718
|
+
[currentAgg.valueField ?? '']: 1,
|
|
719
|
+
};
|
|
720
|
+
}
|
|
721
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? '']?.[currentAgg.valueField ?? '']?.toString() ?? '';
|
|
722
|
+
if (disambiguationIndex === '1')
|
|
723
|
+
disambiguationIndex = '';
|
|
724
|
+
const valueFieldAlias = processColumnReference((currentAgg.valueField || 'count'), databaseType, undefined, false, true);
|
|
725
|
+
const valueAliasSubstring = currentAgg.valueField
|
|
726
|
+
? `${processColumnReference(currentAgg.valueField, databaseType, undefined, true)} AS ${valueFieldAlias}`
|
|
727
|
+
: '';
|
|
728
|
+
let value2AliasSubstring = '';
|
|
729
|
+
const disambiguation = pivot.aggregations?.length > 1
|
|
730
|
+
? `${disambiguationIndex}_${currentAgg.aggregationType}`
|
|
731
|
+
: '';
|
|
732
|
+
// If the field type is bool, wrap it in a CASE WHEN
|
|
733
|
+
let valueExpr = !currentAgg.valueField ? '*' : valueFieldAlias;
|
|
734
|
+
valueExpr = currentAgg.valueFieldType === 'bool'
|
|
735
|
+
? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`
|
|
736
|
+
: valueExpr;
|
|
737
|
+
if (currentAgg.aggregationType === 'percentage') {
|
|
738
|
+
if (!currentAgg.valueField) {
|
|
739
|
+
throw new Error('No value field provided for percentage aggregation');
|
|
740
|
+
}
|
|
741
|
+
const valueField2Alias = processColumnReference(currentAgg.valueField2 ?? currentAgg.valueField, databaseType, undefined, false, true);
|
|
742
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === 'bool'
|
|
743
|
+
? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`
|
|
744
|
+
: valueField2Alias;
|
|
745
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2
|
|
746
|
+
? `${processColumnReference(currentAgg.valueField2, databaseType, undefined, true)} AS ${valueField2Alias}`
|
|
747
|
+
: '';
|
|
748
|
+
const percentageExpr = currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2
|
|
749
|
+
? `sum(${valueExpr}) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === 'bool' ? 'COUNT(*)' : 'SUM(sum(' + valueExpr + ')) OVER ()'}`
|
|
750
|
+
: `sum(${valueExpr}) / GREATEST(sum(${value2Expr}), 1)`;
|
|
751
|
+
quillAggSelects = [
|
|
752
|
+
...quillAggSelects,
|
|
753
|
+
`${percentageExpr} as ${processColumnReference(`${currentAgg.valueField ?? ''}${disambiguation}`, databaseType, undefined, false, true)}`,
|
|
754
|
+
];
|
|
755
|
+
}
|
|
756
|
+
else {
|
|
757
|
+
quillAggSelects = [
|
|
758
|
+
...quillAggSelects,
|
|
759
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference((currentAgg.valueField || 'count') + disambiguation, databaseType)}`,
|
|
760
|
+
];
|
|
761
|
+
}
|
|
762
|
+
if (valueAliasSubstring)
|
|
763
|
+
valueFieldAliases.push(valueAliasSubstring);
|
|
764
|
+
if (value2AliasSubstring)
|
|
765
|
+
valueFieldAliases.push(value2AliasSubstring);
|
|
766
|
+
});
|
|
767
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
768
|
+
const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit
|
|
769
|
+
? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType)} ${pivot.sortDirection || ''} `
|
|
770
|
+
: '';
|
|
771
|
+
const pivotQuery = `, quill_alias AS (
|
|
772
|
+
SELECT ${valueFieldAliases.join(', ')} FROM quill_base_table
|
|
773
|
+
),
|
|
774
|
+
quill_qt_agg AS (
|
|
775
|
+
SELECT ${quillAggSelects.join(', ')} FROM quill_alias
|
|
776
|
+
),
|
|
777
|
+
quill_base_pivot AS (
|
|
778
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === 'mssql'
|
|
779
|
+
? `TOP ${pivot.rowLimit}`
|
|
780
|
+
: ''} * FROM quill_qt_agg qt
|
|
781
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== 'mssql'
|
|
782
|
+
? ` LIMIT ${pivot.rowLimit}`
|
|
783
|
+
: ''}
|
|
784
|
+
)
|
|
785
|
+
SELECT * FROM quill_base_pivot`
|
|
508
786
|
.replace(/\s+/g, ' ')
|
|
509
787
|
.trim();
|
|
510
788
|
return itemQuery.replace(/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/, pivotQuery);
|
|
@@ -516,19 +794,19 @@ function additionalProcessingOnPivotQuery(pivot, query, additionalProcessing, da
|
|
|
516
794
|
if (!isValidBaseQuery) {
|
|
517
795
|
return undefined;
|
|
518
796
|
}
|
|
797
|
+
if (!pivot.aggregations || pivot.aggregations.length === 0) {
|
|
798
|
+
if (pivot.aggregationType) {
|
|
799
|
+
pivot.aggregations = [{ aggregationType: pivot.aggregationType, valueField: pivot.valueField, valueField2: pivot.valueField2 }];
|
|
800
|
+
}
|
|
801
|
+
else {
|
|
802
|
+
throw new Error('No aggregations provided for pivot');
|
|
803
|
+
}
|
|
804
|
+
}
|
|
519
805
|
let rowsPerPage = 0;
|
|
520
806
|
let currentInterval = 0;
|
|
521
807
|
let offset = 0;
|
|
522
808
|
let limit = 1000;
|
|
523
|
-
let sortQuery =
|
|
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
|
-
: ''}`;
|
|
809
|
+
let sortQuery = '';
|
|
532
810
|
if (additionalProcessing.page) {
|
|
533
811
|
const page = additionalProcessing.page.page || 0;
|
|
534
812
|
if (additionalProcessing.page.rowsPerRequest) {
|
|
@@ -538,9 +816,18 @@ function additionalProcessingOnPivotQuery(pivot, query, additionalProcessing, da
|
|
|
538
816
|
currentInterval = page ? Math.floor(page / (limit / rowsPerPage)) : 0;
|
|
539
817
|
offset = currentInterval * limit;
|
|
540
818
|
}
|
|
819
|
+
const disambiguation = pivot.aggregations.length > 1
|
|
820
|
+
? `_${(0, textProcessing_1.matchCasing)(pivot.aggregations?.[0]?.aggregationType, pivot.aggregations?.[0]?.valueField)}`
|
|
821
|
+
: '';
|
|
541
822
|
if (additionalProcessing.sort) {
|
|
542
823
|
sortQuery = `ORDER BY ${processColumnReference(additionalProcessing.sort.field, databaseType)} ${additionalProcessing.sort.direction || ''}`;
|
|
543
824
|
}
|
|
825
|
+
else {
|
|
826
|
+
const valueFieldAlias = processColumnReference((pivot.aggregations?.[0]?.valueField ?? '') + disambiguation, databaseType, undefined, false, true);
|
|
827
|
+
const defaultSortField = pivot.sortField || pivot.rowField || valueFieldAlias;
|
|
828
|
+
const defaultSortDirection = pivot.sortDirection || '';
|
|
829
|
+
sortQuery = `ORDER BY ${processColumnReference(defaultSortField, databaseType)} ${defaultSortDirection}`;
|
|
830
|
+
}
|
|
544
831
|
const additionalProcessingQuery = `
|
|
545
832
|
SELECT *
|
|
546
833
|
FROM quill_base_pivot ${sortQuery}${databaseType === 'mssql' ? ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY` : ` LIMIT ${limit} OFFSET ${offset}`}
|