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