@quillsql/react 2.15.17 → 2.16.0
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/index.cjs +854 -2041
- package/dist/index.js +831 -2018
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -646,12 +646,9 @@ var formatPercent = (value) => {
|
|
|
646
646
|
return formatterPercent.format(Number(value));
|
|
647
647
|
};
|
|
648
648
|
var _getUTCDateHelper = (value, fmt) => {
|
|
649
|
-
if (value === null || value === void 0) {
|
|
650
|
-
return "-";
|
|
651
|
-
}
|
|
652
649
|
const parsedDate = (0, import_date_fns.parse)(value, fmt, /* @__PURE__ */ new Date());
|
|
653
650
|
const utcDate = (0, import_date_fns.isValid)(parsedDate) ? (0, import_date_fns_tz.utcToZonedTime)(parsedDate, "UTC") : (0, import_date_fns_tz.utcToZonedTime)(new Date(value), "UTC");
|
|
654
|
-
if (!(0, import_date_fns.isValid)(utcDate)) return
|
|
651
|
+
if (!(0, import_date_fns.isValid)(utcDate)) return value;
|
|
655
652
|
return (0, import_date_fns.format)(utcDate, fmt);
|
|
656
653
|
};
|
|
657
654
|
var format_YYYY = (value) => _getUTCDateHelper(value, "yyyy");
|
|
@@ -662,11 +659,8 @@ var format_MMM_dd_yyyy = (value) => {
|
|
|
662
659
|
return _getUTCDateHelper(value, "dd MMM yyyy");
|
|
663
660
|
};
|
|
664
661
|
var format_MMM_d_MMM_d = (value, dateRange, databaseType) => {
|
|
665
|
-
if (value === null || value === void 0) {
|
|
666
|
-
return "-";
|
|
667
|
-
}
|
|
668
662
|
const utcDate = (0, import_date_fns.parseISO)(value.split("T")[0]);
|
|
669
|
-
if (!(0, import_date_fns.isValid)(utcDate)) return "
|
|
663
|
+
if (!(0, import_date_fns.isValid)(utcDate)) return "Invalid date";
|
|
670
664
|
let weekStartsOn = 1;
|
|
671
665
|
if (databaseType && ["mssql"].includes(databaseType)) {
|
|
672
666
|
weekStartsOn = 0;
|
|
@@ -697,21 +691,15 @@ var format_MMM_d_MMM_d = (value, dateRange, databaseType) => {
|
|
|
697
691
|
}
|
|
698
692
|
};
|
|
699
693
|
var format_MMM_dd_hh_mm_ap_pm = (value) => {
|
|
700
|
-
if (value === null || value === void 0) {
|
|
701
|
-
return "-";
|
|
702
|
-
}
|
|
703
694
|
const utcDate = (0, import_date_fns_tz.utcToZonedTime)(new Date(value), "UTC");
|
|
704
|
-
if (!(0, import_date_fns.isValid)(utcDate)) return "
|
|
695
|
+
if (!(0, import_date_fns.isValid)(utcDate)) return "Invalid date";
|
|
705
696
|
const formatStr = utcDate.getMinutes() === 0 ? "MMM do h a" : "MMM do h:mm a";
|
|
706
697
|
const res = (0, import_date_fns.format)(utcDate, formatStr);
|
|
707
698
|
return res.slice(0, -2) + res.slice(-2).toLowerCase();
|
|
708
699
|
};
|
|
709
700
|
var format_wo_yyyy = (value) => {
|
|
710
|
-
if (value === null || value === void 0) {
|
|
711
|
-
return "-";
|
|
712
|
-
}
|
|
713
701
|
const utcDate = (0, import_date_fns_tz.utcToZonedTime)(new Date(value), "UTC");
|
|
714
|
-
if (!(0, import_date_fns.isValid)(utcDate)) return "
|
|
702
|
+
if (!(0, import_date_fns.isValid)(utcDate)) return "Invalid date";
|
|
715
703
|
return `${(0, import_date_fns.getWeek)(utcDate)},${utcDate.getFullYear()}`;
|
|
716
704
|
};
|
|
717
705
|
function parseNumber(value) {
|
|
@@ -14793,21 +14781,6 @@ function isDateFormat(xAxisFormat) {
|
|
|
14793
14781
|
const isDate = DATE_FORMATS.includes(xAxisFormat);
|
|
14794
14782
|
return isDate;
|
|
14795
14783
|
}
|
|
14796
|
-
function getComparisonInterval(comparisonRange, dateBucket) {
|
|
14797
|
-
const dayCount = (0, import_date_fns5.differenceInDays)(
|
|
14798
|
-
comparisonRange.endDate,
|
|
14799
|
-
comparisonRange.startDate
|
|
14800
|
-
);
|
|
14801
|
-
if (!isNaN(dayCount)) {
|
|
14802
|
-
if (dateBucket === "month") {
|
|
14803
|
-
return Math.floor(dayCount / 30) + " month";
|
|
14804
|
-
} else if (dateBucket === "year") {
|
|
14805
|
-
return Math.floor(dayCount / 365) + " year";
|
|
14806
|
-
} else {
|
|
14807
|
-
return dayCount + " day";
|
|
14808
|
-
}
|
|
14809
|
-
}
|
|
14810
|
-
}
|
|
14811
14784
|
function getDateBucketFromRange(dateRange) {
|
|
14812
14785
|
const difference = (0, import_date_fns5.differenceInDays)(dateRange.end, dateRange.start);
|
|
14813
14786
|
if (difference < 14) {
|
|
@@ -16621,439 +16594,854 @@ function parseValueFromBigQueryDates(rows, columns) {
|
|
|
16621
16594
|
});
|
|
16622
16595
|
}
|
|
16623
16596
|
|
|
16624
|
-
// src/utils/
|
|
16625
|
-
|
|
16626
|
-
var import_date_fns_tz2 = require("date-fns-tz");
|
|
16627
|
-
function mergeComparisonRange(resp) {
|
|
16628
|
-
if (resp.chartType === "table") return resp;
|
|
16629
|
-
const compRows = resp.compareRows;
|
|
16630
|
-
if (!compRows) return resp;
|
|
16631
|
-
const newRows = resp.rows.map((row, i) => {
|
|
16632
|
-
if (i < compRows.length) {
|
|
16633
|
-
const compRow = compRows[i];
|
|
16634
|
-
const newRow = { ...row };
|
|
16635
|
-
for (const [key, value] of Object.entries(compRow)) {
|
|
16636
|
-
newRow[`comparison_${key}`] = value;
|
|
16637
|
-
}
|
|
16638
|
-
return newRow;
|
|
16639
|
-
}
|
|
16640
|
-
return row;
|
|
16641
|
-
});
|
|
16642
|
-
return { ...resp, rows: newRows };
|
|
16643
|
-
}
|
|
16644
|
-
function dateAdder(date, interval2) {
|
|
16645
|
-
const match = interval2.match(/^(\d+)\s+(day|month|year)$/);
|
|
16646
|
-
if (!match) {
|
|
16647
|
-
throw new Error(`Invalid interval format: ${interval2}`);
|
|
16648
|
-
}
|
|
16649
|
-
const [, valueStr, unit] = match;
|
|
16650
|
-
if (!valueStr || !unit) {
|
|
16651
|
-
throw new Error("Could not parse interval");
|
|
16652
|
-
}
|
|
16653
|
-
const value = parseInt(valueStr, 10);
|
|
16654
|
-
const parsedDate = typeof date === "string" ? new Date(date) : date;
|
|
16655
|
-
switch (unit) {
|
|
16656
|
-
case "day":
|
|
16657
|
-
return (0, import_date_fns7.add)(parsedDate, { days: value });
|
|
16658
|
-
case "month":
|
|
16659
|
-
return (0, import_date_fns7.add)(parsedDate, { months: value });
|
|
16660
|
-
case "year":
|
|
16661
|
-
return (0, import_date_fns7.add)(parsedDate, { years: value });
|
|
16662
|
-
default:
|
|
16663
|
-
throw new Error(`Unsupported interval unit: ${unit}`);
|
|
16664
|
-
}
|
|
16665
|
-
}
|
|
16666
|
-
function dateTrunc(date, granularity = "day", databaseType) {
|
|
16667
|
-
const weekStartsOn = databaseType === "mssql" ? 0 : 1;
|
|
16668
|
-
const timeZone = "UTC";
|
|
16669
|
-
const zonedDate = (0, import_date_fns_tz2.utcToZonedTime)(date, timeZone);
|
|
16670
|
-
switch (granularity.toLowerCase()) {
|
|
16671
|
-
case "week":
|
|
16672
|
-
return (0, import_date_fns7.startOfWeek)(zonedDate, { weekStartsOn });
|
|
16673
|
-
case "month":
|
|
16674
|
-
return (0, import_date_fns7.startOfMonth)(zonedDate);
|
|
16675
|
-
case "day":
|
|
16676
|
-
return (0, import_date_fns7.startOfDay)(zonedDate);
|
|
16677
|
-
case "year":
|
|
16678
|
-
return (0, import_date_fns7.startOfYear)(zonedDate);
|
|
16679
|
-
default:
|
|
16680
|
-
throw new Error(`Unsupported granularity: ${granularity}`);
|
|
16681
|
-
}
|
|
16682
|
-
}
|
|
16683
|
-
function mergeComparisonPivotColumns({
|
|
16684
|
-
pivot,
|
|
16685
|
-
rows,
|
|
16686
|
-
compRows
|
|
16687
|
-
}) {
|
|
16688
|
-
if (!compRows || !compRows.length) return rows;
|
|
16689
|
-
const mappedCompRows = compRows.filter((compRow) => compRow.name !== pivot.rowField).map((compRow) => ({ ...compRow, name: `comparison_${compRow.name}` }));
|
|
16690
|
-
return rows.concat(mappedCompRows);
|
|
16691
|
-
}
|
|
16692
|
-
function mergeComparisonPivotRows({
|
|
16597
|
+
// src/utils/pivotConstructor.ts
|
|
16598
|
+
async function generatePivotWithSQL({
|
|
16693
16599
|
pivot,
|
|
16694
|
-
|
|
16695
|
-
|
|
16696
|
-
databaseType,
|
|
16600
|
+
report,
|
|
16601
|
+
client,
|
|
16697
16602
|
dateBucket,
|
|
16698
|
-
|
|
16699
|
-
|
|
16603
|
+
dateFilter,
|
|
16604
|
+
distinctStrings,
|
|
16605
|
+
dashboardName,
|
|
16606
|
+
tenants,
|
|
16607
|
+
additionalProcessing,
|
|
16608
|
+
pivotQuery,
|
|
16609
|
+
comparisonPivotQuery,
|
|
16610
|
+
getPivotRowCount = true,
|
|
16611
|
+
caller,
|
|
16612
|
+
getToken
|
|
16700
16613
|
}) {
|
|
16701
|
-
|
|
16702
|
-
if (pivot.
|
|
16703
|
-
|
|
16704
|
-
|
|
16705
|
-
|
|
16706
|
-
|
|
16707
|
-
|
|
16708
|
-
|
|
16709
|
-
|
|
16710
|
-
|
|
16711
|
-
|
|
16712
|
-
}
|
|
16713
|
-
if (pivot.rowField) {
|
|
16714
|
-
return merge1DPivotRows(
|
|
16715
|
-
pivot,
|
|
16716
|
-
rows,
|
|
16717
|
-
compRows,
|
|
16718
|
-
databaseType,
|
|
16719
|
-
dateBucket,
|
|
16720
|
-
comparisonInterval
|
|
16721
|
-
);
|
|
16722
|
-
}
|
|
16723
|
-
return mergeAggregatedRows(pivot, rows, compRows);
|
|
16724
|
-
}
|
|
16725
|
-
function merge2DPivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
|
|
16726
|
-
if (!pivot || !pivot.columnField) {
|
|
16727
|
-
return [];
|
|
16728
|
-
}
|
|
16729
|
-
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
16730
|
-
return merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues);
|
|
16731
|
-
}
|
|
16732
|
-
return merge2DDatePivotRows(
|
|
16733
|
-
pivot,
|
|
16734
|
-
rows,
|
|
16735
|
-
compRows,
|
|
16736
|
-
columnFieldValues,
|
|
16737
|
-
databaseType,
|
|
16738
|
-
dateBucket,
|
|
16739
|
-
comparisonInterval
|
|
16740
|
-
);
|
|
16741
|
-
}
|
|
16742
|
-
function merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues) {
|
|
16743
|
-
if (!pivot.rowField || !pivot.aggregations?.some((agg) => agg.valueField)) {
|
|
16744
|
-
return rows;
|
|
16614
|
+
const databaseType = client.databaseType || "postgresql";
|
|
16615
|
+
if (!pivot.aggregations?.length && pivot.aggregationType) {
|
|
16616
|
+
pivot.aggregations = [
|
|
16617
|
+
{
|
|
16618
|
+
aggregationType: pivot.aggregationType,
|
|
16619
|
+
valueField: pivot.valueField,
|
|
16620
|
+
valueFieldType: pivot.valueFieldType,
|
|
16621
|
+
valueField2: pivot.valueField2,
|
|
16622
|
+
valueField2Type: pivot.valueField2Type
|
|
16623
|
+
}
|
|
16624
|
+
];
|
|
16745
16625
|
}
|
|
16746
|
-
|
|
16747
|
-
|
|
16748
|
-
|
|
16749
|
-
|
|
16750
|
-
|
|
16751
|
-
|
|
16752
|
-
|
|
16753
|
-
|
|
16754
|
-
|
|
16755
|
-
|
|
16756
|
-
|
|
16757
|
-
|
|
16758
|
-
|
|
16759
|
-
|
|
16760
|
-
|
|
16761
|
-
|
|
16762
|
-
|
|
16763
|
-
|
|
16764
|
-
|
|
16765
|
-
|
|
16766
|
-
|
|
16767
|
-
|
|
16768
|
-
const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
|
|
16769
|
-
const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
|
|
16770
|
-
const matchingCompRow = compRows.find((compRow) => {
|
|
16771
|
-
const comparisonDateWithInterval = dateAdder(
|
|
16772
|
-
compRow[pivot.rowField],
|
|
16773
|
-
comparisonInterval
|
|
16774
|
-
);
|
|
16775
|
-
const truncatedCompRowDate = dateTrunc(
|
|
16776
|
-
comparisonDateWithInterval,
|
|
16777
|
-
dateBucket,
|
|
16778
|
-
databaseType
|
|
16779
|
-
);
|
|
16780
|
-
return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
|
|
16781
|
-
});
|
|
16782
|
-
const comparisonFields = columnFieldValues.reduce(
|
|
16783
|
-
(acc, fieldValue) => {
|
|
16784
|
-
acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
|
|
16785
|
-
return acc;
|
|
16786
|
-
},
|
|
16787
|
-
{}
|
|
16788
|
-
);
|
|
16789
|
-
return {
|
|
16790
|
-
...row,
|
|
16791
|
-
...comparisonFields
|
|
16792
|
-
};
|
|
16626
|
+
const pivotConfig = {
|
|
16627
|
+
rowField: pivot.rowField,
|
|
16628
|
+
rowFieldType: pivot.rowFieldType,
|
|
16629
|
+
columnField: pivot.columnField,
|
|
16630
|
+
aggregations: pivot.aggregations?.map((agg) => ({
|
|
16631
|
+
aggregationType: agg.aggregationType,
|
|
16632
|
+
valueField: agg.valueField,
|
|
16633
|
+
valueFieldType: agg.valueFieldType
|
|
16634
|
+
}))
|
|
16635
|
+
};
|
|
16636
|
+
const resp = await quillFetch({
|
|
16637
|
+
client,
|
|
16638
|
+
task: "pivot-template",
|
|
16639
|
+
metadata: {
|
|
16640
|
+
clientId: client.clientId,
|
|
16641
|
+
pivot: pivotConfig,
|
|
16642
|
+
itemQuery: report?.queryString,
|
|
16643
|
+
dashboardName,
|
|
16644
|
+
tenants
|
|
16645
|
+
},
|
|
16646
|
+
credentials: "same-origin",
|
|
16647
|
+
getToken
|
|
16793
16648
|
});
|
|
16794
|
-
|
|
16795
|
-
|
|
16796
|
-
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
16797
|
-
return merge1DStringPivotRows(pivot, rows, compRows);
|
|
16649
|
+
if (resp.data?.success === false) {
|
|
16650
|
+
throw resp.data.errorMessage;
|
|
16798
16651
|
}
|
|
16799
|
-
|
|
16800
|
-
|
|
16801
|
-
|
|
16802
|
-
|
|
16803
|
-
|
|
16804
|
-
|
|
16805
|
-
|
|
16806
|
-
|
|
16807
|
-
|
|
16808
|
-
|
|
16809
|
-
|
|
16810
|
-
|
|
16652
|
+
const queryResponseRows = resp.data?.rows || resp.queries?.queryResults?.[0]?.rows || [];
|
|
16653
|
+
const queryResponseFields = resp.data?.fields || resp.queries?.queryResults?.[0]?.fields || [];
|
|
16654
|
+
const rowCount = resp.queries?.queryResults?.[1]?.rows?.[0]?.row_count || 0;
|
|
16655
|
+
parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
|
|
16656
|
+
const responseRows = queryResponseRows;
|
|
16657
|
+
const responseFields = queryResponseFields;
|
|
16658
|
+
const rows = pivot.rowField ? responseRows.map(
|
|
16659
|
+
(row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
|
|
16660
|
+
) : responseRows;
|
|
16661
|
+
if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
|
|
16662
|
+
rows.forEach((row) => {
|
|
16663
|
+
Object.keys(row).forEach((key) => {
|
|
16664
|
+
const processedKey = processColumnName(key);
|
|
16665
|
+
if (processedKey !== key) {
|
|
16666
|
+
row[processedKey] = row[key];
|
|
16667
|
+
delete row[key];
|
|
16668
|
+
}
|
|
16669
|
+
});
|
|
16670
|
+
});
|
|
16811
16671
|
}
|
|
16812
|
-
|
|
16813
|
-
|
|
16814
|
-
|
|
16815
|
-
|
|
16816
|
-
|
|
16817
|
-
|
|
16818
|
-
|
|
16819
|
-
|
|
16820
|
-
|
|
16821
|
-
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
|
|
16672
|
+
const columns = responseFields?.map((field) => ({
|
|
16673
|
+
field: processColumnName(field.field || field.name),
|
|
16674
|
+
label: snakeCaseToTitleCase(
|
|
16675
|
+
processColumnName(
|
|
16676
|
+
(field.field || field.name).replace("comparison_", "comparison ")
|
|
16677
|
+
)
|
|
16678
|
+
),
|
|
16679
|
+
format: (field.field || field.name) === pivot.rowField ? "string" : pivot.aggregations?.find(
|
|
16680
|
+
(agg) => agg.valueField === (field.field || field.name) || `${agg.valueField}_percentage` === (field.field || field.name) || !agg.valueField && agg.aggregationType === "percentage" && (field.field || field.name)?.endsWith("percentage")
|
|
16681
|
+
)?.aggregationType === "percentage" ? "percent" : "whole_number",
|
|
16682
|
+
fieldType: field.fieldType,
|
|
16683
|
+
jsType: field.jsType,
|
|
16684
|
+
dataTypeID: field.dataTypeID
|
|
16685
|
+
})).filter(
|
|
16686
|
+
(field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
|
|
16687
|
+
).sort((a, b) => {
|
|
16688
|
+
if (a.field === pivot.rowField) {
|
|
16689
|
+
return -1;
|
|
16825
16690
|
}
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
|
|
16691
|
+
if (b.field === pivot.rowField) {
|
|
16692
|
+
return 1;
|
|
16693
|
+
}
|
|
16694
|
+
return 0;
|
|
16830
16695
|
});
|
|
16831
|
-
|
|
16832
|
-
|
|
16833
|
-
|
|
16834
|
-
|
|
16835
|
-
|
|
16836
|
-
|
|
16837
|
-
|
|
16838
|
-
|
|
16839
|
-
|
|
16840
|
-
|
|
16841
|
-
|
|
16842
|
-
|
|
16843
|
-
|
|
16844
|
-
|
|
16845
|
-
|
|
16696
|
+
if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
|
|
16697
|
+
rows.forEach((row) => {
|
|
16698
|
+
row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
16699
|
+
let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
16700
|
+
if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
|
|
16701
|
+
const rowDate = new Date(value);
|
|
16702
|
+
if (rowDate < dateFilter.startDate) {
|
|
16703
|
+
value = dateFilter.startDate.toISOString();
|
|
16704
|
+
} else if (rowDate > dateFilter.endDate) {
|
|
16705
|
+
value = dateFilter.endDate.toISOString();
|
|
16706
|
+
}
|
|
16707
|
+
}
|
|
16708
|
+
const dateString = getDateString(
|
|
16709
|
+
value,
|
|
16710
|
+
dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
|
|
16846
16711
|
dateBucket,
|
|
16847
16712
|
databaseType
|
|
16848
16713
|
);
|
|
16849
|
-
|
|
16714
|
+
row[pivot.rowField || ""] = dateString;
|
|
16850
16715
|
});
|
|
16851
|
-
|
|
16852
|
-
|
|
16853
|
-
|
|
16854
|
-
|
|
16855
|
-
|
|
16856
|
-
|
|
16857
|
-
|
|
16858
|
-
|
|
16716
|
+
if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
|
|
16717
|
+
const dateSet = new Set(
|
|
16718
|
+
rows.map((row) => row[pivot.rowField || ""])
|
|
16719
|
+
);
|
|
16720
|
+
for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
|
|
16721
|
+
const formattedDate = getDateString(
|
|
16722
|
+
date.toISOString(),
|
|
16723
|
+
{ start: dateFilter.startDate, end: dateFilter.endDate },
|
|
16724
|
+
dateBucket,
|
|
16725
|
+
databaseType
|
|
16726
|
+
);
|
|
16727
|
+
if (!dateSet.has(formattedDate)) {
|
|
16728
|
+
const newRow = {};
|
|
16729
|
+
newRow[pivot.rowField] = formattedDate;
|
|
16730
|
+
newRow.__quillRawDate = date.toISOString();
|
|
16731
|
+
rows.push(newRow);
|
|
16732
|
+
dateSet.add(formattedDate);
|
|
16733
|
+
}
|
|
16859
16734
|
}
|
|
16860
16735
|
}
|
|
16861
|
-
|
|
16862
|
-
|
|
16863
|
-
|
|
16864
|
-
|
|
16736
|
+
if (!pivot.sort) {
|
|
16737
|
+
rows.sort((a, b) => {
|
|
16738
|
+
if (a.__quillRawDate < b.__quillRawDate) {
|
|
16739
|
+
return -1;
|
|
16740
|
+
}
|
|
16741
|
+
if (a.__quillRawDate > b.__quillRawDate) {
|
|
16742
|
+
return 1;
|
|
16743
|
+
}
|
|
16744
|
+
return 0;
|
|
16745
|
+
});
|
|
16746
|
+
}
|
|
16747
|
+
}
|
|
16748
|
+
columns?.forEach((column, index) => {
|
|
16749
|
+
if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
|
|
16750
|
+
column.label = "Count";
|
|
16751
|
+
}
|
|
16752
|
+
});
|
|
16753
|
+
const numericColumns = columns?.filter(
|
|
16754
|
+
(column) => column.format === "whole_number" || column.format === "percentage"
|
|
16755
|
+
);
|
|
16756
|
+
rows.forEach((row) => {
|
|
16757
|
+
numericColumns?.forEach((column) => {
|
|
16758
|
+
row[column.field] = row[column.field] ?? 0;
|
|
16759
|
+
});
|
|
16865
16760
|
});
|
|
16761
|
+
return {
|
|
16762
|
+
rows,
|
|
16763
|
+
columns: columns ?? [],
|
|
16764
|
+
rowCount: rowCount || rows.length,
|
|
16765
|
+
pivotQuery: report?.queryString || "",
|
|
16766
|
+
comparisonPivotQuery: comparisonPivotQuery || ""
|
|
16767
|
+
};
|
|
16866
16768
|
}
|
|
16867
|
-
function
|
|
16868
|
-
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
aggregationSuffix = "_PERCENTAGE";
|
|
16875
|
-
} else {
|
|
16876
|
-
aggregationSuffix = "_percentage";
|
|
16769
|
+
function generatePivotTableYAxis(pivot, cols, yAxisField) {
|
|
16770
|
+
if (pivot?.aggregationType === "count") {
|
|
16771
|
+
return [
|
|
16772
|
+
{
|
|
16773
|
+
field: pivot.valueField ?? "count",
|
|
16774
|
+
label: yAxisField.label,
|
|
16775
|
+
format: yAxisField.format
|
|
16877
16776
|
}
|
|
16777
|
+
];
|
|
16778
|
+
}
|
|
16779
|
+
return [
|
|
16780
|
+
{
|
|
16781
|
+
field: pivot.valueField ?? "count",
|
|
16782
|
+
label: yAxisField.label,
|
|
16783
|
+
format: yAxisField.format
|
|
16878
16784
|
}
|
|
16879
|
-
|
|
16880
|
-
[`comparison_${pivot.valueField}${aggregationSuffix}`]: compRows[i]?.[`${pivot.valueField}${aggregationSuffix}`]
|
|
16881
|
-
};
|
|
16882
|
-
return { ...row, ...compRow };
|
|
16883
|
-
});
|
|
16785
|
+
];
|
|
16884
16786
|
}
|
|
16885
|
-
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
|
|
16891
|
-
|
|
16787
|
+
function generatePivotTitle(pivot) {
|
|
16788
|
+
if (pivot.rowField && !pivot.valueField && pivot.aggregations?.[0]) {
|
|
16789
|
+
return snakeAndCamelCaseToTitleCase(
|
|
16790
|
+
`${pivot.aggregations[0].aggregationType} of ${pivot.rowField}${pivot.columnField ? ` by ${pivot.columnField}` : ""}
|
|
16791
|
+
`
|
|
16792
|
+
);
|
|
16793
|
+
} else if (!pivot.rowField && pivot.aggregations?.[0]?.valueField) {
|
|
16794
|
+
return snakeAndCamelCaseToTitleCase(
|
|
16795
|
+
`${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
|
|
16796
|
+
`
|
|
16797
|
+
);
|
|
16892
16798
|
}
|
|
16893
|
-
return
|
|
16894
|
-
}
|
|
16895
|
-
|
|
16896
|
-
if (aggType === "count" && hasColumnField) return "SUM";
|
|
16897
|
-
return aggType?.toLowerCase() === "average" ? "AVG" : aggType?.toLowerCase();
|
|
16898
|
-
}
|
|
16899
|
-
function replaceBigQuerySpecialCharacters(column) {
|
|
16900
|
-
return column.replaceAll("/", "quill_forward_slash");
|
|
16799
|
+
return snakeAndCamelCaseToTitleCase(
|
|
16800
|
+
`${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
|
|
16801
|
+
);
|
|
16901
16802
|
}
|
|
16902
|
-
function
|
|
16903
|
-
|
|
16904
|
-
|
|
16905
|
-
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
-
|
|
16909
|
-
|
|
16910
|
-
|
|
16911
|
-
|
|
16912
|
-
|
|
16913
|
-
|
|
16914
|
-
|
|
16915
|
-
|
|
16916
|
-
|
|
16917
|
-
|
|
16918
|
-
|
|
16919
|
-
|
|
16920
|
-
|
|
16921
|
-
|
|
16922
|
-
|
|
16923
|
-
|
|
16924
|
-
|
|
16925
|
-
|
|
16926
|
-
|
|
16927
|
-
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
return fallbackOnNull ? `${fallbackOnNull}` : "_";
|
|
16934
|
-
}
|
|
16935
|
-
if (isColumnFieldAlias) {
|
|
16936
|
-
return `"${column.replaceAll('"', "")}"`;
|
|
16937
|
-
}
|
|
16938
|
-
if (isValueFieldAlias) {
|
|
16939
|
-
const cleanedColumn = column.replaceAll(")", "").replaceAll("(", "_");
|
|
16940
|
-
return `${cleanedColumn}`;
|
|
16941
|
-
}
|
|
16942
|
-
return column;
|
|
16943
|
-
}
|
|
16944
|
-
case "bigquery": {
|
|
16945
|
-
if (column === "") {
|
|
16946
|
-
return fallbackOnNull ? `\`${fallbackOnNull}\`` : "`_`";
|
|
16947
|
-
}
|
|
16948
|
-
if (isColumnFieldAlias) {
|
|
16949
|
-
return `\`${replaceBigQuerySpecialCharacters(column.replaceAll("`", ""))}\``;
|
|
16950
|
-
}
|
|
16951
|
-
const columnParts = column.split(".");
|
|
16952
|
-
if (columnParts.length > 1) {
|
|
16953
|
-
return `\`` + columnParts.map((part) => part.replaceAll(`\``, "")).join("`.`") + `\``;
|
|
16954
|
-
}
|
|
16955
|
-
return `\`${replaceBigQuerySpecialCharacters(column.replaceAll("`", ""))}\``;
|
|
16956
|
-
}
|
|
16957
|
-
case "mssql": {
|
|
16958
|
-
if (column === "") {
|
|
16959
|
-
return fallbackOnNull ? `[${fallbackOnNull}]` : `[_]`;
|
|
16960
|
-
}
|
|
16961
|
-
if (isColumnFieldAlias) {
|
|
16962
|
-
return `[${column.replaceAll("]", "").replaceAll("[", "")}]`;
|
|
16963
|
-
}
|
|
16964
|
-
const columnParts = column.split(".");
|
|
16965
|
-
if (columnParts.length > 1) {
|
|
16966
|
-
return `[` + columnParts.map((part) => part.replaceAll("]", "").replaceAll("[", "")).join("].[`") + `]`;
|
|
16967
|
-
}
|
|
16968
|
-
return `[${column.replaceAll("]", "").replaceAll("[", "")}]`;
|
|
16803
|
+
async function generatePivotTable({
|
|
16804
|
+
pivot,
|
|
16805
|
+
dateBucket,
|
|
16806
|
+
dateFilter,
|
|
16807
|
+
report,
|
|
16808
|
+
client,
|
|
16809
|
+
getToken,
|
|
16810
|
+
eventTracking,
|
|
16811
|
+
uniqueValues,
|
|
16812
|
+
dashboardName,
|
|
16813
|
+
tenants,
|
|
16814
|
+
additionalProcessing,
|
|
16815
|
+
caller,
|
|
16816
|
+
pivotQuery
|
|
16817
|
+
}) {
|
|
16818
|
+
try {
|
|
16819
|
+
if (report && client) {
|
|
16820
|
+
const pivotTable = await generatePivotWithSQL({
|
|
16821
|
+
pivotQuery,
|
|
16822
|
+
pivot,
|
|
16823
|
+
report,
|
|
16824
|
+
client,
|
|
16825
|
+
dateBucket,
|
|
16826
|
+
dateFilter,
|
|
16827
|
+
dashboardName,
|
|
16828
|
+
tenants,
|
|
16829
|
+
additionalProcessing,
|
|
16830
|
+
caller,
|
|
16831
|
+
getToken
|
|
16832
|
+
});
|
|
16833
|
+
return pivotTable;
|
|
16969
16834
|
}
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16835
|
+
} catch (e) {
|
|
16836
|
+
eventTracking?.logError?.({
|
|
16837
|
+
type: "bug",
|
|
16838
|
+
// TODO: determine type
|
|
16839
|
+
severity: "high",
|
|
16840
|
+
message: "Error generating pivot table",
|
|
16841
|
+
errorMessage: e.message,
|
|
16842
|
+
errorStack: e.stack,
|
|
16843
|
+
errorData: {
|
|
16844
|
+
caller: "PivotModal",
|
|
16845
|
+
function: "generatePivotTable"
|
|
16980
16846
|
}
|
|
16981
|
-
|
|
16982
|
-
}
|
|
16983
|
-
default:
|
|
16984
|
-
return column;
|
|
16847
|
+
});
|
|
16848
|
+
throw Error(`Failed to generate pivot table with SQL: ${e}`);
|
|
16985
16849
|
}
|
|
16850
|
+
throw Error("Failed to generate pivot table: invalid report");
|
|
16986
16851
|
}
|
|
16987
|
-
|
|
16988
|
-
|
|
16989
|
-
|
|
16990
|
-
|
|
16991
|
-
|
|
16992
|
-
|
|
16993
|
-
|
|
16994
|
-
|
|
16995
|
-
|
|
16996
|
-
|
|
16852
|
+
|
|
16853
|
+
// src/utils/paginationProcessing.ts
|
|
16854
|
+
var DEFAULT_PAGINATION = {
|
|
16855
|
+
page: 0,
|
|
16856
|
+
rowsPerPage: 10,
|
|
16857
|
+
rowsPerRequest: 600
|
|
16858
|
+
};
|
|
16859
|
+
var DEFAULT_TABLE_PAGINATION = {
|
|
16860
|
+
page: 0,
|
|
16861
|
+
rowsPerPage: 10,
|
|
16862
|
+
rowsPerRequest: 50
|
|
16863
|
+
};
|
|
16864
|
+
function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
|
|
16865
|
+
if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
|
|
16866
|
+
return false;
|
|
16997
16867
|
}
|
|
16998
|
-
|
|
16868
|
+
const indexAdjustedPage = page;
|
|
16869
|
+
const pageInterval = Math.floor(
|
|
16870
|
+
indexAdjustedPage * pagination.rowsPerPage / pagination.rowsPerRequest
|
|
16871
|
+
);
|
|
16872
|
+
const indexAdjustedPreviousPage = maxPage;
|
|
16873
|
+
const previousPageInterval = Math.floor(
|
|
16874
|
+
indexAdjustedPreviousPage * pagination.rowsPerPage / pagination.rowsPerRequest
|
|
16875
|
+
);
|
|
16876
|
+
return pageInterval > previousPageInterval;
|
|
16999
16877
|
}
|
|
17000
|
-
function
|
|
17001
|
-
|
|
17002
|
-
|
|
17003
|
-
return `date_trunc('${dateBucket}', ${dateField})`;
|
|
17004
|
-
}
|
|
17005
|
-
if (["clickhouse"].includes(databaseType.toLowerCase())) {
|
|
17006
|
-
return `dateTrunc('${dateBucket}', ${dateField})`;
|
|
17007
|
-
}
|
|
17008
|
-
if (["databricks"].includes(databaseType.toLowerCase())) {
|
|
17009
|
-
return `DATE_TRUNC('${dateBucket}', ${dateField})`;
|
|
17010
|
-
}
|
|
17011
|
-
if (["mysql"].includes(databaseType.toLowerCase())) {
|
|
17012
|
-
switch (dateBucket.toLowerCase()) {
|
|
17013
|
-
case "year":
|
|
17014
|
-
return `DATE_FORMAT(${dateField}, '%Y-01-01 00:00:00')`;
|
|
17015
|
-
case "month":
|
|
17016
|
-
return `DATE_FORMAT(${dateField}, '%Y-%m-01 00:00:00')`;
|
|
17017
|
-
case "week":
|
|
17018
|
-
return `DATE_FORMAT(${dateField}, '%Y-%U-1 00:00:00')`;
|
|
17019
|
-
case "day":
|
|
17020
|
-
default:
|
|
17021
|
-
return `DATE(${dateField})`;
|
|
17022
|
-
}
|
|
17023
|
-
}
|
|
17024
|
-
if (["mssql"].includes(databaseType.toLowerCase())) {
|
|
17025
|
-
return `DATETRUNC(${dateBucket}, ${dateField})`;
|
|
16878
|
+
function shouldSortInMemory(pagination, rowCount) {
|
|
16879
|
+
if (!rowCount || rowCount < pagination.rowsPerRequest) {
|
|
16880
|
+
return true;
|
|
17026
16881
|
}
|
|
17027
|
-
return
|
|
17028
|
-
}
|
|
17029
|
-
function processValueField(aggType, databaseType, valueField) {
|
|
17030
|
-
if (aggType === "min" || aggType === "max" || aggType?.toLowerCase() === "average")
|
|
17031
|
-
return `${processColumnReference(valueField, databaseType)} ELSE null`;
|
|
17032
|
-
if (aggType === "count") return `1 ELSE 0`;
|
|
17033
|
-
return valueField ? `${processColumnReference(valueField, databaseType)} ELSE 0` : `1 ELSE 0`;
|
|
16882
|
+
return false;
|
|
17034
16883
|
}
|
|
17035
|
-
|
|
17036
|
-
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
|
|
17043
|
-
|
|
17044
|
-
|
|
17045
|
-
|
|
17046
|
-
|
|
17047
|
-
|
|
17048
|
-
|
|
17049
|
-
|
|
17050
|
-
|
|
17051
|
-
|
|
17052
|
-
|
|
16884
|
+
|
|
16885
|
+
// src/utils/dashboard.ts
|
|
16886
|
+
var defaultDashboardItem = {
|
|
16887
|
+
id: "",
|
|
16888
|
+
name: "",
|
|
16889
|
+
dashboardName: "",
|
|
16890
|
+
rows: [],
|
|
16891
|
+
compareRows: [],
|
|
16892
|
+
columns: [],
|
|
16893
|
+
chartType: "",
|
|
16894
|
+
pivot: null,
|
|
16895
|
+
yAxisFields: [],
|
|
16896
|
+
xAxisLabel: "",
|
|
16897
|
+
xAxisField: "",
|
|
16898
|
+
xAxisFormat: "string",
|
|
16899
|
+
order: -1,
|
|
16900
|
+
filtersApplied: [],
|
|
16901
|
+
queryString: "",
|
|
16902
|
+
rowCount: 0,
|
|
16903
|
+
columnInternal: []
|
|
16904
|
+
};
|
|
16905
|
+
async function cleanDashboardItem({
|
|
16906
|
+
item,
|
|
16907
|
+
dashboardFilters,
|
|
16908
|
+
getToken,
|
|
16909
|
+
eventTracking,
|
|
16910
|
+
client,
|
|
16911
|
+
dateBucket,
|
|
16912
|
+
additionalProcessing,
|
|
16913
|
+
customFields,
|
|
16914
|
+
skipPivotFetch,
|
|
16915
|
+
tenants
|
|
16916
|
+
}) {
|
|
16917
|
+
if (!item) return defaultDashboardItem;
|
|
16918
|
+
if (!item.rows) {
|
|
16919
|
+
return {
|
|
16920
|
+
...defaultDashboardItem,
|
|
16921
|
+
id: item._id,
|
|
16922
|
+
name: item.name
|
|
16923
|
+
};
|
|
17053
16924
|
}
|
|
17054
|
-
|
|
17055
|
-
|
|
17056
|
-
|
|
16925
|
+
const fields = item.fields || [];
|
|
16926
|
+
const columnsWithCustomFields = [...item.columns ?? []];
|
|
16927
|
+
if (item.includeCustomFields && item.rows?.length > 0) {
|
|
16928
|
+
const tables = item.referencedTables ?? [];
|
|
16929
|
+
tables.forEach((table) => {
|
|
16930
|
+
const _customFields = customFields?.[table] ?? [];
|
|
16931
|
+
_customFields.forEach((field) => {
|
|
16932
|
+
const isJsonCustomField = !!field.refColumn;
|
|
16933
|
+
if (item.rows[0][field.field] !== void 0 && !item.columns.some((col) => col.field === field.field)) {
|
|
16934
|
+
const result_field = fields.find((f) => f.name === field.field);
|
|
16935
|
+
const converted_field = convertPostgresColumn(result_field ?? {});
|
|
16936
|
+
columnsWithCustomFields.push({
|
|
16937
|
+
field: field.field,
|
|
16938
|
+
format: converted_field.format,
|
|
16939
|
+
label: snakeAndCamelCaseToTitleCase(field.field),
|
|
16940
|
+
fieldType: converted_field.fieldType,
|
|
16941
|
+
dataTypeID: converted_field.dataTypeID,
|
|
16942
|
+
jsType: converted_field.jsType,
|
|
16943
|
+
inferFormat: isJsonCustomField
|
|
16944
|
+
});
|
|
16945
|
+
}
|
|
16946
|
+
});
|
|
16947
|
+
});
|
|
16948
|
+
}
|
|
16949
|
+
const processedColumns = item.columns.map((col) => {
|
|
16950
|
+
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
16951
|
+
});
|
|
16952
|
+
const columnInternal = (item.includeCustomFields ? columnsWithCustomFields : item.columns).map((col) => {
|
|
16953
|
+
const field = item.fields?.find((f) => f.name === col.field);
|
|
16954
|
+
const converted_field = convertPostgresColumn(field ?? {});
|
|
16955
|
+
return {
|
|
16956
|
+
fieldType: converted_field.fieldType,
|
|
16957
|
+
dataTypeID: converted_field.dataTypeID,
|
|
16958
|
+
jsType: converted_field.jsType,
|
|
16959
|
+
...col,
|
|
16960
|
+
label: snakeAndCamelCaseToTitleCase(col.label)
|
|
16961
|
+
};
|
|
16962
|
+
});
|
|
16963
|
+
let pivotTable;
|
|
16964
|
+
let pivotError;
|
|
16965
|
+
try {
|
|
16966
|
+
const shouldPaginatePivotAsTable = item.chartType === "table";
|
|
16967
|
+
const pivotChartProcessing = {
|
|
16968
|
+
page: DEFAULT_PAGINATION
|
|
16969
|
+
};
|
|
16970
|
+
pivotTable = await getPivotTable(
|
|
16971
|
+
{
|
|
16972
|
+
...item,
|
|
16973
|
+
pivot: item.pivot && !skipPivotFetch ? {
|
|
16974
|
+
...item.pivot,
|
|
16975
|
+
aggregations: item.pivot.aggregations ?? [
|
|
16976
|
+
{
|
|
16977
|
+
valueField: item.pivot.valueField,
|
|
16978
|
+
valueFieldType: item.pivot.valueFieldType,
|
|
16979
|
+
valueField2: item.pivot.valueField2,
|
|
16980
|
+
valueField2Type: item.pivot.valueField2Type,
|
|
16981
|
+
aggregationType: item.pivot.aggregationType
|
|
16982
|
+
}
|
|
16983
|
+
]
|
|
16984
|
+
} : void 0
|
|
16985
|
+
},
|
|
16986
|
+
dashboardFilters,
|
|
16987
|
+
item.dashboardName,
|
|
16988
|
+
getToken,
|
|
16989
|
+
client,
|
|
16990
|
+
eventTracking,
|
|
16991
|
+
dateBucket,
|
|
16992
|
+
shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
|
|
16993
|
+
tenants,
|
|
16994
|
+
customFields
|
|
16995
|
+
);
|
|
16996
|
+
} catch (e) {
|
|
16997
|
+
pivotTable = void 0;
|
|
16998
|
+
eventTracking?.logError?.({
|
|
16999
|
+
type: "bug",
|
|
17000
|
+
// TODO: determine type
|
|
17001
|
+
severity: "high",
|
|
17002
|
+
message: "Error fetching pivot table",
|
|
17003
|
+
errorMessage: e.message,
|
|
17004
|
+
errorStack: e.stack,
|
|
17005
|
+
errorData: {
|
|
17006
|
+
caller: "cleanDashboardItem",
|
|
17007
|
+
function: "cleanDashboardItem"
|
|
17008
|
+
}
|
|
17009
|
+
});
|
|
17010
|
+
console.error("Error fetching pivot table", e);
|
|
17011
|
+
pivotError = "Error fetching pivot table";
|
|
17012
|
+
}
|
|
17013
|
+
const referenceLineYValues = [];
|
|
17014
|
+
for (const key in item) {
|
|
17015
|
+
if (key.startsWith("referenceLine_")) {
|
|
17016
|
+
const field = key.slice(14);
|
|
17017
|
+
if (!item[key] || !item[key][0]) continue;
|
|
17018
|
+
const value = Object.values(item[key][0])[0];
|
|
17019
|
+
referenceLineYValues.push({ label: field, query: [value, value] });
|
|
17020
|
+
}
|
|
17021
|
+
}
|
|
17022
|
+
if (item.referenceLines) {
|
|
17023
|
+
for (const referenceLine of item.referenceLines) {
|
|
17024
|
+
if (Array.isArray(referenceLine.query)) {
|
|
17025
|
+
referenceLineYValues.push({
|
|
17026
|
+
label: referenceLine.label,
|
|
17027
|
+
query: referenceLine.query
|
|
17028
|
+
});
|
|
17029
|
+
} else if (referenceLine.query === "") {
|
|
17030
|
+
referenceLineYValues.push({
|
|
17031
|
+
label: referenceLine.label,
|
|
17032
|
+
query: (pivotTable?.rows ? pivotTable.rows : item.rows).map(
|
|
17033
|
+
(row) => Number(row[referenceLine.label]) || 0
|
|
17034
|
+
)
|
|
17035
|
+
});
|
|
17036
|
+
}
|
|
17037
|
+
}
|
|
17038
|
+
}
|
|
17039
|
+
return {
|
|
17040
|
+
id: item._id ?? item.id,
|
|
17041
|
+
name: item.name,
|
|
17042
|
+
dashboardName: item.dashboardName,
|
|
17043
|
+
// section: item.section,
|
|
17044
|
+
rows: item.rows,
|
|
17045
|
+
pivotRows: pivotTable ? pivotTable.rows : void 0,
|
|
17046
|
+
pivotColumns: pivotTable ? pivotTable.columns : void 0,
|
|
17047
|
+
compareRows: item.compareRows,
|
|
17048
|
+
columns: processedColumns.map((column) => {
|
|
17049
|
+
return {
|
|
17050
|
+
field: column.field,
|
|
17051
|
+
format: column.format,
|
|
17052
|
+
label: column.label,
|
|
17053
|
+
inferFormat: column.inferFormat
|
|
17054
|
+
};
|
|
17055
|
+
}),
|
|
17056
|
+
includeCustomFields: item.includeCustomFields,
|
|
17057
|
+
columnInternal,
|
|
17058
|
+
columnsWithCustomFields,
|
|
17059
|
+
chartType: item.chartType,
|
|
17060
|
+
dateField: item.dateField,
|
|
17061
|
+
pivot: pivotError ? void 0 : item.pivot ? {
|
|
17062
|
+
...item.pivot,
|
|
17063
|
+
aggregations: item.pivot.aggregations ?? [
|
|
17064
|
+
{
|
|
17065
|
+
valueField: item.pivot.valueField,
|
|
17066
|
+
valueFieldType: item.pivot.valueFieldType,
|
|
17067
|
+
valueField2: item.pivot.valueField2,
|
|
17068
|
+
valueField2Type: item.pivot.valueField2Type,
|
|
17069
|
+
aggregationType: item.pivot.aggregationType
|
|
17070
|
+
}
|
|
17071
|
+
],
|
|
17072
|
+
columnValues: item.distinctStrings
|
|
17073
|
+
} : void 0,
|
|
17074
|
+
yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
|
|
17075
|
+
xAxisLabel: item.xAxisLabel,
|
|
17076
|
+
xAxisField: item.xAxisField,
|
|
17077
|
+
xAxisFormat: item.xAxisFormat,
|
|
17078
|
+
order: item.order,
|
|
17079
|
+
filtersApplied: item.filtersApplied,
|
|
17080
|
+
filterMap: item.filterMap,
|
|
17081
|
+
flags: item.flags,
|
|
17082
|
+
rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
|
|
17083
|
+
pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
|
|
17084
|
+
template: item.template,
|
|
17085
|
+
sort: item.sort,
|
|
17086
|
+
itemQuery: item.itemQuery,
|
|
17087
|
+
queryString: item.queryString,
|
|
17088
|
+
pivotQuery: pivotTable?.pivotQuery,
|
|
17089
|
+
comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
|
|
17090
|
+
referencedTables: item?.referencedTables || [],
|
|
17091
|
+
referencedColumns: item?.referencedColumns || {},
|
|
17092
|
+
error: item.error ?? pivotError,
|
|
17093
|
+
referenceLineYValues,
|
|
17094
|
+
referenceLines: item.referenceLines
|
|
17095
|
+
};
|
|
17096
|
+
}
|
|
17097
|
+
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
|
|
17098
|
+
if (!report) return void 0;
|
|
17099
|
+
const dateFilter = Object.values(dashboardFilters ?? {}).find(
|
|
17100
|
+
(filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
|
|
17101
|
+
);
|
|
17102
|
+
if (dateFilter?.operator === "BETWEEN") {
|
|
17103
|
+
dateFilter.startDate = dateFilter.value[0];
|
|
17104
|
+
dateFilter.endDate = dateFilter.value[1];
|
|
17105
|
+
}
|
|
17106
|
+
const pivot = report?.pivot;
|
|
17107
|
+
const data = report || {};
|
|
17108
|
+
if (pivot && client) {
|
|
17109
|
+
if (report.rowCount === 0 || report.rows.length === 0) {
|
|
17110
|
+
const columns = [];
|
|
17111
|
+
if (pivot.rowField) {
|
|
17112
|
+
columns.push({
|
|
17113
|
+
field: pivot.rowField,
|
|
17114
|
+
label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
|
|
17115
|
+
format: pivot.rowFieldType || "string",
|
|
17116
|
+
jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
|
|
17117
|
+
fieldType: pivot.rowFieldType || "string",
|
|
17118
|
+
dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
|
|
17119
|
+
});
|
|
17120
|
+
}
|
|
17121
|
+
for (const agg of pivot.aggregations ?? []) {
|
|
17122
|
+
if (agg.valueField) {
|
|
17123
|
+
columns.push({
|
|
17124
|
+
field: agg.valueField,
|
|
17125
|
+
label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
|
|
17126
|
+
//FIXME: valueFieldType is not always the same as the format
|
|
17127
|
+
format: agg.valueFieldType ?? "whole_number",
|
|
17128
|
+
jsType: agg.valueFieldType ?? "number",
|
|
17129
|
+
fieldType: agg.valueFieldType ?? "number",
|
|
17130
|
+
dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
|
|
17131
|
+
});
|
|
17132
|
+
}
|
|
17133
|
+
}
|
|
17134
|
+
return {
|
|
17135
|
+
rows: [],
|
|
17136
|
+
rowCount: 0,
|
|
17137
|
+
pivotQuery: report.queryString ?? "",
|
|
17138
|
+
columns
|
|
17139
|
+
};
|
|
17140
|
+
}
|
|
17141
|
+
try {
|
|
17142
|
+
let dateBucket = dateBucketInitial;
|
|
17143
|
+
let filterDateRange = void 0;
|
|
17144
|
+
if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
|
|
17145
|
+
filterDateRange = {
|
|
17146
|
+
start: dateFilter.startDate,
|
|
17147
|
+
end: dateFilter.endDate
|
|
17148
|
+
};
|
|
17149
|
+
} else if (report.dateRange) {
|
|
17150
|
+
filterDateRange = report.dateRange;
|
|
17151
|
+
}
|
|
17152
|
+
if (!dateBucket && filterDateRange) {
|
|
17153
|
+
dateBucket = getDateBucketFromRange(filterDateRange);
|
|
17154
|
+
}
|
|
17155
|
+
const pivotTable = await generatePivotWithSQL({
|
|
17156
|
+
pivot,
|
|
17157
|
+
report,
|
|
17158
|
+
client,
|
|
17159
|
+
dateBucket,
|
|
17160
|
+
dateFilter,
|
|
17161
|
+
dashboardName,
|
|
17162
|
+
tenants,
|
|
17163
|
+
additionalProcessing,
|
|
17164
|
+
getToken
|
|
17165
|
+
});
|
|
17166
|
+
return pivotTable;
|
|
17167
|
+
} catch (e) {
|
|
17168
|
+
eventTracking?.logError?.({
|
|
17169
|
+
type: "bug",
|
|
17170
|
+
// TODO: determine type
|
|
17171
|
+
severity: "high",
|
|
17172
|
+
message: "Error fetching pivot table",
|
|
17173
|
+
errorMessage: e.message,
|
|
17174
|
+
errorStack: e.stack,
|
|
17175
|
+
errorData: {
|
|
17176
|
+
caller: "getPivotTable",
|
|
17177
|
+
function: "getPivotTable"
|
|
17178
|
+
}
|
|
17179
|
+
});
|
|
17180
|
+
console.error("Error fetching pivot table", e);
|
|
17181
|
+
throw e;
|
|
17182
|
+
}
|
|
17183
|
+
}
|
|
17184
|
+
return pivot && data.rows ? generatePivotTable({
|
|
17185
|
+
pivot,
|
|
17186
|
+
report,
|
|
17187
|
+
client,
|
|
17188
|
+
uniqueValues: report.distinctStrings,
|
|
17189
|
+
dashboardName,
|
|
17190
|
+
tenants,
|
|
17191
|
+
dateFilter,
|
|
17192
|
+
additionalProcessing,
|
|
17193
|
+
getToken,
|
|
17194
|
+
eventTracking
|
|
17195
|
+
}) : void 0;
|
|
17196
|
+
}
|
|
17197
|
+
function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
|
|
17198
|
+
if (!pivotTable) return itemInfo?.yAxisFields ?? [];
|
|
17199
|
+
const pivot = itemInfo?.pivot || config?.pivot;
|
|
17200
|
+
if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
|
|
17201
|
+
const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
|
|
17202
|
+
return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
|
|
17203
|
+
}
|
|
17204
|
+
async function getDashboard(dashboardName, client, getToken, tenants, flags) {
|
|
17205
|
+
const { data: resp } = await quillFetch({
|
|
17206
|
+
client,
|
|
17207
|
+
task: "dashboard",
|
|
17208
|
+
metadata: {
|
|
17209
|
+
name: dashboardName,
|
|
17210
|
+
clientId: client.publicKey,
|
|
17211
|
+
databaseType: client.databaseType,
|
|
17212
|
+
useNewNodeSql: true,
|
|
17213
|
+
tenants,
|
|
17214
|
+
flags
|
|
17215
|
+
},
|
|
17216
|
+
getToken
|
|
17217
|
+
});
|
|
17218
|
+
return {
|
|
17219
|
+
...resp,
|
|
17220
|
+
createdAt: resp.createdAt && new Date(resp.createdAt),
|
|
17221
|
+
dateFilter: resp.dateFilter ? {
|
|
17222
|
+
...resp.dateFilter,
|
|
17223
|
+
presetOptions: resp.dateFilter.presetOptions?.map(
|
|
17224
|
+
(preset) => ({
|
|
17225
|
+
...preset,
|
|
17226
|
+
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
17227
|
+
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
17228
|
+
})
|
|
17229
|
+
),
|
|
17230
|
+
defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
|
|
17231
|
+
(preset) => ({
|
|
17232
|
+
...preset,
|
|
17233
|
+
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
17234
|
+
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
17235
|
+
})
|
|
17236
|
+
)
|
|
17237
|
+
} : void 0
|
|
17238
|
+
};
|
|
17239
|
+
}
|
|
17240
|
+
|
|
17241
|
+
// src/utils/chartBuilder.ts
|
|
17242
|
+
var numberFormatOptions = [
|
|
17243
|
+
"whole_number",
|
|
17244
|
+
"one_decimal_place",
|
|
17245
|
+
"two_decimal_places",
|
|
17246
|
+
"dollar_amount",
|
|
17247
|
+
"dollar_cents",
|
|
17248
|
+
"percentage"
|
|
17249
|
+
];
|
|
17250
|
+
var dateFormatOptions = [
|
|
17251
|
+
"MMM_yyyy",
|
|
17252
|
+
"MMM_dd",
|
|
17253
|
+
"MMM_dd_yyyy",
|
|
17254
|
+
"MMM_dd_hh:mm_ap_pm",
|
|
17255
|
+
"hh_ap_pm",
|
|
17256
|
+
"date",
|
|
17257
|
+
"timestamptz"
|
|
17258
|
+
];
|
|
17259
|
+
var NUMBER_OPTIONS = [
|
|
17260
|
+
{ value: "whole_number", label: "whole number" },
|
|
17261
|
+
{ value: "one_decimal_place", label: "one decimal place" },
|
|
17262
|
+
{ value: "two_decimal_places", label: "two decimal places" },
|
|
17263
|
+
{ value: "dollar_amount", label: "dollar amount" },
|
|
17264
|
+
{ value: "dollar_cents", label: "dollar and cent amount" },
|
|
17265
|
+
{ value: "percent", label: "percentage" }
|
|
17266
|
+
];
|
|
17267
|
+
var DATE_OPTIONS = [
|
|
17268
|
+
{ value: "MMM_yyyy", label: "month" },
|
|
17269
|
+
{ value: "MMM_dd", label: "day" },
|
|
17270
|
+
{ value: "MMM_dd_yyyy", label: "day and year" },
|
|
17271
|
+
{ value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
|
|
17272
|
+
{ value: "hh_ap_pm", label: "hour" }
|
|
17273
|
+
];
|
|
17274
|
+
var ALL_FORMAT_OPTIONS = [
|
|
17275
|
+
...NUMBER_OPTIONS,
|
|
17276
|
+
...DATE_OPTIONS,
|
|
17277
|
+
{ value: "string", label: "string" }
|
|
17278
|
+
];
|
|
17279
|
+
function createInitialFormData(columns) {
|
|
17280
|
+
const firstNumberColumn = columns?.find(
|
|
17281
|
+
(col) => numberFormatOptions.includes(col.format)
|
|
17282
|
+
);
|
|
17283
|
+
const firstStringColumn = columns?.find(
|
|
17284
|
+
(col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
|
|
17285
|
+
);
|
|
17286
|
+
const firstDateColumn = columns?.find(
|
|
17287
|
+
(col) => dateFormatOptions.includes(col.format)
|
|
17288
|
+
);
|
|
17289
|
+
const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
|
|
17290
|
+
const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
|
|
17291
|
+
const formEmptyState = {
|
|
17292
|
+
name: "",
|
|
17293
|
+
columns: columns.map((col) => {
|
|
17294
|
+
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
17295
|
+
}),
|
|
17296
|
+
xAxisField,
|
|
17297
|
+
xAxisFormat,
|
|
17298
|
+
yAxisFields: [
|
|
17299
|
+
{
|
|
17300
|
+
field: firstNumberColumn?.field || columns?.[0]?.field || "",
|
|
17301
|
+
label: "",
|
|
17302
|
+
format: firstNumberColumn?.format || columns?.[0]?.format || "string"
|
|
17303
|
+
}
|
|
17304
|
+
],
|
|
17305
|
+
xAxisLabel: "",
|
|
17306
|
+
chartType: firstNumberColumn ? "line" : "table",
|
|
17307
|
+
pivot: null,
|
|
17308
|
+
template: true,
|
|
17309
|
+
referenceLines: []
|
|
17310
|
+
};
|
|
17311
|
+
return formEmptyState;
|
|
17312
|
+
}
|
|
17313
|
+
|
|
17314
|
+
// src/utils/error.ts
|
|
17315
|
+
var DataLoadError = class extends Error {
|
|
17316
|
+
data;
|
|
17317
|
+
constructor(message, data) {
|
|
17318
|
+
super(message);
|
|
17319
|
+
this.name = "DataLoadError";
|
|
17320
|
+
this.data = data;
|
|
17321
|
+
}
|
|
17322
|
+
};
|
|
17323
|
+
|
|
17324
|
+
// src/utils/errorProcessing.ts
|
|
17325
|
+
function processFilterErrorList(resp) {
|
|
17326
|
+
if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
|
|
17327
|
+
return;
|
|
17328
|
+
}
|
|
17329
|
+
}
|
|
17330
|
+
|
|
17331
|
+
// src/utils/queryConstructor.ts
|
|
17332
|
+
function replaceBigQuerySpecialCharacters(column) {
|
|
17333
|
+
return column.replaceAll("/", "quill_forward_slash");
|
|
17334
|
+
}
|
|
17335
|
+
function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
|
|
17336
|
+
switch (databaseType.toLowerCase()) {
|
|
17337
|
+
case "postgresql":
|
|
17338
|
+
case "clickhouse": {
|
|
17339
|
+
if (column === "") {
|
|
17340
|
+
return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
|
|
17341
|
+
}
|
|
17342
|
+
if (isColumnFieldAlias) {
|
|
17343
|
+
return `"${column.replaceAll('"', "")}"`;
|
|
17344
|
+
}
|
|
17345
|
+
const columnParts = column.split(".");
|
|
17346
|
+
if (columnParts.length > 1) {
|
|
17347
|
+
return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
|
|
17348
|
+
}
|
|
17349
|
+
return `"${column.replaceAll('"', "")}"`;
|
|
17350
|
+
}
|
|
17351
|
+
case "mysql": {
|
|
17352
|
+
if (column === "") {
|
|
17353
|
+
return fallbackOnNull ? `${fallbackOnNull}` : "_";
|
|
17354
|
+
}
|
|
17355
|
+
if (isColumnFieldAlias) {
|
|
17356
|
+
return `\`${column.replaceAll(`\``, "").replaceAll(`"`, "")}\``;
|
|
17357
|
+
}
|
|
17358
|
+
const columnParts = column.split(".");
|
|
17359
|
+
if (columnParts.length > 1) {
|
|
17360
|
+
return `\`` + columnParts.map((part) => part.replaceAll(`\``, "")).join("`.`") + `\``;
|
|
17361
|
+
}
|
|
17362
|
+
return `\`${column.replaceAll(`\``, "")}\``;
|
|
17363
|
+
}
|
|
17364
|
+
case "snowflake": {
|
|
17365
|
+
if (column === "") {
|
|
17366
|
+
return fallbackOnNull ? `${fallbackOnNull}` : "_";
|
|
17367
|
+
}
|
|
17368
|
+
if (isColumnFieldAlias) {
|
|
17369
|
+
return `"${column.replaceAll('"', "")}"`;
|
|
17370
|
+
}
|
|
17371
|
+
if (isValueFieldAlias) {
|
|
17372
|
+
const cleanedColumn = column.replaceAll(")", "").replaceAll("(", "_");
|
|
17373
|
+
return `${cleanedColumn}`;
|
|
17374
|
+
}
|
|
17375
|
+
return column;
|
|
17376
|
+
}
|
|
17377
|
+
case "bigquery": {
|
|
17378
|
+
if (column === "") {
|
|
17379
|
+
return fallbackOnNull ? `\`${fallbackOnNull}\`` : "`_`";
|
|
17380
|
+
}
|
|
17381
|
+
if (isColumnFieldAlias) {
|
|
17382
|
+
return `\`${replaceBigQuerySpecialCharacters(column.replaceAll("`", ""))}\``;
|
|
17383
|
+
}
|
|
17384
|
+
const columnParts = column.split(".");
|
|
17385
|
+
if (columnParts.length > 1) {
|
|
17386
|
+
return `\`` + columnParts.map((part) => part.replaceAll(`\``, "")).join("`.`") + `\``;
|
|
17387
|
+
}
|
|
17388
|
+
return `\`${replaceBigQuerySpecialCharacters(column.replaceAll("`", ""))}\``;
|
|
17389
|
+
}
|
|
17390
|
+
case "mssql": {
|
|
17391
|
+
if (column === "") {
|
|
17392
|
+
return fallbackOnNull ? `[${fallbackOnNull}]` : `[_]`;
|
|
17393
|
+
}
|
|
17394
|
+
if (isColumnFieldAlias) {
|
|
17395
|
+
return `[${column.replaceAll("]", "").replaceAll("[", "")}]`;
|
|
17396
|
+
}
|
|
17397
|
+
const columnParts = column.split(".");
|
|
17398
|
+
if (columnParts.length > 1) {
|
|
17399
|
+
return `[` + columnParts.map((part) => part.replaceAll("]", "").replaceAll("[", "")).join("].[`") + `]`;
|
|
17400
|
+
}
|
|
17401
|
+
return `[${column.replaceAll("]", "").replaceAll("[", "")}]`;
|
|
17402
|
+
}
|
|
17403
|
+
case "databricks": {
|
|
17404
|
+
if (column === "") {
|
|
17405
|
+
return fallbackOnNull ? `[${fallbackOnNull}]` : `_`;
|
|
17406
|
+
}
|
|
17407
|
+
if (isColumnFieldAlias) {
|
|
17408
|
+
return `\`${column.replaceAll(`\``, "").replaceAll(`"`, "")}\``;
|
|
17409
|
+
}
|
|
17410
|
+
const columnParts = column.split(".");
|
|
17411
|
+
if (columnParts.length > 1) {
|
|
17412
|
+
return `\`` + columnParts.map((part) => part.replaceAll(`\``, "")).join("`.`") + `\``;
|
|
17413
|
+
}
|
|
17414
|
+
return `\`${column.replaceAll(`\``, "")}\``;
|
|
17415
|
+
}
|
|
17416
|
+
default:
|
|
17417
|
+
return column;
|
|
17418
|
+
}
|
|
17419
|
+
}
|
|
17420
|
+
function replaceSpacesWithUnderscores(column) {
|
|
17421
|
+
return column.replaceAll(" ", "_");
|
|
17422
|
+
}
|
|
17423
|
+
function generateCountQuery(fields, query, databaseType) {
|
|
17424
|
+
let countQuery = [];
|
|
17425
|
+
let cteQuery = `WITH querytable AS (${query.replace(";", "")}) `;
|
|
17426
|
+
let cte = [];
|
|
17427
|
+
switch (databaseType.toLowerCase()) {
|
|
17428
|
+
case "mysql":
|
|
17429
|
+
cte = fields.map((field, index) => {
|
|
17430
|
+
return `, distinct_cte_${index} AS (SELECT DISTINCT ${processColumnReference(field, databaseType, void 0, true)} FROM querytable LIMIT ${MAX_PIVOT_UNIQUE_VALUES + 1})`;
|
|
17431
|
+
});
|
|
17432
|
+
countQuery = fields.map((field, index) => {
|
|
17433
|
+
return `SELECT '${field}' AS ${processColumnReference("field", databaseType)}, COUNT(*) AS ${processColumnReference("count", databaseType)} FROM distinct_cte_${index}`;
|
|
17434
|
+
});
|
|
17435
|
+
cteQuery += cte.join(" ");
|
|
17436
|
+
break;
|
|
17437
|
+
default:
|
|
17438
|
+
countQuery = fields.map((field) => {
|
|
17439
|
+
return `SELECT '${field}' AS ${processColumnReference("field", databaseType)}, COUNT(DISTINCT ${processColumnReference(field, databaseType, void 0, true)}) AS ${processColumnReference("count", databaseType)} FROM querytable`;
|
|
17440
|
+
});
|
|
17441
|
+
}
|
|
17442
|
+
return cteQuery + countQuery.join(" UNION ALL ");
|
|
17443
|
+
}
|
|
17444
|
+
function generateDistinctQuery(stringFields, query, databaseType) {
|
|
17057
17445
|
switch (databaseType.toLowerCase()) {
|
|
17058
17446
|
case "mysql":
|
|
17059
17447
|
return generateDistinctQueryMySQL(stringFields, query);
|
|
@@ -17150,1123 +17538,12 @@ function generateMinMaxDateRangeQueries(columnFields, query, databaseType) {
|
|
|
17150
17538
|
const distinctQueries = columnFields.map((field) => {
|
|
17151
17539
|
const wrappedField = ["postgresql", "clickhouse"].includes(
|
|
17152
17540
|
databaseType.toLowerCase()
|
|
17153
|
-
) ?
|
|
17154
|
-
return `SELECT '${field}' AS field, ${min2}(${wrappedField})${cast} AS min_range, ${max2}(${wrappedField})${cast} AS max_range FROM querytable`;
|
|
17541
|
+
) ? processColumnReference(field, databaseType) : field;
|
|
17542
|
+
return `SELECT '${field}' AS ${processColumnReference("field", databaseType)}, ${min2}(${wrappedField})${cast} AS ${processColumnReference("min_range", databaseType)}, ${max2}(${wrappedField})${cast} AS ${processColumnReference("max_range", databaseType)} FROM querytable`;
|
|
17155
17543
|
});
|
|
17156
17544
|
const distinctQuery = distinctQueries.join(" UNION ALL ");
|
|
17157
17545
|
return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
|
|
17158
17546
|
}
|
|
17159
|
-
function generatePivotQuery(pivot, itemQuery, databaseType, distinctStrings, dateBucket) {
|
|
17160
|
-
if (!isValidPivot(pivot).valid) {
|
|
17161
|
-
return void 0;
|
|
17162
|
-
}
|
|
17163
|
-
if (pivot.columnField && distinctStrings && distinctStrings.length > 0) {
|
|
17164
|
-
return create2DPivotQuery(
|
|
17165
|
-
pivot,
|
|
17166
|
-
itemQuery,
|
|
17167
|
-
databaseType,
|
|
17168
|
-
distinctStrings,
|
|
17169
|
-
dateBucket
|
|
17170
|
-
);
|
|
17171
|
-
}
|
|
17172
|
-
if (pivot.rowField) {
|
|
17173
|
-
return create1DPivotQuery(pivot, itemQuery, dateBucket, databaseType);
|
|
17174
|
-
}
|
|
17175
|
-
return createAggregationValuePivot(pivot, itemQuery, databaseType);
|
|
17176
|
-
}
|
|
17177
|
-
function create2DPivotQuery(pivot, itemQuery, databaseType, columnFieldValues, dateBucket) {
|
|
17178
|
-
if (!pivot || !pivot.columnField) {
|
|
17179
|
-
return void 0;
|
|
17180
|
-
}
|
|
17181
|
-
if (isStringType(pivot.rowFieldType ?? "") || !pivot.rowFieldType) {
|
|
17182
|
-
return create2DStringPivotQuery(
|
|
17183
|
-
pivot,
|
|
17184
|
-
itemQuery,
|
|
17185
|
-
columnFieldValues,
|
|
17186
|
-
databaseType
|
|
17187
|
-
);
|
|
17188
|
-
}
|
|
17189
|
-
return create2DDatePivotQuery(
|
|
17190
|
-
pivot,
|
|
17191
|
-
itemQuery,
|
|
17192
|
-
columnFieldValues,
|
|
17193
|
-
databaseType,
|
|
17194
|
-
dateBucket
|
|
17195
|
-
);
|
|
17196
|
-
}
|
|
17197
|
-
function create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType) {
|
|
17198
|
-
const isValidBaseQuery = itemQuery.match(
|
|
17199
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17200
|
-
);
|
|
17201
|
-
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField)
|
|
17202
|
-
return void 0;
|
|
17203
|
-
const rowField = pivot.rowField;
|
|
17204
|
-
if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
|
|
17205
|
-
throw new Error("No value field provided for pivot");
|
|
17206
|
-
if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
|
|
17207
|
-
throw new Error("No aggregation type provided for pivot");
|
|
17208
|
-
const columnField = pivot.columnField;
|
|
17209
|
-
const rowFieldAlias = processColumnReference(
|
|
17210
|
-
rowField,
|
|
17211
|
-
databaseType,
|
|
17212
|
-
void 0,
|
|
17213
|
-
false,
|
|
17214
|
-
true
|
|
17215
|
-
);
|
|
17216
|
-
const columnFieldAlias = processColumnReference(
|
|
17217
|
-
columnField,
|
|
17218
|
-
databaseType,
|
|
17219
|
-
void 0,
|
|
17220
|
-
false,
|
|
17221
|
-
true
|
|
17222
|
-
);
|
|
17223
|
-
let caseWhens = [];
|
|
17224
|
-
let valueAliases = [];
|
|
17225
|
-
const seenAggs = {};
|
|
17226
|
-
pivot.aggregations?.forEach((currentAgg) => {
|
|
17227
|
-
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17228
|
-
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17229
|
-
} else {
|
|
17230
|
-
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17231
|
-
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17232
|
-
[currentAgg.valueField ?? ""]: 1
|
|
17233
|
-
};
|
|
17234
|
-
}
|
|
17235
|
-
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
|
|
17236
|
-
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17237
|
-
const valueFieldAlias = processColumnReference(
|
|
17238
|
-
currentAgg.valueField || rowField || "count",
|
|
17239
|
-
databaseType,
|
|
17240
|
-
void 0,
|
|
17241
|
-
false,
|
|
17242
|
-
true
|
|
17243
|
-
);
|
|
17244
|
-
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17245
|
-
let value2AliasSubstring = "";
|
|
17246
|
-
const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
|
|
17247
|
-
(acc, v) => acc + v
|
|
17248
|
-
) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
|
|
17249
|
-
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
|
|
17250
|
-
const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
|
|
17251
|
-
currentAgg.aggregationType,
|
|
17252
|
-
databaseType,
|
|
17253
|
-
valueFieldAlias
|
|
17254
|
-
);
|
|
17255
|
-
if (currentAgg.aggregationType === "percentage") {
|
|
17256
|
-
if (!currentAgg.valueField)
|
|
17257
|
-
throw new Error("No value field provided for pivot");
|
|
17258
|
-
const valueField2Alias = processColumnReference(
|
|
17259
|
-
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17260
|
-
databaseType,
|
|
17261
|
-
void 0,
|
|
17262
|
-
false,
|
|
17263
|
-
true
|
|
17264
|
-
);
|
|
17265
|
-
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17266
|
-
if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
|
|
17267
|
-
caseWhens = [
|
|
17268
|
-
...caseWhens,
|
|
17269
|
-
...columnFieldValues.map((column) => {
|
|
17270
|
-
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17271
|
-
column,
|
|
17272
|
-
databaseType
|
|
17273
|
-
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
|
|
17274
|
-
column + disambiguation,
|
|
17275
|
-
databaseType,
|
|
17276
|
-
"_",
|
|
17277
|
-
true
|
|
17278
|
-
)}`;
|
|
17279
|
-
})
|
|
17280
|
-
];
|
|
17281
|
-
} else {
|
|
17282
|
-
value2AliasSubstring = `${processColumnReference(
|
|
17283
|
-
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17284
|
-
databaseType,
|
|
17285
|
-
void 0,
|
|
17286
|
-
true
|
|
17287
|
-
)} AS ${valueField2Alias}`;
|
|
17288
|
-
caseWhens = [
|
|
17289
|
-
...caseWhens,
|
|
17290
|
-
...columnFieldValues.map((column) => {
|
|
17291
|
-
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17292
|
-
column,
|
|
17293
|
-
databaseType
|
|
17294
|
-
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17295
|
-
column,
|
|
17296
|
-
databaseType
|
|
17297
|
-
)}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
|
|
17298
|
-
column + disambiguation,
|
|
17299
|
-
databaseType,
|
|
17300
|
-
"_",
|
|
17301
|
-
true
|
|
17302
|
-
)}`;
|
|
17303
|
-
})
|
|
17304
|
-
];
|
|
17305
|
-
}
|
|
17306
|
-
} else {
|
|
17307
|
-
caseWhens = [
|
|
17308
|
-
...caseWhens,
|
|
17309
|
-
...columnFieldValues.map((column) => {
|
|
17310
|
-
return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17311
|
-
column,
|
|
17312
|
-
databaseType
|
|
17313
|
-
)}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
|
|
17314
|
-
})
|
|
17315
|
-
];
|
|
17316
|
-
}
|
|
17317
|
-
if (valueAliasSubstring) valueAliases.push(valueAliasSubstring);
|
|
17318
|
-
if (value2AliasSubstring) valueAliases.push(value2AliasSubstring);
|
|
17319
|
-
});
|
|
17320
|
-
valueAliases = [
|
|
17321
|
-
`${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
|
|
17322
|
-
...valueAliases,
|
|
17323
|
-
`${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
|
|
17324
|
-
];
|
|
17325
|
-
valueAliases = Array.from(new Set(valueAliases));
|
|
17326
|
-
const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
|
|
17327
|
-
const pivotQuery = `
|
|
17328
|
-
,quill_alias AS (
|
|
17329
|
-
SELECT ${valueAliases.length > 0 ? `${valueAliases.join(", ")}` : ""}
|
|
17330
|
-
FROM quill_base_table
|
|
17331
|
-
),
|
|
17332
|
-
quill_qt_cw AS (
|
|
17333
|
-
SELECT ${rowFieldAlias}
|
|
17334
|
-
${caseWhens.length > 0 ? `, ${caseWhens.join(", ")}` : ""}
|
|
17335
|
-
FROM quill_alias
|
|
17336
|
-
GROUP BY ${rowFieldAlias}
|
|
17337
|
-
),
|
|
17338
|
-
quill_base_pivot AS (
|
|
17339
|
-
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
|
|
17340
|
-
FROM quill_qt_cw qt
|
|
17341
|
-
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17342
|
-
)
|
|
17343
|
-
SELECT * FROM quill_base_pivot
|
|
17344
|
-
`.replace(/\s+/g, " ").trim();
|
|
17345
|
-
return itemQuery.replace(
|
|
17346
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17347
|
-
pivotQuery
|
|
17348
|
-
);
|
|
17349
|
-
}
|
|
17350
|
-
function create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseType, dateBucket = "month") {
|
|
17351
|
-
const isValidBaseQuery = itemQuery.match(
|
|
17352
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17353
|
-
);
|
|
17354
|
-
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField) {
|
|
17355
|
-
return void 0;
|
|
17356
|
-
}
|
|
17357
|
-
if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
|
|
17358
|
-
throw new Error("No value field provided for pivot");
|
|
17359
|
-
if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
|
|
17360
|
-
throw new Error("No aggregation type provided for pivot");
|
|
17361
|
-
const rowField = pivot.rowField;
|
|
17362
|
-
const columnField = pivot.columnField;
|
|
17363
|
-
const rowFieldAlias = processColumnReference(
|
|
17364
|
-
rowField,
|
|
17365
|
-
databaseType,
|
|
17366
|
-
void 0,
|
|
17367
|
-
false,
|
|
17368
|
-
true
|
|
17369
|
-
);
|
|
17370
|
-
const columnFieldAlias = processColumnReference(
|
|
17371
|
-
columnField,
|
|
17372
|
-
databaseType,
|
|
17373
|
-
void 0,
|
|
17374
|
-
false,
|
|
17375
|
-
true
|
|
17376
|
-
);
|
|
17377
|
-
let caseWhens = [];
|
|
17378
|
-
let valueFieldAliases = [];
|
|
17379
|
-
const seenAggs = {};
|
|
17380
|
-
pivot.aggregations?.forEach((currentAgg) => {
|
|
17381
|
-
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17382
|
-
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17383
|
-
} else {
|
|
17384
|
-
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17385
|
-
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17386
|
-
[currentAgg.valueField ?? ""]: 1
|
|
17387
|
-
};
|
|
17388
|
-
}
|
|
17389
|
-
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
|
|
17390
|
-
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17391
|
-
const valueFieldAlias = processColumnReference(
|
|
17392
|
-
currentAgg.valueField ?? rowField,
|
|
17393
|
-
databaseType,
|
|
17394
|
-
void 0,
|
|
17395
|
-
false,
|
|
17396
|
-
true
|
|
17397
|
-
);
|
|
17398
|
-
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17399
|
-
let value2AliasSubstring = "";
|
|
17400
|
-
const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
|
|
17401
|
-
(acc, v) => acc + v
|
|
17402
|
-
) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
|
|
17403
|
-
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
|
|
17404
|
-
const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
|
|
17405
|
-
currentAgg.aggregationType,
|
|
17406
|
-
databaseType,
|
|
17407
|
-
valueFieldAlias
|
|
17408
|
-
);
|
|
17409
|
-
if (currentAgg.aggregationType === "percentage") {
|
|
17410
|
-
if (!currentAgg.valueField)
|
|
17411
|
-
throw new Error("No value field provided for pivot");
|
|
17412
|
-
const valueField2Alias = processColumnReference(
|
|
17413
|
-
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17414
|
-
databaseType,
|
|
17415
|
-
void 0,
|
|
17416
|
-
false,
|
|
17417
|
-
true
|
|
17418
|
-
);
|
|
17419
|
-
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17420
|
-
if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
|
|
17421
|
-
caseWhens = [
|
|
17422
|
-
...caseWhens,
|
|
17423
|
-
...columnFieldValues.map((column) => {
|
|
17424
|
-
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17425
|
-
column,
|
|
17426
|
-
databaseType
|
|
17427
|
-
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
|
|
17428
|
-
column + disambiguation,
|
|
17429
|
-
databaseType,
|
|
17430
|
-
"_",
|
|
17431
|
-
true
|
|
17432
|
-
)}`;
|
|
17433
|
-
})
|
|
17434
|
-
];
|
|
17435
|
-
} else {
|
|
17436
|
-
value2AliasSubstring = `${processColumnReference(
|
|
17437
|
-
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17438
|
-
databaseType,
|
|
17439
|
-
void 0,
|
|
17440
|
-
true
|
|
17441
|
-
)} AS ${valueField2Alias}`;
|
|
17442
|
-
caseWhens = [
|
|
17443
|
-
...caseWhens,
|
|
17444
|
-
...columnFieldValues.map((column) => {
|
|
17445
|
-
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17446
|
-
column,
|
|
17447
|
-
databaseType
|
|
17448
|
-
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17449
|
-
column,
|
|
17450
|
-
databaseType
|
|
17451
|
-
)}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
|
|
17452
|
-
column + disambiguation,
|
|
17453
|
-
databaseType,
|
|
17454
|
-
"_",
|
|
17455
|
-
true
|
|
17456
|
-
)}`;
|
|
17457
|
-
})
|
|
17458
|
-
];
|
|
17459
|
-
}
|
|
17460
|
-
} else {
|
|
17461
|
-
caseWhens = [
|
|
17462
|
-
...caseWhens,
|
|
17463
|
-
...columnFieldValues.map((column) => {
|
|
17464
|
-
return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17465
|
-
column,
|
|
17466
|
-
databaseType
|
|
17467
|
-
)}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
|
|
17468
|
-
})
|
|
17469
|
-
];
|
|
17470
|
-
}
|
|
17471
|
-
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17472
|
-
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17473
|
-
});
|
|
17474
|
-
valueFieldAliases = [
|
|
17475
|
-
`${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
|
|
17476
|
-
...valueFieldAliases,
|
|
17477
|
-
`${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
|
|
17478
|
-
];
|
|
17479
|
-
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17480
|
-
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17481
|
-
const pivotQuery = `
|
|
17482
|
-
, quill_alias AS (SELECT ${valueFieldAliases.length > 0 ? `${valueFieldAliases.join(", ")}` : ""} FROM quill_base_table),
|
|
17483
|
-
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)}),
|
|
17484
|
-
quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17485
|
-
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
|
|
17486
|
-
SELECT * FROM quill_base_pivot
|
|
17487
|
-
`.replace(/\s+/g, " ").trim();
|
|
17488
|
-
return itemQuery.replace(
|
|
17489
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17490
|
-
pivotQuery
|
|
17491
|
-
);
|
|
17492
|
-
}
|
|
17493
|
-
function create1DPivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
|
|
17494
|
-
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
17495
|
-
return create1DStringPivotQuery(pivot, itemQuery, databaseType);
|
|
17496
|
-
}
|
|
17497
|
-
return create1DDatePivotQuery(pivot, itemQuery, dateBucket, databaseType);
|
|
17498
|
-
}
|
|
17499
|
-
function create1DStringPivotQuery(pivot, itemQuery, databaseType) {
|
|
17500
|
-
const isValidBaseQuery = itemQuery.match(
|
|
17501
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17502
|
-
);
|
|
17503
|
-
if (!isValidBaseQuery) return void 0;
|
|
17504
|
-
const rowField = pivot.rowField;
|
|
17505
|
-
const rowAlias = processColumnReference(
|
|
17506
|
-
rowField,
|
|
17507
|
-
databaseType,
|
|
17508
|
-
void 0,
|
|
17509
|
-
true
|
|
17510
|
-
);
|
|
17511
|
-
let quillAggSelects = [rowAlias];
|
|
17512
|
-
let valueFieldAliases = [];
|
|
17513
|
-
const seenAggs = {};
|
|
17514
|
-
pivot.aggregations?.forEach((currentAgg) => {
|
|
17515
|
-
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17516
|
-
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17517
|
-
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17518
|
-
} else {
|
|
17519
|
-
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17520
|
-
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17521
|
-
[currentAgg.valueField ?? ""]: 1
|
|
17522
|
-
};
|
|
17523
|
-
}
|
|
17524
|
-
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17525
|
-
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17526
|
-
const valueFieldAlias = processColumnReference(
|
|
17527
|
-
currentAgg.valueField || rowField || "count",
|
|
17528
|
-
databaseType,
|
|
17529
|
-
void 0,
|
|
17530
|
-
false,
|
|
17531
|
-
true
|
|
17532
|
-
);
|
|
17533
|
-
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17534
|
-
let value2AliasSubstring = "";
|
|
17535
|
-
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
|
|
17536
|
-
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17537
|
-
if (currentAgg.valueFieldType === "bool") {
|
|
17538
|
-
valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
|
|
17539
|
-
}
|
|
17540
|
-
if (currentAgg.aggregationType === "percentage") {
|
|
17541
|
-
let countPercentage = false;
|
|
17542
|
-
if (!currentAgg.valueField) {
|
|
17543
|
-
countPercentage = true;
|
|
17544
|
-
}
|
|
17545
|
-
const valueField2Alias = processColumnReference(
|
|
17546
|
-
currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
|
|
17547
|
-
databaseType,
|
|
17548
|
-
void 0,
|
|
17549
|
-
false,
|
|
17550
|
-
true
|
|
17551
|
-
);
|
|
17552
|
-
let value2Expr = valueField2Alias;
|
|
17553
|
-
if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
|
|
17554
|
-
value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
|
|
17555
|
-
}
|
|
17556
|
-
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17557
|
-
const percentageExpr = countPercentage ? "CAST(COUNT(*) AS FLOAT) / (SELECT COUNT(*) FROM quill_base_table)" : currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
|
|
17558
|
-
quillAggSelects = [
|
|
17559
|
-
...quillAggSelects,
|
|
17560
|
-
`${percentageExpr} as ${processColumnReference(
|
|
17561
|
-
`${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
|
|
17562
|
-
databaseType,
|
|
17563
|
-
void 0,
|
|
17564
|
-
false,
|
|
17565
|
-
true
|
|
17566
|
-
)}`
|
|
17567
|
-
];
|
|
17568
|
-
} else {
|
|
17569
|
-
quillAggSelects = [
|
|
17570
|
-
...quillAggSelects,
|
|
17571
|
-
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
|
|
17572
|
-
(currentAgg.valueField || "count") + disambiguation,
|
|
17573
|
-
databaseType
|
|
17574
|
-
)}`
|
|
17575
|
-
];
|
|
17576
|
-
}
|
|
17577
|
-
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17578
|
-
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17579
|
-
});
|
|
17580
|
-
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17581
|
-
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17582
|
-
const pivotQuery = `, quill_alias AS (
|
|
17583
|
-
SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
|
|
17584
|
-
FROM quill_base_table
|
|
17585
|
-
),
|
|
17586
|
-
quill_qt_cw AS (
|
|
17587
|
-
SELECT ${quillAggSelects.join(", ")} FROM quill_alias GROUP BY ${rowAlias}
|
|
17588
|
-
),
|
|
17589
|
-
quill_base_pivot AS (
|
|
17590
|
-
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
|
|
17591
|
-
FROM quill_qt_cw qt ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17592
|
-
)
|
|
17593
|
-
SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
|
|
17594
|
-
return itemQuery.replace(
|
|
17595
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17596
|
-
pivotQuery
|
|
17597
|
-
);
|
|
17598
|
-
}
|
|
17599
|
-
function create1DDatePivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
|
|
17600
|
-
const isValidBaseQuery = itemQuery.match(
|
|
17601
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17602
|
-
);
|
|
17603
|
-
if (!isValidBaseQuery) {
|
|
17604
|
-
return void 0;
|
|
17605
|
-
}
|
|
17606
|
-
const rowField = pivot.rowField || "";
|
|
17607
|
-
const rowFieldAlias = processColumnReference(
|
|
17608
|
-
rowField,
|
|
17609
|
-
databaseType,
|
|
17610
|
-
void 0
|
|
17611
|
-
);
|
|
17612
|
-
let quillAggSelects = [
|
|
17613
|
-
`${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(rowField, databaseType)}`
|
|
17614
|
-
];
|
|
17615
|
-
let valueFieldAliases = [];
|
|
17616
|
-
const seenAggs = {};
|
|
17617
|
-
pivot.aggregations?.forEach((currentAgg) => {
|
|
17618
|
-
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17619
|
-
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17620
|
-
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17621
|
-
} else {
|
|
17622
|
-
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17623
|
-
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17624
|
-
[currentAgg.valueField ?? ""]: 1
|
|
17625
|
-
};
|
|
17626
|
-
}
|
|
17627
|
-
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17628
|
-
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17629
|
-
const valueFieldAlias = processColumnReference(
|
|
17630
|
-
currentAgg.valueField || rowField || "count",
|
|
17631
|
-
databaseType,
|
|
17632
|
-
void 0,
|
|
17633
|
-
false,
|
|
17634
|
-
true
|
|
17635
|
-
);
|
|
17636
|
-
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17637
|
-
let value2AliasSubstring = "";
|
|
17638
|
-
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
|
|
17639
|
-
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17640
|
-
if (currentAgg.valueFieldType === "bool") {
|
|
17641
|
-
valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
|
|
17642
|
-
}
|
|
17643
|
-
if (currentAgg.aggregationType === "percentage") {
|
|
17644
|
-
let countPercentage = false;
|
|
17645
|
-
if (!currentAgg.valueField) {
|
|
17646
|
-
countPercentage = true;
|
|
17647
|
-
}
|
|
17648
|
-
const valueField2Alias = processColumnReference(
|
|
17649
|
-
currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
|
|
17650
|
-
databaseType,
|
|
17651
|
-
void 0,
|
|
17652
|
-
false,
|
|
17653
|
-
true
|
|
17654
|
-
);
|
|
17655
|
-
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17656
|
-
let value2Expr = valueField2Alias;
|
|
17657
|
-
if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
|
|
17658
|
-
value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
|
|
17659
|
-
}
|
|
17660
|
-
const percentageExpr = countPercentage ? "CAST(COUNT(*) AS FLOAT) / (SELECT COUNT(*) FROM quill_base_table)" : currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
|
|
17661
|
-
quillAggSelects = [
|
|
17662
|
-
...quillAggSelects,
|
|
17663
|
-
`${percentageExpr} as ${processColumnReference(
|
|
17664
|
-
`${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
|
|
17665
|
-
databaseType,
|
|
17666
|
-
void 0,
|
|
17667
|
-
false,
|
|
17668
|
-
true
|
|
17669
|
-
)}`
|
|
17670
|
-
];
|
|
17671
|
-
} else {
|
|
17672
|
-
quillAggSelects = [
|
|
17673
|
-
...quillAggSelects,
|
|
17674
|
-
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference((currentAgg.valueField || "count") + disambiguation, databaseType)}`
|
|
17675
|
-
];
|
|
17676
|
-
}
|
|
17677
|
-
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17678
|
-
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17679
|
-
});
|
|
17680
|
-
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17681
|
-
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17682
|
-
const pivotQuery = `, quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowFieldAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
|
|
17683
|
-
FROM quill_base_table),
|
|
17684
|
-
quill_qt_agg AS (SELECT ${quillAggSelects.join(", ")}
|
|
17685
|
-
FROM quill_alias GROUP BY ${databaseType.toLowerCase() === "clickhouse" ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
|
|
17686
|
-
quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17687
|
-
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
|
|
17688
|
-
SELECT * FROM quill_base_pivot
|
|
17689
|
-
`.replace(/\s+/g, " ").trim();
|
|
17690
|
-
return itemQuery.replace(
|
|
17691
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17692
|
-
pivotQuery
|
|
17693
|
-
);
|
|
17694
|
-
}
|
|
17695
|
-
function createAggregationValuePivot(pivot, itemQuery, databaseType) {
|
|
17696
|
-
const isValidBaseQuery = itemQuery.match(
|
|
17697
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17698
|
-
);
|
|
17699
|
-
if (!isValidBaseQuery) return void 0;
|
|
17700
|
-
let quillAggSelects = [];
|
|
17701
|
-
let valueFieldAliases = [];
|
|
17702
|
-
const seenAggs = {};
|
|
17703
|
-
pivot.aggregations?.forEach((currentAgg) => {
|
|
17704
|
-
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17705
|
-
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17706
|
-
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17707
|
-
} else {
|
|
17708
|
-
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17709
|
-
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17710
|
-
[currentAgg.valueField ?? ""]: 1
|
|
17711
|
-
};
|
|
17712
|
-
}
|
|
17713
|
-
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17714
|
-
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17715
|
-
const valueFieldAlias = processColumnReference(
|
|
17716
|
-
currentAgg.valueField || "count",
|
|
17717
|
-
databaseType,
|
|
17718
|
-
void 0,
|
|
17719
|
-
false,
|
|
17720
|
-
true
|
|
17721
|
-
);
|
|
17722
|
-
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17723
|
-
let value2AliasSubstring = "";
|
|
17724
|
-
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}_${currentAgg.aggregationType}` : "";
|
|
17725
|
-
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17726
|
-
valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : valueExpr;
|
|
17727
|
-
if (currentAgg.aggregationType === "percentage") {
|
|
17728
|
-
if (!currentAgg.valueField) {
|
|
17729
|
-
throw new Error("No value field provided for percentage aggregation");
|
|
17730
|
-
}
|
|
17731
|
-
const valueField2Alias = processColumnReference(
|
|
17732
|
-
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17733
|
-
databaseType,
|
|
17734
|
-
void 0,
|
|
17735
|
-
false,
|
|
17736
|
-
true
|
|
17737
|
-
);
|
|
17738
|
-
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17739
|
-
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17740
|
-
const percentageExpr = currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
|
|
17741
|
-
quillAggSelects = [
|
|
17742
|
-
...quillAggSelects,
|
|
17743
|
-
`${percentageExpr} as ${processColumnReference(
|
|
17744
|
-
`${currentAgg.valueField ?? ""}${disambiguation}`,
|
|
17745
|
-
databaseType,
|
|
17746
|
-
void 0,
|
|
17747
|
-
false,
|
|
17748
|
-
true
|
|
17749
|
-
)}`
|
|
17750
|
-
];
|
|
17751
|
-
} else {
|
|
17752
|
-
quillAggSelects = [
|
|
17753
|
-
...quillAggSelects,
|
|
17754
|
-
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
|
|
17755
|
-
(currentAgg.valueField || "count") + disambiguation,
|
|
17756
|
-
databaseType
|
|
17757
|
-
)}`
|
|
17758
|
-
];
|
|
17759
|
-
}
|
|
17760
|
-
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17761
|
-
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17762
|
-
});
|
|
17763
|
-
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17764
|
-
if (valueFieldAliases.length === 0) {
|
|
17765
|
-
valueFieldAliases = ["*"];
|
|
17766
|
-
}
|
|
17767
|
-
const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
|
|
17768
|
-
const pivotQuery = `, quill_alias AS (
|
|
17769
|
-
SELECT ${valueFieldAliases.join(", ")} FROM quill_base_table
|
|
17770
|
-
),
|
|
17771
|
-
quill_qt_agg AS (
|
|
17772
|
-
SELECT ${quillAggSelects.join(", ")} FROM quill_alias
|
|
17773
|
-
),
|
|
17774
|
-
quill_base_pivot AS (
|
|
17775
|
-
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17776
|
-
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17777
|
-
)
|
|
17778
|
-
SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
|
|
17779
|
-
return itemQuery.replace(
|
|
17780
|
-
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17781
|
-
pivotQuery
|
|
17782
|
-
);
|
|
17783
|
-
}
|
|
17784
|
-
function additionalProcessingOnPivotQuery(pivot, query, additionalProcessing, databaseType = "postgresql") {
|
|
17785
|
-
if (!additionalProcessing || !query) return query;
|
|
17786
|
-
const isValidBaseQuery = query.match(
|
|
17787
|
-
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
|
|
17788
|
-
);
|
|
17789
|
-
if (!isValidBaseQuery) {
|
|
17790
|
-
return void 0;
|
|
17791
|
-
}
|
|
17792
|
-
if (!pivot.aggregations || pivot.aggregations.length === 0) {
|
|
17793
|
-
if (pivot.aggregationType) {
|
|
17794
|
-
pivot.aggregations = [
|
|
17795
|
-
{
|
|
17796
|
-
aggregationType: pivot.aggregationType,
|
|
17797
|
-
valueField: pivot.valueField,
|
|
17798
|
-
valueField2: pivot.valueField2
|
|
17799
|
-
}
|
|
17800
|
-
];
|
|
17801
|
-
} else {
|
|
17802
|
-
throw new Error("No aggregations provided for pivot");
|
|
17803
|
-
}
|
|
17804
|
-
}
|
|
17805
|
-
let rowsPerPage = 0;
|
|
17806
|
-
let currentInterval = 0;
|
|
17807
|
-
let offset = 0;
|
|
17808
|
-
let limit = 1e3;
|
|
17809
|
-
let sortQuery = "";
|
|
17810
|
-
if (additionalProcessing.page) {
|
|
17811
|
-
const page = additionalProcessing.page.page || 0;
|
|
17812
|
-
if (additionalProcessing.page.rowsPerRequest) {
|
|
17813
|
-
limit = additionalProcessing.page.rowsPerRequest;
|
|
17814
|
-
}
|
|
17815
|
-
rowsPerPage = additionalProcessing.page.rowsPerPage || 0;
|
|
17816
|
-
currentInterval = page ? Math.floor(page / (limit / rowsPerPage)) : 0;
|
|
17817
|
-
offset = currentInterval * limit;
|
|
17818
|
-
}
|
|
17819
|
-
const disambiguation = pivot.aggregations.length > 1 ? `_${matchCasing(pivot.aggregations?.[0]?.aggregationType, pivot.aggregations?.[0]?.valueField)}` : "";
|
|
17820
|
-
if (additionalProcessing.sort) {
|
|
17821
|
-
sortQuery = `ORDER BY ${processColumnReference(additionalProcessing.sort.field, databaseType, void 0, true)} ${additionalProcessing.sort.direction || ""}`;
|
|
17822
|
-
} else {
|
|
17823
|
-
const valueFieldAlias = processColumnReference(
|
|
17824
|
-
(pivot.aggregations?.[0]?.valueField ?? "") + disambiguation,
|
|
17825
|
-
databaseType,
|
|
17826
|
-
void 0,
|
|
17827
|
-
false,
|
|
17828
|
-
true
|
|
17829
|
-
);
|
|
17830
|
-
const defaultSortField = pivot.sortField || pivot.rowField || valueFieldAlias;
|
|
17831
|
-
const defaultSortDirection = pivot.sortDirection || "";
|
|
17832
|
-
if (defaultSortField !== `"_"`) {
|
|
17833
|
-
sortQuery = `ORDER BY ${processColumnReference(defaultSortField, databaseType, void 0, true)} ${defaultSortDirection}`;
|
|
17834
|
-
} else {
|
|
17835
|
-
sortQuery = "";
|
|
17836
|
-
}
|
|
17837
|
-
}
|
|
17838
|
-
const additionalProcessingQuery = `
|
|
17839
|
-
SELECT *
|
|
17840
|
-
FROM quill_base_pivot ${sortQuery}${databaseType.toLowerCase() === "mssql" ? ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY` : ` LIMIT ${limit} OFFSET ${offset}`}
|
|
17841
|
-
`.replace(/\s+/g, " ").trim();
|
|
17842
|
-
return query.replace(
|
|
17843
|
-
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
|
|
17844
|
-
additionalProcessingQuery
|
|
17845
|
-
);
|
|
17846
|
-
}
|
|
17847
|
-
function generateRowCountQuery(query, databaseType) {
|
|
17848
|
-
if (!query) return query;
|
|
17849
|
-
const isValidBaseQuery = query.match(
|
|
17850
|
-
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
|
|
17851
|
-
);
|
|
17852
|
-
if (!isValidBaseQuery) {
|
|
17853
|
-
return void 0;
|
|
17854
|
-
}
|
|
17855
|
-
const rowCountQuery = `, subview_row_count_cte AS (SELECT * FROM quill_base_pivot)
|
|
17856
|
-
SELECT count(*) as ${processColumnReference("row_count", databaseType || "postgresql", void 0, true)} FROM subview_row_count_cte
|
|
17857
|
-
`.replace(/\s+/g, " ").trim();
|
|
17858
|
-
return query.replace(
|
|
17859
|
-
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
|
|
17860
|
-
rowCountQuery
|
|
17861
|
-
);
|
|
17862
|
-
}
|
|
17863
|
-
|
|
17864
|
-
// src/utils/pivotConstructor.ts
|
|
17865
|
-
async function generatePivotWithSQL({
|
|
17866
|
-
pivot,
|
|
17867
|
-
report,
|
|
17868
|
-
client,
|
|
17869
|
-
dateBucket,
|
|
17870
|
-
dateFilter,
|
|
17871
|
-
distinctStrings,
|
|
17872
|
-
dashboardName,
|
|
17873
|
-
tenants,
|
|
17874
|
-
additionalProcessing,
|
|
17875
|
-
pivotQuery,
|
|
17876
|
-
comparisonPivotQuery,
|
|
17877
|
-
getPivotRowCount = true,
|
|
17878
|
-
caller,
|
|
17879
|
-
getToken
|
|
17880
|
-
}) {
|
|
17881
|
-
let sqlQuery = pivotQuery;
|
|
17882
|
-
let comparisonPivotSql = comparisonPivotQuery;
|
|
17883
|
-
const databaseType = client.databaseType || "postgresql";
|
|
17884
|
-
if (!pivotQuery && pivot.columnField && !pivot.columnValues && !distinctStrings) {
|
|
17885
|
-
if (!report?.rows) {
|
|
17886
|
-
throw new Error("No distinct strings provided for column field");
|
|
17887
|
-
} else {
|
|
17888
|
-
distinctStrings = Array.from(
|
|
17889
|
-
new Set(
|
|
17890
|
-
report.rows.map((row) => row[pivot.columnField]).filter((value) => value !== null && value !== void 0)
|
|
17891
|
-
)
|
|
17892
|
-
);
|
|
17893
|
-
}
|
|
17894
|
-
}
|
|
17895
|
-
if (!pivot.aggregations?.length && pivot.aggregationType) {
|
|
17896
|
-
pivot.aggregations = [
|
|
17897
|
-
{
|
|
17898
|
-
aggregationType: pivot.aggregationType,
|
|
17899
|
-
valueField: pivot.valueField,
|
|
17900
|
-
valueFieldType: pivot.valueFieldType,
|
|
17901
|
-
valueField2: pivot.valueField2,
|
|
17902
|
-
valueField2Type: pivot.valueField2Type
|
|
17903
|
-
}
|
|
17904
|
-
];
|
|
17905
|
-
}
|
|
17906
|
-
let comparisonInterval = void 0;
|
|
17907
|
-
if (dateFilter && dateFilter.comparisonRange) {
|
|
17908
|
-
comparisonInterval = getComparisonInterval(
|
|
17909
|
-
{
|
|
17910
|
-
startDate: dateFilter.comparisonRange.startDate,
|
|
17911
|
-
endDate: dateFilter.comparisonRange.endDate
|
|
17912
|
-
},
|
|
17913
|
-
dateBucket
|
|
17914
|
-
);
|
|
17915
|
-
}
|
|
17916
|
-
if (pivot.rowField && !pivot.rowFieldType) {
|
|
17917
|
-
const rowColumn = report?.columns.find(
|
|
17918
|
-
(column) => column.field === pivot.rowField
|
|
17919
|
-
);
|
|
17920
|
-
pivot.rowFieldType = rowColumn?.format || "string";
|
|
17921
|
-
}
|
|
17922
|
-
const filteredDistinctStrings = distinctStrings?.filter(
|
|
17923
|
-
(value) => value !== null && value !== void 0 && value !== ""
|
|
17924
|
-
);
|
|
17925
|
-
const pivotColumnFields = filteredDistinctStrings?.slice(
|
|
17926
|
-
0,
|
|
17927
|
-
MAX_PIVOT_UNIQUE_VALUES
|
|
17928
|
-
);
|
|
17929
|
-
if (!pivotQuery && report) {
|
|
17930
|
-
if (!report.itemQuery) {
|
|
17931
|
-
throw Error("No item query found in report");
|
|
17932
|
-
}
|
|
17933
|
-
const itemQuery = report.itemQuery[0];
|
|
17934
|
-
const comparisonQuery = report.itemQuery[1];
|
|
17935
|
-
if (!itemQuery) {
|
|
17936
|
-
throw Error("No item query found in report");
|
|
17937
|
-
}
|
|
17938
|
-
sqlQuery = generatePivotQuery(
|
|
17939
|
-
pivot,
|
|
17940
|
-
itemQuery,
|
|
17941
|
-
databaseType,
|
|
17942
|
-
pivotColumnFields,
|
|
17943
|
-
dateBucket
|
|
17944
|
-
);
|
|
17945
|
-
comparisonPivotSql = comparisonQuery ? generatePivotQuery(
|
|
17946
|
-
pivot,
|
|
17947
|
-
comparisonQuery,
|
|
17948
|
-
databaseType,
|
|
17949
|
-
pivotColumnFields,
|
|
17950
|
-
dateBucket
|
|
17951
|
-
) : "";
|
|
17952
|
-
}
|
|
17953
|
-
if (!sqlQuery) {
|
|
17954
|
-
throw "Error generating pivot query";
|
|
17955
|
-
}
|
|
17956
|
-
const paginatedSqlQuery = additionalProcessingOnPivotQuery(
|
|
17957
|
-
pivot,
|
|
17958
|
-
sqlQuery,
|
|
17959
|
-
additionalProcessing,
|
|
17960
|
-
client.databaseType
|
|
17961
|
-
);
|
|
17962
|
-
const paginatedComparisonQuery = comparisonPivotSql ? additionalProcessingOnPivotQuery(
|
|
17963
|
-
pivot,
|
|
17964
|
-
comparisonPivotSql,
|
|
17965
|
-
additionalProcessing,
|
|
17966
|
-
client.databaseType
|
|
17967
|
-
) : "";
|
|
17968
|
-
const preQueries = [paginatedSqlQuery];
|
|
17969
|
-
getPivotRowCount = getPivotRowCount && (report?.chartType === "table" || caller === "ReportBuilder");
|
|
17970
|
-
if (getPivotRowCount) {
|
|
17971
|
-
const pivotRowCountQuery = generateRowCountQuery(
|
|
17972
|
-
sqlQuery,
|
|
17973
|
-
client.databaseType
|
|
17974
|
-
);
|
|
17975
|
-
preQueries.push(pivotRowCountQuery);
|
|
17976
|
-
}
|
|
17977
|
-
if (paginatedComparisonQuery) {
|
|
17978
|
-
preQueries.push(paginatedComparisonQuery);
|
|
17979
|
-
}
|
|
17980
|
-
const { data: resp } = await quillFetch({
|
|
17981
|
-
client,
|
|
17982
|
-
task: "query",
|
|
17983
|
-
metadata: {
|
|
17984
|
-
preQueries,
|
|
17985
|
-
clientId: client.publicKey,
|
|
17986
|
-
databaseType,
|
|
17987
|
-
runQueryConfig: {
|
|
17988
|
-
overridePost: true,
|
|
17989
|
-
convertDatatypes: true
|
|
17990
|
-
},
|
|
17991
|
-
useNewNodeSql: true,
|
|
17992
|
-
dashboardName,
|
|
17993
|
-
tenants
|
|
17994
|
-
},
|
|
17995
|
-
urlParameters: `caller=generatePivot&task=query`,
|
|
17996
|
-
credentials: "same-origin",
|
|
17997
|
-
getToken
|
|
17998
|
-
});
|
|
17999
|
-
if (resp.success === false) {
|
|
18000
|
-
throw resp.errorMessage;
|
|
18001
|
-
}
|
|
18002
|
-
const queryResponseRows = resp?.queryResults?.[0]?.rows || [];
|
|
18003
|
-
const queryResponseFields = resp?.queryResults?.[0]?.fields || [];
|
|
18004
|
-
const queryComparisonResponseRows = (getPivotRowCount ? resp?.queryResults?.[2]?.rows : resp?.queryResults?.[1]?.rows) || [];
|
|
18005
|
-
const queryComparisonResponseFields = (getPivotRowCount ? resp?.queryResults?.[2]?.fields : resp?.queryResults?.[1]?.fields) || [];
|
|
18006
|
-
parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
|
|
18007
|
-
parseValueFromBigQueryDates(
|
|
18008
|
-
queryComparisonResponseRows,
|
|
18009
|
-
queryComparisonResponseFields
|
|
18010
|
-
);
|
|
18011
|
-
const responseRows = mergeComparisonPivotRows({
|
|
18012
|
-
pivot,
|
|
18013
|
-
rows: queryResponseRows,
|
|
18014
|
-
compRows: queryComparisonResponseRows,
|
|
18015
|
-
databaseType,
|
|
18016
|
-
dateBucket,
|
|
18017
|
-
comparisonInterval,
|
|
18018
|
-
columnFieldValues: pivotColumnFields
|
|
18019
|
-
});
|
|
18020
|
-
const responseFields = mergeComparisonPivotColumns({
|
|
18021
|
-
pivot,
|
|
18022
|
-
rows: queryResponseFields,
|
|
18023
|
-
compRows: queryComparisonResponseFields
|
|
18024
|
-
});
|
|
18025
|
-
const rows = pivot.rowField ? responseRows.map(
|
|
18026
|
-
(row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
|
|
18027
|
-
) : responseRows;
|
|
18028
|
-
if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
|
|
18029
|
-
rows.forEach((row) => {
|
|
18030
|
-
Object.keys(row).forEach((key) => {
|
|
18031
|
-
const processedKey = processColumnName(key);
|
|
18032
|
-
if (processedKey !== key) {
|
|
18033
|
-
row[processedKey] = row[key];
|
|
18034
|
-
delete row[key];
|
|
18035
|
-
}
|
|
18036
|
-
});
|
|
18037
|
-
});
|
|
18038
|
-
}
|
|
18039
|
-
const columns = responseFields?.map((field) => ({
|
|
18040
|
-
field: processColumnName(field.name),
|
|
18041
|
-
label: snakeCaseToTitleCase(
|
|
18042
|
-
processColumnName(field.name.replace("comparison_", "comparison "))
|
|
18043
|
-
),
|
|
18044
|
-
format: field.name === pivot.rowField ? "string" : (
|
|
18045
|
-
// This scary equation is calculating which aggregation a column is associated with.
|
|
18046
|
-
// Eg you have 7 columns and 2 aggregations, you can assume column 0 is the row field, 1-3 is aggregation 0, and 4-6 is aggregation 1.
|
|
18047
|
-
// pivot.aggregations?.[
|
|
18048
|
-
// Math.floor(
|
|
18049
|
-
// (index - 1) /
|
|
18050
|
-
// Math.floor(
|
|
18051
|
-
// (responseFields.length - 1) /
|
|
18052
|
-
// (pivot.aggregations?.length ?? 1),
|
|
18053
|
-
// ),
|
|
18054
|
-
// )
|
|
18055
|
-
// ]?.aggregationType === 'percentage'
|
|
18056
|
-
pivot.aggregations?.find(
|
|
18057
|
-
(agg) => agg.valueField === field.name || `${agg.valueField}_percentage` === field.name || !agg.valueField && agg.aggregationType === "percentage" && field.name.endsWith("percentage")
|
|
18058
|
-
)?.aggregationType === "percentage" ? "percent" : "whole_number"
|
|
18059
|
-
),
|
|
18060
|
-
fieldType: field.fieldType,
|
|
18061
|
-
jsType: field.jsType,
|
|
18062
|
-
dataTypeID: field.dataTypeID
|
|
18063
|
-
})).filter(
|
|
18064
|
-
(field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
|
|
18065
|
-
).sort((a, b) => {
|
|
18066
|
-
if (a.field === pivot.rowField) {
|
|
18067
|
-
return -1;
|
|
18068
|
-
}
|
|
18069
|
-
if (b.field === pivot.rowField) {
|
|
18070
|
-
return 1;
|
|
18071
|
-
}
|
|
18072
|
-
return 0;
|
|
18073
|
-
});
|
|
18074
|
-
if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
|
|
18075
|
-
rows.forEach((row) => {
|
|
18076
|
-
row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
18077
|
-
let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
18078
|
-
if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
|
|
18079
|
-
const rowDate = new Date(value);
|
|
18080
|
-
if (rowDate < dateFilter.startDate) {
|
|
18081
|
-
value = dateFilter.startDate.toISOString();
|
|
18082
|
-
} else if (rowDate > dateFilter.endDate) {
|
|
18083
|
-
value = dateFilter.endDate.toISOString();
|
|
18084
|
-
}
|
|
18085
|
-
}
|
|
18086
|
-
const dateString = getDateString(
|
|
18087
|
-
value,
|
|
18088
|
-
dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
|
|
18089
|
-
dateBucket,
|
|
18090
|
-
databaseType
|
|
18091
|
-
);
|
|
18092
|
-
row[pivot.rowField || ""] = dateString;
|
|
18093
|
-
});
|
|
18094
|
-
if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
|
|
18095
|
-
const dateSet = new Set(
|
|
18096
|
-
rows.map((row) => row[pivot.rowField || ""])
|
|
18097
|
-
);
|
|
18098
|
-
for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
|
|
18099
|
-
const formattedDate = getDateString(
|
|
18100
|
-
date.toISOString(),
|
|
18101
|
-
{ start: dateFilter.startDate, end: dateFilter.endDate },
|
|
18102
|
-
dateBucket,
|
|
18103
|
-
databaseType
|
|
18104
|
-
);
|
|
18105
|
-
if (!dateSet.has(formattedDate)) {
|
|
18106
|
-
const newRow = {};
|
|
18107
|
-
newRow[pivot.rowField] = formattedDate;
|
|
18108
|
-
newRow.__quillRawDate = date.toISOString();
|
|
18109
|
-
rows.push(newRow);
|
|
18110
|
-
dateSet.add(formattedDate);
|
|
18111
|
-
}
|
|
18112
|
-
}
|
|
18113
|
-
}
|
|
18114
|
-
if (!pivot.sort) {
|
|
18115
|
-
rows.sort((a, b) => {
|
|
18116
|
-
if (a.__quillRawDate < b.__quillRawDate) {
|
|
18117
|
-
return -1;
|
|
18118
|
-
}
|
|
18119
|
-
if (a.__quillRawDate > b.__quillRawDate) {
|
|
18120
|
-
return 1;
|
|
18121
|
-
}
|
|
18122
|
-
return 0;
|
|
18123
|
-
});
|
|
18124
|
-
}
|
|
18125
|
-
}
|
|
18126
|
-
columns?.forEach((column, index) => {
|
|
18127
|
-
if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
|
|
18128
|
-
column.label = "Count";
|
|
18129
|
-
}
|
|
18130
|
-
});
|
|
18131
|
-
const numericColumns = columns?.filter(
|
|
18132
|
-
(column) => column.format === "whole_number" || column.format === "percentage"
|
|
18133
|
-
);
|
|
18134
|
-
rows.forEach((row) => {
|
|
18135
|
-
numericColumns?.forEach((column) => {
|
|
18136
|
-
row[column.field] = row[column.field] ?? 0;
|
|
18137
|
-
});
|
|
18138
|
-
});
|
|
18139
|
-
return {
|
|
18140
|
-
rows,
|
|
18141
|
-
columns: columns ?? [],
|
|
18142
|
-
rowCount: getPivotRowCount ? Number(resp?.queryResults?.[1]?.rows?.[0]?.["row_count"]) ?? rows.length : 0,
|
|
18143
|
-
pivotQuery: sqlQuery,
|
|
18144
|
-
comparisonPivotQuery: comparisonPivotSql
|
|
18145
|
-
};
|
|
18146
|
-
}
|
|
18147
|
-
function generatePivotTableYAxis(pivot, cols, yAxisField) {
|
|
18148
|
-
if (pivot?.aggregationType === "count") {
|
|
18149
|
-
return [
|
|
18150
|
-
{
|
|
18151
|
-
field: pivot.valueField ?? "count",
|
|
18152
|
-
label: yAxisField.label,
|
|
18153
|
-
format: yAxisField.format
|
|
18154
|
-
}
|
|
18155
|
-
];
|
|
18156
|
-
}
|
|
18157
|
-
return [
|
|
18158
|
-
{
|
|
18159
|
-
field: pivot.valueField ?? "count",
|
|
18160
|
-
label: yAxisField.label,
|
|
18161
|
-
format: yAxisField.format
|
|
18162
|
-
}
|
|
18163
|
-
];
|
|
18164
|
-
}
|
|
18165
|
-
function generatePivotTitle(pivot) {
|
|
18166
|
-
if (pivot.rowField && !pivot.valueField && pivot.aggregations?.[0]) {
|
|
18167
|
-
return snakeAndCamelCaseToTitleCase(
|
|
18168
|
-
`${pivot.aggregations[0].aggregationType} of ${pivot.rowField}${pivot.columnField ? ` by ${pivot.columnField}` : ""}
|
|
18169
|
-
`
|
|
18170
|
-
);
|
|
18171
|
-
} else if (!pivot.rowField && pivot.aggregations?.[0]?.valueField) {
|
|
18172
|
-
return snakeAndCamelCaseToTitleCase(
|
|
18173
|
-
`${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
|
|
18174
|
-
`
|
|
18175
|
-
);
|
|
18176
|
-
}
|
|
18177
|
-
return snakeAndCamelCaseToTitleCase(
|
|
18178
|
-
`${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
|
|
18179
|
-
);
|
|
18180
|
-
}
|
|
18181
|
-
async function generatePivotTable({
|
|
18182
|
-
pivot,
|
|
18183
|
-
dateBucket,
|
|
18184
|
-
dateFilter,
|
|
18185
|
-
report,
|
|
18186
|
-
client,
|
|
18187
|
-
getToken,
|
|
18188
|
-
eventTracking,
|
|
18189
|
-
uniqueValues,
|
|
18190
|
-
dashboardName,
|
|
18191
|
-
tenants,
|
|
18192
|
-
additionalProcessing,
|
|
18193
|
-
caller,
|
|
18194
|
-
pivotQuery
|
|
18195
|
-
}) {
|
|
18196
|
-
try {
|
|
18197
|
-
if (report && client) {
|
|
18198
|
-
const pivotTable = await generatePivotWithSQL({
|
|
18199
|
-
pivotQuery,
|
|
18200
|
-
pivot,
|
|
18201
|
-
report,
|
|
18202
|
-
client,
|
|
18203
|
-
dateBucket,
|
|
18204
|
-
dateFilter,
|
|
18205
|
-
distinctStrings: pivot.columnField && uniqueValues?.[pivot.columnField] ? uniqueValues[pivot.columnField] : [],
|
|
18206
|
-
dashboardName,
|
|
18207
|
-
tenants,
|
|
18208
|
-
additionalProcessing,
|
|
18209
|
-
caller,
|
|
18210
|
-
getToken
|
|
18211
|
-
});
|
|
18212
|
-
return pivotTable;
|
|
18213
|
-
}
|
|
18214
|
-
} catch (e) {
|
|
18215
|
-
eventTracking?.logError?.({
|
|
18216
|
-
type: "bug",
|
|
18217
|
-
// TODO: determine type
|
|
18218
|
-
severity: "high",
|
|
18219
|
-
message: "Error generating pivot table",
|
|
18220
|
-
errorMessage: e.message,
|
|
18221
|
-
errorStack: e.stack,
|
|
18222
|
-
errorData: {
|
|
18223
|
-
caller: "PivotModal",
|
|
18224
|
-
function: "generatePivotTable"
|
|
18225
|
-
}
|
|
18226
|
-
});
|
|
18227
|
-
throw Error(`Failed to generate pivot table with SQL: ${e}`);
|
|
18228
|
-
}
|
|
18229
|
-
throw Error("Failed to generate pivot table: invalid report");
|
|
18230
|
-
}
|
|
18231
|
-
|
|
18232
|
-
// src/utils/errorProcessing.ts
|
|
18233
|
-
function processFilterErrorList(resp) {
|
|
18234
|
-
if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
|
|
18235
|
-
return;
|
|
18236
|
-
}
|
|
18237
|
-
}
|
|
18238
|
-
|
|
18239
|
-
// src/utils/paginationProcessing.ts
|
|
18240
|
-
var DEFAULT_PAGINATION = {
|
|
18241
|
-
page: 0,
|
|
18242
|
-
rowsPerPage: 10,
|
|
18243
|
-
rowsPerRequest: 600
|
|
18244
|
-
};
|
|
18245
|
-
var DEFAULT_TABLE_PAGINATION = {
|
|
18246
|
-
page: 0,
|
|
18247
|
-
rowsPerPage: 10,
|
|
18248
|
-
rowsPerRequest: 50
|
|
18249
|
-
};
|
|
18250
|
-
function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
|
|
18251
|
-
if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
|
|
18252
|
-
return false;
|
|
18253
|
-
}
|
|
18254
|
-
const indexAdjustedPage = page;
|
|
18255
|
-
const pageInterval = Math.floor(
|
|
18256
|
-
indexAdjustedPage * pagination.rowsPerPage / pagination.rowsPerRequest
|
|
18257
|
-
);
|
|
18258
|
-
const indexAdjustedPreviousPage = maxPage;
|
|
18259
|
-
const previousPageInterval = Math.floor(
|
|
18260
|
-
indexAdjustedPreviousPage * pagination.rowsPerPage / pagination.rowsPerRequest
|
|
18261
|
-
);
|
|
18262
|
-
return pageInterval > previousPageInterval;
|
|
18263
|
-
}
|
|
18264
|
-
function shouldSortInMemory(pagination, rowCount) {
|
|
18265
|
-
if (!rowCount || rowCount < pagination.rowsPerRequest) {
|
|
18266
|
-
return true;
|
|
18267
|
-
}
|
|
18268
|
-
return false;
|
|
18269
|
-
}
|
|
18270
17547
|
|
|
18271
17548
|
// src/utils/tableProcessing.ts
|
|
18272
17549
|
var getUniqueValuesByQuery = async ({
|
|
@@ -19008,493 +18285,8 @@ var fetchTableByAST = async (ast, client, getToken, tenants, eventTracking, dash
|
|
|
19008
18285
|
return { rows, columns, rowCount, error, itemQuery, referencedTables };
|
|
19009
18286
|
};
|
|
19010
18287
|
|
|
19011
|
-
// src/utils/dashboard.ts
|
|
19012
|
-
var defaultDashboardItem = {
|
|
19013
|
-
id: "",
|
|
19014
|
-
name: "",
|
|
19015
|
-
dashboardName: "",
|
|
19016
|
-
rows: [],
|
|
19017
|
-
compareRows: [],
|
|
19018
|
-
columns: [],
|
|
19019
|
-
chartType: "",
|
|
19020
|
-
pivot: null,
|
|
19021
|
-
yAxisFields: [],
|
|
19022
|
-
xAxisLabel: "",
|
|
19023
|
-
xAxisField: "",
|
|
19024
|
-
xAxisFormat: "string",
|
|
19025
|
-
order: -1,
|
|
19026
|
-
filtersApplied: [],
|
|
19027
|
-
queryString: "",
|
|
19028
|
-
rowCount: 0,
|
|
19029
|
-
columnInternal: []
|
|
19030
|
-
};
|
|
19031
|
-
async function cleanDashboardItem({
|
|
19032
|
-
item,
|
|
19033
|
-
dashboardFilters,
|
|
19034
|
-
getToken,
|
|
19035
|
-
eventTracking,
|
|
19036
|
-
client,
|
|
19037
|
-
dateBucket,
|
|
19038
|
-
additionalProcessing,
|
|
19039
|
-
customFields,
|
|
19040
|
-
skipPivotFetch,
|
|
19041
|
-
tenants
|
|
19042
|
-
}) {
|
|
19043
|
-
if (!item) return defaultDashboardItem;
|
|
19044
|
-
if (!item.rows) {
|
|
19045
|
-
return {
|
|
19046
|
-
...defaultDashboardItem,
|
|
19047
|
-
id: item._id,
|
|
19048
|
-
name: item.name
|
|
19049
|
-
};
|
|
19050
|
-
}
|
|
19051
|
-
const fields = item.fields || [];
|
|
19052
|
-
const columnsWithCustomFields = [...item.columns ?? []];
|
|
19053
|
-
if (item.includeCustomFields && item.rows?.length > 0) {
|
|
19054
|
-
const tables = item.referencedTables ?? [];
|
|
19055
|
-
tables.forEach((table) => {
|
|
19056
|
-
const _customFields = customFields?.[table] ?? [];
|
|
19057
|
-
_customFields.forEach((field) => {
|
|
19058
|
-
const isJsonCustomField = !!field.refColumn;
|
|
19059
|
-
if (item.rows[0][field.field] !== void 0 && !item.columns.some((col) => col.field === field.field)) {
|
|
19060
|
-
const result_field = fields.find((f) => f.name === field.field);
|
|
19061
|
-
const converted_field = convertPostgresColumn(result_field ?? {});
|
|
19062
|
-
columnsWithCustomFields.push({
|
|
19063
|
-
field: field.field,
|
|
19064
|
-
format: converted_field.format,
|
|
19065
|
-
label: snakeAndCamelCaseToTitleCase(field.field),
|
|
19066
|
-
fieldType: converted_field.fieldType,
|
|
19067
|
-
dataTypeID: converted_field.dataTypeID,
|
|
19068
|
-
jsType: converted_field.jsType,
|
|
19069
|
-
inferFormat: isJsonCustomField
|
|
19070
|
-
});
|
|
19071
|
-
}
|
|
19072
|
-
});
|
|
19073
|
-
});
|
|
19074
|
-
}
|
|
19075
|
-
const processedColumns = item.columns.map((col) => {
|
|
19076
|
-
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
19077
|
-
});
|
|
19078
|
-
const columnInternal = (item.includeCustomFields ? columnsWithCustomFields : item.columns).map((col) => {
|
|
19079
|
-
const field = item.fields?.find((f) => f.name === col.field);
|
|
19080
|
-
const converted_field = convertPostgresColumn(field ?? {});
|
|
19081
|
-
return {
|
|
19082
|
-
fieldType: converted_field.fieldType,
|
|
19083
|
-
dataTypeID: converted_field.dataTypeID,
|
|
19084
|
-
jsType: converted_field.jsType,
|
|
19085
|
-
...col,
|
|
19086
|
-
label: snakeAndCamelCaseToTitleCase(col.label)
|
|
19087
|
-
};
|
|
19088
|
-
});
|
|
19089
|
-
let pivotTable;
|
|
19090
|
-
let pivotError;
|
|
19091
|
-
try {
|
|
19092
|
-
const shouldPaginatePivotAsTable = item.chartType === "table";
|
|
19093
|
-
const pivotChartProcessing = {
|
|
19094
|
-
page: DEFAULT_PAGINATION
|
|
19095
|
-
};
|
|
19096
|
-
pivotTable = await getPivotTable(
|
|
19097
|
-
{
|
|
19098
|
-
...item,
|
|
19099
|
-
pivot: item.pivot && !skipPivotFetch ? {
|
|
19100
|
-
...item.pivot,
|
|
19101
|
-
aggregations: item.pivot.aggregations ?? [
|
|
19102
|
-
{
|
|
19103
|
-
valueField: item.pivot.valueField,
|
|
19104
|
-
valueFieldType: item.pivot.valueFieldType,
|
|
19105
|
-
valueField2: item.pivot.valueField2,
|
|
19106
|
-
valueField2Type: item.pivot.valueField2Type,
|
|
19107
|
-
aggregationType: item.pivot.aggregationType
|
|
19108
|
-
}
|
|
19109
|
-
]
|
|
19110
|
-
} : void 0
|
|
19111
|
-
},
|
|
19112
|
-
dashboardFilters,
|
|
19113
|
-
item.dashboardName,
|
|
19114
|
-
getToken,
|
|
19115
|
-
client,
|
|
19116
|
-
eventTracking,
|
|
19117
|
-
dateBucket,
|
|
19118
|
-
shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
|
|
19119
|
-
tenants,
|
|
19120
|
-
customFields
|
|
19121
|
-
);
|
|
19122
|
-
} catch (e) {
|
|
19123
|
-
pivotTable = void 0;
|
|
19124
|
-
eventTracking?.logError?.({
|
|
19125
|
-
type: "bug",
|
|
19126
|
-
// TODO: determine type
|
|
19127
|
-
severity: "high",
|
|
19128
|
-
message: "Error fetching pivot table",
|
|
19129
|
-
errorMessage: e.message,
|
|
19130
|
-
errorStack: e.stack,
|
|
19131
|
-
errorData: {
|
|
19132
|
-
caller: "cleanDashboardItem",
|
|
19133
|
-
function: "cleanDashboardItem"
|
|
19134
|
-
}
|
|
19135
|
-
});
|
|
19136
|
-
console.error("Error fetching pivot table", e);
|
|
19137
|
-
pivotError = "Error fetching pivot table";
|
|
19138
|
-
}
|
|
19139
|
-
const referenceLineYValues = [];
|
|
19140
|
-
for (const key in item) {
|
|
19141
|
-
if (key.startsWith("referenceLine_")) {
|
|
19142
|
-
const field = key.slice(14);
|
|
19143
|
-
if (!item[key] || !item[key][0]) continue;
|
|
19144
|
-
const value = Object.values(item[key][0])[0];
|
|
19145
|
-
referenceLineYValues.push({ label: field, query: [value, value] });
|
|
19146
|
-
}
|
|
19147
|
-
}
|
|
19148
|
-
if (item.referenceLines) {
|
|
19149
|
-
for (const referenceLine of item.referenceLines) {
|
|
19150
|
-
if (Array.isArray(referenceLine.query)) {
|
|
19151
|
-
referenceLineYValues.push({
|
|
19152
|
-
label: referenceLine.label,
|
|
19153
|
-
query: referenceLine.query
|
|
19154
|
-
});
|
|
19155
|
-
} else if (referenceLine.query === "") {
|
|
19156
|
-
referenceLineYValues.push({
|
|
19157
|
-
label: referenceLine.label,
|
|
19158
|
-
query: (pivotTable?.rows ? pivotTable.rows : item.rows).map(
|
|
19159
|
-
(row) => Number(row[referenceLine.label]) || 0
|
|
19160
|
-
)
|
|
19161
|
-
});
|
|
19162
|
-
}
|
|
19163
|
-
}
|
|
19164
|
-
}
|
|
19165
|
-
return {
|
|
19166
|
-
id: item._id ?? item.id,
|
|
19167
|
-
name: item.name,
|
|
19168
|
-
dashboardName: item.dashboardName,
|
|
19169
|
-
// section: item.section,
|
|
19170
|
-
rows: item.rows,
|
|
19171
|
-
pivotRows: pivotTable ? pivotTable.rows : void 0,
|
|
19172
|
-
pivotColumns: pivotTable ? pivotTable.columns : void 0,
|
|
19173
|
-
compareRows: item.compareRows,
|
|
19174
|
-
columns: processedColumns.map((column) => {
|
|
19175
|
-
return {
|
|
19176
|
-
field: column.field,
|
|
19177
|
-
format: column.format,
|
|
19178
|
-
label: column.label,
|
|
19179
|
-
inferFormat: column.inferFormat
|
|
19180
|
-
};
|
|
19181
|
-
}),
|
|
19182
|
-
includeCustomFields: item.includeCustomFields,
|
|
19183
|
-
columnInternal,
|
|
19184
|
-
columnsWithCustomFields,
|
|
19185
|
-
chartType: item.chartType,
|
|
19186
|
-
dateField: item.dateField,
|
|
19187
|
-
pivot: pivotError ? void 0 : item.pivot ? {
|
|
19188
|
-
...item.pivot,
|
|
19189
|
-
aggregations: item.pivot.aggregations ?? [
|
|
19190
|
-
{
|
|
19191
|
-
valueField: item.pivot.valueField,
|
|
19192
|
-
valueFieldType: item.pivot.valueFieldType,
|
|
19193
|
-
valueField2: item.pivot.valueField2,
|
|
19194
|
-
valueField2Type: item.pivot.valueField2Type,
|
|
19195
|
-
aggregationType: item.pivot.aggregationType
|
|
19196
|
-
}
|
|
19197
|
-
],
|
|
19198
|
-
columnValues: item.distinctStrings
|
|
19199
|
-
} : void 0,
|
|
19200
|
-
yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
|
|
19201
|
-
xAxisLabel: item.xAxisLabel,
|
|
19202
|
-
xAxisField: item.xAxisField,
|
|
19203
|
-
xAxisFormat: item.xAxisFormat,
|
|
19204
|
-
order: item.order,
|
|
19205
|
-
filtersApplied: item.filtersApplied,
|
|
19206
|
-
filterMap: item.filterMap,
|
|
19207
|
-
flags: item.flags,
|
|
19208
|
-
rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
|
|
19209
|
-
pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
|
|
19210
|
-
template: item.template,
|
|
19211
|
-
sort: item.sort,
|
|
19212
|
-
itemQuery: item.itemQuery,
|
|
19213
|
-
queryString: item.queryString,
|
|
19214
|
-
pivotQuery: pivotTable?.pivotQuery,
|
|
19215
|
-
comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
|
|
19216
|
-
referencedTables: item?.referencedTables || [],
|
|
19217
|
-
referencedColumns: item?.referencedColumns || {},
|
|
19218
|
-
error: item.error ?? pivotError,
|
|
19219
|
-
referenceLineYValues,
|
|
19220
|
-
referenceLines: item.referenceLines
|
|
19221
|
-
};
|
|
19222
|
-
}
|
|
19223
|
-
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
|
|
19224
|
-
if (!report) return void 0;
|
|
19225
|
-
const dateFilter = Object.values(dashboardFilters ?? {}).find(
|
|
19226
|
-
(filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
|
|
19227
|
-
);
|
|
19228
|
-
if (dateFilter?.operator === "BETWEEN") {
|
|
19229
|
-
dateFilter.startDate = dateFilter.value[0];
|
|
19230
|
-
dateFilter.endDate = dateFilter.value[1];
|
|
19231
|
-
}
|
|
19232
|
-
const pivot = report?.pivot;
|
|
19233
|
-
const data = report || {};
|
|
19234
|
-
if (pivot && client) {
|
|
19235
|
-
if (report.rowCount === 0 || report.rows.length === 0) {
|
|
19236
|
-
const columns = [];
|
|
19237
|
-
if (pivot.rowField) {
|
|
19238
|
-
columns.push({
|
|
19239
|
-
field: pivot.rowField,
|
|
19240
|
-
label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
|
|
19241
|
-
format: pivot.rowFieldType || "string",
|
|
19242
|
-
jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
|
|
19243
|
-
fieldType: pivot.rowFieldType || "string",
|
|
19244
|
-
dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
|
|
19245
|
-
});
|
|
19246
|
-
}
|
|
19247
|
-
for (const agg of pivot.aggregations ?? []) {
|
|
19248
|
-
if (agg.valueField) {
|
|
19249
|
-
columns.push({
|
|
19250
|
-
field: agg.valueField,
|
|
19251
|
-
label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
|
|
19252
|
-
//FIXME: valueFieldType is not always the same as the format
|
|
19253
|
-
format: agg.valueFieldType ?? "whole_number",
|
|
19254
|
-
jsType: agg.valueFieldType ?? "number",
|
|
19255
|
-
fieldType: agg.valueFieldType ?? "number",
|
|
19256
|
-
dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
|
|
19257
|
-
});
|
|
19258
|
-
}
|
|
19259
|
-
}
|
|
19260
|
-
const pivotQuery = generatePivotQuery(
|
|
19261
|
-
pivot,
|
|
19262
|
-
report.itemQuery?.[0],
|
|
19263
|
-
client.databaseType
|
|
19264
|
-
);
|
|
19265
|
-
return {
|
|
19266
|
-
rows: [],
|
|
19267
|
-
rowCount: 0,
|
|
19268
|
-
pivotQuery: pivotQuery ?? "",
|
|
19269
|
-
columns
|
|
19270
|
-
};
|
|
19271
|
-
}
|
|
19272
|
-
try {
|
|
19273
|
-
let dateBucket = dateBucketInitial;
|
|
19274
|
-
let filterDateRange = void 0;
|
|
19275
|
-
if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
|
|
19276
|
-
filterDateRange = {
|
|
19277
|
-
start: dateFilter.startDate,
|
|
19278
|
-
end: dateFilter.endDate
|
|
19279
|
-
};
|
|
19280
|
-
} else if (report.dateRange) {
|
|
19281
|
-
filterDateRange = report.dateRange;
|
|
19282
|
-
}
|
|
19283
|
-
if (!dateBucket && filterDateRange) {
|
|
19284
|
-
dateBucket = getDateBucketFromRange(filterDateRange);
|
|
19285
|
-
}
|
|
19286
|
-
if (pivot.columnField && !report.distinctStrings) {
|
|
19287
|
-
const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
|
|
19288
|
-
if (!columnFieldColumn) {
|
|
19289
|
-
console.error(
|
|
19290
|
-
"could not find pivot column field on report",
|
|
19291
|
-
pivot.columnField
|
|
19292
|
-
);
|
|
19293
|
-
}
|
|
19294
|
-
const unique = await getUniqueValuesByQuery({
|
|
19295
|
-
columns: [columnFieldColumn],
|
|
19296
|
-
query: report.queryString,
|
|
19297
|
-
client,
|
|
19298
|
-
getToken,
|
|
19299
|
-
dashboardName,
|
|
19300
|
-
tenants,
|
|
19301
|
-
customFields: customFields ?? {},
|
|
19302
|
-
eventTracking
|
|
19303
|
-
});
|
|
19304
|
-
report.distinctStrings = unique?.[pivot.columnField] ?? [];
|
|
19305
|
-
}
|
|
19306
|
-
if (pivot.columnField && !report.distinctStrings) {
|
|
19307
|
-
const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
|
|
19308
|
-
if (!columnFieldColumn) {
|
|
19309
|
-
console.error(
|
|
19310
|
-
"could not find pivot column field on report",
|
|
19311
|
-
pivot.columnField
|
|
19312
|
-
);
|
|
19313
|
-
}
|
|
19314
|
-
const unique = await getUniqueValuesByQuery({
|
|
19315
|
-
columns: [columnFieldColumn],
|
|
19316
|
-
query: report.queryString,
|
|
19317
|
-
client,
|
|
19318
|
-
getToken,
|
|
19319
|
-
dashboardName,
|
|
19320
|
-
tenants,
|
|
19321
|
-
customFields: customFields ?? {},
|
|
19322
|
-
eventTracking
|
|
19323
|
-
});
|
|
19324
|
-
report.distinctStrings = unique?.[pivot.columnField] ?? [];
|
|
19325
|
-
}
|
|
19326
|
-
const pivotTable = await generatePivotWithSQL({
|
|
19327
|
-
pivot,
|
|
19328
|
-
report,
|
|
19329
|
-
client,
|
|
19330
|
-
dateBucket,
|
|
19331
|
-
dateFilter,
|
|
19332
|
-
distinctStrings: report.distinctStrings,
|
|
19333
|
-
dashboardName,
|
|
19334
|
-
tenants,
|
|
19335
|
-
additionalProcessing,
|
|
19336
|
-
getToken
|
|
19337
|
-
});
|
|
19338
|
-
return pivotTable;
|
|
19339
|
-
} catch (e) {
|
|
19340
|
-
eventTracking?.logError?.({
|
|
19341
|
-
type: "bug",
|
|
19342
|
-
// TODO: determine type
|
|
19343
|
-
severity: "high",
|
|
19344
|
-
message: "Error fetching pivot table",
|
|
19345
|
-
errorMessage: e.message,
|
|
19346
|
-
errorStack: e.stack,
|
|
19347
|
-
errorData: {
|
|
19348
|
-
caller: "getPivotTable",
|
|
19349
|
-
function: "getPivotTable"
|
|
19350
|
-
}
|
|
19351
|
-
});
|
|
19352
|
-
console.error("Error fetching pivot table", e);
|
|
19353
|
-
throw e;
|
|
19354
|
-
}
|
|
19355
|
-
}
|
|
19356
|
-
return pivot && data.rows ? generatePivotTable({
|
|
19357
|
-
pivot,
|
|
19358
|
-
report,
|
|
19359
|
-
client,
|
|
19360
|
-
uniqueValues: report.distinctStrings,
|
|
19361
|
-
dashboardName,
|
|
19362
|
-
tenants,
|
|
19363
|
-
dateFilter,
|
|
19364
|
-
additionalProcessing,
|
|
19365
|
-
getToken,
|
|
19366
|
-
eventTracking
|
|
19367
|
-
}) : void 0;
|
|
19368
|
-
}
|
|
19369
|
-
function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
|
|
19370
|
-
if (!pivotTable) return itemInfo?.yAxisFields ?? [];
|
|
19371
|
-
const pivot = itemInfo?.pivot || config?.pivot;
|
|
19372
|
-
if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
|
|
19373
|
-
const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
|
|
19374
|
-
return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
|
|
19375
|
-
}
|
|
19376
|
-
async function getDashboard(dashboardName, client, getToken, tenants, flags) {
|
|
19377
|
-
const { data: resp } = await quillFetch({
|
|
19378
|
-
client,
|
|
19379
|
-
task: "dashboard",
|
|
19380
|
-
metadata: {
|
|
19381
|
-
name: dashboardName,
|
|
19382
|
-
clientId: client.publicKey,
|
|
19383
|
-
databaseType: client.databaseType,
|
|
19384
|
-
useNewNodeSql: true,
|
|
19385
|
-
tenants,
|
|
19386
|
-
flags
|
|
19387
|
-
},
|
|
19388
|
-
getToken
|
|
19389
|
-
});
|
|
19390
|
-
return {
|
|
19391
|
-
...resp,
|
|
19392
|
-
createdAt: resp.createdAt && new Date(resp.createdAt),
|
|
19393
|
-
dateFilter: resp.dateFilter ? {
|
|
19394
|
-
...resp.dateFilter,
|
|
19395
|
-
presetOptions: resp.dateFilter.presetOptions?.map(
|
|
19396
|
-
(preset) => ({
|
|
19397
|
-
...preset,
|
|
19398
|
-
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
19399
|
-
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
19400
|
-
})
|
|
19401
|
-
),
|
|
19402
|
-
defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
|
|
19403
|
-
(preset) => ({
|
|
19404
|
-
...preset,
|
|
19405
|
-
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
19406
|
-
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
19407
|
-
})
|
|
19408
|
-
)
|
|
19409
|
-
} : void 0
|
|
19410
|
-
};
|
|
19411
|
-
}
|
|
19412
|
-
|
|
19413
|
-
// src/utils/chartBuilder.ts
|
|
19414
|
-
var numberFormatOptions = [
|
|
19415
|
-
"whole_number",
|
|
19416
|
-
"one_decimal_place",
|
|
19417
|
-
"two_decimal_places",
|
|
19418
|
-
"dollar_amount",
|
|
19419
|
-
"dollar_cents",
|
|
19420
|
-
"percentage"
|
|
19421
|
-
];
|
|
19422
|
-
var dateFormatOptions = [
|
|
19423
|
-
"MMM_yyyy",
|
|
19424
|
-
"MMM_dd",
|
|
19425
|
-
"MMM_dd_yyyy",
|
|
19426
|
-
"MMM_dd_hh:mm_ap_pm",
|
|
19427
|
-
"hh_ap_pm",
|
|
19428
|
-
"date",
|
|
19429
|
-
"timestamptz"
|
|
19430
|
-
];
|
|
19431
|
-
var NUMBER_OPTIONS = [
|
|
19432
|
-
{ value: "whole_number", label: "whole number" },
|
|
19433
|
-
{ value: "one_decimal_place", label: "one decimal place" },
|
|
19434
|
-
{ value: "two_decimal_places", label: "two decimal places" },
|
|
19435
|
-
{ value: "dollar_amount", label: "dollar amount" },
|
|
19436
|
-
{ value: "dollar_cents", label: "dollar and cent amount" },
|
|
19437
|
-
{ value: "percent", label: "percentage" }
|
|
19438
|
-
];
|
|
19439
|
-
var DATE_OPTIONS = [
|
|
19440
|
-
{ value: "MMM_yyyy", label: "month" },
|
|
19441
|
-
{ value: "MMM_dd", label: "day" },
|
|
19442
|
-
{ value: "MMM_dd_yyyy", label: "day and year" },
|
|
19443
|
-
{ value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
|
|
19444
|
-
{ value: "hh_ap_pm", label: "hour" }
|
|
19445
|
-
];
|
|
19446
|
-
var ALL_FORMAT_OPTIONS = [
|
|
19447
|
-
...NUMBER_OPTIONS,
|
|
19448
|
-
...DATE_OPTIONS,
|
|
19449
|
-
{ value: "string", label: "string" }
|
|
19450
|
-
];
|
|
19451
|
-
function createInitialFormData(columns) {
|
|
19452
|
-
const firstNumberColumn = columns?.find(
|
|
19453
|
-
(col) => numberFormatOptions.includes(col.format)
|
|
19454
|
-
);
|
|
19455
|
-
const firstStringColumn = columns?.find(
|
|
19456
|
-
(col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
|
|
19457
|
-
);
|
|
19458
|
-
const firstDateColumn = columns?.find(
|
|
19459
|
-
(col) => dateFormatOptions.includes(col.format)
|
|
19460
|
-
);
|
|
19461
|
-
const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
|
|
19462
|
-
const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
|
|
19463
|
-
const formEmptyState = {
|
|
19464
|
-
name: "",
|
|
19465
|
-
columns: columns.map((col) => {
|
|
19466
|
-
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
19467
|
-
}),
|
|
19468
|
-
xAxisField,
|
|
19469
|
-
xAxisFormat,
|
|
19470
|
-
yAxisFields: [
|
|
19471
|
-
{
|
|
19472
|
-
field: firstNumberColumn?.field || columns?.[0]?.field || "",
|
|
19473
|
-
label: "",
|
|
19474
|
-
format: firstNumberColumn?.format || columns?.[0]?.format || "string"
|
|
19475
|
-
}
|
|
19476
|
-
],
|
|
19477
|
-
xAxisLabel: "",
|
|
19478
|
-
chartType: firstNumberColumn ? "line" : "table",
|
|
19479
|
-
pivot: null,
|
|
19480
|
-
template: true,
|
|
19481
|
-
referenceLines: []
|
|
19482
|
-
};
|
|
19483
|
-
return formEmptyState;
|
|
19484
|
-
}
|
|
19485
|
-
|
|
19486
|
-
// src/utils/error.ts
|
|
19487
|
-
var DataLoadError = class extends Error {
|
|
19488
|
-
data;
|
|
19489
|
-
constructor(message, data) {
|
|
19490
|
-
super(message);
|
|
19491
|
-
this.name = "DataLoadError";
|
|
19492
|
-
this.data = data;
|
|
19493
|
-
}
|
|
19494
|
-
};
|
|
19495
|
-
|
|
19496
18288
|
// src/components/ReportBuilder/convert.ts
|
|
19497
|
-
var
|
|
18289
|
+
var import_date_fns7 = require("date-fns");
|
|
19498
18290
|
function recursiveSearchAndReplace(node, search, replace) {
|
|
19499
18291
|
if (typeof node !== "object") {
|
|
19500
18292
|
return;
|
|
@@ -19803,7 +18595,7 @@ function convertStringComparison(node, databaseType) {
|
|
|
19803
18595
|
searchAndReplace(element);
|
|
19804
18596
|
});
|
|
19805
18597
|
} else if (typeof obj === "object" && obj !== null) {
|
|
19806
|
-
if (obj.type === "binary_expr" && (obj.operator === "=" && !(0,
|
|
18598
|
+
if (obj.type === "binary_expr" && (obj.operator === "=" && !(0, import_date_fns7.isValid)((0, import_date_fns7.parseISO)(obj.right.value)) || // don't do it on date objects
|
|
19807
18599
|
obj.operator === "LIKE" || obj.operator === "ILIKE") && obj.left && (obj.left.type === "column_ref" || obj.left.type === "double_quote_string") && obj.right && obj.right.type === "single_quote_string") {
|
|
19808
18600
|
obj.operator = "LIKE";
|
|
19809
18601
|
obj.left = {
|
|
@@ -23144,6 +21936,29 @@ var import_jspdf = __toESM(require("jspdf"), 1);
|
|
|
23144
21936
|
|
|
23145
21937
|
// src/hooks/useDashboard.ts
|
|
23146
21938
|
var import_react2 = require("react");
|
|
21939
|
+
|
|
21940
|
+
// src/utils/merge.ts
|
|
21941
|
+
var import_date_fns8 = require("date-fns");
|
|
21942
|
+
var import_date_fns_tz2 = require("date-fns-tz");
|
|
21943
|
+
function mergeComparisonRange(resp) {
|
|
21944
|
+
if (resp.chartType === "table") return resp;
|
|
21945
|
+
const compRows = resp.compareRows;
|
|
21946
|
+
if (!compRows) return resp;
|
|
21947
|
+
const newRows = resp.rows.map((row, i) => {
|
|
21948
|
+
if (i < compRows.length) {
|
|
21949
|
+
const compRow = compRows[i];
|
|
21950
|
+
const newRow = { ...row };
|
|
21951
|
+
for (const [key, value] of Object.entries(compRow)) {
|
|
21952
|
+
newRow[`comparison_${key}`] = value;
|
|
21953
|
+
}
|
|
21954
|
+
return newRow;
|
|
21955
|
+
}
|
|
21956
|
+
return row;
|
|
21957
|
+
});
|
|
21958
|
+
return { ...resp, rows: newRows };
|
|
21959
|
+
}
|
|
21960
|
+
|
|
21961
|
+
// src/hooks/useDashboard.ts
|
|
23147
21962
|
var useDashboardInternal = (dashboardName, customFilters) => {
|
|
23148
21963
|
const [dashboard] = (0, import_react2.useContext)(DashboardContext);
|
|
23149
21964
|
const {
|
|
@@ -28368,7 +27183,7 @@ var ChartTooltipPrimary = (props) => /* @__PURE__ */ (0, import_jsx_runtime31.js
|
|
|
28368
27183
|
paddingTop: 2,
|
|
28369
27184
|
paddingBottom: 2
|
|
28370
27185
|
},
|
|
28371
|
-
children:
|
|
27186
|
+
children: !isNaN(new Date(props.label)) && props.dateFormatter ? props.dateFormatter(props.label) : !isNaN(new Date(props.label)) ? (0, import_date_fns10.format)(new Date(props.label), "MMM yyyy") : props.label
|
|
28372
27187
|
}
|
|
28373
27188
|
)
|
|
28374
27189
|
}
|
|
@@ -28417,9 +27232,9 @@ function reformatComparisonPayload(props, primaryLabel, comparisonLabel) {
|
|
|
28417
27232
|
const nameKey = isComparison ? `comparison_${props.xAxisField}` : props.xAxisField;
|
|
28418
27233
|
const days = LABEL_TO_DAYS[primaryLabel] ?? 0;
|
|
28419
27234
|
const primaryDate = item.payload[props.xAxisField] ?? 0;
|
|
28420
|
-
const compDate =
|
|
27235
|
+
const compDate = (0, import_date_fns10.subDays)(new Date(primaryDate), days + 1);
|
|
28421
27236
|
const date = item.payload[nameKey] ?? (0, import_date_fns10.format)(compDate, props.xAxisFormat);
|
|
28422
|
-
const name2 = props.dateFormatter
|
|
27237
|
+
const name2 = props.dateFormatter(date);
|
|
28423
27238
|
const color2 = item.color;
|
|
28424
27239
|
const value = props.valueFormatter(item.value, item.name);
|
|
28425
27240
|
if (!columnsByKey[""]) {
|
|
@@ -28451,7 +27266,7 @@ function reformatComparisonPayload(props, primaryLabel, comparisonLabel) {
|
|
|
28451
27266
|
return columnsByKey;
|
|
28452
27267
|
}
|
|
28453
27268
|
function getTooltipLabel(props, altTooltipLabel, isDateXAxis) {
|
|
28454
|
-
return props.payload.length <= 2 && altTooltipLabel && isDateXAxis ?
|
|
27269
|
+
return props.payload.length <= 2 && altTooltipLabel && isDateXAxis ? !isNaN(new Date(altTooltipLabel)) && props.dateFormatter ? props.dateFormatter(altTooltipLabel) : !isNaN(new Date(altTooltipLabel)) ? (0, import_date_fns10.format)(new Date(altTooltipLabel), "MMM yyyy") : altTooltipLabel : !isNaN(new Date(props.label)) && props.dateFormatter ? props.dateFormatter(props.label) : !isNaN(new Date(props.label)) ? (0, import_date_fns10.format)(new Date(props.label), "MMM yyyy") : props.label;
|
|
28455
27270
|
}
|
|
28456
27271
|
function ChartTooltipComparison(props) {
|
|
28457
27272
|
const isDateXAxis = isDateFormat(props.xAxisFormat);
|
|
@@ -42572,7 +41387,6 @@ function ChartBuilder({
|
|
|
42572
41387
|
}, [reportId]);
|
|
42573
41388
|
const [windowWidth, setWindowWidth] = (0, import_react43.useState)(1200);
|
|
42574
41389
|
const [rows, setRows] = (0, import_react43.useState)(report?.rows ?? []);
|
|
42575
|
-
const [itemQuery, setItemQuery] = (0, import_react43.useState)(report?.itemQuery);
|
|
42576
41390
|
const [rowCount, setRowCount] = (0, import_react43.useState)(report?.rowCount ?? 0);
|
|
42577
41391
|
const [maxPage, setMaxPage] = (0, import_react43.useState)(0);
|
|
42578
41392
|
const [isLoading, setIsLoading] = (0, import_react43.useState)(false);
|
|
@@ -43302,7 +42116,7 @@ function ChartBuilder({
|
|
|
43302
42116
|
pivot,
|
|
43303
42117
|
dateBucket,
|
|
43304
42118
|
dateFilter,
|
|
43305
|
-
report: report ? { ...report, ...tableInfo
|
|
42119
|
+
report: report ? { ...report, ...tableInfo } : void 0,
|
|
43306
42120
|
client,
|
|
43307
42121
|
uniqueValues,
|
|
43308
42122
|
dashboardName: destinationDashboardName,
|
|
@@ -43463,7 +42277,6 @@ function ChartBuilder({
|
|
|
43463
42277
|
setCurrentProcessing(processing);
|
|
43464
42278
|
setRows(tableInfo.rows);
|
|
43465
42279
|
setProcessedColumns(processColumns(tableInfo.columns));
|
|
43466
|
-
setItemQuery(tableInfo.itemQuery);
|
|
43467
42280
|
fetchRowCount(processing, overrideFilters);
|
|
43468
42281
|
if (formData.pivot) {
|
|
43469
42282
|
try {
|
|
@@ -44369,7 +43182,7 @@ function ChartBuilder({
|
|
|
44369
43182
|
uniqueValuesIsLoading: initialUniqueValuesIsLoading,
|
|
44370
43183
|
initialSelectedPivotTable: selectedPivotTable,
|
|
44371
43184
|
pivotRecommendationsEnabled,
|
|
44372
|
-
report
|
|
43185
|
+
report,
|
|
44373
43186
|
dashboardName: destinationDashboardName || "",
|
|
44374
43187
|
dateFilter: filtersEnabled ? currentDashboardFilters?.find(
|
|
44375
43188
|
(f) => f.filterType === "date_range"
|