@quillsql/react 2.16.0 → 2.16.1
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 +2230 -870
- package/dist/index.d.cts +36 -5
- package/dist/index.d.ts +36 -5
- package/dist/index.js +2234 -874
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -14781,6 +14781,21 @@ function isDateFormat(xAxisFormat) {
|
|
|
14781
14781
|
const isDate = DATE_FORMATS.includes(xAxisFormat);
|
|
14782
14782
|
return isDate;
|
|
14783
14783
|
}
|
|
14784
|
+
function getComparisonInterval(comparisonRange, dateBucket) {
|
|
14785
|
+
const dayCount = (0, import_date_fns5.differenceInDays)(
|
|
14786
|
+
comparisonRange.endDate,
|
|
14787
|
+
comparisonRange.startDate
|
|
14788
|
+
);
|
|
14789
|
+
if (!isNaN(dayCount)) {
|
|
14790
|
+
if (dateBucket === "month") {
|
|
14791
|
+
return Math.floor(dayCount / 30) + " month";
|
|
14792
|
+
} else if (dateBucket === "year") {
|
|
14793
|
+
return Math.floor(dayCount / 365) + " year";
|
|
14794
|
+
} else {
|
|
14795
|
+
return dayCount + " day";
|
|
14796
|
+
}
|
|
14797
|
+
}
|
|
14798
|
+
}
|
|
14784
14799
|
function getDateBucketFromRange(dateRange) {
|
|
14785
14800
|
const difference = (0, import_date_fns5.differenceInDays)(dateRange.end, dateRange.start);
|
|
14786
14801
|
if (difference < 14) {
|
|
@@ -16594,759 +16609,299 @@ function parseValueFromBigQueryDates(rows, columns) {
|
|
|
16594
16609
|
});
|
|
16595
16610
|
}
|
|
16596
16611
|
|
|
16597
|
-
// src/utils/
|
|
16598
|
-
|
|
16599
|
-
|
|
16600
|
-
|
|
16601
|
-
|
|
16602
|
-
|
|
16603
|
-
|
|
16604
|
-
|
|
16605
|
-
|
|
16606
|
-
|
|
16607
|
-
|
|
16608
|
-
|
|
16609
|
-
|
|
16610
|
-
getPivotRowCount = true,
|
|
16611
|
-
caller,
|
|
16612
|
-
getToken
|
|
16613
|
-
}) {
|
|
16614
|
-
const databaseType = client.databaseType || "postgresql";
|
|
16615
|
-
if (!pivot.aggregations?.length && pivot.aggregationType) {
|
|
16616
|
-
pivot.aggregations = [
|
|
16617
|
-
{
|
|
16618
|
-
aggregationType: pivot.aggregationType,
|
|
16619
|
-
valueField: pivot.valueField,
|
|
16620
|
-
valueFieldType: pivot.valueFieldType,
|
|
16621
|
-
valueField2: pivot.valueField2,
|
|
16622
|
-
valueField2Type: pivot.valueField2Type
|
|
16612
|
+
// src/utils/merge.ts
|
|
16613
|
+
var import_date_fns7 = require("date-fns");
|
|
16614
|
+
var import_date_fns_tz2 = require("date-fns-tz");
|
|
16615
|
+
function mergeComparisonRange(resp) {
|
|
16616
|
+
if (resp.chartType === "table") return resp;
|
|
16617
|
+
const compRows = resp.compareRows;
|
|
16618
|
+
if (!compRows) return resp;
|
|
16619
|
+
const newRows = resp.rows.map((row, i) => {
|
|
16620
|
+
if (i < compRows.length) {
|
|
16621
|
+
const compRow = compRows[i];
|
|
16622
|
+
const newRow = { ...row };
|
|
16623
|
+
for (const [key, value] of Object.entries(compRow)) {
|
|
16624
|
+
newRow[`comparison_${key}`] = value;
|
|
16623
16625
|
}
|
|
16624
|
-
|
|
16625
|
-
|
|
16626
|
-
|
|
16627
|
-
rowField: pivot.rowField,
|
|
16628
|
-
rowFieldType: pivot.rowFieldType,
|
|
16629
|
-
columnField: pivot.columnField,
|
|
16630
|
-
aggregations: pivot.aggregations?.map((agg) => ({
|
|
16631
|
-
aggregationType: agg.aggregationType,
|
|
16632
|
-
valueField: agg.valueField,
|
|
16633
|
-
valueFieldType: agg.valueFieldType
|
|
16634
|
-
}))
|
|
16635
|
-
};
|
|
16636
|
-
const resp = await quillFetch({
|
|
16637
|
-
client,
|
|
16638
|
-
task: "pivot-template",
|
|
16639
|
-
metadata: {
|
|
16640
|
-
clientId: client.clientId,
|
|
16641
|
-
pivot: pivotConfig,
|
|
16642
|
-
itemQuery: report?.queryString,
|
|
16643
|
-
dashboardName,
|
|
16644
|
-
tenants
|
|
16645
|
-
},
|
|
16646
|
-
credentials: "same-origin",
|
|
16647
|
-
getToken
|
|
16626
|
+
return newRow;
|
|
16627
|
+
}
|
|
16628
|
+
return row;
|
|
16648
16629
|
});
|
|
16649
|
-
|
|
16650
|
-
|
|
16630
|
+
return { ...resp, rows: newRows };
|
|
16631
|
+
}
|
|
16632
|
+
function dateAdder(date, interval2) {
|
|
16633
|
+
const match = interval2.match(/^(\d+)\s+(day|month|year)$/);
|
|
16634
|
+
if (!match) {
|
|
16635
|
+
throw new Error(`Invalid interval format: ${interval2}`);
|
|
16651
16636
|
}
|
|
16652
|
-
const
|
|
16653
|
-
|
|
16654
|
-
|
|
16655
|
-
parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
|
|
16656
|
-
const responseRows = queryResponseRows;
|
|
16657
|
-
const responseFields = queryResponseFields;
|
|
16658
|
-
const rows = pivot.rowField ? responseRows.map(
|
|
16659
|
-
(row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
|
|
16660
|
-
) : responseRows;
|
|
16661
|
-
if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
|
|
16662
|
-
rows.forEach((row) => {
|
|
16663
|
-
Object.keys(row).forEach((key) => {
|
|
16664
|
-
const processedKey = processColumnName(key);
|
|
16665
|
-
if (processedKey !== key) {
|
|
16666
|
-
row[processedKey] = row[key];
|
|
16667
|
-
delete row[key];
|
|
16668
|
-
}
|
|
16669
|
-
});
|
|
16670
|
-
});
|
|
16637
|
+
const [, valueStr, unit] = match;
|
|
16638
|
+
if (!valueStr || !unit) {
|
|
16639
|
+
throw new Error("Could not parse interval");
|
|
16671
16640
|
}
|
|
16672
|
-
const
|
|
16673
|
-
|
|
16674
|
-
|
|
16675
|
-
|
|
16676
|
-
|
|
16677
|
-
|
|
16678
|
-
|
|
16679
|
-
|
|
16680
|
-
|
|
16681
|
-
|
|
16682
|
-
|
|
16683
|
-
jsType: field.jsType,
|
|
16684
|
-
dataTypeID: field.dataTypeID
|
|
16685
|
-
})).filter(
|
|
16686
|
-
(field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
|
|
16687
|
-
).sort((a, b) => {
|
|
16688
|
-
if (a.field === pivot.rowField) {
|
|
16689
|
-
return -1;
|
|
16690
|
-
}
|
|
16691
|
-
if (b.field === pivot.rowField) {
|
|
16692
|
-
return 1;
|
|
16693
|
-
}
|
|
16694
|
-
return 0;
|
|
16695
|
-
});
|
|
16696
|
-
if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
|
|
16697
|
-
rows.forEach((row) => {
|
|
16698
|
-
row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
16699
|
-
let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
16700
|
-
if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
|
|
16701
|
-
const rowDate = new Date(value);
|
|
16702
|
-
if (rowDate < dateFilter.startDate) {
|
|
16703
|
-
value = dateFilter.startDate.toISOString();
|
|
16704
|
-
} else if (rowDate > dateFilter.endDate) {
|
|
16705
|
-
value = dateFilter.endDate.toISOString();
|
|
16706
|
-
}
|
|
16707
|
-
}
|
|
16708
|
-
const dateString = getDateString(
|
|
16709
|
-
value,
|
|
16710
|
-
dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
|
|
16711
|
-
dateBucket,
|
|
16712
|
-
databaseType
|
|
16713
|
-
);
|
|
16714
|
-
row[pivot.rowField || ""] = dateString;
|
|
16715
|
-
});
|
|
16716
|
-
if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
|
|
16717
|
-
const dateSet = new Set(
|
|
16718
|
-
rows.map((row) => row[pivot.rowField || ""])
|
|
16719
|
-
);
|
|
16720
|
-
for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
|
|
16721
|
-
const formattedDate = getDateString(
|
|
16722
|
-
date.toISOString(),
|
|
16723
|
-
{ start: dateFilter.startDate, end: dateFilter.endDate },
|
|
16724
|
-
dateBucket,
|
|
16725
|
-
databaseType
|
|
16726
|
-
);
|
|
16727
|
-
if (!dateSet.has(formattedDate)) {
|
|
16728
|
-
const newRow = {};
|
|
16729
|
-
newRow[pivot.rowField] = formattedDate;
|
|
16730
|
-
newRow.__quillRawDate = date.toISOString();
|
|
16731
|
-
rows.push(newRow);
|
|
16732
|
-
dateSet.add(formattedDate);
|
|
16733
|
-
}
|
|
16734
|
-
}
|
|
16735
|
-
}
|
|
16736
|
-
if (!pivot.sort) {
|
|
16737
|
-
rows.sort((a, b) => {
|
|
16738
|
-
if (a.__quillRawDate < b.__quillRawDate) {
|
|
16739
|
-
return -1;
|
|
16740
|
-
}
|
|
16741
|
-
if (a.__quillRawDate > b.__quillRawDate) {
|
|
16742
|
-
return 1;
|
|
16743
|
-
}
|
|
16744
|
-
return 0;
|
|
16745
|
-
});
|
|
16746
|
-
}
|
|
16641
|
+
const value = parseInt(valueStr, 10);
|
|
16642
|
+
const parsedDate = typeof date === "string" ? new Date(date) : date;
|
|
16643
|
+
switch (unit) {
|
|
16644
|
+
case "day":
|
|
16645
|
+
return (0, import_date_fns7.add)(parsedDate, { days: value });
|
|
16646
|
+
case "month":
|
|
16647
|
+
return (0, import_date_fns7.add)(parsedDate, { months: value });
|
|
16648
|
+
case "year":
|
|
16649
|
+
return (0, import_date_fns7.add)(parsedDate, { years: value });
|
|
16650
|
+
default:
|
|
16651
|
+
throw new Error(`Unsupported interval unit: ${unit}`);
|
|
16747
16652
|
}
|
|
16748
|
-
columns?.forEach((column, index) => {
|
|
16749
|
-
if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
|
|
16750
|
-
column.label = "Count";
|
|
16751
|
-
}
|
|
16752
|
-
});
|
|
16753
|
-
const numericColumns = columns?.filter(
|
|
16754
|
-
(column) => column.format === "whole_number" || column.format === "percentage"
|
|
16755
|
-
);
|
|
16756
|
-
rows.forEach((row) => {
|
|
16757
|
-
numericColumns?.forEach((column) => {
|
|
16758
|
-
row[column.field] = row[column.field] ?? 0;
|
|
16759
|
-
});
|
|
16760
|
-
});
|
|
16761
|
-
return {
|
|
16762
|
-
rows,
|
|
16763
|
-
columns: columns ?? [],
|
|
16764
|
-
rowCount: rowCount || rows.length,
|
|
16765
|
-
pivotQuery: report?.queryString || "",
|
|
16766
|
-
comparisonPivotQuery: comparisonPivotQuery || ""
|
|
16767
|
-
};
|
|
16768
16653
|
}
|
|
16769
|
-
function
|
|
16770
|
-
|
|
16771
|
-
|
|
16772
|
-
|
|
16773
|
-
|
|
16774
|
-
|
|
16775
|
-
|
|
16776
|
-
|
|
16777
|
-
|
|
16654
|
+
function dateTrunc(date, granularity = "day", databaseType) {
|
|
16655
|
+
const weekStartsOn = databaseType === "mssql" ? 0 : 1;
|
|
16656
|
+
const timeZone = "UTC";
|
|
16657
|
+
const zonedDate = (0, import_date_fns_tz2.utcToZonedTime)(date, timeZone);
|
|
16658
|
+
switch (granularity.toLowerCase()) {
|
|
16659
|
+
case "week":
|
|
16660
|
+
return (0, import_date_fns7.startOfWeek)(zonedDate, { weekStartsOn });
|
|
16661
|
+
case "month":
|
|
16662
|
+
return (0, import_date_fns7.startOfMonth)(zonedDate);
|
|
16663
|
+
case "day":
|
|
16664
|
+
return (0, import_date_fns7.startOfDay)(zonedDate);
|
|
16665
|
+
case "year":
|
|
16666
|
+
return (0, import_date_fns7.startOfYear)(zonedDate);
|
|
16667
|
+
default:
|
|
16668
|
+
throw new Error(`Unsupported granularity: ${granularity}`);
|
|
16778
16669
|
}
|
|
16779
|
-
return [
|
|
16780
|
-
{
|
|
16781
|
-
field: pivot.valueField ?? "count",
|
|
16782
|
-
label: yAxisField.label,
|
|
16783
|
-
format: yAxisField.format
|
|
16784
|
-
}
|
|
16785
|
-
];
|
|
16786
16670
|
}
|
|
16787
|
-
function
|
|
16788
|
-
|
|
16789
|
-
|
|
16790
|
-
|
|
16791
|
-
|
|
16792
|
-
|
|
16793
|
-
|
|
16794
|
-
|
|
16795
|
-
`${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
|
|
16796
|
-
`
|
|
16797
|
-
);
|
|
16798
|
-
}
|
|
16799
|
-
return snakeAndCamelCaseToTitleCase(
|
|
16800
|
-
`${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
|
|
16801
|
-
);
|
|
16671
|
+
function mergeComparisonPivotColumns({
|
|
16672
|
+
pivot,
|
|
16673
|
+
rows,
|
|
16674
|
+
compRows
|
|
16675
|
+
}) {
|
|
16676
|
+
if (!compRows || !compRows.length) return rows;
|
|
16677
|
+
const mappedCompRows = compRows.filter((compRow) => compRow.name !== pivot.rowField).map((compRow) => ({ ...compRow, name: `comparison_${compRow.name}` }));
|
|
16678
|
+
return rows.concat(mappedCompRows);
|
|
16802
16679
|
}
|
|
16803
|
-
|
|
16680
|
+
function mergeComparisonPivotRows({
|
|
16804
16681
|
pivot,
|
|
16682
|
+
rows,
|
|
16683
|
+
compRows,
|
|
16684
|
+
databaseType,
|
|
16805
16685
|
dateBucket,
|
|
16806
|
-
|
|
16807
|
-
|
|
16808
|
-
client,
|
|
16809
|
-
getToken,
|
|
16810
|
-
eventTracking,
|
|
16811
|
-
uniqueValues,
|
|
16812
|
-
dashboardName,
|
|
16813
|
-
tenants,
|
|
16814
|
-
additionalProcessing,
|
|
16815
|
-
caller,
|
|
16816
|
-
pivotQuery
|
|
16686
|
+
comparisonInterval,
|
|
16687
|
+
columnFieldValues
|
|
16817
16688
|
}) {
|
|
16818
|
-
|
|
16819
|
-
|
|
16820
|
-
|
|
16821
|
-
|
|
16822
|
-
|
|
16823
|
-
|
|
16824
|
-
|
|
16825
|
-
|
|
16826
|
-
|
|
16827
|
-
|
|
16828
|
-
|
|
16829
|
-
additionalProcessing,
|
|
16830
|
-
caller,
|
|
16831
|
-
getToken
|
|
16832
|
-
});
|
|
16833
|
-
return pivotTable;
|
|
16834
|
-
}
|
|
16835
|
-
} catch (e) {
|
|
16836
|
-
eventTracking?.logError?.({
|
|
16837
|
-
type: "bug",
|
|
16838
|
-
// TODO: determine type
|
|
16839
|
-
severity: "high",
|
|
16840
|
-
message: "Error generating pivot table",
|
|
16841
|
-
errorMessage: e.message,
|
|
16842
|
-
errorStack: e.stack,
|
|
16843
|
-
errorData: {
|
|
16844
|
-
caller: "PivotModal",
|
|
16845
|
-
function: "generatePivotTable"
|
|
16846
|
-
}
|
|
16847
|
-
});
|
|
16848
|
-
throw Error(`Failed to generate pivot table with SQL: ${e}`);
|
|
16689
|
+
if (!compRows || !compRows.length) return rows;
|
|
16690
|
+
if (pivot.columnField && columnFieldValues && columnFieldValues.length > 0) {
|
|
16691
|
+
return merge2DPivotRows(
|
|
16692
|
+
pivot,
|
|
16693
|
+
rows,
|
|
16694
|
+
compRows,
|
|
16695
|
+
columnFieldValues,
|
|
16696
|
+
databaseType,
|
|
16697
|
+
dateBucket,
|
|
16698
|
+
comparisonInterval
|
|
16699
|
+
);
|
|
16849
16700
|
}
|
|
16850
|
-
|
|
16701
|
+
if (pivot.rowField) {
|
|
16702
|
+
return merge1DPivotRows(
|
|
16703
|
+
pivot,
|
|
16704
|
+
rows,
|
|
16705
|
+
compRows,
|
|
16706
|
+
databaseType,
|
|
16707
|
+
dateBucket,
|
|
16708
|
+
comparisonInterval
|
|
16709
|
+
);
|
|
16710
|
+
}
|
|
16711
|
+
return mergeAggregatedRows(pivot, rows, compRows);
|
|
16851
16712
|
}
|
|
16852
|
-
|
|
16853
|
-
|
|
16854
|
-
|
|
16855
|
-
page: 0,
|
|
16856
|
-
rowsPerPage: 10,
|
|
16857
|
-
rowsPerRequest: 600
|
|
16858
|
-
};
|
|
16859
|
-
var DEFAULT_TABLE_PAGINATION = {
|
|
16860
|
-
page: 0,
|
|
16861
|
-
rowsPerPage: 10,
|
|
16862
|
-
rowsPerRequest: 50
|
|
16863
|
-
};
|
|
16864
|
-
function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
|
|
16865
|
-
if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
|
|
16866
|
-
return false;
|
|
16713
|
+
function merge2DPivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
|
|
16714
|
+
if (!pivot || !pivot.columnField) {
|
|
16715
|
+
return [];
|
|
16867
16716
|
}
|
|
16868
|
-
|
|
16869
|
-
|
|
16870
|
-
|
|
16871
|
-
|
|
16872
|
-
|
|
16873
|
-
|
|
16874
|
-
|
|
16717
|
+
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
16718
|
+
return merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues);
|
|
16719
|
+
}
|
|
16720
|
+
return merge2DDatePivotRows(
|
|
16721
|
+
pivot,
|
|
16722
|
+
rows,
|
|
16723
|
+
compRows,
|
|
16724
|
+
columnFieldValues,
|
|
16725
|
+
databaseType,
|
|
16726
|
+
dateBucket,
|
|
16727
|
+
comparisonInterval
|
|
16875
16728
|
);
|
|
16876
|
-
return pageInterval > previousPageInterval;
|
|
16877
16729
|
}
|
|
16878
|
-
function
|
|
16879
|
-
if (!
|
|
16880
|
-
return
|
|
16730
|
+
function merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues) {
|
|
16731
|
+
if (!pivot.rowField || !pivot.aggregations?.some((agg) => agg.valueField)) {
|
|
16732
|
+
return rows;
|
|
16881
16733
|
}
|
|
16882
|
-
return
|
|
16734
|
+
return rows.map((row) => {
|
|
16735
|
+
const matchingCompRow = compRows.find(
|
|
16736
|
+
(compRow) => compRow[pivot.rowField] === row[pivot.rowField]
|
|
16737
|
+
);
|
|
16738
|
+
const comparisonFields = columnFieldValues.reduce(
|
|
16739
|
+
(acc, fieldValue) => {
|
|
16740
|
+
acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
|
|
16741
|
+
return acc;
|
|
16742
|
+
},
|
|
16743
|
+
{}
|
|
16744
|
+
);
|
|
16745
|
+
return {
|
|
16746
|
+
...row,
|
|
16747
|
+
...comparisonFields
|
|
16748
|
+
};
|
|
16749
|
+
});
|
|
16883
16750
|
}
|
|
16884
|
-
|
|
16885
|
-
|
|
16886
|
-
|
|
16887
|
-
|
|
16888
|
-
|
|
16889
|
-
|
|
16890
|
-
|
|
16891
|
-
|
|
16892
|
-
|
|
16893
|
-
|
|
16894
|
-
|
|
16895
|
-
|
|
16896
|
-
|
|
16897
|
-
|
|
16898
|
-
|
|
16899
|
-
|
|
16900
|
-
|
|
16901
|
-
|
|
16902
|
-
|
|
16903
|
-
|
|
16904
|
-
|
|
16905
|
-
|
|
16906
|
-
|
|
16907
|
-
|
|
16908
|
-
|
|
16909
|
-
|
|
16910
|
-
client,
|
|
16911
|
-
dateBucket,
|
|
16912
|
-
additionalProcessing,
|
|
16913
|
-
customFields,
|
|
16914
|
-
skipPivotFetch,
|
|
16915
|
-
tenants
|
|
16916
|
-
}) {
|
|
16917
|
-
if (!item) return defaultDashboardItem;
|
|
16918
|
-
if (!item.rows) {
|
|
16751
|
+
function merge2DDatePivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
|
|
16752
|
+
if (!comparisonInterval || !pivot.rowField) {
|
|
16753
|
+
return rows;
|
|
16754
|
+
}
|
|
16755
|
+
return rows.map((row) => {
|
|
16756
|
+
const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
|
|
16757
|
+
const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
|
|
16758
|
+
const matchingCompRow = compRows.find((compRow) => {
|
|
16759
|
+
const comparisonDateWithInterval = dateAdder(
|
|
16760
|
+
compRow[pivot.rowField],
|
|
16761
|
+
comparisonInterval
|
|
16762
|
+
);
|
|
16763
|
+
const truncatedCompRowDate = dateTrunc(
|
|
16764
|
+
comparisonDateWithInterval,
|
|
16765
|
+
dateBucket,
|
|
16766
|
+
databaseType
|
|
16767
|
+
);
|
|
16768
|
+
return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
|
|
16769
|
+
});
|
|
16770
|
+
const comparisonFields = columnFieldValues.reduce(
|
|
16771
|
+
(acc, fieldValue) => {
|
|
16772
|
+
acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
|
|
16773
|
+
return acc;
|
|
16774
|
+
},
|
|
16775
|
+
{}
|
|
16776
|
+
);
|
|
16919
16777
|
return {
|
|
16920
|
-
...
|
|
16921
|
-
|
|
16922
|
-
name: item.name
|
|
16778
|
+
...row,
|
|
16779
|
+
...comparisonFields
|
|
16923
16780
|
};
|
|
16781
|
+
});
|
|
16782
|
+
}
|
|
16783
|
+
function merge1DPivotRows(pivot, rows, compRows, databaseType, dateBucket, comparisonInterval) {
|
|
16784
|
+
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
16785
|
+
return merge1DStringPivotRows(pivot, rows, compRows);
|
|
16924
16786
|
}
|
|
16925
|
-
|
|
16926
|
-
|
|
16927
|
-
|
|
16928
|
-
|
|
16929
|
-
|
|
16930
|
-
|
|
16931
|
-
|
|
16932
|
-
|
|
16933
|
-
|
|
16934
|
-
|
|
16935
|
-
|
|
16936
|
-
|
|
16937
|
-
field: field.field,
|
|
16938
|
-
format: converted_field.format,
|
|
16939
|
-
label: snakeAndCamelCaseToTitleCase(field.field),
|
|
16940
|
-
fieldType: converted_field.fieldType,
|
|
16941
|
-
dataTypeID: converted_field.dataTypeID,
|
|
16942
|
-
jsType: converted_field.jsType,
|
|
16943
|
-
inferFormat: isJsonCustomField
|
|
16944
|
-
});
|
|
16945
|
-
}
|
|
16946
|
-
});
|
|
16947
|
-
});
|
|
16787
|
+
return merge1DDatePivotRows(
|
|
16788
|
+
pivot,
|
|
16789
|
+
rows,
|
|
16790
|
+
compRows,
|
|
16791
|
+
databaseType,
|
|
16792
|
+
dateBucket,
|
|
16793
|
+
comparisonInterval
|
|
16794
|
+
);
|
|
16795
|
+
}
|
|
16796
|
+
function merge1DStringPivotRows(pivot, rows, compRows) {
|
|
16797
|
+
if (!pivot.rowField || !pivot.valueField) {
|
|
16798
|
+
return rows;
|
|
16948
16799
|
}
|
|
16949
|
-
|
|
16950
|
-
|
|
16951
|
-
|
|
16952
|
-
|
|
16953
|
-
|
|
16954
|
-
|
|
16800
|
+
return rows.map((row) => {
|
|
16801
|
+
const matchingCompRow = compRows.find(
|
|
16802
|
+
(compRow) => compRow[pivot.rowField] === row[pivot.rowField]
|
|
16803
|
+
);
|
|
16804
|
+
let aggregationSuffix = "";
|
|
16805
|
+
if (matchingCompRow && pivot.aggregationType === "percentage") {
|
|
16806
|
+
if (matchingCompRow[`${pivot.valueField}_Percentage`]) {
|
|
16807
|
+
aggregationSuffix = "_Percentage";
|
|
16808
|
+
} else if (matchingCompRow[`${pivot.valueField}_PERCENTAGE`]) {
|
|
16809
|
+
aggregationSuffix = "_PERCENTAGE";
|
|
16810
|
+
} else {
|
|
16811
|
+
aggregationSuffix = "_percentage";
|
|
16812
|
+
}
|
|
16813
|
+
}
|
|
16955
16814
|
return {
|
|
16956
|
-
|
|
16957
|
-
|
|
16958
|
-
jsType: converted_field.jsType,
|
|
16959
|
-
...col,
|
|
16960
|
-
label: snakeAndCamelCaseToTitleCase(col.label)
|
|
16815
|
+
...row,
|
|
16816
|
+
[`comparison_${pivot.valueField}${aggregationSuffix}`]: matchingCompRow ? matchingCompRow[`${pivot.valueField}${aggregationSuffix}`] : null
|
|
16961
16817
|
};
|
|
16962
16818
|
});
|
|
16963
|
-
|
|
16964
|
-
|
|
16965
|
-
|
|
16966
|
-
|
|
16967
|
-
|
|
16968
|
-
|
|
16819
|
+
}
|
|
16820
|
+
function merge1DDatePivotRows(pivot, rows, compRows, databaseType, dateBucket, comparisonInterval) {
|
|
16821
|
+
if (!comparisonInterval || !pivot.rowField) {
|
|
16822
|
+
return rows;
|
|
16823
|
+
}
|
|
16824
|
+
return rows.map((row) => {
|
|
16825
|
+
const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
|
|
16826
|
+
const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
|
|
16827
|
+
const matchingCompRow = compRows.find((compRow) => {
|
|
16828
|
+
const comparisonDateWithInterval = dateAdder(
|
|
16829
|
+
compRow[`${pivot.rowField}`],
|
|
16830
|
+
comparisonInterval
|
|
16831
|
+
);
|
|
16832
|
+
const truncatedCompRowDate = dateTrunc(
|
|
16833
|
+
comparisonDateWithInterval,
|
|
16834
|
+
dateBucket,
|
|
16835
|
+
databaseType
|
|
16836
|
+
);
|
|
16837
|
+
return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
|
|
16838
|
+
});
|
|
16839
|
+
let aggregationSuffix = "";
|
|
16840
|
+
if (matchingCompRow && pivot.aggregationType === "percentage") {
|
|
16841
|
+
if (matchingCompRow[`${pivot.valueField}_Percentage`]) {
|
|
16842
|
+
aggregationSuffix = "_Percentage";
|
|
16843
|
+
} else if (matchingCompRow[`${pivot.valueField}_PERCENTAGE`]) {
|
|
16844
|
+
aggregationSuffix = "_PERCENTAGE";
|
|
16845
|
+
} else {
|
|
16846
|
+
aggregationSuffix = "_percentage";
|
|
16847
|
+
}
|
|
16848
|
+
}
|
|
16849
|
+
return {
|
|
16850
|
+
...row,
|
|
16851
|
+
[`comparison_${pivot.valueField}${aggregationSuffix}`]: matchingCompRow?.[`${pivot.valueField}${aggregationSuffix}`] || null
|
|
16969
16852
|
};
|
|
16970
|
-
|
|
16971
|
-
|
|
16972
|
-
|
|
16973
|
-
|
|
16974
|
-
|
|
16975
|
-
|
|
16976
|
-
|
|
16977
|
-
|
|
16978
|
-
|
|
16979
|
-
|
|
16980
|
-
|
|
16981
|
-
|
|
16982
|
-
}
|
|
16983
|
-
]
|
|
16984
|
-
} : void 0
|
|
16985
|
-
},
|
|
16986
|
-
dashboardFilters,
|
|
16987
|
-
item.dashboardName,
|
|
16988
|
-
getToken,
|
|
16989
|
-
client,
|
|
16990
|
-
eventTracking,
|
|
16991
|
-
dateBucket,
|
|
16992
|
-
shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
|
|
16993
|
-
tenants,
|
|
16994
|
-
customFields
|
|
16995
|
-
);
|
|
16996
|
-
} catch (e) {
|
|
16997
|
-
pivotTable = void 0;
|
|
16998
|
-
eventTracking?.logError?.({
|
|
16999
|
-
type: "bug",
|
|
17000
|
-
// TODO: determine type
|
|
17001
|
-
severity: "high",
|
|
17002
|
-
message: "Error fetching pivot table",
|
|
17003
|
-
errorMessage: e.message,
|
|
17004
|
-
errorStack: e.stack,
|
|
17005
|
-
errorData: {
|
|
17006
|
-
caller: "cleanDashboardItem",
|
|
17007
|
-
function: "cleanDashboardItem"
|
|
16853
|
+
});
|
|
16854
|
+
}
|
|
16855
|
+
function mergeAggregatedRows(pivot, rows, compRows) {
|
|
16856
|
+
return rows.map((row, i) => {
|
|
16857
|
+
let aggregationSuffix = "";
|
|
16858
|
+
if (compRows[i] && pivot.aggregationType === "percentage") {
|
|
16859
|
+
if (compRows[i][`${pivot.valueField}_Percentage`]) {
|
|
16860
|
+
aggregationSuffix = "_Percentage";
|
|
16861
|
+
} else if (compRows[i][`${pivot.valueField}_PERCENTAGE`]) {
|
|
16862
|
+
aggregationSuffix = "_PERCENTAGE";
|
|
16863
|
+
} else {
|
|
16864
|
+
aggregationSuffix = "_percentage";
|
|
17008
16865
|
}
|
|
17009
|
-
});
|
|
17010
|
-
console.error("Error fetching pivot table", e);
|
|
17011
|
-
pivotError = "Error fetching pivot table";
|
|
17012
|
-
}
|
|
17013
|
-
const referenceLineYValues = [];
|
|
17014
|
-
for (const key in item) {
|
|
17015
|
-
if (key.startsWith("referenceLine_")) {
|
|
17016
|
-
const field = key.slice(14);
|
|
17017
|
-
if (!item[key] || !item[key][0]) continue;
|
|
17018
|
-
const value = Object.values(item[key][0])[0];
|
|
17019
|
-
referenceLineYValues.push({ label: field, query: [value, value] });
|
|
17020
16866
|
}
|
|
16867
|
+
const compRow = {
|
|
16868
|
+
[`comparison_${pivot.valueField}${aggregationSuffix}`]: compRows[i]?.[`${pivot.valueField}${aggregationSuffix}`]
|
|
16869
|
+
};
|
|
16870
|
+
return { ...row, ...compRow };
|
|
16871
|
+
});
|
|
16872
|
+
}
|
|
16873
|
+
|
|
16874
|
+
// src/utils/queryConstructor.ts
|
|
16875
|
+
function processSingleQuotes(value, databaseType) {
|
|
16876
|
+
if (["postgresql", "snowflake", "clickhouse"].includes(
|
|
16877
|
+
databaseType.toLowerCase()
|
|
16878
|
+
)) {
|
|
16879
|
+
return value.replaceAll("'", "''");
|
|
17021
16880
|
}
|
|
17022
|
-
|
|
17023
|
-
|
|
17024
|
-
|
|
17025
|
-
|
|
17026
|
-
|
|
17027
|
-
|
|
17028
|
-
|
|
17029
|
-
|
|
17030
|
-
|
|
17031
|
-
|
|
17032
|
-
|
|
17033
|
-
|
|
17034
|
-
|
|
17035
|
-
|
|
16881
|
+
return value.replaceAll("'", "\\'");
|
|
16882
|
+
}
|
|
16883
|
+
function processAggType(aggType, hasColumnField = false) {
|
|
16884
|
+
if (aggType === "count" && hasColumnField) return "SUM";
|
|
16885
|
+
return aggType?.toLowerCase() === "average" ? "AVG" : aggType?.toLowerCase();
|
|
16886
|
+
}
|
|
16887
|
+
function replaceBigQuerySpecialCharacters(column) {
|
|
16888
|
+
return column.replaceAll("/", "quill_forward_slash");
|
|
16889
|
+
}
|
|
16890
|
+
function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
|
|
16891
|
+
switch (databaseType.toLowerCase()) {
|
|
16892
|
+
case "postgresql":
|
|
16893
|
+
case "clickhouse": {
|
|
16894
|
+
if (column === "") {
|
|
16895
|
+
return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
|
|
16896
|
+
}
|
|
16897
|
+
if (isColumnFieldAlias) {
|
|
16898
|
+
return `"${column.replaceAll('"', "")}"`;
|
|
17036
16899
|
}
|
|
17037
|
-
|
|
17038
|
-
|
|
17039
|
-
|
|
17040
|
-
|
|
17041
|
-
|
|
17042
|
-
dashboardName: item.dashboardName,
|
|
17043
|
-
// section: item.section,
|
|
17044
|
-
rows: item.rows,
|
|
17045
|
-
pivotRows: pivotTable ? pivotTable.rows : void 0,
|
|
17046
|
-
pivotColumns: pivotTable ? pivotTable.columns : void 0,
|
|
17047
|
-
compareRows: item.compareRows,
|
|
17048
|
-
columns: processedColumns.map((column) => {
|
|
17049
|
-
return {
|
|
17050
|
-
field: column.field,
|
|
17051
|
-
format: column.format,
|
|
17052
|
-
label: column.label,
|
|
17053
|
-
inferFormat: column.inferFormat
|
|
17054
|
-
};
|
|
17055
|
-
}),
|
|
17056
|
-
includeCustomFields: item.includeCustomFields,
|
|
17057
|
-
columnInternal,
|
|
17058
|
-
columnsWithCustomFields,
|
|
17059
|
-
chartType: item.chartType,
|
|
17060
|
-
dateField: item.dateField,
|
|
17061
|
-
pivot: pivotError ? void 0 : item.pivot ? {
|
|
17062
|
-
...item.pivot,
|
|
17063
|
-
aggregations: item.pivot.aggregations ?? [
|
|
17064
|
-
{
|
|
17065
|
-
valueField: item.pivot.valueField,
|
|
17066
|
-
valueFieldType: item.pivot.valueFieldType,
|
|
17067
|
-
valueField2: item.pivot.valueField2,
|
|
17068
|
-
valueField2Type: item.pivot.valueField2Type,
|
|
17069
|
-
aggregationType: item.pivot.aggregationType
|
|
17070
|
-
}
|
|
17071
|
-
],
|
|
17072
|
-
columnValues: item.distinctStrings
|
|
17073
|
-
} : void 0,
|
|
17074
|
-
yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
|
|
17075
|
-
xAxisLabel: item.xAxisLabel,
|
|
17076
|
-
xAxisField: item.xAxisField,
|
|
17077
|
-
xAxisFormat: item.xAxisFormat,
|
|
17078
|
-
order: item.order,
|
|
17079
|
-
filtersApplied: item.filtersApplied,
|
|
17080
|
-
filterMap: item.filterMap,
|
|
17081
|
-
flags: item.flags,
|
|
17082
|
-
rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
|
|
17083
|
-
pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
|
|
17084
|
-
template: item.template,
|
|
17085
|
-
sort: item.sort,
|
|
17086
|
-
itemQuery: item.itemQuery,
|
|
17087
|
-
queryString: item.queryString,
|
|
17088
|
-
pivotQuery: pivotTable?.pivotQuery,
|
|
17089
|
-
comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
|
|
17090
|
-
referencedTables: item?.referencedTables || [],
|
|
17091
|
-
referencedColumns: item?.referencedColumns || {},
|
|
17092
|
-
error: item.error ?? pivotError,
|
|
17093
|
-
referenceLineYValues,
|
|
17094
|
-
referenceLines: item.referenceLines
|
|
17095
|
-
};
|
|
17096
|
-
}
|
|
17097
|
-
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
|
|
17098
|
-
if (!report) return void 0;
|
|
17099
|
-
const dateFilter = Object.values(dashboardFilters ?? {}).find(
|
|
17100
|
-
(filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
|
|
17101
|
-
);
|
|
17102
|
-
if (dateFilter?.operator === "BETWEEN") {
|
|
17103
|
-
dateFilter.startDate = dateFilter.value[0];
|
|
17104
|
-
dateFilter.endDate = dateFilter.value[1];
|
|
17105
|
-
}
|
|
17106
|
-
const pivot = report?.pivot;
|
|
17107
|
-
const data = report || {};
|
|
17108
|
-
if (pivot && client) {
|
|
17109
|
-
if (report.rowCount === 0 || report.rows.length === 0) {
|
|
17110
|
-
const columns = [];
|
|
17111
|
-
if (pivot.rowField) {
|
|
17112
|
-
columns.push({
|
|
17113
|
-
field: pivot.rowField,
|
|
17114
|
-
label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
|
|
17115
|
-
format: pivot.rowFieldType || "string",
|
|
17116
|
-
jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
|
|
17117
|
-
fieldType: pivot.rowFieldType || "string",
|
|
17118
|
-
dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
|
|
17119
|
-
});
|
|
17120
|
-
}
|
|
17121
|
-
for (const agg of pivot.aggregations ?? []) {
|
|
17122
|
-
if (agg.valueField) {
|
|
17123
|
-
columns.push({
|
|
17124
|
-
field: agg.valueField,
|
|
17125
|
-
label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
|
|
17126
|
-
//FIXME: valueFieldType is not always the same as the format
|
|
17127
|
-
format: agg.valueFieldType ?? "whole_number",
|
|
17128
|
-
jsType: agg.valueFieldType ?? "number",
|
|
17129
|
-
fieldType: agg.valueFieldType ?? "number",
|
|
17130
|
-
dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
|
|
17131
|
-
});
|
|
17132
|
-
}
|
|
17133
|
-
}
|
|
17134
|
-
return {
|
|
17135
|
-
rows: [],
|
|
17136
|
-
rowCount: 0,
|
|
17137
|
-
pivotQuery: report.queryString ?? "",
|
|
17138
|
-
columns
|
|
17139
|
-
};
|
|
17140
|
-
}
|
|
17141
|
-
try {
|
|
17142
|
-
let dateBucket = dateBucketInitial;
|
|
17143
|
-
let filterDateRange = void 0;
|
|
17144
|
-
if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
|
|
17145
|
-
filterDateRange = {
|
|
17146
|
-
start: dateFilter.startDate,
|
|
17147
|
-
end: dateFilter.endDate
|
|
17148
|
-
};
|
|
17149
|
-
} else if (report.dateRange) {
|
|
17150
|
-
filterDateRange = report.dateRange;
|
|
17151
|
-
}
|
|
17152
|
-
if (!dateBucket && filterDateRange) {
|
|
17153
|
-
dateBucket = getDateBucketFromRange(filterDateRange);
|
|
17154
|
-
}
|
|
17155
|
-
const pivotTable = await generatePivotWithSQL({
|
|
17156
|
-
pivot,
|
|
17157
|
-
report,
|
|
17158
|
-
client,
|
|
17159
|
-
dateBucket,
|
|
17160
|
-
dateFilter,
|
|
17161
|
-
dashboardName,
|
|
17162
|
-
tenants,
|
|
17163
|
-
additionalProcessing,
|
|
17164
|
-
getToken
|
|
17165
|
-
});
|
|
17166
|
-
return pivotTable;
|
|
17167
|
-
} catch (e) {
|
|
17168
|
-
eventTracking?.logError?.({
|
|
17169
|
-
type: "bug",
|
|
17170
|
-
// TODO: determine type
|
|
17171
|
-
severity: "high",
|
|
17172
|
-
message: "Error fetching pivot table",
|
|
17173
|
-
errorMessage: e.message,
|
|
17174
|
-
errorStack: e.stack,
|
|
17175
|
-
errorData: {
|
|
17176
|
-
caller: "getPivotTable",
|
|
17177
|
-
function: "getPivotTable"
|
|
17178
|
-
}
|
|
17179
|
-
});
|
|
17180
|
-
console.error("Error fetching pivot table", e);
|
|
17181
|
-
throw e;
|
|
17182
|
-
}
|
|
17183
|
-
}
|
|
17184
|
-
return pivot && data.rows ? generatePivotTable({
|
|
17185
|
-
pivot,
|
|
17186
|
-
report,
|
|
17187
|
-
client,
|
|
17188
|
-
uniqueValues: report.distinctStrings,
|
|
17189
|
-
dashboardName,
|
|
17190
|
-
tenants,
|
|
17191
|
-
dateFilter,
|
|
17192
|
-
additionalProcessing,
|
|
17193
|
-
getToken,
|
|
17194
|
-
eventTracking
|
|
17195
|
-
}) : void 0;
|
|
17196
|
-
}
|
|
17197
|
-
function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
|
|
17198
|
-
if (!pivotTable) return itemInfo?.yAxisFields ?? [];
|
|
17199
|
-
const pivot = itemInfo?.pivot || config?.pivot;
|
|
17200
|
-
if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
|
|
17201
|
-
const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
|
|
17202
|
-
return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
|
|
17203
|
-
}
|
|
17204
|
-
async function getDashboard(dashboardName, client, getToken, tenants, flags) {
|
|
17205
|
-
const { data: resp } = await quillFetch({
|
|
17206
|
-
client,
|
|
17207
|
-
task: "dashboard",
|
|
17208
|
-
metadata: {
|
|
17209
|
-
name: dashboardName,
|
|
17210
|
-
clientId: client.publicKey,
|
|
17211
|
-
databaseType: client.databaseType,
|
|
17212
|
-
useNewNodeSql: true,
|
|
17213
|
-
tenants,
|
|
17214
|
-
flags
|
|
17215
|
-
},
|
|
17216
|
-
getToken
|
|
17217
|
-
});
|
|
17218
|
-
return {
|
|
17219
|
-
...resp,
|
|
17220
|
-
createdAt: resp.createdAt && new Date(resp.createdAt),
|
|
17221
|
-
dateFilter: resp.dateFilter ? {
|
|
17222
|
-
...resp.dateFilter,
|
|
17223
|
-
presetOptions: resp.dateFilter.presetOptions?.map(
|
|
17224
|
-
(preset) => ({
|
|
17225
|
-
...preset,
|
|
17226
|
-
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
17227
|
-
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
17228
|
-
})
|
|
17229
|
-
),
|
|
17230
|
-
defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
|
|
17231
|
-
(preset) => ({
|
|
17232
|
-
...preset,
|
|
17233
|
-
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
17234
|
-
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
17235
|
-
})
|
|
17236
|
-
)
|
|
17237
|
-
} : void 0
|
|
17238
|
-
};
|
|
17239
|
-
}
|
|
17240
|
-
|
|
17241
|
-
// src/utils/chartBuilder.ts
|
|
17242
|
-
var numberFormatOptions = [
|
|
17243
|
-
"whole_number",
|
|
17244
|
-
"one_decimal_place",
|
|
17245
|
-
"two_decimal_places",
|
|
17246
|
-
"dollar_amount",
|
|
17247
|
-
"dollar_cents",
|
|
17248
|
-
"percentage"
|
|
17249
|
-
];
|
|
17250
|
-
var dateFormatOptions = [
|
|
17251
|
-
"MMM_yyyy",
|
|
17252
|
-
"MMM_dd",
|
|
17253
|
-
"MMM_dd_yyyy",
|
|
17254
|
-
"MMM_dd_hh:mm_ap_pm",
|
|
17255
|
-
"hh_ap_pm",
|
|
17256
|
-
"date",
|
|
17257
|
-
"timestamptz"
|
|
17258
|
-
];
|
|
17259
|
-
var NUMBER_OPTIONS = [
|
|
17260
|
-
{ value: "whole_number", label: "whole number" },
|
|
17261
|
-
{ value: "one_decimal_place", label: "one decimal place" },
|
|
17262
|
-
{ value: "two_decimal_places", label: "two decimal places" },
|
|
17263
|
-
{ value: "dollar_amount", label: "dollar amount" },
|
|
17264
|
-
{ value: "dollar_cents", label: "dollar and cent amount" },
|
|
17265
|
-
{ value: "percent", label: "percentage" }
|
|
17266
|
-
];
|
|
17267
|
-
var DATE_OPTIONS = [
|
|
17268
|
-
{ value: "MMM_yyyy", label: "month" },
|
|
17269
|
-
{ value: "MMM_dd", label: "day" },
|
|
17270
|
-
{ value: "MMM_dd_yyyy", label: "day and year" },
|
|
17271
|
-
{ value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
|
|
17272
|
-
{ value: "hh_ap_pm", label: "hour" }
|
|
17273
|
-
];
|
|
17274
|
-
var ALL_FORMAT_OPTIONS = [
|
|
17275
|
-
...NUMBER_OPTIONS,
|
|
17276
|
-
...DATE_OPTIONS,
|
|
17277
|
-
{ value: "string", label: "string" }
|
|
17278
|
-
];
|
|
17279
|
-
function createInitialFormData(columns) {
|
|
17280
|
-
const firstNumberColumn = columns?.find(
|
|
17281
|
-
(col) => numberFormatOptions.includes(col.format)
|
|
17282
|
-
);
|
|
17283
|
-
const firstStringColumn = columns?.find(
|
|
17284
|
-
(col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
|
|
17285
|
-
);
|
|
17286
|
-
const firstDateColumn = columns?.find(
|
|
17287
|
-
(col) => dateFormatOptions.includes(col.format)
|
|
17288
|
-
);
|
|
17289
|
-
const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
|
|
17290
|
-
const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
|
|
17291
|
-
const formEmptyState = {
|
|
17292
|
-
name: "",
|
|
17293
|
-
columns: columns.map((col) => {
|
|
17294
|
-
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
17295
|
-
}),
|
|
17296
|
-
xAxisField,
|
|
17297
|
-
xAxisFormat,
|
|
17298
|
-
yAxisFields: [
|
|
17299
|
-
{
|
|
17300
|
-
field: firstNumberColumn?.field || columns?.[0]?.field || "",
|
|
17301
|
-
label: "",
|
|
17302
|
-
format: firstNumberColumn?.format || columns?.[0]?.format || "string"
|
|
17303
|
-
}
|
|
17304
|
-
],
|
|
17305
|
-
xAxisLabel: "",
|
|
17306
|
-
chartType: firstNumberColumn ? "line" : "table",
|
|
17307
|
-
pivot: null,
|
|
17308
|
-
template: true,
|
|
17309
|
-
referenceLines: []
|
|
17310
|
-
};
|
|
17311
|
-
return formEmptyState;
|
|
17312
|
-
}
|
|
17313
|
-
|
|
17314
|
-
// src/utils/error.ts
|
|
17315
|
-
var DataLoadError = class extends Error {
|
|
17316
|
-
data;
|
|
17317
|
-
constructor(message, data) {
|
|
17318
|
-
super(message);
|
|
17319
|
-
this.name = "DataLoadError";
|
|
17320
|
-
this.data = data;
|
|
17321
|
-
}
|
|
17322
|
-
};
|
|
17323
|
-
|
|
17324
|
-
// src/utils/errorProcessing.ts
|
|
17325
|
-
function processFilterErrorList(resp) {
|
|
17326
|
-
if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
|
|
17327
|
-
return;
|
|
17328
|
-
}
|
|
17329
|
-
}
|
|
17330
|
-
|
|
17331
|
-
// src/utils/queryConstructor.ts
|
|
17332
|
-
function replaceBigQuerySpecialCharacters(column) {
|
|
17333
|
-
return column.replaceAll("/", "quill_forward_slash");
|
|
17334
|
-
}
|
|
17335
|
-
function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
|
|
17336
|
-
switch (databaseType.toLowerCase()) {
|
|
17337
|
-
case "postgresql":
|
|
17338
|
-
case "clickhouse": {
|
|
17339
|
-
if (column === "") {
|
|
17340
|
-
return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
|
|
17341
|
-
}
|
|
17342
|
-
if (isColumnFieldAlias) {
|
|
17343
|
-
return `"${column.replaceAll('"', "")}"`;
|
|
17344
|
-
}
|
|
17345
|
-
const columnParts = column.split(".");
|
|
17346
|
-
if (columnParts.length > 1) {
|
|
17347
|
-
return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
|
|
17348
|
-
}
|
|
17349
|
-
return `"${column.replaceAll('"', "")}"`;
|
|
16900
|
+
const columnParts = column.split(".");
|
|
16901
|
+
if (columnParts.length > 1) {
|
|
16902
|
+
return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
|
|
16903
|
+
}
|
|
16904
|
+
return `"${column.replaceAll('"', "")}"`;
|
|
17350
16905
|
}
|
|
17351
16906
|
case "mysql": {
|
|
17352
16907
|
if (column === "") {
|
|
@@ -17420,6 +16975,51 @@ function processColumnReference(column, databaseType, fallbackOnNull, isColumnFi
|
|
|
17420
16975
|
function replaceSpacesWithUnderscores(column) {
|
|
17421
16976
|
return column.replaceAll(" ", "_");
|
|
17422
16977
|
}
|
|
16978
|
+
function processInterval(interval2, rowField, databaseType) {
|
|
16979
|
+
if (["postgresql", "snowflake", "clickhouse"].includes(
|
|
16980
|
+
databaseType.toLowerCase()
|
|
16981
|
+
)) {
|
|
16982
|
+
return `(${processColumnReference(rowField, databaseType)} + INTERVAL '${interval2}')`;
|
|
16983
|
+
} else if (databaseType.toLowerCase() === "mysql") {
|
|
16984
|
+
return `(${processColumnReference(rowField, databaseType)} + INTERVAL ${interval2})`;
|
|
16985
|
+
}
|
|
16986
|
+
return `TIMESTAMP_ADD(${processColumnReference(rowField, databaseType)}, INTERVAL ${interval2} )`;
|
|
16987
|
+
}
|
|
16988
|
+
function processDateTrunc(dateBucket, rowField, databaseType, comparisonInterval) {
|
|
16989
|
+
const dateField = comparisonInterval ? processInterval(comparisonInterval, rowField, databaseType) : processColumnReference(rowField, databaseType);
|
|
16990
|
+
if (["postgresql", "snowflake"].includes(databaseType.toLowerCase())) {
|
|
16991
|
+
return `date_trunc('${dateBucket}', ${dateField})`;
|
|
16992
|
+
}
|
|
16993
|
+
if (["clickhouse"].includes(databaseType.toLowerCase())) {
|
|
16994
|
+
return `dateTrunc('${dateBucket}', ${dateField})`;
|
|
16995
|
+
}
|
|
16996
|
+
if (["databricks"].includes(databaseType.toLowerCase())) {
|
|
16997
|
+
return `DATE_TRUNC('${dateBucket}', ${dateField})`;
|
|
16998
|
+
}
|
|
16999
|
+
if (["mysql"].includes(databaseType.toLowerCase())) {
|
|
17000
|
+
switch (dateBucket.toLowerCase()) {
|
|
17001
|
+
case "year":
|
|
17002
|
+
return `DATE_FORMAT(${dateField}, '%Y-01-01 00:00:00')`;
|
|
17003
|
+
case "month":
|
|
17004
|
+
return `DATE_FORMAT(${dateField}, '%Y-%m-01 00:00:00')`;
|
|
17005
|
+
case "week":
|
|
17006
|
+
return `DATE_FORMAT(${dateField}, '%Y-%U-1 00:00:00')`;
|
|
17007
|
+
case "day":
|
|
17008
|
+
default:
|
|
17009
|
+
return `DATE(${dateField})`;
|
|
17010
|
+
}
|
|
17011
|
+
}
|
|
17012
|
+
if (["mssql"].includes(databaseType.toLowerCase())) {
|
|
17013
|
+
return `DATETRUNC(${dateBucket}, ${dateField})`;
|
|
17014
|
+
}
|
|
17015
|
+
return `TIMESTAMP_TRUNC(${dateField}, ${dateBucket})`;
|
|
17016
|
+
}
|
|
17017
|
+
function processValueField(aggType, databaseType, valueField) {
|
|
17018
|
+
if (aggType === "min" || aggType === "max" || aggType?.toLowerCase() === "average")
|
|
17019
|
+
return `${processColumnReference(valueField, databaseType)} ELSE null`;
|
|
17020
|
+
if (aggType === "count") return `1 ELSE 0`;
|
|
17021
|
+
return valueField ? `${processColumnReference(valueField, databaseType)} ELSE 0` : `1 ELSE 0`;
|
|
17022
|
+
}
|
|
17423
17023
|
function generateCountQuery(fields, query, databaseType) {
|
|
17424
17024
|
let countQuery = [];
|
|
17425
17025
|
let cteQuery = `WITH querytable AS (${query.replace(";", "")}) `;
|
|
@@ -17538,12 +17138,1123 @@ function generateMinMaxDateRangeQueries(columnFields, query, databaseType) {
|
|
|
17538
17138
|
const distinctQueries = columnFields.map((field) => {
|
|
17539
17139
|
const wrappedField = ["postgresql", "clickhouse"].includes(
|
|
17540
17140
|
databaseType.toLowerCase()
|
|
17541
|
-
) ?
|
|
17542
|
-
return `SELECT '${field}' AS
|
|
17141
|
+
) ? `"${field}"` : field;
|
|
17142
|
+
return `SELECT '${field}' AS field, ${min2}(${wrappedField})${cast} AS min_range, ${max2}(${wrappedField})${cast} AS max_range FROM querytable`;
|
|
17543
17143
|
});
|
|
17544
17144
|
const distinctQuery = distinctQueries.join(" UNION ALL ");
|
|
17545
17145
|
return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
|
|
17546
17146
|
}
|
|
17147
|
+
function generatePivotQuery(pivot, itemQuery, databaseType, distinctStrings, dateBucket) {
|
|
17148
|
+
if (!isValidPivot(pivot).valid) {
|
|
17149
|
+
return void 0;
|
|
17150
|
+
}
|
|
17151
|
+
if (pivot.columnField && distinctStrings && distinctStrings.length > 0) {
|
|
17152
|
+
return create2DPivotQuery(
|
|
17153
|
+
pivot,
|
|
17154
|
+
itemQuery,
|
|
17155
|
+
databaseType,
|
|
17156
|
+
distinctStrings,
|
|
17157
|
+
dateBucket
|
|
17158
|
+
);
|
|
17159
|
+
}
|
|
17160
|
+
if (pivot.rowField) {
|
|
17161
|
+
return create1DPivotQuery(pivot, itemQuery, dateBucket, databaseType);
|
|
17162
|
+
}
|
|
17163
|
+
return createAggregationValuePivot(pivot, itemQuery, databaseType);
|
|
17164
|
+
}
|
|
17165
|
+
function create2DPivotQuery(pivot, itemQuery, databaseType, columnFieldValues, dateBucket) {
|
|
17166
|
+
if (!pivot || !pivot.columnField) {
|
|
17167
|
+
return void 0;
|
|
17168
|
+
}
|
|
17169
|
+
if (isStringType(pivot.rowFieldType ?? "") || !pivot.rowFieldType) {
|
|
17170
|
+
return create2DStringPivotQuery(
|
|
17171
|
+
pivot,
|
|
17172
|
+
itemQuery,
|
|
17173
|
+
columnFieldValues,
|
|
17174
|
+
databaseType
|
|
17175
|
+
);
|
|
17176
|
+
}
|
|
17177
|
+
return create2DDatePivotQuery(
|
|
17178
|
+
pivot,
|
|
17179
|
+
itemQuery,
|
|
17180
|
+
columnFieldValues,
|
|
17181
|
+
databaseType,
|
|
17182
|
+
dateBucket
|
|
17183
|
+
);
|
|
17184
|
+
}
|
|
17185
|
+
function create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType) {
|
|
17186
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17187
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17188
|
+
);
|
|
17189
|
+
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField)
|
|
17190
|
+
return void 0;
|
|
17191
|
+
const rowField = pivot.rowField;
|
|
17192
|
+
if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
|
|
17193
|
+
throw new Error("No value field provided for pivot");
|
|
17194
|
+
if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
|
|
17195
|
+
throw new Error("No aggregation type provided for pivot");
|
|
17196
|
+
const columnField = pivot.columnField;
|
|
17197
|
+
const rowFieldAlias = processColumnReference(
|
|
17198
|
+
rowField,
|
|
17199
|
+
databaseType,
|
|
17200
|
+
void 0,
|
|
17201
|
+
false,
|
|
17202
|
+
true
|
|
17203
|
+
);
|
|
17204
|
+
const columnFieldAlias = processColumnReference(
|
|
17205
|
+
columnField,
|
|
17206
|
+
databaseType,
|
|
17207
|
+
void 0,
|
|
17208
|
+
false,
|
|
17209
|
+
true
|
|
17210
|
+
);
|
|
17211
|
+
let caseWhens = [];
|
|
17212
|
+
let valueAliases = [];
|
|
17213
|
+
const seenAggs = {};
|
|
17214
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17215
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17216
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17217
|
+
} else {
|
|
17218
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17219
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17220
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17221
|
+
};
|
|
17222
|
+
}
|
|
17223
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
|
|
17224
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17225
|
+
const valueFieldAlias = processColumnReference(
|
|
17226
|
+
currentAgg.valueField || rowField || "count",
|
|
17227
|
+
databaseType,
|
|
17228
|
+
void 0,
|
|
17229
|
+
false,
|
|
17230
|
+
true
|
|
17231
|
+
);
|
|
17232
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17233
|
+
let value2AliasSubstring = "";
|
|
17234
|
+
const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
|
|
17235
|
+
(acc, v) => acc + v
|
|
17236
|
+
) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
|
|
17237
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
|
|
17238
|
+
const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
|
|
17239
|
+
currentAgg.aggregationType,
|
|
17240
|
+
databaseType,
|
|
17241
|
+
valueFieldAlias
|
|
17242
|
+
);
|
|
17243
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17244
|
+
if (!currentAgg.valueField)
|
|
17245
|
+
throw new Error("No value field provided for pivot");
|
|
17246
|
+
const valueField2Alias = processColumnReference(
|
|
17247
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17248
|
+
databaseType,
|
|
17249
|
+
void 0,
|
|
17250
|
+
false,
|
|
17251
|
+
true
|
|
17252
|
+
);
|
|
17253
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17254
|
+
if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
|
|
17255
|
+
caseWhens = [
|
|
17256
|
+
...caseWhens,
|
|
17257
|
+
...columnFieldValues.map((column) => {
|
|
17258
|
+
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17259
|
+
column,
|
|
17260
|
+
databaseType
|
|
17261
|
+
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
|
|
17262
|
+
column + disambiguation,
|
|
17263
|
+
databaseType,
|
|
17264
|
+
"_",
|
|
17265
|
+
true
|
|
17266
|
+
)}`;
|
|
17267
|
+
})
|
|
17268
|
+
];
|
|
17269
|
+
} else {
|
|
17270
|
+
value2AliasSubstring = `${processColumnReference(
|
|
17271
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17272
|
+
databaseType,
|
|
17273
|
+
void 0,
|
|
17274
|
+
true
|
|
17275
|
+
)} AS ${valueField2Alias}`;
|
|
17276
|
+
caseWhens = [
|
|
17277
|
+
...caseWhens,
|
|
17278
|
+
...columnFieldValues.map((column) => {
|
|
17279
|
+
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17280
|
+
column,
|
|
17281
|
+
databaseType
|
|
17282
|
+
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17283
|
+
column,
|
|
17284
|
+
databaseType
|
|
17285
|
+
)}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
|
|
17286
|
+
column + disambiguation,
|
|
17287
|
+
databaseType,
|
|
17288
|
+
"_",
|
|
17289
|
+
true
|
|
17290
|
+
)}`;
|
|
17291
|
+
})
|
|
17292
|
+
];
|
|
17293
|
+
}
|
|
17294
|
+
} else {
|
|
17295
|
+
caseWhens = [
|
|
17296
|
+
...caseWhens,
|
|
17297
|
+
...columnFieldValues.map((column) => {
|
|
17298
|
+
return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17299
|
+
column,
|
|
17300
|
+
databaseType
|
|
17301
|
+
)}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
|
|
17302
|
+
})
|
|
17303
|
+
];
|
|
17304
|
+
}
|
|
17305
|
+
if (valueAliasSubstring) valueAliases.push(valueAliasSubstring);
|
|
17306
|
+
if (value2AliasSubstring) valueAliases.push(value2AliasSubstring);
|
|
17307
|
+
});
|
|
17308
|
+
valueAliases = [
|
|
17309
|
+
`${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
|
|
17310
|
+
...valueAliases,
|
|
17311
|
+
`${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
|
|
17312
|
+
];
|
|
17313
|
+
valueAliases = Array.from(new Set(valueAliases));
|
|
17314
|
+
const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
|
|
17315
|
+
const pivotQuery = `
|
|
17316
|
+
,quill_alias AS (
|
|
17317
|
+
SELECT ${valueAliases.length > 0 ? `${valueAliases.join(", ")}` : ""}
|
|
17318
|
+
FROM quill_base_table
|
|
17319
|
+
),
|
|
17320
|
+
quill_qt_cw AS (
|
|
17321
|
+
SELECT ${rowFieldAlias}
|
|
17322
|
+
${caseWhens.length > 0 ? `, ${caseWhens.join(", ")}` : ""}
|
|
17323
|
+
FROM quill_alias
|
|
17324
|
+
GROUP BY ${rowFieldAlias}
|
|
17325
|
+
),
|
|
17326
|
+
quill_base_pivot AS (
|
|
17327
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
|
|
17328
|
+
FROM quill_qt_cw qt
|
|
17329
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17330
|
+
)
|
|
17331
|
+
SELECT * FROM quill_base_pivot
|
|
17332
|
+
`.replace(/\s+/g, " ").trim();
|
|
17333
|
+
return itemQuery.replace(
|
|
17334
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17335
|
+
pivotQuery
|
|
17336
|
+
);
|
|
17337
|
+
}
|
|
17338
|
+
function create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseType, dateBucket = "month") {
|
|
17339
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17340
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17341
|
+
);
|
|
17342
|
+
if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField) {
|
|
17343
|
+
return void 0;
|
|
17344
|
+
}
|
|
17345
|
+
if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
|
|
17346
|
+
throw new Error("No value field provided for pivot");
|
|
17347
|
+
if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
|
|
17348
|
+
throw new Error("No aggregation type provided for pivot");
|
|
17349
|
+
const rowField = pivot.rowField;
|
|
17350
|
+
const columnField = pivot.columnField;
|
|
17351
|
+
const rowFieldAlias = processColumnReference(
|
|
17352
|
+
rowField,
|
|
17353
|
+
databaseType,
|
|
17354
|
+
void 0,
|
|
17355
|
+
false,
|
|
17356
|
+
true
|
|
17357
|
+
);
|
|
17358
|
+
const columnFieldAlias = processColumnReference(
|
|
17359
|
+
columnField,
|
|
17360
|
+
databaseType,
|
|
17361
|
+
void 0,
|
|
17362
|
+
false,
|
|
17363
|
+
true
|
|
17364
|
+
);
|
|
17365
|
+
let caseWhens = [];
|
|
17366
|
+
let valueFieldAliases = [];
|
|
17367
|
+
const seenAggs = {};
|
|
17368
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17369
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17370
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17371
|
+
} else {
|
|
17372
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17373
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17374
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17375
|
+
};
|
|
17376
|
+
}
|
|
17377
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
|
|
17378
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17379
|
+
const valueFieldAlias = processColumnReference(
|
|
17380
|
+
currentAgg.valueField ?? rowField,
|
|
17381
|
+
databaseType,
|
|
17382
|
+
void 0,
|
|
17383
|
+
false,
|
|
17384
|
+
true
|
|
17385
|
+
);
|
|
17386
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17387
|
+
let value2AliasSubstring = "";
|
|
17388
|
+
const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
|
|
17389
|
+
(acc, v) => acc + v
|
|
17390
|
+
) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
|
|
17391
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
|
|
17392
|
+
const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
|
|
17393
|
+
currentAgg.aggregationType,
|
|
17394
|
+
databaseType,
|
|
17395
|
+
valueFieldAlias
|
|
17396
|
+
);
|
|
17397
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17398
|
+
if (!currentAgg.valueField)
|
|
17399
|
+
throw new Error("No value field provided for pivot");
|
|
17400
|
+
const valueField2Alias = processColumnReference(
|
|
17401
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17402
|
+
databaseType,
|
|
17403
|
+
void 0,
|
|
17404
|
+
false,
|
|
17405
|
+
true
|
|
17406
|
+
);
|
|
17407
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17408
|
+
if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
|
|
17409
|
+
caseWhens = [
|
|
17410
|
+
...caseWhens,
|
|
17411
|
+
...columnFieldValues.map((column) => {
|
|
17412
|
+
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17413
|
+
column,
|
|
17414
|
+
databaseType
|
|
17415
|
+
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
|
|
17416
|
+
column + disambiguation,
|
|
17417
|
+
databaseType,
|
|
17418
|
+
"_",
|
|
17419
|
+
true
|
|
17420
|
+
)}`;
|
|
17421
|
+
})
|
|
17422
|
+
];
|
|
17423
|
+
} else {
|
|
17424
|
+
value2AliasSubstring = `${processColumnReference(
|
|
17425
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17426
|
+
databaseType,
|
|
17427
|
+
void 0,
|
|
17428
|
+
true
|
|
17429
|
+
)} AS ${valueField2Alias}`;
|
|
17430
|
+
caseWhens = [
|
|
17431
|
+
...caseWhens,
|
|
17432
|
+
...columnFieldValues.map((column) => {
|
|
17433
|
+
return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17434
|
+
column,
|
|
17435
|
+
databaseType
|
|
17436
|
+
)}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17437
|
+
column,
|
|
17438
|
+
databaseType
|
|
17439
|
+
)}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
|
|
17440
|
+
column + disambiguation,
|
|
17441
|
+
databaseType,
|
|
17442
|
+
"_",
|
|
17443
|
+
true
|
|
17444
|
+
)}`;
|
|
17445
|
+
})
|
|
17446
|
+
];
|
|
17447
|
+
}
|
|
17448
|
+
} else {
|
|
17449
|
+
caseWhens = [
|
|
17450
|
+
...caseWhens,
|
|
17451
|
+
...columnFieldValues.map((column) => {
|
|
17452
|
+
return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
|
|
17453
|
+
column,
|
|
17454
|
+
databaseType
|
|
17455
|
+
)}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
|
|
17456
|
+
})
|
|
17457
|
+
];
|
|
17458
|
+
}
|
|
17459
|
+
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17460
|
+
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17461
|
+
});
|
|
17462
|
+
valueFieldAliases = [
|
|
17463
|
+
`${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
|
|
17464
|
+
...valueFieldAliases,
|
|
17465
|
+
`${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
|
|
17466
|
+
];
|
|
17467
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17468
|
+
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17469
|
+
const pivotQuery = `
|
|
17470
|
+
, quill_alias AS (SELECT ${valueFieldAliases.length > 0 ? `${valueFieldAliases.join(", ")}` : ""} FROM quill_base_table),
|
|
17471
|
+
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)}),
|
|
17472
|
+
quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17473
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
|
|
17474
|
+
SELECT * FROM quill_base_pivot
|
|
17475
|
+
`.replace(/\s+/g, " ").trim();
|
|
17476
|
+
return itemQuery.replace(
|
|
17477
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17478
|
+
pivotQuery
|
|
17479
|
+
);
|
|
17480
|
+
}
|
|
17481
|
+
function create1DPivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
|
|
17482
|
+
if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
|
|
17483
|
+
return create1DStringPivotQuery(pivot, itemQuery, databaseType);
|
|
17484
|
+
}
|
|
17485
|
+
return create1DDatePivotQuery(pivot, itemQuery, dateBucket, databaseType);
|
|
17486
|
+
}
|
|
17487
|
+
function create1DStringPivotQuery(pivot, itemQuery, databaseType) {
|
|
17488
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17489
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17490
|
+
);
|
|
17491
|
+
if (!isValidBaseQuery) return void 0;
|
|
17492
|
+
const rowField = pivot.rowField;
|
|
17493
|
+
const rowAlias = processColumnReference(
|
|
17494
|
+
rowField,
|
|
17495
|
+
databaseType,
|
|
17496
|
+
void 0,
|
|
17497
|
+
true
|
|
17498
|
+
);
|
|
17499
|
+
let quillAggSelects = [rowAlias];
|
|
17500
|
+
let valueFieldAliases = [];
|
|
17501
|
+
const seenAggs = {};
|
|
17502
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17503
|
+
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17504
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17505
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17506
|
+
} else {
|
|
17507
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17508
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17509
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17510
|
+
};
|
|
17511
|
+
}
|
|
17512
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17513
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17514
|
+
const valueFieldAlias = processColumnReference(
|
|
17515
|
+
currentAgg.valueField || rowField || "count",
|
|
17516
|
+
databaseType,
|
|
17517
|
+
void 0,
|
|
17518
|
+
false,
|
|
17519
|
+
true
|
|
17520
|
+
);
|
|
17521
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17522
|
+
let value2AliasSubstring = "";
|
|
17523
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
|
|
17524
|
+
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17525
|
+
if (currentAgg.valueFieldType === "bool") {
|
|
17526
|
+
valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
|
|
17527
|
+
}
|
|
17528
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17529
|
+
let countPercentage = false;
|
|
17530
|
+
if (!currentAgg.valueField) {
|
|
17531
|
+
countPercentage = true;
|
|
17532
|
+
}
|
|
17533
|
+
const valueField2Alias = processColumnReference(
|
|
17534
|
+
currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
|
|
17535
|
+
databaseType,
|
|
17536
|
+
void 0,
|
|
17537
|
+
false,
|
|
17538
|
+
true
|
|
17539
|
+
);
|
|
17540
|
+
let value2Expr = valueField2Alias;
|
|
17541
|
+
if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
|
|
17542
|
+
value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
|
|
17543
|
+
}
|
|
17544
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17545
|
+
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)`;
|
|
17546
|
+
quillAggSelects = [
|
|
17547
|
+
...quillAggSelects,
|
|
17548
|
+
`${percentageExpr} as ${processColumnReference(
|
|
17549
|
+
`${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
|
|
17550
|
+
databaseType,
|
|
17551
|
+
void 0,
|
|
17552
|
+
false,
|
|
17553
|
+
true
|
|
17554
|
+
)}`
|
|
17555
|
+
];
|
|
17556
|
+
} else {
|
|
17557
|
+
quillAggSelects = [
|
|
17558
|
+
...quillAggSelects,
|
|
17559
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
|
|
17560
|
+
(currentAgg.valueField || "count") + disambiguation,
|
|
17561
|
+
databaseType
|
|
17562
|
+
)}`
|
|
17563
|
+
];
|
|
17564
|
+
}
|
|
17565
|
+
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17566
|
+
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17567
|
+
});
|
|
17568
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17569
|
+
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17570
|
+
const pivotQuery = `, quill_alias AS (
|
|
17571
|
+
SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
|
|
17572
|
+
FROM quill_base_table
|
|
17573
|
+
),
|
|
17574
|
+
quill_qt_cw AS (
|
|
17575
|
+
SELECT ${quillAggSelects.join(", ")} FROM quill_alias GROUP BY ${rowAlias}
|
|
17576
|
+
),
|
|
17577
|
+
quill_base_pivot AS (
|
|
17578
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
|
|
17579
|
+
FROM quill_qt_cw qt ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17580
|
+
)
|
|
17581
|
+
SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
|
|
17582
|
+
return itemQuery.replace(
|
|
17583
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17584
|
+
pivotQuery
|
|
17585
|
+
);
|
|
17586
|
+
}
|
|
17587
|
+
function create1DDatePivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
|
|
17588
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17589
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17590
|
+
);
|
|
17591
|
+
if (!isValidBaseQuery) {
|
|
17592
|
+
return void 0;
|
|
17593
|
+
}
|
|
17594
|
+
const rowField = pivot.rowField || "";
|
|
17595
|
+
const rowFieldAlias = processColumnReference(
|
|
17596
|
+
rowField,
|
|
17597
|
+
databaseType,
|
|
17598
|
+
void 0
|
|
17599
|
+
);
|
|
17600
|
+
let quillAggSelects = [
|
|
17601
|
+
`${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(rowField, databaseType)}`
|
|
17602
|
+
];
|
|
17603
|
+
let valueFieldAliases = [];
|
|
17604
|
+
const seenAggs = {};
|
|
17605
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17606
|
+
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17607
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17608
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17609
|
+
} else {
|
|
17610
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17611
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17612
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17613
|
+
};
|
|
17614
|
+
}
|
|
17615
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17616
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17617
|
+
const valueFieldAlias = processColumnReference(
|
|
17618
|
+
currentAgg.valueField || rowField || "count",
|
|
17619
|
+
databaseType,
|
|
17620
|
+
void 0,
|
|
17621
|
+
false,
|
|
17622
|
+
true
|
|
17623
|
+
);
|
|
17624
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17625
|
+
let value2AliasSubstring = "";
|
|
17626
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
|
|
17627
|
+
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17628
|
+
if (currentAgg.valueFieldType === "bool") {
|
|
17629
|
+
valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
|
|
17630
|
+
}
|
|
17631
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17632
|
+
let countPercentage = false;
|
|
17633
|
+
if (!currentAgg.valueField) {
|
|
17634
|
+
countPercentage = true;
|
|
17635
|
+
}
|
|
17636
|
+
const valueField2Alias = processColumnReference(
|
|
17637
|
+
currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
|
|
17638
|
+
databaseType,
|
|
17639
|
+
void 0,
|
|
17640
|
+
false,
|
|
17641
|
+
true
|
|
17642
|
+
);
|
|
17643
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17644
|
+
let value2Expr = valueField2Alias;
|
|
17645
|
+
if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
|
|
17646
|
+
value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
|
|
17647
|
+
}
|
|
17648
|
+
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)`;
|
|
17649
|
+
quillAggSelects = [
|
|
17650
|
+
...quillAggSelects,
|
|
17651
|
+
`${percentageExpr} as ${processColumnReference(
|
|
17652
|
+
`${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
|
|
17653
|
+
databaseType,
|
|
17654
|
+
void 0,
|
|
17655
|
+
false,
|
|
17656
|
+
true
|
|
17657
|
+
)}`
|
|
17658
|
+
];
|
|
17659
|
+
} else {
|
|
17660
|
+
quillAggSelects = [
|
|
17661
|
+
...quillAggSelects,
|
|
17662
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference((currentAgg.valueField || "count") + disambiguation, databaseType)}`
|
|
17663
|
+
];
|
|
17664
|
+
}
|
|
17665
|
+
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17666
|
+
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17667
|
+
});
|
|
17668
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17669
|
+
const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
|
|
17670
|
+
const pivotQuery = `, quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowFieldAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
|
|
17671
|
+
FROM quill_base_table),
|
|
17672
|
+
quill_qt_agg AS (SELECT ${quillAggSelects.join(", ")}
|
|
17673
|
+
FROM quill_alias GROUP BY ${databaseType.toLowerCase() === "clickhouse" ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
|
|
17674
|
+
quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17675
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
|
|
17676
|
+
SELECT * FROM quill_base_pivot
|
|
17677
|
+
`.replace(/\s+/g, " ").trim();
|
|
17678
|
+
return itemQuery.replace(
|
|
17679
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17680
|
+
pivotQuery
|
|
17681
|
+
);
|
|
17682
|
+
}
|
|
17683
|
+
function createAggregationValuePivot(pivot, itemQuery, databaseType) {
|
|
17684
|
+
const isValidBaseQuery = itemQuery.match(
|
|
17685
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
|
|
17686
|
+
);
|
|
17687
|
+
if (!isValidBaseQuery) return void 0;
|
|
17688
|
+
let quillAggSelects = [];
|
|
17689
|
+
let valueFieldAliases = [];
|
|
17690
|
+
const seenAggs = {};
|
|
17691
|
+
pivot.aggregations?.forEach((currentAgg) => {
|
|
17692
|
+
if (!currentAgg.valueField) currentAgg.valueField = void 0;
|
|
17693
|
+
if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
|
|
17694
|
+
seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
|
|
17695
|
+
} else {
|
|
17696
|
+
seenAggs[currentAgg.aggregationType ?? ""] = {
|
|
17697
|
+
...seenAggs[currentAgg.aggregationType ?? ""],
|
|
17698
|
+
[currentAgg.valueField ?? ""]: 1
|
|
17699
|
+
};
|
|
17700
|
+
}
|
|
17701
|
+
let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
|
|
17702
|
+
if (disambiguationIndex === "1") disambiguationIndex = "";
|
|
17703
|
+
const valueFieldAlias = processColumnReference(
|
|
17704
|
+
currentAgg.valueField || "count",
|
|
17705
|
+
databaseType,
|
|
17706
|
+
void 0,
|
|
17707
|
+
false,
|
|
17708
|
+
true
|
|
17709
|
+
);
|
|
17710
|
+
const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
|
|
17711
|
+
let value2AliasSubstring = "";
|
|
17712
|
+
const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}_${currentAgg.aggregationType}` : "";
|
|
17713
|
+
let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
|
|
17714
|
+
valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : valueExpr;
|
|
17715
|
+
if (currentAgg.aggregationType === "percentage") {
|
|
17716
|
+
if (!currentAgg.valueField) {
|
|
17717
|
+
throw new Error("No value field provided for percentage aggregation");
|
|
17718
|
+
}
|
|
17719
|
+
const valueField2Alias = processColumnReference(
|
|
17720
|
+
currentAgg.valueField2 ?? currentAgg.valueField,
|
|
17721
|
+
databaseType,
|
|
17722
|
+
void 0,
|
|
17723
|
+
false,
|
|
17724
|
+
true
|
|
17725
|
+
);
|
|
17726
|
+
const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
|
|
17727
|
+
value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
|
|
17728
|
+
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)`;
|
|
17729
|
+
quillAggSelects = [
|
|
17730
|
+
...quillAggSelects,
|
|
17731
|
+
`${percentageExpr} as ${processColumnReference(
|
|
17732
|
+
`${currentAgg.valueField ?? ""}${disambiguation}`,
|
|
17733
|
+
databaseType,
|
|
17734
|
+
void 0,
|
|
17735
|
+
false,
|
|
17736
|
+
true
|
|
17737
|
+
)}`
|
|
17738
|
+
];
|
|
17739
|
+
} else {
|
|
17740
|
+
quillAggSelects = [
|
|
17741
|
+
...quillAggSelects,
|
|
17742
|
+
`${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
|
|
17743
|
+
(currentAgg.valueField || "count") + disambiguation,
|
|
17744
|
+
databaseType
|
|
17745
|
+
)}`
|
|
17746
|
+
];
|
|
17747
|
+
}
|
|
17748
|
+
if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
|
|
17749
|
+
if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
|
|
17750
|
+
});
|
|
17751
|
+
valueFieldAliases = Array.from(new Set(valueFieldAliases));
|
|
17752
|
+
if (valueFieldAliases.length === 0) {
|
|
17753
|
+
valueFieldAliases = ["*"];
|
|
17754
|
+
}
|
|
17755
|
+
const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
|
|
17756
|
+
const pivotQuery = `, quill_alias AS (
|
|
17757
|
+
SELECT ${valueFieldAliases.join(", ")} FROM quill_base_table
|
|
17758
|
+
),
|
|
17759
|
+
quill_qt_agg AS (
|
|
17760
|
+
SELECT ${quillAggSelects.join(", ")} FROM quill_alias
|
|
17761
|
+
),
|
|
17762
|
+
quill_base_pivot AS (
|
|
17763
|
+
SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
|
|
17764
|
+
${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
|
|
17765
|
+
)
|
|
17766
|
+
SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
|
|
17767
|
+
return itemQuery.replace(
|
|
17768
|
+
/SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
|
|
17769
|
+
pivotQuery
|
|
17770
|
+
);
|
|
17771
|
+
}
|
|
17772
|
+
function additionalProcessingOnPivotQuery(pivot, query, additionalProcessing, databaseType = "postgresql") {
|
|
17773
|
+
if (!additionalProcessing || !query) return query;
|
|
17774
|
+
const isValidBaseQuery = query.match(
|
|
17775
|
+
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
|
|
17776
|
+
);
|
|
17777
|
+
if (!isValidBaseQuery) {
|
|
17778
|
+
return void 0;
|
|
17779
|
+
}
|
|
17780
|
+
if (!pivot.aggregations || pivot.aggregations.length === 0) {
|
|
17781
|
+
if (pivot.aggregationType) {
|
|
17782
|
+
pivot.aggregations = [
|
|
17783
|
+
{
|
|
17784
|
+
aggregationType: pivot.aggregationType,
|
|
17785
|
+
valueField: pivot.valueField,
|
|
17786
|
+
valueField2: pivot.valueField2
|
|
17787
|
+
}
|
|
17788
|
+
];
|
|
17789
|
+
} else {
|
|
17790
|
+
throw new Error("No aggregations provided for pivot");
|
|
17791
|
+
}
|
|
17792
|
+
}
|
|
17793
|
+
let rowsPerPage = 0;
|
|
17794
|
+
let currentInterval = 0;
|
|
17795
|
+
let offset = 0;
|
|
17796
|
+
let limit = 1e3;
|
|
17797
|
+
let sortQuery = "";
|
|
17798
|
+
if (additionalProcessing.page) {
|
|
17799
|
+
const page = additionalProcessing.page.page || 0;
|
|
17800
|
+
if (additionalProcessing.page.rowsPerRequest) {
|
|
17801
|
+
limit = additionalProcessing.page.rowsPerRequest;
|
|
17802
|
+
}
|
|
17803
|
+
rowsPerPage = additionalProcessing.page.rowsPerPage || 0;
|
|
17804
|
+
currentInterval = page ? Math.floor(page / (limit / rowsPerPage)) : 0;
|
|
17805
|
+
offset = currentInterval * limit;
|
|
17806
|
+
}
|
|
17807
|
+
const disambiguation = pivot.aggregations.length > 1 ? `_${matchCasing(pivot.aggregations?.[0]?.aggregationType, pivot.aggregations?.[0]?.valueField)}` : "";
|
|
17808
|
+
if (additionalProcessing.sort) {
|
|
17809
|
+
sortQuery = `ORDER BY ${processColumnReference(additionalProcessing.sort.field, databaseType, void 0, true)} ${additionalProcessing.sort.direction || ""}`;
|
|
17810
|
+
} else {
|
|
17811
|
+
const valueFieldAlias = processColumnReference(
|
|
17812
|
+
(pivot.aggregations?.[0]?.valueField ?? "") + disambiguation,
|
|
17813
|
+
databaseType,
|
|
17814
|
+
void 0,
|
|
17815
|
+
false,
|
|
17816
|
+
true
|
|
17817
|
+
);
|
|
17818
|
+
const defaultSortField = pivot.sortField || pivot.rowField || valueFieldAlias;
|
|
17819
|
+
const defaultSortDirection = pivot.sortDirection || "";
|
|
17820
|
+
if (defaultSortField !== `"_"`) {
|
|
17821
|
+
sortQuery = `ORDER BY ${processColumnReference(defaultSortField, databaseType, void 0, true)} ${defaultSortDirection}`;
|
|
17822
|
+
} else {
|
|
17823
|
+
sortQuery = "";
|
|
17824
|
+
}
|
|
17825
|
+
}
|
|
17826
|
+
const additionalProcessingQuery = `
|
|
17827
|
+
SELECT *
|
|
17828
|
+
FROM quill_base_pivot ${sortQuery}${databaseType.toLowerCase() === "mssql" ? ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY` : ` LIMIT ${limit} OFFSET ${offset}`}
|
|
17829
|
+
`.replace(/\s+/g, " ").trim();
|
|
17830
|
+
return query.replace(
|
|
17831
|
+
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
|
|
17832
|
+
additionalProcessingQuery
|
|
17833
|
+
);
|
|
17834
|
+
}
|
|
17835
|
+
function generateRowCountQuery(query, databaseType) {
|
|
17836
|
+
if (!query) return query;
|
|
17837
|
+
const isValidBaseQuery = query.match(
|
|
17838
|
+
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
|
|
17839
|
+
);
|
|
17840
|
+
if (!isValidBaseQuery) {
|
|
17841
|
+
return void 0;
|
|
17842
|
+
}
|
|
17843
|
+
const rowCountQuery = `, subview_row_count_cte AS (SELECT * FROM quill_base_pivot)
|
|
17844
|
+
SELECT count(*) as ${processColumnReference("row_count", databaseType || "postgresql", void 0, true)} FROM subview_row_count_cte
|
|
17845
|
+
`.replace(/\s+/g, " ").trim();
|
|
17846
|
+
return query.replace(
|
|
17847
|
+
/SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
|
|
17848
|
+
rowCountQuery
|
|
17849
|
+
);
|
|
17850
|
+
}
|
|
17851
|
+
|
|
17852
|
+
// src/utils/pivotConstructor.ts
|
|
17853
|
+
async function generatePivotWithSQL({
|
|
17854
|
+
pivot,
|
|
17855
|
+
report,
|
|
17856
|
+
client,
|
|
17857
|
+
dateBucket,
|
|
17858
|
+
dateFilter,
|
|
17859
|
+
distinctStrings,
|
|
17860
|
+
dashboardName,
|
|
17861
|
+
tenants,
|
|
17862
|
+
additionalProcessing,
|
|
17863
|
+
pivotQuery,
|
|
17864
|
+
comparisonPivotQuery,
|
|
17865
|
+
getPivotRowCount = true,
|
|
17866
|
+
caller,
|
|
17867
|
+
getToken
|
|
17868
|
+
}) {
|
|
17869
|
+
let sqlQuery = pivotQuery;
|
|
17870
|
+
let comparisonPivotSql = comparisonPivotQuery;
|
|
17871
|
+
const databaseType = client.databaseType || "postgresql";
|
|
17872
|
+
if (!pivotQuery && pivot.columnField && !pivot.columnValues && !distinctStrings) {
|
|
17873
|
+
if (!report?.rows) {
|
|
17874
|
+
throw new Error("No distinct strings provided for column field");
|
|
17875
|
+
} else {
|
|
17876
|
+
distinctStrings = Array.from(
|
|
17877
|
+
new Set(
|
|
17878
|
+
report.rows.map((row) => row[pivot.columnField]).filter((value) => value !== null && value !== void 0)
|
|
17879
|
+
)
|
|
17880
|
+
);
|
|
17881
|
+
}
|
|
17882
|
+
}
|
|
17883
|
+
if (!pivot.aggregations?.length && pivot.aggregationType) {
|
|
17884
|
+
pivot.aggregations = [
|
|
17885
|
+
{
|
|
17886
|
+
aggregationType: pivot.aggregationType,
|
|
17887
|
+
valueField: pivot.valueField,
|
|
17888
|
+
valueFieldType: pivot.valueFieldType,
|
|
17889
|
+
valueField2: pivot.valueField2,
|
|
17890
|
+
valueField2Type: pivot.valueField2Type
|
|
17891
|
+
}
|
|
17892
|
+
];
|
|
17893
|
+
}
|
|
17894
|
+
let comparisonInterval = void 0;
|
|
17895
|
+
if (dateFilter && dateFilter.comparisonRange) {
|
|
17896
|
+
comparisonInterval = getComparisonInterval(
|
|
17897
|
+
{
|
|
17898
|
+
startDate: dateFilter.comparisonRange.startDate,
|
|
17899
|
+
endDate: dateFilter.comparisonRange.endDate
|
|
17900
|
+
},
|
|
17901
|
+
dateBucket
|
|
17902
|
+
);
|
|
17903
|
+
}
|
|
17904
|
+
if (pivot.rowField && !pivot.rowFieldType) {
|
|
17905
|
+
const rowColumn = report?.columns.find(
|
|
17906
|
+
(column) => column.field === pivot.rowField
|
|
17907
|
+
);
|
|
17908
|
+
pivot.rowFieldType = rowColumn?.format || "string";
|
|
17909
|
+
}
|
|
17910
|
+
const filteredDistinctStrings = distinctStrings?.filter(
|
|
17911
|
+
(value) => value !== null && value !== void 0 && value !== ""
|
|
17912
|
+
);
|
|
17913
|
+
const pivotColumnFields = filteredDistinctStrings?.slice(
|
|
17914
|
+
0,
|
|
17915
|
+
MAX_PIVOT_UNIQUE_VALUES
|
|
17916
|
+
);
|
|
17917
|
+
if (!pivotQuery && report) {
|
|
17918
|
+
if (!report.itemQuery) {
|
|
17919
|
+
throw Error("No item query found in report");
|
|
17920
|
+
}
|
|
17921
|
+
const itemQuery = report.itemQuery[0];
|
|
17922
|
+
const comparisonQuery = report.itemQuery[1];
|
|
17923
|
+
if (!itemQuery) {
|
|
17924
|
+
throw Error("No item query found in report");
|
|
17925
|
+
}
|
|
17926
|
+
sqlQuery = generatePivotQuery(
|
|
17927
|
+
pivot,
|
|
17928
|
+
itemQuery,
|
|
17929
|
+
databaseType,
|
|
17930
|
+
pivotColumnFields,
|
|
17931
|
+
dateBucket
|
|
17932
|
+
);
|
|
17933
|
+
comparisonPivotSql = comparisonQuery ? generatePivotQuery(
|
|
17934
|
+
pivot,
|
|
17935
|
+
comparisonQuery,
|
|
17936
|
+
databaseType,
|
|
17937
|
+
pivotColumnFields,
|
|
17938
|
+
dateBucket
|
|
17939
|
+
) : "";
|
|
17940
|
+
}
|
|
17941
|
+
if (!sqlQuery) {
|
|
17942
|
+
throw "Error generating pivot query";
|
|
17943
|
+
}
|
|
17944
|
+
const paginatedSqlQuery = additionalProcessingOnPivotQuery(
|
|
17945
|
+
pivot,
|
|
17946
|
+
sqlQuery,
|
|
17947
|
+
additionalProcessing,
|
|
17948
|
+
client.databaseType
|
|
17949
|
+
);
|
|
17950
|
+
const paginatedComparisonQuery = comparisonPivotSql ? additionalProcessingOnPivotQuery(
|
|
17951
|
+
pivot,
|
|
17952
|
+
comparisonPivotSql,
|
|
17953
|
+
additionalProcessing,
|
|
17954
|
+
client.databaseType
|
|
17955
|
+
) : "";
|
|
17956
|
+
const preQueries = [paginatedSqlQuery];
|
|
17957
|
+
getPivotRowCount = getPivotRowCount && (report?.chartType === "table" || caller === "ReportBuilder");
|
|
17958
|
+
if (getPivotRowCount) {
|
|
17959
|
+
const pivotRowCountQuery = generateRowCountQuery(
|
|
17960
|
+
sqlQuery,
|
|
17961
|
+
client.databaseType
|
|
17962
|
+
);
|
|
17963
|
+
preQueries.push(pivotRowCountQuery);
|
|
17964
|
+
}
|
|
17965
|
+
if (paginatedComparisonQuery) {
|
|
17966
|
+
preQueries.push(paginatedComparisonQuery);
|
|
17967
|
+
}
|
|
17968
|
+
const { data: resp } = await quillFetch({
|
|
17969
|
+
client,
|
|
17970
|
+
task: "query",
|
|
17971
|
+
metadata: {
|
|
17972
|
+
preQueries,
|
|
17973
|
+
clientId: client.publicKey,
|
|
17974
|
+
databaseType,
|
|
17975
|
+
runQueryConfig: {
|
|
17976
|
+
overridePost: true,
|
|
17977
|
+
convertDatatypes: true
|
|
17978
|
+
},
|
|
17979
|
+
useNewNodeSql: true,
|
|
17980
|
+
dashboardName,
|
|
17981
|
+
tenants
|
|
17982
|
+
},
|
|
17983
|
+
urlParameters: `caller=generatePivot&task=query`,
|
|
17984
|
+
credentials: "same-origin",
|
|
17985
|
+
getToken
|
|
17986
|
+
});
|
|
17987
|
+
if (resp.success === false) {
|
|
17988
|
+
throw resp.errorMessage;
|
|
17989
|
+
}
|
|
17990
|
+
const queryResponseRows = resp?.queryResults?.[0]?.rows || [];
|
|
17991
|
+
const queryResponseFields = resp?.queryResults?.[0]?.fields || [];
|
|
17992
|
+
const queryComparisonResponseRows = (getPivotRowCount ? resp?.queryResults?.[2]?.rows : resp?.queryResults?.[1]?.rows) || [];
|
|
17993
|
+
const queryComparisonResponseFields = (getPivotRowCount ? resp?.queryResults?.[2]?.fields : resp?.queryResults?.[1]?.fields) || [];
|
|
17994
|
+
parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
|
|
17995
|
+
parseValueFromBigQueryDates(
|
|
17996
|
+
queryComparisonResponseRows,
|
|
17997
|
+
queryComparisonResponseFields
|
|
17998
|
+
);
|
|
17999
|
+
const responseRows = mergeComparisonPivotRows({
|
|
18000
|
+
pivot,
|
|
18001
|
+
rows: queryResponseRows,
|
|
18002
|
+
compRows: queryComparisonResponseRows,
|
|
18003
|
+
databaseType,
|
|
18004
|
+
dateBucket,
|
|
18005
|
+
comparisonInterval,
|
|
18006
|
+
columnFieldValues: pivotColumnFields
|
|
18007
|
+
});
|
|
18008
|
+
const responseFields = mergeComparisonPivotColumns({
|
|
18009
|
+
pivot,
|
|
18010
|
+
rows: queryResponseFields,
|
|
18011
|
+
compRows: queryComparisonResponseFields
|
|
18012
|
+
});
|
|
18013
|
+
const rows = pivot.rowField ? responseRows.map(
|
|
18014
|
+
(row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
|
|
18015
|
+
) : responseRows;
|
|
18016
|
+
if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
|
|
18017
|
+
rows.forEach((row) => {
|
|
18018
|
+
Object.keys(row).forEach((key) => {
|
|
18019
|
+
const processedKey = processColumnName(key);
|
|
18020
|
+
if (processedKey !== key) {
|
|
18021
|
+
row[processedKey] = row[key];
|
|
18022
|
+
delete row[key];
|
|
18023
|
+
}
|
|
18024
|
+
});
|
|
18025
|
+
});
|
|
18026
|
+
}
|
|
18027
|
+
const columns = responseFields?.map((field) => ({
|
|
18028
|
+
field: processColumnName(field.name),
|
|
18029
|
+
label: snakeCaseToTitleCase(
|
|
18030
|
+
processColumnName(field.name.replace("comparison_", "comparison "))
|
|
18031
|
+
),
|
|
18032
|
+
format: field.name === pivot.rowField ? "string" : (
|
|
18033
|
+
// This scary equation is calculating which aggregation a column is associated with.
|
|
18034
|
+
// 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.
|
|
18035
|
+
// pivot.aggregations?.[
|
|
18036
|
+
// Math.floor(
|
|
18037
|
+
// (index - 1) /
|
|
18038
|
+
// Math.floor(
|
|
18039
|
+
// (responseFields.length - 1) /
|
|
18040
|
+
// (pivot.aggregations?.length ?? 1),
|
|
18041
|
+
// ),
|
|
18042
|
+
// )
|
|
18043
|
+
// ]?.aggregationType === 'percentage'
|
|
18044
|
+
pivot.aggregations?.find(
|
|
18045
|
+
(agg) => agg.valueField === field.name || `${agg.valueField}_percentage` === field.name || !agg.valueField && agg.aggregationType === "percentage" && field.name.endsWith("percentage")
|
|
18046
|
+
)?.aggregationType === "percentage" ? "percent" : "whole_number"
|
|
18047
|
+
),
|
|
18048
|
+
fieldType: field.fieldType,
|
|
18049
|
+
jsType: field.jsType,
|
|
18050
|
+
dataTypeID: field.dataTypeID
|
|
18051
|
+
})).filter(
|
|
18052
|
+
(field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
|
|
18053
|
+
).sort((a, b) => {
|
|
18054
|
+
if (a.field === pivot.rowField) {
|
|
18055
|
+
return -1;
|
|
18056
|
+
}
|
|
18057
|
+
if (b.field === pivot.rowField) {
|
|
18058
|
+
return 1;
|
|
18059
|
+
}
|
|
18060
|
+
return 0;
|
|
18061
|
+
});
|
|
18062
|
+
if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
|
|
18063
|
+
rows.forEach((row) => {
|
|
18064
|
+
row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
18065
|
+
let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
|
|
18066
|
+
if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
|
|
18067
|
+
const rowDate = new Date(value);
|
|
18068
|
+
if (rowDate < dateFilter.startDate) {
|
|
18069
|
+
value = dateFilter.startDate.toISOString();
|
|
18070
|
+
} else if (rowDate > dateFilter.endDate) {
|
|
18071
|
+
value = dateFilter.endDate.toISOString();
|
|
18072
|
+
}
|
|
18073
|
+
}
|
|
18074
|
+
const dateString = getDateString(
|
|
18075
|
+
value,
|
|
18076
|
+
dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
|
|
18077
|
+
dateBucket,
|
|
18078
|
+
databaseType
|
|
18079
|
+
);
|
|
18080
|
+
row[pivot.rowField || ""] = dateString;
|
|
18081
|
+
});
|
|
18082
|
+
if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
|
|
18083
|
+
const dateSet = new Set(
|
|
18084
|
+
rows.map((row) => row[pivot.rowField || ""])
|
|
18085
|
+
);
|
|
18086
|
+
for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
|
|
18087
|
+
const formattedDate = getDateString(
|
|
18088
|
+
date.toISOString(),
|
|
18089
|
+
{ start: dateFilter.startDate, end: dateFilter.endDate },
|
|
18090
|
+
dateBucket,
|
|
18091
|
+
databaseType
|
|
18092
|
+
);
|
|
18093
|
+
if (!dateSet.has(formattedDate)) {
|
|
18094
|
+
const newRow = {};
|
|
18095
|
+
newRow[pivot.rowField] = formattedDate;
|
|
18096
|
+
newRow.__quillRawDate = date.toISOString();
|
|
18097
|
+
rows.push(newRow);
|
|
18098
|
+
dateSet.add(formattedDate);
|
|
18099
|
+
}
|
|
18100
|
+
}
|
|
18101
|
+
}
|
|
18102
|
+
if (!pivot.sort) {
|
|
18103
|
+
rows.sort((a, b) => {
|
|
18104
|
+
if (a.__quillRawDate < b.__quillRawDate) {
|
|
18105
|
+
return -1;
|
|
18106
|
+
}
|
|
18107
|
+
if (a.__quillRawDate > b.__quillRawDate) {
|
|
18108
|
+
return 1;
|
|
18109
|
+
}
|
|
18110
|
+
return 0;
|
|
18111
|
+
});
|
|
18112
|
+
}
|
|
18113
|
+
}
|
|
18114
|
+
columns?.forEach((column, index) => {
|
|
18115
|
+
if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
|
|
18116
|
+
column.label = "Count";
|
|
18117
|
+
}
|
|
18118
|
+
});
|
|
18119
|
+
const numericColumns = columns?.filter(
|
|
18120
|
+
(column) => column.format === "whole_number" || column.format === "percentage"
|
|
18121
|
+
);
|
|
18122
|
+
rows.forEach((row) => {
|
|
18123
|
+
numericColumns?.forEach((column) => {
|
|
18124
|
+
row[column.field] = row[column.field] ?? 0;
|
|
18125
|
+
});
|
|
18126
|
+
});
|
|
18127
|
+
return {
|
|
18128
|
+
rows,
|
|
18129
|
+
columns: columns ?? [],
|
|
18130
|
+
rowCount: getPivotRowCount ? Number(resp?.queryResults?.[1]?.rows?.[0]?.["row_count"]) ?? rows.length : 0,
|
|
18131
|
+
pivotQuery: sqlQuery,
|
|
18132
|
+
comparisonPivotQuery: comparisonPivotSql
|
|
18133
|
+
};
|
|
18134
|
+
}
|
|
18135
|
+
function generatePivotTableYAxis(pivot, cols, yAxisField) {
|
|
18136
|
+
if (pivot?.aggregationType === "count") {
|
|
18137
|
+
return [
|
|
18138
|
+
{
|
|
18139
|
+
field: pivot.valueField ?? "count",
|
|
18140
|
+
label: yAxisField.label,
|
|
18141
|
+
format: yAxisField.format
|
|
18142
|
+
}
|
|
18143
|
+
];
|
|
18144
|
+
}
|
|
18145
|
+
return [
|
|
18146
|
+
{
|
|
18147
|
+
field: pivot.valueField ?? "count",
|
|
18148
|
+
label: yAxisField.label,
|
|
18149
|
+
format: yAxisField.format
|
|
18150
|
+
}
|
|
18151
|
+
];
|
|
18152
|
+
}
|
|
18153
|
+
function generatePivotTitle(pivot) {
|
|
18154
|
+
if (pivot.rowField && !pivot.valueField && pivot.aggregations?.[0]) {
|
|
18155
|
+
return snakeAndCamelCaseToTitleCase(
|
|
18156
|
+
`${pivot.aggregations[0].aggregationType} of ${pivot.rowField}${pivot.columnField ? ` by ${pivot.columnField}` : ""}
|
|
18157
|
+
`
|
|
18158
|
+
);
|
|
18159
|
+
} else if (!pivot.rowField && pivot.aggregations?.[0]?.valueField) {
|
|
18160
|
+
return snakeAndCamelCaseToTitleCase(
|
|
18161
|
+
`${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
|
|
18162
|
+
`
|
|
18163
|
+
);
|
|
18164
|
+
}
|
|
18165
|
+
return snakeAndCamelCaseToTitleCase(
|
|
18166
|
+
`${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
|
|
18167
|
+
);
|
|
18168
|
+
}
|
|
18169
|
+
async function generatePivotTable({
|
|
18170
|
+
pivot,
|
|
18171
|
+
dateBucket,
|
|
18172
|
+
dateFilter,
|
|
18173
|
+
report,
|
|
18174
|
+
client,
|
|
18175
|
+
getToken,
|
|
18176
|
+
eventTracking,
|
|
18177
|
+
uniqueValues,
|
|
18178
|
+
dashboardName,
|
|
18179
|
+
tenants,
|
|
18180
|
+
additionalProcessing,
|
|
18181
|
+
caller,
|
|
18182
|
+
pivotQuery
|
|
18183
|
+
}) {
|
|
18184
|
+
try {
|
|
18185
|
+
if (report && client) {
|
|
18186
|
+
const pivotTable = await generatePivotWithSQL({
|
|
18187
|
+
pivotQuery,
|
|
18188
|
+
pivot,
|
|
18189
|
+
report,
|
|
18190
|
+
client,
|
|
18191
|
+
dateBucket,
|
|
18192
|
+
dateFilter,
|
|
18193
|
+
distinctStrings: pivot.columnField && uniqueValues?.[pivot.columnField] ? uniqueValues[pivot.columnField] : [],
|
|
18194
|
+
dashboardName,
|
|
18195
|
+
tenants,
|
|
18196
|
+
additionalProcessing,
|
|
18197
|
+
caller,
|
|
18198
|
+
getToken
|
|
18199
|
+
});
|
|
18200
|
+
return pivotTable;
|
|
18201
|
+
}
|
|
18202
|
+
} catch (e) {
|
|
18203
|
+
eventTracking?.logError?.({
|
|
18204
|
+
type: "bug",
|
|
18205
|
+
// TODO: determine type
|
|
18206
|
+
severity: "high",
|
|
18207
|
+
message: "Error generating pivot table",
|
|
18208
|
+
errorMessage: e.message,
|
|
18209
|
+
errorStack: e.stack,
|
|
18210
|
+
errorData: {
|
|
18211
|
+
caller: "PivotModal",
|
|
18212
|
+
function: "generatePivotTable"
|
|
18213
|
+
}
|
|
18214
|
+
});
|
|
18215
|
+
throw Error(`Failed to generate pivot table with SQL: ${e}`);
|
|
18216
|
+
}
|
|
18217
|
+
throw Error("Failed to generate pivot table: invalid report");
|
|
18218
|
+
}
|
|
18219
|
+
|
|
18220
|
+
// src/utils/errorProcessing.ts
|
|
18221
|
+
function processFilterErrorList(resp) {
|
|
18222
|
+
if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
|
|
18223
|
+
return;
|
|
18224
|
+
}
|
|
18225
|
+
}
|
|
18226
|
+
|
|
18227
|
+
// src/utils/paginationProcessing.ts
|
|
18228
|
+
var DEFAULT_PAGINATION = {
|
|
18229
|
+
page: 0,
|
|
18230
|
+
rowsPerPage: 10,
|
|
18231
|
+
rowsPerRequest: 600
|
|
18232
|
+
};
|
|
18233
|
+
var DEFAULT_TABLE_PAGINATION = {
|
|
18234
|
+
page: 0,
|
|
18235
|
+
rowsPerPage: 10,
|
|
18236
|
+
rowsPerRequest: 50
|
|
18237
|
+
};
|
|
18238
|
+
function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
|
|
18239
|
+
if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
|
|
18240
|
+
return false;
|
|
18241
|
+
}
|
|
18242
|
+
const indexAdjustedPage = page;
|
|
18243
|
+
const pageInterval = Math.floor(
|
|
18244
|
+
indexAdjustedPage * pagination.rowsPerPage / pagination.rowsPerRequest
|
|
18245
|
+
);
|
|
18246
|
+
const indexAdjustedPreviousPage = maxPage;
|
|
18247
|
+
const previousPageInterval = Math.floor(
|
|
18248
|
+
indexAdjustedPreviousPage * pagination.rowsPerPage / pagination.rowsPerRequest
|
|
18249
|
+
);
|
|
18250
|
+
return pageInterval > previousPageInterval;
|
|
18251
|
+
}
|
|
18252
|
+
function shouldSortInMemory(pagination, rowCount) {
|
|
18253
|
+
if (!rowCount || rowCount < pagination.rowsPerRequest) {
|
|
18254
|
+
return true;
|
|
18255
|
+
}
|
|
18256
|
+
return false;
|
|
18257
|
+
}
|
|
17547
18258
|
|
|
17548
18259
|
// src/utils/tableProcessing.ts
|
|
17549
18260
|
var getUniqueValuesByQuery = async ({
|
|
@@ -18203,90 +18914,575 @@ var fetchResultsByReport = async ({
|
|
|
18203
18914
|
if (client.databaseType && client.databaseType.toLowerCase() === "bigquery") {
|
|
18204
18915
|
parseValueFromBigQueryDates(rows, columns);
|
|
18205
18916
|
}
|
|
18206
|
-
return { rows, columns, rowCount, error };
|
|
18207
|
-
};
|
|
18208
|
-
var fetchTableByAST = async (ast, client, getToken, tenants, eventTracking, dashboardName, processing, customFields, rowsOnly, rowCountOnly) => {
|
|
18209
|
-
let rows = [];
|
|
18210
|
-
let columns = [];
|
|
18211
|
-
let rowCount;
|
|
18212
|
-
let error;
|
|
18213
|
-
let itemQuery;
|
|
18214
|
-
let referencedTables;
|
|
18215
|
-
try {
|
|
18216
|
-
const fetchResp = await quillFetch({
|
|
18217
|
-
client,
|
|
18218
|
-
task: "patterns",
|
|
18219
|
-
metadata: {
|
|
18220
|
-
clientId: client.publicKey,
|
|
18221
|
-
ast,
|
|
18222
|
-
customFields,
|
|
18223
|
-
additionalProcessing: processing,
|
|
18224
|
-
useUpdatedDataGathering: true,
|
|
18225
|
-
useNewNodeSql: true,
|
|
18226
|
-
rowsOnly,
|
|
18227
|
-
rowCountOnly,
|
|
18228
|
-
dashboardName,
|
|
18229
|
-
tenants
|
|
18230
|
-
},
|
|
18231
|
-
getToken
|
|
18232
|
-
});
|
|
18233
|
-
const resp = await parseFetchResponse(
|
|
18234
|
-
client,
|
|
18235
|
-
"patterns",
|
|
18236
|
-
fetchResp,
|
|
18237
|
-
getToken
|
|
18238
|
-
);
|
|
18239
|
-
if (resp.errorMessage || resp.name === "error") {
|
|
18240
|
-
throw new Error(resp.errorMessage);
|
|
18241
|
-
}
|
|
18242
|
-
processFilterErrorList(resp);
|
|
18243
|
-
if (resp.rowCount !== void 0) {
|
|
18244
|
-
rowCount = resp.rowCount;
|
|
18917
|
+
return { rows, columns, rowCount, error };
|
|
18918
|
+
};
|
|
18919
|
+
var fetchTableByAST = async (ast, client, getToken, tenants, eventTracking, dashboardName, processing, customFields, rowsOnly, rowCountOnly) => {
|
|
18920
|
+
let rows = [];
|
|
18921
|
+
let columns = [];
|
|
18922
|
+
let rowCount;
|
|
18923
|
+
let error;
|
|
18924
|
+
let itemQuery;
|
|
18925
|
+
let referencedTables;
|
|
18926
|
+
try {
|
|
18927
|
+
const fetchResp = await quillFetch({
|
|
18928
|
+
client,
|
|
18929
|
+
task: "patterns",
|
|
18930
|
+
metadata: {
|
|
18931
|
+
clientId: client.publicKey,
|
|
18932
|
+
ast,
|
|
18933
|
+
customFields,
|
|
18934
|
+
additionalProcessing: processing,
|
|
18935
|
+
useUpdatedDataGathering: true,
|
|
18936
|
+
useNewNodeSql: true,
|
|
18937
|
+
rowsOnly,
|
|
18938
|
+
rowCountOnly,
|
|
18939
|
+
dashboardName,
|
|
18940
|
+
tenants
|
|
18941
|
+
},
|
|
18942
|
+
getToken
|
|
18943
|
+
});
|
|
18944
|
+
const resp = await parseFetchResponse(
|
|
18945
|
+
client,
|
|
18946
|
+
"patterns",
|
|
18947
|
+
fetchResp,
|
|
18948
|
+
getToken
|
|
18949
|
+
);
|
|
18950
|
+
if (resp.errorMessage || resp.name === "error") {
|
|
18951
|
+
throw new Error(resp.errorMessage);
|
|
18952
|
+
}
|
|
18953
|
+
processFilterErrorList(resp);
|
|
18954
|
+
if (resp.rowCount !== void 0) {
|
|
18955
|
+
rowCount = resp.rowCount;
|
|
18956
|
+
}
|
|
18957
|
+
const gatheredRows = resp.rows && resp.rows.length ? resp.rows : [];
|
|
18958
|
+
columns = resp.fields.map((elem) => convertPostgresColumn(elem));
|
|
18959
|
+
rows = gatheredRows;
|
|
18960
|
+
itemQuery = resp.itemQuery;
|
|
18961
|
+
referencedTables = resp.referencedTables;
|
|
18962
|
+
if (customFields) {
|
|
18963
|
+
const tables = referencedTables ?? [];
|
|
18964
|
+
tables.forEach((table) => {
|
|
18965
|
+
const _customFields = customFields?.[table] ?? [];
|
|
18966
|
+
columns.forEach((col) => {
|
|
18967
|
+
if (_customFields.some((field) => {
|
|
18968
|
+
return field.field === col.field;
|
|
18969
|
+
})) {
|
|
18970
|
+
col.inferFormat = true;
|
|
18971
|
+
}
|
|
18972
|
+
});
|
|
18973
|
+
});
|
|
18974
|
+
}
|
|
18975
|
+
} catch (e) {
|
|
18976
|
+
eventTracking?.logError?.({
|
|
18977
|
+
type: "bug",
|
|
18978
|
+
// TODO: determine type
|
|
18979
|
+
severity: "high",
|
|
18980
|
+
message: "Error fetching table by AST",
|
|
18981
|
+
errorMessage: e.message,
|
|
18982
|
+
errorStack: e.stack,
|
|
18983
|
+
errorData: {
|
|
18984
|
+
caller: "fetchTableByAST",
|
|
18985
|
+
function: "fetchTableByAST"
|
|
18986
|
+
}
|
|
18987
|
+
});
|
|
18988
|
+
rows = [];
|
|
18989
|
+
columns = [];
|
|
18990
|
+
rowCount = 0;
|
|
18991
|
+
error = e.message;
|
|
18992
|
+
}
|
|
18993
|
+
if (client.databaseType && client.databaseType.toLowerCase() === "bigquery") {
|
|
18994
|
+
parseValueFromBigQueryDates(rows, columns);
|
|
18995
|
+
}
|
|
18996
|
+
return { rows, columns, rowCount, error, itemQuery, referencedTables };
|
|
18997
|
+
};
|
|
18998
|
+
|
|
18999
|
+
// src/utils/dashboard.ts
|
|
19000
|
+
var defaultDashboardItem = {
|
|
19001
|
+
id: "",
|
|
19002
|
+
name: "",
|
|
19003
|
+
dashboardName: "",
|
|
19004
|
+
rows: [],
|
|
19005
|
+
compareRows: [],
|
|
19006
|
+
columns: [],
|
|
19007
|
+
chartType: "",
|
|
19008
|
+
pivot: null,
|
|
19009
|
+
yAxisFields: [],
|
|
19010
|
+
xAxisLabel: "",
|
|
19011
|
+
xAxisField: "",
|
|
19012
|
+
xAxisFormat: "string",
|
|
19013
|
+
order: -1,
|
|
19014
|
+
filtersApplied: [],
|
|
19015
|
+
queryString: "",
|
|
19016
|
+
rowCount: 0,
|
|
19017
|
+
columnInternal: []
|
|
19018
|
+
};
|
|
19019
|
+
async function cleanDashboardItem({
|
|
19020
|
+
item,
|
|
19021
|
+
dashboardFilters,
|
|
19022
|
+
getToken,
|
|
19023
|
+
eventTracking,
|
|
19024
|
+
client,
|
|
19025
|
+
dateBucket,
|
|
19026
|
+
additionalProcessing,
|
|
19027
|
+
customFields,
|
|
19028
|
+
skipPivotFetch,
|
|
19029
|
+
tenants
|
|
19030
|
+
}) {
|
|
19031
|
+
if (!item) return defaultDashboardItem;
|
|
19032
|
+
if (!item.rows) {
|
|
19033
|
+
return {
|
|
19034
|
+
...defaultDashboardItem,
|
|
19035
|
+
id: item._id,
|
|
19036
|
+
name: item.name
|
|
19037
|
+
};
|
|
19038
|
+
}
|
|
19039
|
+
const fields = item.fields || [];
|
|
19040
|
+
const columnsWithCustomFields = [...item.columns ?? []];
|
|
19041
|
+
if (item.includeCustomFields && item.rows?.length > 0) {
|
|
19042
|
+
const tables = item.referencedTables ?? [];
|
|
19043
|
+
tables.forEach((table) => {
|
|
19044
|
+
const _customFields = customFields?.[table] ?? [];
|
|
19045
|
+
_customFields.forEach((field) => {
|
|
19046
|
+
const isJsonCustomField = !!field.refColumn;
|
|
19047
|
+
if (item.rows[0][field.field] !== void 0 && !item.columns.some((col) => col.field === field.field)) {
|
|
19048
|
+
const result_field = fields.find((f) => f.name === field.field);
|
|
19049
|
+
const converted_field = convertPostgresColumn(result_field ?? {});
|
|
19050
|
+
columnsWithCustomFields.push({
|
|
19051
|
+
field: field.field,
|
|
19052
|
+
format: converted_field.format,
|
|
19053
|
+
label: snakeAndCamelCaseToTitleCase(field.field),
|
|
19054
|
+
fieldType: converted_field.fieldType,
|
|
19055
|
+
dataTypeID: converted_field.dataTypeID,
|
|
19056
|
+
jsType: converted_field.jsType,
|
|
19057
|
+
inferFormat: isJsonCustomField
|
|
19058
|
+
});
|
|
19059
|
+
}
|
|
19060
|
+
});
|
|
19061
|
+
});
|
|
19062
|
+
}
|
|
19063
|
+
const processedColumns = item.columns.map((col) => {
|
|
19064
|
+
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
19065
|
+
});
|
|
19066
|
+
const columnInternal = (item.includeCustomFields ? columnsWithCustomFields : item.columns).map((col) => {
|
|
19067
|
+
const field = item.fields?.find((f) => f.name === col.field);
|
|
19068
|
+
const converted_field = convertPostgresColumn(field ?? {});
|
|
19069
|
+
return {
|
|
19070
|
+
fieldType: converted_field.fieldType,
|
|
19071
|
+
dataTypeID: converted_field.dataTypeID,
|
|
19072
|
+
jsType: converted_field.jsType,
|
|
19073
|
+
...col,
|
|
19074
|
+
label: snakeAndCamelCaseToTitleCase(col.label)
|
|
19075
|
+
};
|
|
19076
|
+
});
|
|
19077
|
+
let pivotTable;
|
|
19078
|
+
let pivotError;
|
|
19079
|
+
try {
|
|
19080
|
+
const shouldPaginatePivotAsTable = item.chartType === "table";
|
|
19081
|
+
const pivotChartProcessing = {
|
|
19082
|
+
page: DEFAULT_PAGINATION
|
|
19083
|
+
};
|
|
19084
|
+
pivotTable = await getPivotTable(
|
|
19085
|
+
{
|
|
19086
|
+
...item,
|
|
19087
|
+
pivot: item.pivot && !skipPivotFetch ? {
|
|
19088
|
+
...item.pivot,
|
|
19089
|
+
aggregations: item.pivot.aggregations ?? [
|
|
19090
|
+
{
|
|
19091
|
+
valueField: item.pivot.valueField,
|
|
19092
|
+
valueFieldType: item.pivot.valueFieldType,
|
|
19093
|
+
valueField2: item.pivot.valueField2,
|
|
19094
|
+
valueField2Type: item.pivot.valueField2Type,
|
|
19095
|
+
aggregationType: item.pivot.aggregationType
|
|
19096
|
+
}
|
|
19097
|
+
]
|
|
19098
|
+
} : void 0
|
|
19099
|
+
},
|
|
19100
|
+
dashboardFilters,
|
|
19101
|
+
item.dashboardName,
|
|
19102
|
+
getToken,
|
|
19103
|
+
client,
|
|
19104
|
+
eventTracking,
|
|
19105
|
+
dateBucket,
|
|
19106
|
+
shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
|
|
19107
|
+
tenants,
|
|
19108
|
+
customFields
|
|
19109
|
+
);
|
|
19110
|
+
} catch (e) {
|
|
19111
|
+
pivotTable = void 0;
|
|
19112
|
+
eventTracking?.logError?.({
|
|
19113
|
+
type: "bug",
|
|
19114
|
+
// TODO: determine type
|
|
19115
|
+
severity: "high",
|
|
19116
|
+
message: "Error fetching pivot table",
|
|
19117
|
+
errorMessage: e.message,
|
|
19118
|
+
errorStack: e.stack,
|
|
19119
|
+
errorData: {
|
|
19120
|
+
caller: "cleanDashboardItem",
|
|
19121
|
+
function: "cleanDashboardItem"
|
|
19122
|
+
}
|
|
19123
|
+
});
|
|
19124
|
+
console.error("Error fetching pivot table", e);
|
|
19125
|
+
pivotError = "Error fetching pivot table";
|
|
19126
|
+
}
|
|
19127
|
+
const referenceLineYValues = [];
|
|
19128
|
+
for (const key in item) {
|
|
19129
|
+
if (key.startsWith("referenceLine_")) {
|
|
19130
|
+
const field = key.slice(14);
|
|
19131
|
+
if (!item[key] || !item[key][0]) continue;
|
|
19132
|
+
const value = Object.values(item[key][0])[0];
|
|
19133
|
+
referenceLineYValues.push({ label: field, query: [value, value] });
|
|
19134
|
+
}
|
|
19135
|
+
}
|
|
19136
|
+
if (item.referenceLines) {
|
|
19137
|
+
for (const referenceLine of item.referenceLines) {
|
|
19138
|
+
if (Array.isArray(referenceLine.query)) {
|
|
19139
|
+
referenceLineYValues.push({
|
|
19140
|
+
label: referenceLine.label,
|
|
19141
|
+
query: referenceLine.query
|
|
19142
|
+
});
|
|
19143
|
+
} else if (referenceLine.query === "") {
|
|
19144
|
+
referenceLineYValues.push({
|
|
19145
|
+
label: referenceLine.label,
|
|
19146
|
+
query: (pivotTable?.rows ? pivotTable.rows : item.rows).map(
|
|
19147
|
+
(row) => Number(row[referenceLine.label]) || 0
|
|
19148
|
+
)
|
|
19149
|
+
});
|
|
19150
|
+
}
|
|
19151
|
+
}
|
|
19152
|
+
}
|
|
19153
|
+
return {
|
|
19154
|
+
id: item._id ?? item.id,
|
|
19155
|
+
name: item.name,
|
|
19156
|
+
dashboardName: item.dashboardName,
|
|
19157
|
+
// section: item.section,
|
|
19158
|
+
rows: item.rows,
|
|
19159
|
+
pivotRows: pivotTable ? pivotTable.rows : void 0,
|
|
19160
|
+
pivotColumns: pivotTable ? pivotTable.columns : void 0,
|
|
19161
|
+
compareRows: item.compareRows,
|
|
19162
|
+
columns: processedColumns.map((column) => {
|
|
19163
|
+
return {
|
|
19164
|
+
field: column.field,
|
|
19165
|
+
format: column.format,
|
|
19166
|
+
label: column.label,
|
|
19167
|
+
inferFormat: column.inferFormat
|
|
19168
|
+
};
|
|
19169
|
+
}),
|
|
19170
|
+
includeCustomFields: item.includeCustomFields,
|
|
19171
|
+
columnInternal,
|
|
19172
|
+
columnsWithCustomFields,
|
|
19173
|
+
chartType: item.chartType,
|
|
19174
|
+
dateField: item.dateField,
|
|
19175
|
+
pivot: pivotError ? void 0 : item.pivot ? {
|
|
19176
|
+
...item.pivot,
|
|
19177
|
+
aggregations: item.pivot.aggregations ?? [
|
|
19178
|
+
{
|
|
19179
|
+
valueField: item.pivot.valueField,
|
|
19180
|
+
valueFieldType: item.pivot.valueFieldType,
|
|
19181
|
+
valueField2: item.pivot.valueField2,
|
|
19182
|
+
valueField2Type: item.pivot.valueField2Type,
|
|
19183
|
+
aggregationType: item.pivot.aggregationType
|
|
19184
|
+
}
|
|
19185
|
+
],
|
|
19186
|
+
columnValues: item.distinctStrings
|
|
19187
|
+
} : void 0,
|
|
19188
|
+
yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
|
|
19189
|
+
xAxisLabel: item.xAxisLabel,
|
|
19190
|
+
xAxisField: item.xAxisField,
|
|
19191
|
+
xAxisFormat: item.xAxisFormat,
|
|
19192
|
+
order: item.order,
|
|
19193
|
+
filtersApplied: item.filtersApplied,
|
|
19194
|
+
filterMap: item.filterMap,
|
|
19195
|
+
flags: item.flags,
|
|
19196
|
+
rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
|
|
19197
|
+
pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
|
|
19198
|
+
template: item.template,
|
|
19199
|
+
sort: item.sort,
|
|
19200
|
+
itemQuery: item.itemQuery,
|
|
19201
|
+
queryString: item.queryString,
|
|
19202
|
+
pivotQuery: pivotTable?.pivotQuery,
|
|
19203
|
+
comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
|
|
19204
|
+
referencedTables: item?.referencedTables || [],
|
|
19205
|
+
referencedColumns: item?.referencedColumns || {},
|
|
19206
|
+
error: item.error ?? pivotError,
|
|
19207
|
+
referenceLineYValues,
|
|
19208
|
+
referenceLines: item.referenceLines
|
|
19209
|
+
};
|
|
19210
|
+
}
|
|
19211
|
+
async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
|
|
19212
|
+
if (!report) return void 0;
|
|
19213
|
+
const dateFilter = Object.values(dashboardFilters ?? {}).find(
|
|
19214
|
+
(filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
|
|
19215
|
+
);
|
|
19216
|
+
if (dateFilter?.operator === "BETWEEN") {
|
|
19217
|
+
dateFilter.startDate = dateFilter.value[0];
|
|
19218
|
+
dateFilter.endDate = dateFilter.value[1];
|
|
19219
|
+
}
|
|
19220
|
+
const pivot = report?.pivot;
|
|
19221
|
+
const data = report || {};
|
|
19222
|
+
if (pivot && client) {
|
|
19223
|
+
if (report.rowCount === 0 || report.rows.length === 0) {
|
|
19224
|
+
const columns = [];
|
|
19225
|
+
if (pivot.rowField) {
|
|
19226
|
+
columns.push({
|
|
19227
|
+
field: pivot.rowField,
|
|
19228
|
+
label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
|
|
19229
|
+
format: pivot.rowFieldType || "string",
|
|
19230
|
+
jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
|
|
19231
|
+
fieldType: pivot.rowFieldType || "string",
|
|
19232
|
+
dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
|
|
19233
|
+
});
|
|
19234
|
+
}
|
|
19235
|
+
for (const agg of pivot.aggregations ?? []) {
|
|
19236
|
+
if (agg.valueField) {
|
|
19237
|
+
columns.push({
|
|
19238
|
+
field: agg.valueField,
|
|
19239
|
+
label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
|
|
19240
|
+
//FIXME: valueFieldType is not always the same as the format
|
|
19241
|
+
format: agg.valueFieldType ?? "whole_number",
|
|
19242
|
+
jsType: agg.valueFieldType ?? "number",
|
|
19243
|
+
fieldType: agg.valueFieldType ?? "number",
|
|
19244
|
+
dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
|
|
19245
|
+
});
|
|
19246
|
+
}
|
|
19247
|
+
}
|
|
19248
|
+
const pivotQuery = generatePivotQuery(
|
|
19249
|
+
pivot,
|
|
19250
|
+
report.itemQuery?.[0],
|
|
19251
|
+
client.databaseType
|
|
19252
|
+
);
|
|
19253
|
+
return {
|
|
19254
|
+
rows: [],
|
|
19255
|
+
rowCount: 0,
|
|
19256
|
+
pivotQuery: pivotQuery ?? "",
|
|
19257
|
+
columns
|
|
19258
|
+
};
|
|
18245
19259
|
}
|
|
18246
|
-
|
|
18247
|
-
|
|
18248
|
-
|
|
18249
|
-
|
|
18250
|
-
|
|
18251
|
-
|
|
18252
|
-
|
|
18253
|
-
|
|
18254
|
-
|
|
18255
|
-
|
|
18256
|
-
|
|
18257
|
-
|
|
18258
|
-
|
|
18259
|
-
|
|
18260
|
-
|
|
19260
|
+
try {
|
|
19261
|
+
let dateBucket = dateBucketInitial;
|
|
19262
|
+
let filterDateRange = void 0;
|
|
19263
|
+
if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
|
|
19264
|
+
filterDateRange = {
|
|
19265
|
+
start: dateFilter.startDate,
|
|
19266
|
+
end: dateFilter.endDate
|
|
19267
|
+
};
|
|
19268
|
+
} else if (report.dateRange) {
|
|
19269
|
+
filterDateRange = report.dateRange;
|
|
19270
|
+
}
|
|
19271
|
+
if (!dateBucket && filterDateRange) {
|
|
19272
|
+
dateBucket = getDateBucketFromRange(filterDateRange);
|
|
19273
|
+
}
|
|
19274
|
+
if (pivot.columnField && !report.distinctStrings) {
|
|
19275
|
+
const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
|
|
19276
|
+
if (!columnFieldColumn) {
|
|
19277
|
+
console.error(
|
|
19278
|
+
"could not find pivot column field on report",
|
|
19279
|
+
pivot.columnField
|
|
19280
|
+
);
|
|
19281
|
+
}
|
|
19282
|
+
const unique = await getUniqueValuesByQuery({
|
|
19283
|
+
columns: [columnFieldColumn],
|
|
19284
|
+
query: report.queryString,
|
|
19285
|
+
client,
|
|
19286
|
+
getToken,
|
|
19287
|
+
dashboardName,
|
|
19288
|
+
tenants,
|
|
19289
|
+
customFields: customFields ?? {},
|
|
19290
|
+
eventTracking
|
|
19291
|
+
});
|
|
19292
|
+
report.distinctStrings = unique?.[pivot.columnField] ?? [];
|
|
19293
|
+
}
|
|
19294
|
+
if (pivot.columnField && !report.distinctStrings) {
|
|
19295
|
+
const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
|
|
19296
|
+
if (!columnFieldColumn) {
|
|
19297
|
+
console.error(
|
|
19298
|
+
"could not find pivot column field on report",
|
|
19299
|
+
pivot.columnField
|
|
19300
|
+
);
|
|
19301
|
+
}
|
|
19302
|
+
const unique = await getUniqueValuesByQuery({
|
|
19303
|
+
columns: [columnFieldColumn],
|
|
19304
|
+
query: report.queryString,
|
|
19305
|
+
client,
|
|
19306
|
+
getToken,
|
|
19307
|
+
dashboardName,
|
|
19308
|
+
tenants,
|
|
19309
|
+
customFields: customFields ?? {},
|
|
19310
|
+
eventTracking
|
|
18261
19311
|
});
|
|
19312
|
+
report.distinctStrings = unique?.[pivot.columnField] ?? [];
|
|
19313
|
+
}
|
|
19314
|
+
const pivotTable = await generatePivotWithSQL({
|
|
19315
|
+
pivot,
|
|
19316
|
+
report,
|
|
19317
|
+
client,
|
|
19318
|
+
dateBucket,
|
|
19319
|
+
dateFilter,
|
|
19320
|
+
distinctStrings: report.distinctStrings,
|
|
19321
|
+
dashboardName,
|
|
19322
|
+
tenants,
|
|
19323
|
+
additionalProcessing,
|
|
19324
|
+
getToken
|
|
19325
|
+
});
|
|
19326
|
+
return pivotTable;
|
|
19327
|
+
} catch (e) {
|
|
19328
|
+
eventTracking?.logError?.({
|
|
19329
|
+
type: "bug",
|
|
19330
|
+
// TODO: determine type
|
|
19331
|
+
severity: "high",
|
|
19332
|
+
message: "Error fetching pivot table",
|
|
19333
|
+
errorMessage: e.message,
|
|
19334
|
+
errorStack: e.stack,
|
|
19335
|
+
errorData: {
|
|
19336
|
+
caller: "getPivotTable",
|
|
19337
|
+
function: "getPivotTable"
|
|
19338
|
+
}
|
|
18262
19339
|
});
|
|
19340
|
+
console.error("Error fetching pivot table", e);
|
|
19341
|
+
throw e;
|
|
18263
19342
|
}
|
|
18264
|
-
} catch (e) {
|
|
18265
|
-
eventTracking?.logError?.({
|
|
18266
|
-
type: "bug",
|
|
18267
|
-
// TODO: determine type
|
|
18268
|
-
severity: "high",
|
|
18269
|
-
message: "Error fetching table by AST",
|
|
18270
|
-
errorMessage: e.message,
|
|
18271
|
-
errorStack: e.stack,
|
|
18272
|
-
errorData: {
|
|
18273
|
-
caller: "fetchTableByAST",
|
|
18274
|
-
function: "fetchTableByAST"
|
|
18275
|
-
}
|
|
18276
|
-
});
|
|
18277
|
-
rows = [];
|
|
18278
|
-
columns = [];
|
|
18279
|
-
rowCount = 0;
|
|
18280
|
-
error = e.message;
|
|
18281
19343
|
}
|
|
18282
|
-
|
|
18283
|
-
|
|
19344
|
+
return pivot && data.rows ? generatePivotTable({
|
|
19345
|
+
pivot,
|
|
19346
|
+
report,
|
|
19347
|
+
client,
|
|
19348
|
+
uniqueValues: report.distinctStrings,
|
|
19349
|
+
dashboardName,
|
|
19350
|
+
tenants,
|
|
19351
|
+
dateFilter,
|
|
19352
|
+
additionalProcessing,
|
|
19353
|
+
getToken,
|
|
19354
|
+
eventTracking
|
|
19355
|
+
}) : void 0;
|
|
19356
|
+
}
|
|
19357
|
+
function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
|
|
19358
|
+
if (!pivotTable) return itemInfo?.yAxisFields ?? [];
|
|
19359
|
+
const pivot = itemInfo?.pivot || config?.pivot;
|
|
19360
|
+
if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
|
|
19361
|
+
const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
|
|
19362
|
+
return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
|
|
19363
|
+
}
|
|
19364
|
+
async function getDashboard(dashboardName, client, getToken, tenants, flags) {
|
|
19365
|
+
const { data: resp } = await quillFetch({
|
|
19366
|
+
client,
|
|
19367
|
+
task: "dashboard",
|
|
19368
|
+
metadata: {
|
|
19369
|
+
name: dashboardName,
|
|
19370
|
+
clientId: client.publicKey,
|
|
19371
|
+
databaseType: client.databaseType,
|
|
19372
|
+
useNewNodeSql: true,
|
|
19373
|
+
tenants,
|
|
19374
|
+
flags
|
|
19375
|
+
},
|
|
19376
|
+
getToken
|
|
19377
|
+
});
|
|
19378
|
+
return {
|
|
19379
|
+
...resp,
|
|
19380
|
+
createdAt: resp.createdAt && new Date(resp.createdAt),
|
|
19381
|
+
dateFilter: resp.dateFilter ? {
|
|
19382
|
+
...resp.dateFilter,
|
|
19383
|
+
presetOptions: resp.dateFilter.presetOptions?.map(
|
|
19384
|
+
(preset) => ({
|
|
19385
|
+
...preset,
|
|
19386
|
+
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
19387
|
+
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
19388
|
+
})
|
|
19389
|
+
),
|
|
19390
|
+
defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
|
|
19391
|
+
(preset) => ({
|
|
19392
|
+
...preset,
|
|
19393
|
+
loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
|
|
19394
|
+
loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
|
|
19395
|
+
})
|
|
19396
|
+
)
|
|
19397
|
+
} : void 0
|
|
19398
|
+
};
|
|
19399
|
+
}
|
|
19400
|
+
|
|
19401
|
+
// src/utils/chartBuilder.ts
|
|
19402
|
+
var numberFormatOptions = [
|
|
19403
|
+
"whole_number",
|
|
19404
|
+
"one_decimal_place",
|
|
19405
|
+
"two_decimal_places",
|
|
19406
|
+
"dollar_amount",
|
|
19407
|
+
"dollar_cents",
|
|
19408
|
+
"percentage"
|
|
19409
|
+
];
|
|
19410
|
+
var dateFormatOptions = [
|
|
19411
|
+
"MMM_yyyy",
|
|
19412
|
+
"MMM_dd",
|
|
19413
|
+
"MMM_dd_yyyy",
|
|
19414
|
+
"MMM_dd_hh:mm_ap_pm",
|
|
19415
|
+
"hh_ap_pm",
|
|
19416
|
+
"date",
|
|
19417
|
+
"timestamptz"
|
|
19418
|
+
];
|
|
19419
|
+
var NUMBER_OPTIONS = [
|
|
19420
|
+
{ value: "whole_number", label: "whole number" },
|
|
19421
|
+
{ value: "one_decimal_place", label: "one decimal place" },
|
|
19422
|
+
{ value: "two_decimal_places", label: "two decimal places" },
|
|
19423
|
+
{ value: "dollar_amount", label: "dollar amount" },
|
|
19424
|
+
{ value: "dollar_cents", label: "dollar and cent amount" },
|
|
19425
|
+
{ value: "percent", label: "percentage" }
|
|
19426
|
+
];
|
|
19427
|
+
var DATE_OPTIONS = [
|
|
19428
|
+
{ value: "MMM_yyyy", label: "month" },
|
|
19429
|
+
{ value: "MMM_dd", label: "day" },
|
|
19430
|
+
{ value: "MMM_dd_yyyy", label: "day and year" },
|
|
19431
|
+
{ value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
|
|
19432
|
+
{ value: "hh_ap_pm", label: "hour" }
|
|
19433
|
+
];
|
|
19434
|
+
var ALL_FORMAT_OPTIONS = [
|
|
19435
|
+
...NUMBER_OPTIONS,
|
|
19436
|
+
...DATE_OPTIONS,
|
|
19437
|
+
{ value: "string", label: "string" }
|
|
19438
|
+
];
|
|
19439
|
+
function createInitialFormData(columns) {
|
|
19440
|
+
const firstNumberColumn = columns?.find(
|
|
19441
|
+
(col) => numberFormatOptions.includes(col.format)
|
|
19442
|
+
);
|
|
19443
|
+
const firstStringColumn = columns?.find(
|
|
19444
|
+
(col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
|
|
19445
|
+
);
|
|
19446
|
+
const firstDateColumn = columns?.find(
|
|
19447
|
+
(col) => dateFormatOptions.includes(col.format)
|
|
19448
|
+
);
|
|
19449
|
+
const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
|
|
19450
|
+
const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
|
|
19451
|
+
const formEmptyState = {
|
|
19452
|
+
name: "",
|
|
19453
|
+
columns: columns.map((col) => {
|
|
19454
|
+
return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
|
|
19455
|
+
}),
|
|
19456
|
+
xAxisField,
|
|
19457
|
+
xAxisFormat,
|
|
19458
|
+
yAxisFields: [
|
|
19459
|
+
{
|
|
19460
|
+
field: firstNumberColumn?.field || columns?.[0]?.field || "",
|
|
19461
|
+
label: "",
|
|
19462
|
+
format: firstNumberColumn?.format || columns?.[0]?.format || "string"
|
|
19463
|
+
}
|
|
19464
|
+
],
|
|
19465
|
+
xAxisLabel: "",
|
|
19466
|
+
chartType: firstNumberColumn ? "line" : "table",
|
|
19467
|
+
pivot: null,
|
|
19468
|
+
template: true,
|
|
19469
|
+
referenceLines: []
|
|
19470
|
+
};
|
|
19471
|
+
return formEmptyState;
|
|
19472
|
+
}
|
|
19473
|
+
|
|
19474
|
+
// src/utils/error.ts
|
|
19475
|
+
var DataLoadError = class extends Error {
|
|
19476
|
+
data;
|
|
19477
|
+
constructor(message, data) {
|
|
19478
|
+
super(message);
|
|
19479
|
+
this.name = "DataLoadError";
|
|
19480
|
+
this.data = data;
|
|
18284
19481
|
}
|
|
18285
|
-
return { rows, columns, rowCount, error, itemQuery, referencedTables };
|
|
18286
19482
|
};
|
|
18287
19483
|
|
|
18288
19484
|
// src/components/ReportBuilder/convert.ts
|
|
18289
|
-
var
|
|
19485
|
+
var import_date_fns8 = require("date-fns");
|
|
18290
19486
|
function recursiveSearchAndReplace(node, search, replace) {
|
|
18291
19487
|
if (typeof node !== "object") {
|
|
18292
19488
|
return;
|
|
@@ -18595,7 +19791,7 @@ function convertStringComparison(node, databaseType) {
|
|
|
18595
19791
|
searchAndReplace(element);
|
|
18596
19792
|
});
|
|
18597
19793
|
} else if (typeof obj === "object" && obj !== null) {
|
|
18598
|
-
if (obj.type === "binary_expr" && (obj.operator === "=" && !(0,
|
|
19794
|
+
if (obj.type === "binary_expr" && (obj.operator === "=" && !(0, import_date_fns8.isValid)((0, import_date_fns8.parseISO)(obj.right.value)) || // don't do it on date objects
|
|
18599
19795
|
obj.operator === "LIKE" || obj.operator === "ILIKE") && obj.left && (obj.left.type === "column_ref" || obj.left.type === "double_quote_string") && obj.right && obj.right.type === "single_quote_string") {
|
|
18600
19796
|
obj.operator = "LIKE";
|
|
18601
19797
|
obj.left = {
|
|
@@ -21936,29 +23132,6 @@ var import_jspdf = __toESM(require("jspdf"), 1);
|
|
|
21936
23132
|
|
|
21937
23133
|
// src/hooks/useDashboard.ts
|
|
21938
23134
|
var import_react2 = require("react");
|
|
21939
|
-
|
|
21940
|
-
// src/utils/merge.ts
|
|
21941
|
-
var import_date_fns8 = require("date-fns");
|
|
21942
|
-
var import_date_fns_tz2 = require("date-fns-tz");
|
|
21943
|
-
function mergeComparisonRange(resp) {
|
|
21944
|
-
if (resp.chartType === "table") return resp;
|
|
21945
|
-
const compRows = resp.compareRows;
|
|
21946
|
-
if (!compRows) return resp;
|
|
21947
|
-
const newRows = resp.rows.map((row, i) => {
|
|
21948
|
-
if (i < compRows.length) {
|
|
21949
|
-
const compRow = compRows[i];
|
|
21950
|
-
const newRow = { ...row };
|
|
21951
|
-
for (const [key, value] of Object.entries(compRow)) {
|
|
21952
|
-
newRow[`comparison_${key}`] = value;
|
|
21953
|
-
}
|
|
21954
|
-
return newRow;
|
|
21955
|
-
}
|
|
21956
|
-
return row;
|
|
21957
|
-
});
|
|
21958
|
-
return { ...resp, rows: newRows };
|
|
21959
|
-
}
|
|
21960
|
-
|
|
21961
|
-
// src/hooks/useDashboard.ts
|
|
21962
23135
|
var useDashboardInternal = (dashboardName, customFilters) => {
|
|
21963
23136
|
const [dashboard] = (0, import_react2.useContext)(DashboardContext);
|
|
21964
23137
|
const {
|
|
@@ -30476,23 +31649,53 @@ function QuillMetricComponent({
|
|
|
30476
31649
|
width: "100%"
|
|
30477
31650
|
}
|
|
30478
31651
|
}
|
|
30479
|
-
) : !report?.rows?.[0] || report.rows[0][report.xAxisField] ===
|
|
31652
|
+
) : !report?.rows || report?.rows?.length === 0 || report.rows[0]?.[report.xAxisField] === null || report.rows[0]?.[report.xAxisField] === void 0 ? /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
30480
31653
|
"div",
|
|
30481
31654
|
{
|
|
30482
31655
|
style: {
|
|
30483
|
-
|
|
30484
|
-
|
|
30485
|
-
|
|
30486
|
-
|
|
30487
|
-
|
|
30488
|
-
alignItems: "center",
|
|
30489
|
-
fontSize: 13,
|
|
30490
|
-
fontFamily: theme?.fontFamily,
|
|
30491
|
-
color: theme?.secondaryTextColor,
|
|
30492
|
-
maxWidth: "100%",
|
|
30493
|
-
width: "100%"
|
|
31656
|
+
padding: 0,
|
|
31657
|
+
height: "100%",
|
|
31658
|
+
width: "100%",
|
|
31659
|
+
boxSizing: "content-box",
|
|
31660
|
+
flex: 1
|
|
30494
31661
|
},
|
|
30495
|
-
children:
|
|
31662
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
31663
|
+
"div",
|
|
31664
|
+
{
|
|
31665
|
+
style: {
|
|
31666
|
+
fontFamily: theme?.fontFamily,
|
|
31667
|
+
fontSize: 32,
|
|
31668
|
+
color: theme?.primaryTextColor,
|
|
31669
|
+
fontWeight: "600",
|
|
31670
|
+
textOverflow: "ellipsis",
|
|
31671
|
+
margin: 0,
|
|
31672
|
+
whiteSpace: "nowrap",
|
|
31673
|
+
boxSizing: "content-box",
|
|
31674
|
+
maxWidth: "100%",
|
|
31675
|
+
textAlign: "left",
|
|
31676
|
+
overflow: "hidden",
|
|
31677
|
+
height: "100%",
|
|
31678
|
+
minHeight: "80px",
|
|
31679
|
+
display: "flex",
|
|
31680
|
+
width: "100%",
|
|
31681
|
+
flexDirection: "row",
|
|
31682
|
+
justifyContent: "center",
|
|
31683
|
+
alignItems: "center"
|
|
31684
|
+
},
|
|
31685
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
31686
|
+
"span",
|
|
31687
|
+
{
|
|
31688
|
+
style: {
|
|
31689
|
+
fontFamily: theme?.fontFamily,
|
|
31690
|
+
fontSize: 13,
|
|
31691
|
+
color: theme?.secondaryTextColor,
|
|
31692
|
+
fontWeight: "normal"
|
|
31693
|
+
},
|
|
31694
|
+
children: "No results"
|
|
31695
|
+
}
|
|
31696
|
+
)
|
|
31697
|
+
}
|
|
31698
|
+
)
|
|
30496
31699
|
}
|
|
30497
31700
|
) : /* @__PURE__ */ (0, import_jsx_runtime43.jsx)(
|
|
30498
31701
|
MetricDisplay,
|
|
@@ -31678,7 +32881,7 @@ function USMap({
|
|
|
31678
32881
|
acc[curr[xAxisField]?.toString()] = curr;
|
|
31679
32882
|
return acc;
|
|
31680
32883
|
}, {});
|
|
31681
|
-
const measureField = yAxisFields[0]
|
|
32884
|
+
const measureField = yAxisFields[0]?.field;
|
|
31682
32885
|
const [scaleLog, setScaleLog] = (0, import_react26.useState)(null);
|
|
31683
32886
|
(0, import_react26.useEffect)(() => {
|
|
31684
32887
|
import("d3-scale").then((scale) => {
|
|
@@ -31714,6 +32917,29 @@ function USMap({
|
|
|
31714
32917
|
const hoveredValue = (0, import_react26.useMemo)(() => {
|
|
31715
32918
|
return !hoveredState ? void 0 : mappedData[fipsToNames[hoveredState]?.abbreviation ?? ""]?.[measureField] ?? mappedData[fipsToNames[hoveredState]?.name ?? ""]?.[measureField] ?? mappedData[fipsToNames[hoveredState]?.abbreviation?.toLowerCase() ?? ""]?.[measureField] ?? mappedData[fipsToNames[hoveredState]?.name?.toLowerCase() ?? ""]?.[measureField];
|
|
31716
32919
|
}, [hoveredState, mappedData, measureField]);
|
|
32920
|
+
if (!measureField) {
|
|
32921
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
32922
|
+
"div",
|
|
32923
|
+
{
|
|
32924
|
+
style: {
|
|
32925
|
+
display: "flex",
|
|
32926
|
+
flex: "1 0 auto",
|
|
32927
|
+
marginLeft: "auto",
|
|
32928
|
+
marginRight: "auto",
|
|
32929
|
+
marginTop: "auto",
|
|
32930
|
+
marginBottom: "auto",
|
|
32931
|
+
justifyContent: "center",
|
|
32932
|
+
alignItems: "center",
|
|
32933
|
+
fontSize: 13,
|
|
32934
|
+
color: theme?.secondaryTextColor,
|
|
32935
|
+
fontFamily: theme?.fontFamily,
|
|
32936
|
+
...containerStyle
|
|
32937
|
+
},
|
|
32938
|
+
className,
|
|
32939
|
+
children: "No results"
|
|
32940
|
+
}
|
|
32941
|
+
);
|
|
32942
|
+
}
|
|
31717
32943
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
31718
32944
|
"div",
|
|
31719
32945
|
{
|
|
@@ -31846,7 +33072,7 @@ function WorldMap({
|
|
|
31846
33072
|
acc[curr[xAxisField]?.toString()] = curr;
|
|
31847
33073
|
return acc;
|
|
31848
33074
|
}, {});
|
|
31849
|
-
const measureField = yAxisFields[0]
|
|
33075
|
+
const measureField = yAxisFields[0]?.field;
|
|
31850
33076
|
const [scaleLog, setScaleLog] = (0, import_react26.useState)(null);
|
|
31851
33077
|
(0, import_react26.useEffect)(() => {
|
|
31852
33078
|
import("d3-scale").then((scale) => {
|
|
@@ -31882,6 +33108,29 @@ function WorldMap({
|
|
|
31882
33108
|
const hoveredValue = (0, import_react26.useMemo)(() => {
|
|
31883
33109
|
return !hoveredCountry ? void 0 : mappedData[isoToNames[hoveredCountry]?.abbreviation ?? ""]?.[measureField] ?? mappedData[isoToNames[hoveredCountry]?.name ?? ""]?.[measureField] ?? mappedData[isoToNames[hoveredCountry]?.abbreviation?.toLowerCase() ?? ""]?.[measureField] ?? mappedData[isoToNames[hoveredCountry]?.name?.toLowerCase() ?? ""]?.[measureField];
|
|
31884
33110
|
}, [hoveredCountry, mappedData, measureField]);
|
|
33111
|
+
if (!measureField) {
|
|
33112
|
+
return /* @__PURE__ */ (0, import_jsx_runtime45.jsx)(
|
|
33113
|
+
"div",
|
|
33114
|
+
{
|
|
33115
|
+
style: {
|
|
33116
|
+
display: "flex",
|
|
33117
|
+
flex: "1 0 auto",
|
|
33118
|
+
marginLeft: "auto",
|
|
33119
|
+
marginRight: "auto",
|
|
33120
|
+
marginTop: "auto",
|
|
33121
|
+
marginBottom: "auto",
|
|
33122
|
+
justifyContent: "center",
|
|
33123
|
+
alignItems: "center",
|
|
33124
|
+
fontSize: 13,
|
|
33125
|
+
color: theme?.secondaryTextColor,
|
|
33126
|
+
fontFamily: theme?.fontFamily,
|
|
33127
|
+
...containerStyle
|
|
33128
|
+
},
|
|
33129
|
+
className,
|
|
33130
|
+
children: "No results"
|
|
33131
|
+
}
|
|
33132
|
+
);
|
|
33133
|
+
}
|
|
31885
33134
|
return /* @__PURE__ */ (0, import_jsx_runtime45.jsxs)(
|
|
31886
33135
|
"div",
|
|
31887
33136
|
{
|
|
@@ -34389,27 +35638,41 @@ var ChartDisplay = ({
|
|
|
34389
35638
|
);
|
|
34390
35639
|
}
|
|
34391
35640
|
if (config?.chartType?.toLowerCase() === "metric") {
|
|
34392
|
-
if (!config?.rows || config?.rows?.length === 0 ||
|
|
34393
|
-
config?.rows[0][config?.xAxisField] === null) {
|
|
35641
|
+
if (!config?.rows || config?.rows?.length === 0 || config?.rows[0]?.[config?.xAxisField] === null || config?.rows[0]?.[config?.xAxisField] === void 0) {
|
|
34394
35642
|
return /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
34395
35643
|
"div",
|
|
34396
35644
|
{
|
|
34397
35645
|
style: {
|
|
34398
|
-
display: "flex",
|
|
34399
|
-
flex: "1 0 auto",
|
|
34400
|
-
// height: containerStyle?.height || '100%',
|
|
34401
|
-
margin: "auto",
|
|
34402
|
-
justifyContent: "center",
|
|
34403
|
-
alignItems: "center",
|
|
34404
|
-
fontSize: 13,
|
|
34405
35646
|
fontFamily: theme?.fontFamily,
|
|
34406
|
-
|
|
35647
|
+
fontSize: 32,
|
|
35648
|
+
color: theme?.primaryTextColor,
|
|
35649
|
+
fontWeight: "600",
|
|
35650
|
+
textOverflow: "ellipsis",
|
|
35651
|
+
margin: 0,
|
|
35652
|
+
whiteSpace: "nowrap",
|
|
35653
|
+
boxSizing: "content-box",
|
|
34407
35654
|
maxWidth: "100%",
|
|
35655
|
+
textAlign: "left",
|
|
35656
|
+
overflow: "hidden",
|
|
35657
|
+
height: containerStyle?.height || "100%",
|
|
35658
|
+
display: "flex",
|
|
34408
35659
|
width: "100%",
|
|
35660
|
+
flexDirection: "row",
|
|
35661
|
+
alignItems: "center",
|
|
34409
35662
|
...containerStyle
|
|
34410
35663
|
},
|
|
34411
35664
|
className,
|
|
34412
|
-
children:
|
|
35665
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(
|
|
35666
|
+
"span",
|
|
35667
|
+
{
|
|
35668
|
+
style: {
|
|
35669
|
+
fontFamily: theme?.fontFamily,
|
|
35670
|
+
fontSize: 13,
|
|
35671
|
+
color: theme?.secondaryTextColor
|
|
35672
|
+
},
|
|
35673
|
+
children: "No results"
|
|
35674
|
+
}
|
|
35675
|
+
)
|
|
34413
35676
|
}
|
|
34414
35677
|
);
|
|
34415
35678
|
}
|
|
@@ -41297,15 +42560,19 @@ function ChartBuilderWithModal(props) {
|
|
|
41297
42560
|
title: title || "Add to dashboard",
|
|
41298
42561
|
width: isHorizontalView ? modalWidth : void 0,
|
|
41299
42562
|
height: isHorizontalView ? modalHeight : void 0,
|
|
41300
|
-
children: (
|
|
41301
|
-
|
|
41302
|
-
|
|
41303
|
-
|
|
41304
|
-
|
|
41305
|
-
|
|
41306
|
-
|
|
41307
|
-
|
|
41308
|
-
|
|
42563
|
+
children: (() => {
|
|
42564
|
+
const resolvedReport = props.reportId ? dashboard[props.reportId] ?? props.tempReport : props.tempReport;
|
|
42565
|
+
return resolvedReport ? /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
42566
|
+
ChartBuilder,
|
|
42567
|
+
{
|
|
42568
|
+
...props,
|
|
42569
|
+
tempReport: resolvedReport,
|
|
42570
|
+
filtersEnabled: filtersEnabledState,
|
|
42571
|
+
onFiltersEnabledChanged: setFiltersEnabledState,
|
|
42572
|
+
runQueryOnMount: filtersEnabledState
|
|
42573
|
+
}
|
|
42574
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { style: { padding: 20 }, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(QuillLoadingComponent, {}) });
|
|
42575
|
+
})()
|
|
41309
42576
|
}
|
|
41310
42577
|
) });
|
|
41311
42578
|
}
|
|
@@ -41355,6 +42622,7 @@ function ChartBuilder({
|
|
|
41355
42622
|
hideSubmitButton = false,
|
|
41356
42623
|
hideDateRangeFilter = false,
|
|
41357
42624
|
showTableFormatOptions,
|
|
42625
|
+
showDashboardFilterFields,
|
|
41358
42626
|
initialUniqueValues,
|
|
41359
42627
|
initialUniqueValuesIsLoading,
|
|
41360
42628
|
pivotRecommendationsEnabled = true,
|
|
@@ -41384,9 +42652,10 @@ function ChartBuilder({
|
|
|
41384
42652
|
const { tenants, flags } = (0, import_react43.useContext)(TenantContext);
|
|
41385
42653
|
const report = (0, import_react43.useMemo)(() => {
|
|
41386
42654
|
return reportId && !tempReport ? allReportsById[reportId] : tempReport;
|
|
41387
|
-
}, [reportId]);
|
|
42655
|
+
}, [reportId, tempReport, allReportsById]);
|
|
41388
42656
|
const [windowWidth, setWindowWidth] = (0, import_react43.useState)(1200);
|
|
41389
42657
|
const [rows, setRows] = (0, import_react43.useState)(report?.rows ?? []);
|
|
42658
|
+
const [itemQuery, setItemQuery] = (0, import_react43.useState)(report?.itemQuery);
|
|
41390
42659
|
const [rowCount, setRowCount] = (0, import_react43.useState)(report?.rowCount ?? 0);
|
|
41391
42660
|
const [maxPage, setMaxPage] = (0, import_react43.useState)(0);
|
|
41392
42661
|
const [isLoading, setIsLoading] = (0, import_react43.useState)(false);
|
|
@@ -42116,7 +43385,7 @@ function ChartBuilder({
|
|
|
42116
43385
|
pivot,
|
|
42117
43386
|
dateBucket,
|
|
42118
43387
|
dateFilter,
|
|
42119
|
-
report: report ? { ...report, ...tableInfo } : void 0,
|
|
43388
|
+
report: report ? { ...report, ...tableInfo ?? { itemQuery } } : void 0,
|
|
42120
43389
|
client,
|
|
42121
43390
|
uniqueValues,
|
|
42122
43391
|
dashboardName: destinationDashboardName,
|
|
@@ -42277,6 +43546,7 @@ function ChartBuilder({
|
|
|
42277
43546
|
setCurrentProcessing(processing);
|
|
42278
43547
|
setRows(tableInfo.rows);
|
|
42279
43548
|
setProcessedColumns(processColumns(tableInfo.columns));
|
|
43549
|
+
setItemQuery(tableInfo.itemQuery);
|
|
42280
43550
|
fetchRowCount(processing, overrideFilters);
|
|
42281
43551
|
if (formData.pivot) {
|
|
42282
43552
|
try {
|
|
@@ -43182,7 +44452,7 @@ function ChartBuilder({
|
|
|
43182
44452
|
uniqueValuesIsLoading: initialUniqueValuesIsLoading,
|
|
43183
44453
|
initialSelectedPivotTable: selectedPivotTable,
|
|
43184
44454
|
pivotRecommendationsEnabled,
|
|
43185
|
-
report,
|
|
44455
|
+
report: report ? { ...report, ...{ itemQuery } } : void 0,
|
|
43186
44456
|
dashboardName: destinationDashboardName || "",
|
|
43187
44457
|
dateFilter: filtersEnabled ? currentDashboardFilters?.find(
|
|
43188
44458
|
(f) => f.filterType === "date_range"
|
|
@@ -43875,7 +45145,7 @@ function ChartBuilder({
|
|
|
43875
45145
|
]
|
|
43876
45146
|
}
|
|
43877
45147
|
),
|
|
43878
|
-
specificDashboardFilters.length > 0 && isAdmin && /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
|
|
45148
|
+
specificDashboardFilters.length > 0 && (showDashboardFilterFields || isAdmin) && /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
|
|
43879
45149
|
"div",
|
|
43880
45150
|
{
|
|
43881
45151
|
style: {
|
|
@@ -43886,7 +45156,7 @@ function ChartBuilder({
|
|
|
43886
45156
|
},
|
|
43887
45157
|
children: [
|
|
43888
45158
|
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(HeaderComponent, { label: "Dashboard filter fields" }),
|
|
43889
|
-
isAdmin && formData.dateField && dashboardConfig[formData.dashboardName ?? destinationDashboardName ?? ""]?.config.dateFilter?.label && /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(ChartBuilderInputRowContainer, { children: [
|
|
45159
|
+
(showDashboardFilterFields || isAdmin) && formData.dateField && dashboardConfig[formData.dashboardName ?? destinationDashboardName ?? ""]?.config.dateFilter?.label && /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(ChartBuilderInputRowContainer, { children: [
|
|
43890
45160
|
/* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
|
|
43891
45161
|
TextInputComponent,
|
|
43892
45162
|
{
|
|
@@ -44825,6 +46095,7 @@ function SQLEditor({
|
|
|
44825
46095
|
CheckboxComponent = QuillChartBuilderCheckboxComponent,
|
|
44826
46096
|
defaultQuery,
|
|
44827
46097
|
destinationDashboard,
|
|
46098
|
+
destinationSection,
|
|
44828
46099
|
onChangeQuery,
|
|
44829
46100
|
onChangeData,
|
|
44830
46101
|
onChangeColumns,
|
|
@@ -44834,12 +46105,16 @@ function SQLEditor({
|
|
|
44834
46105
|
onCloseChartBuilder,
|
|
44835
46106
|
isChartBuilderEnabled = false,
|
|
44836
46107
|
isAdminEnabled = false,
|
|
46108
|
+
chartBuilderOptions,
|
|
44837
46109
|
chartBuilderTitle,
|
|
44838
46110
|
runQueryOnMount = false,
|
|
44839
46111
|
onAddToDashboardComplete,
|
|
46112
|
+
onSubmitCreateReport,
|
|
46113
|
+
onSubmitEditReport,
|
|
44840
46114
|
onSaveQueryComplete,
|
|
44841
46115
|
addToDashboardButtonLabel = "Add to dashboard",
|
|
44842
46116
|
report = void 0,
|
|
46117
|
+
reportId = void 0,
|
|
44843
46118
|
organizationName = void 0,
|
|
44844
46119
|
isChartBuilderHorizontalView = true,
|
|
44845
46120
|
containerStyle = { height: "100vh" },
|
|
@@ -44850,7 +46125,7 @@ function SQLEditor({
|
|
|
44850
46125
|
const [sqlPrompt, setSqlPrompt] = (0, import_react45.useState)("");
|
|
44851
46126
|
const [client] = (0, import_react45.useContext)(ClientContext);
|
|
44852
46127
|
const [theme] = (0, import_react45.useContext)(ThemeContext);
|
|
44853
|
-
const { tenants } = (0, import_react45.useContext)(TenantContext);
|
|
46128
|
+
const { tenants, flags } = (0, import_react45.useContext)(TenantContext);
|
|
44854
46129
|
const { dashboards } = useDashboards();
|
|
44855
46130
|
const {
|
|
44856
46131
|
data,
|
|
@@ -44859,6 +46134,7 @@ function SQLEditor({
|
|
|
44859
46134
|
} = useDashboardInternal(destinationDashboard);
|
|
44860
46135
|
const { getToken, quillFetchWithToken } = (0, import_react45.useContext)(FetchContext);
|
|
44861
46136
|
const { eventTracking } = (0, import_react45.useContext)(EventTrackingContext);
|
|
46137
|
+
const { allReportsById } = useAllReports();
|
|
44862
46138
|
const destinationDashboardConfig = (0, import_react45.useMemo)(() => {
|
|
44863
46139
|
return dashboards?.find((d) => d.name === destinationDashboard);
|
|
44864
46140
|
}, [dashboards, destinationDashboard]);
|
|
@@ -44926,6 +46202,46 @@ function SQLEditor({
|
|
|
44926
46202
|
reload();
|
|
44927
46203
|
}
|
|
44928
46204
|
}, [data, dashboardIsLoading]);
|
|
46205
|
+
(0, import_react45.useEffect)(() => {
|
|
46206
|
+
const loadReport = async () => {
|
|
46207
|
+
let reportToLoad;
|
|
46208
|
+
if (!client) {
|
|
46209
|
+
return;
|
|
46210
|
+
}
|
|
46211
|
+
try {
|
|
46212
|
+
if (!reportId) {
|
|
46213
|
+
throw new Error("Report ID is required");
|
|
46214
|
+
}
|
|
46215
|
+
reportToLoad = allReportsById[reportId];
|
|
46216
|
+
if (!reportToLoad) {
|
|
46217
|
+
throw new Error("Report not found");
|
|
46218
|
+
}
|
|
46219
|
+
setQuery(reportToLoad.queryString || "");
|
|
46220
|
+
setTempReport(reportToLoad);
|
|
46221
|
+
if (reportToLoad.rows && reportToLoad.rows.length > 0) {
|
|
46222
|
+
setRows(reportToLoad.rows);
|
|
46223
|
+
setDisplayTable(true);
|
|
46224
|
+
}
|
|
46225
|
+
} catch (err) {
|
|
46226
|
+
console.error(err);
|
|
46227
|
+
eventTracking?.logError?.({
|
|
46228
|
+
type: "bug",
|
|
46229
|
+
severity: "high",
|
|
46230
|
+
message: "Error loading report",
|
|
46231
|
+
errorMessage: err.message,
|
|
46232
|
+
errorStack: err.stack,
|
|
46233
|
+
errorData: {
|
|
46234
|
+
caller: "SQLEditor",
|
|
46235
|
+
function: "loadReport"
|
|
46236
|
+
}
|
|
46237
|
+
});
|
|
46238
|
+
setErrorMessage("Error when loading report");
|
|
46239
|
+
}
|
|
46240
|
+
};
|
|
46241
|
+
if (reportId && client) {
|
|
46242
|
+
loadReport();
|
|
46243
|
+
}
|
|
46244
|
+
}, [allReportsById[reportId || ""], client]);
|
|
44929
46245
|
const dynamicHeight = tableRef.current ? tableRef.current.clientHeight : cachedHeight;
|
|
44930
46246
|
const rowsPerPage = Math.max(
|
|
44931
46247
|
DEFAULT_ROWS_PER_PAGE,
|
|
@@ -45744,13 +47060,38 @@ function SQLEditor({
|
|
|
45744
47060
|
isHorizontalView: isChartBuilderHorizontalView,
|
|
45745
47061
|
isOpen: isChartBuilderOpen,
|
|
45746
47062
|
setIsOpen: setIsChartBuilderOpen,
|
|
45747
|
-
onAddToDashboardComplete
|
|
47063
|
+
onAddToDashboardComplete: reportId || report?.id ? (data2) => {
|
|
47064
|
+
if (onSubmitEditReport) {
|
|
47065
|
+
onSubmitEditReport(data2);
|
|
47066
|
+
} else if (onAddToDashboardComplete) {
|
|
47067
|
+
onAddToDashboardComplete(data2);
|
|
47068
|
+
}
|
|
47069
|
+
if (!isAdminEnabled && destinationDashboard) {
|
|
47070
|
+
reload(destinationDashboard, false, {
|
|
47071
|
+
report: data2,
|
|
47072
|
+
action: "upsert"
|
|
47073
|
+
});
|
|
47074
|
+
}
|
|
47075
|
+
} : (data2) => {
|
|
47076
|
+
if (onSubmitCreateReport) {
|
|
47077
|
+
onSubmitCreateReport(data2);
|
|
47078
|
+
} else if (onAddToDashboardComplete) {
|
|
47079
|
+
onAddToDashboardComplete(data2);
|
|
47080
|
+
}
|
|
47081
|
+
if (!isAdminEnabled && destinationDashboard) {
|
|
47082
|
+
reload(destinationDashboard, false, {
|
|
47083
|
+
report: data2,
|
|
47084
|
+
action: "upsert"
|
|
47085
|
+
});
|
|
47086
|
+
}
|
|
47087
|
+
},
|
|
45748
47088
|
destinationDashboard,
|
|
47089
|
+
destinationSection,
|
|
45749
47090
|
isAdmin: isAdminEnabled,
|
|
45750
47091
|
title: chartBuilderTitle,
|
|
45751
47092
|
buttonLabel: addToDashboardButtonLabel,
|
|
45752
47093
|
tempReport,
|
|
45753
|
-
reportId: report?.id,
|
|
47094
|
+
reportId: reportId || report?.id,
|
|
45754
47095
|
organizationName,
|
|
45755
47096
|
CardComponent,
|
|
45756
47097
|
TableComponent,
|
|
@@ -45775,6 +47116,8 @@ function SQLEditor({
|
|
|
45775
47116
|
CheckboxComponent,
|
|
45776
47117
|
hideDateRangeFilter: true,
|
|
45777
47118
|
hideDeleteButton: true,
|
|
47119
|
+
showTableFormatOptions: chartBuilderOptions?.showTableFormatOptions,
|
|
47120
|
+
showDashboardFilterFields: chartBuilderOptions?.showDashboardFilterFields,
|
|
45778
47121
|
onClickChartElement,
|
|
45779
47122
|
isEditingMode: true
|
|
45780
47123
|
}
|
|
@@ -45794,7 +47137,7 @@ function SQLEditor({
|
|
|
45794
47137
|
isAdmin: false,
|
|
45795
47138
|
title: "Save query",
|
|
45796
47139
|
buttonLabel: "Save query",
|
|
45797
|
-
tempReport,
|
|
47140
|
+
tempReport: { ...tempReport, dashboardName: SAVED_QUERIES_DASHBOARD },
|
|
45798
47141
|
reportId: report?.id,
|
|
45799
47142
|
organizationName,
|
|
45800
47143
|
CardComponent,
|
|
@@ -47557,7 +48900,6 @@ var useReportBuilderInternal = ({
|
|
|
47557
48900
|
}
|
|
47558
48901
|
report = allReportsById[reportId];
|
|
47559
48902
|
if (!report) {
|
|
47560
|
-
console.log("no report");
|
|
47561
48903
|
throw new Error("Report not found");
|
|
47562
48904
|
}
|
|
47563
48905
|
const { ast: newAst, pivot: newPivot } = await fetchASTFromQuillReport(
|
|
@@ -50082,6 +51424,8 @@ var SaveReport = ({
|
|
|
50082
51424
|
onSubmitEditReport = () => void 0,
|
|
50083
51425
|
onSubmitCreateReport = () => void 0,
|
|
50084
51426
|
destinationSection,
|
|
51427
|
+
showTableFormatOptions,
|
|
51428
|
+
showDashboardFilterFields,
|
|
50085
51429
|
SelectComponent = QuillSelectComponent,
|
|
50086
51430
|
TextInputComponent = QuillTextInput,
|
|
50087
51431
|
ButtonComponent = MemoizedButton,
|
|
@@ -50114,6 +51458,7 @@ var SaveReport = ({
|
|
|
50114
51458
|
),
|
|
50115
51459
|
submitButtonLabel
|
|
50116
51460
|
}) => {
|
|
51461
|
+
const { reload } = useDashboardInternal(reportBuilder.destinationDashboard ?? null);
|
|
50117
51462
|
return /* @__PURE__ */ (0, import_jsx_runtime79.jsxs)("div", { children: [
|
|
50118
51463
|
SaveTrigger,
|
|
50119
51464
|
/* @__PURE__ */ (0, import_jsx_runtime79.jsx)(
|
|
@@ -50126,7 +51471,17 @@ var SaveReport = ({
|
|
|
50126
51471
|
isHorizontalView: true,
|
|
50127
51472
|
isOpen,
|
|
50128
51473
|
setIsOpen,
|
|
50129
|
-
onAddToDashboardComplete: reportBuilder.reportId ?
|
|
51474
|
+
onAddToDashboardComplete: reportBuilder.reportId ? (data) => {
|
|
51475
|
+
onSubmitEditReport(data);
|
|
51476
|
+
if (!isAdminEnabled && reportBuilder.destinationDashboard) {
|
|
51477
|
+
reload(reportBuilder.destinationDashboard, false, { report: data, action: "upsert" });
|
|
51478
|
+
}
|
|
51479
|
+
} : (data) => {
|
|
51480
|
+
onSubmitCreateReport(data);
|
|
51481
|
+
if (!isAdminEnabled && reportBuilder.destinationDashboard) {
|
|
51482
|
+
reload(reportBuilder.destinationDashboard, false, { report: data, action: "upsert" });
|
|
51483
|
+
}
|
|
51484
|
+
},
|
|
50130
51485
|
destinationDashboard: reportBuilder.destinationDashboard,
|
|
50131
51486
|
destinationSection,
|
|
50132
51487
|
initialUniqueValues: reportBuilder.columnUniqueValues,
|
|
@@ -50155,6 +51510,8 @@ var SaveReport = ({
|
|
|
50155
51510
|
FormContainer: ChartBuilderFormContainer,
|
|
50156
51511
|
hideDateRangeFilter: true,
|
|
50157
51512
|
hideDeleteButton: true,
|
|
51513
|
+
showTableFormatOptions,
|
|
51514
|
+
showDashboardFilterFields,
|
|
50158
51515
|
buttonLabel: submitButtonLabel ?? (!!reportBuilder.reportId ? "Save changes" : "Add to dashboard"),
|
|
50159
51516
|
onClickChartElement,
|
|
50160
51517
|
isEditingMode: true
|
|
@@ -50250,6 +51607,7 @@ function ReportBuilder({
|
|
|
50250
51607
|
containerStyle,
|
|
50251
51608
|
className,
|
|
50252
51609
|
pivotRecommendationsEnabled = true,
|
|
51610
|
+
chartBuilderOptions,
|
|
50253
51611
|
reportId,
|
|
50254
51612
|
hideCopySQL = true,
|
|
50255
51613
|
isChartBuilderHorizontalView = true,
|
|
@@ -50689,6 +52047,8 @@ function ReportBuilder({
|
|
|
50689
52047
|
ErrorMessageComponent,
|
|
50690
52048
|
PivotRowContainer,
|
|
50691
52049
|
PivotColumnContainer,
|
|
52050
|
+
showTableFormatOptions: chartBuilderOptions?.showTableFormatOptions,
|
|
52051
|
+
showDashboardFilterFields: chartBuilderOptions?.showDashboardFilterFields,
|
|
50692
52052
|
onClickChartElement,
|
|
50693
52053
|
submitButtonLabel
|
|
50694
52054
|
}
|
|
@@ -50709,7 +52069,7 @@ function ReportBuilder({
|
|
|
50709
52069
|
isAdmin: false,
|
|
50710
52070
|
title: "Save query",
|
|
50711
52071
|
buttonLabel: "Save query",
|
|
50712
|
-
tempReport,
|
|
52072
|
+
tempReport: { ...tempReport, dashboardName: SAVED_QUERIES_DASHBOARD },
|
|
50713
52073
|
reportId,
|
|
50714
52074
|
organizationName,
|
|
50715
52075
|
CardComponent,
|