@quillsql/react 2.15.16 → 2.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/dist/index.cjs +1245 -2273
  2. package/dist/index.js +1096 -2111
  3. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14787,21 +14787,6 @@ function isDateFormat(xAxisFormat) {
14787
14787
  const isDate = DATE_FORMATS.includes(xAxisFormat);
14788
14788
  return isDate;
14789
14789
  }
14790
- function getComparisonInterval(comparisonRange, dateBucket) {
14791
- const dayCount = differenceInDays2(
14792
- comparisonRange.endDate,
14793
- comparisonRange.startDate
14794
- );
14795
- if (!isNaN(dayCount)) {
14796
- if (dateBucket === "month") {
14797
- return Math.floor(dayCount / 30) + " month";
14798
- } else if (dateBucket === "year") {
14799
- return Math.floor(dayCount / 365) + " year";
14800
- } else {
14801
- return dayCount + " day";
14802
- }
14803
- }
14804
- }
14805
14790
  function getDateBucketFromRange(dateRange) {
14806
14791
  const difference = differenceInDays2(dateRange.end, dateRange.start);
14807
14792
  if (difference < 14) {
@@ -16615,311 +16600,765 @@ function parseValueFromBigQueryDates(rows, columns) {
16615
16600
  });
16616
16601
  }
16617
16602
 
16618
- // src/utils/merge.ts
16619
- import {
16620
- add,
16621
- startOfDay as startOfDay3,
16622
- startOfMonth,
16623
- startOfWeek as startOfWeek3,
16624
- startOfYear
16625
- } from "date-fns";
16626
- import { utcToZonedTime as utcToZonedTime2 } from "date-fns-tz";
16627
- function mergeComparisonRange(resp) {
16628
- if (resp.chartType === "table") return resp;
16629
- const compRows = resp.compareRows;
16630
- if (!compRows) return resp;
16631
- const newRows = resp.rows.map((row, i) => {
16632
- if (i < compRows.length) {
16633
- const compRow = compRows[i];
16634
- const newRow = { ...row };
16635
- for (const [key, value] of Object.entries(compRow)) {
16636
- newRow[`comparison_${key}`] = value;
16603
+ // src/utils/pivotConstructor.ts
16604
+ async function generatePivotWithSQL({
16605
+ pivot,
16606
+ report,
16607
+ client,
16608
+ dateBucket,
16609
+ dateFilter,
16610
+ distinctStrings,
16611
+ dashboardName,
16612
+ tenants,
16613
+ additionalProcessing,
16614
+ pivotQuery,
16615
+ comparisonPivotQuery,
16616
+ getPivotRowCount = true,
16617
+ caller,
16618
+ getToken
16619
+ }) {
16620
+ const databaseType = client.databaseType || "postgresql";
16621
+ if (!pivot.aggregations?.length && pivot.aggregationType) {
16622
+ pivot.aggregations = [
16623
+ {
16624
+ aggregationType: pivot.aggregationType,
16625
+ valueField: pivot.valueField,
16626
+ valueFieldType: pivot.valueFieldType,
16627
+ valueField2: pivot.valueField2,
16628
+ valueField2Type: pivot.valueField2Type
16637
16629
  }
16638
- return newRow;
16639
- }
16640
- return row;
16630
+ ];
16631
+ }
16632
+ const pivotConfig = {
16633
+ rowField: pivot.rowField,
16634
+ rowFieldType: pivot.rowFieldType,
16635
+ columnField: pivot.columnField,
16636
+ aggregations: pivot.aggregations?.map((agg) => ({
16637
+ aggregationType: agg.aggregationType,
16638
+ valueField: agg.valueField,
16639
+ valueFieldType: agg.valueFieldType
16640
+ }))
16641
+ };
16642
+ const resp = await quillFetch({
16643
+ client,
16644
+ task: "pivot-template",
16645
+ metadata: {
16646
+ clientId: client.clientId,
16647
+ pivot: pivotConfig,
16648
+ itemQuery: report?.queryString,
16649
+ dashboardName,
16650
+ tenants
16651
+ },
16652
+ credentials: "same-origin",
16653
+ getToken
16641
16654
  });
16642
- return { ...resp, rows: newRows };
16643
- }
16644
- function dateAdder(date, interval2) {
16645
- const match = interval2.match(/^(\d+)\s+(day|month|year)$/);
16646
- if (!match) {
16647
- throw new Error(`Invalid interval format: ${interval2}`);
16655
+ if (resp.data?.success === false) {
16656
+ throw resp.data.errorMessage;
16648
16657
  }
16649
- const [, valueStr, unit] = match;
16650
- if (!valueStr || !unit) {
16651
- throw new Error("Could not parse interval");
16658
+ const queryResponseRows = resp.data?.rows || resp.queries?.queryResults?.[0]?.rows || [];
16659
+ const queryResponseFields = resp.data?.fields || resp.queries?.queryResults?.[0]?.fields || [];
16660
+ const rowCount = resp.queries?.queryResults?.[1]?.rows?.[0]?.row_count || 0;
16661
+ parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
16662
+ const responseRows = queryResponseRows;
16663
+ const responseFields = queryResponseFields;
16664
+ const rows = pivot.rowField ? responseRows.map(
16665
+ (row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
16666
+ ) : responseRows;
16667
+ if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
16668
+ rows.forEach((row) => {
16669
+ Object.keys(row).forEach((key) => {
16670
+ const processedKey = processColumnName(key);
16671
+ if (processedKey !== key) {
16672
+ row[processedKey] = row[key];
16673
+ delete row[key];
16674
+ }
16675
+ });
16676
+ });
16652
16677
  }
16653
- const value = parseInt(valueStr, 10);
16654
- const parsedDate = typeof date === "string" ? new Date(date) : date;
16655
- switch (unit) {
16656
- case "day":
16657
- return add(parsedDate, { days: value });
16658
- case "month":
16659
- return add(parsedDate, { months: value });
16660
- case "year":
16661
- return add(parsedDate, { years: value });
16662
- default:
16663
- throw new Error(`Unsupported interval unit: ${unit}`);
16678
+ const columns = responseFields?.map((field) => ({
16679
+ field: processColumnName(field.field || field.name),
16680
+ label: snakeCaseToTitleCase(
16681
+ processColumnName(
16682
+ (field.field || field.name).replace("comparison_", "comparison ")
16683
+ )
16684
+ ),
16685
+ format: (field.field || field.name) === pivot.rowField ? "string" : pivot.aggregations?.find(
16686
+ (agg) => agg.valueField === (field.field || field.name) || `${agg.valueField}_percentage` === (field.field || field.name) || !agg.valueField && agg.aggregationType === "percentage" && (field.field || field.name)?.endsWith("percentage")
16687
+ )?.aggregationType === "percentage" ? "percent" : "whole_number",
16688
+ fieldType: field.fieldType,
16689
+ jsType: field.jsType,
16690
+ dataTypeID: field.dataTypeID
16691
+ })).filter(
16692
+ (field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
16693
+ ).sort((a, b) => {
16694
+ if (a.field === pivot.rowField) {
16695
+ return -1;
16696
+ }
16697
+ if (b.field === pivot.rowField) {
16698
+ return 1;
16699
+ }
16700
+ return 0;
16701
+ });
16702
+ if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
16703
+ rows.forEach((row) => {
16704
+ row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
16705
+ let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
16706
+ if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
16707
+ const rowDate = new Date(value);
16708
+ if (rowDate < dateFilter.startDate) {
16709
+ value = dateFilter.startDate.toISOString();
16710
+ } else if (rowDate > dateFilter.endDate) {
16711
+ value = dateFilter.endDate.toISOString();
16712
+ }
16713
+ }
16714
+ const dateString = getDateString(
16715
+ value,
16716
+ dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
16717
+ dateBucket,
16718
+ databaseType
16719
+ );
16720
+ row[pivot.rowField || ""] = dateString;
16721
+ });
16722
+ if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
16723
+ const dateSet = new Set(
16724
+ rows.map((row) => row[pivot.rowField || ""])
16725
+ );
16726
+ for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
16727
+ const formattedDate = getDateString(
16728
+ date.toISOString(),
16729
+ { start: dateFilter.startDate, end: dateFilter.endDate },
16730
+ dateBucket,
16731
+ databaseType
16732
+ );
16733
+ if (!dateSet.has(formattedDate)) {
16734
+ const newRow = {};
16735
+ newRow[pivot.rowField] = formattedDate;
16736
+ newRow.__quillRawDate = date.toISOString();
16737
+ rows.push(newRow);
16738
+ dateSet.add(formattedDate);
16739
+ }
16740
+ }
16741
+ }
16742
+ if (!pivot.sort) {
16743
+ rows.sort((a, b) => {
16744
+ if (a.__quillRawDate < b.__quillRawDate) {
16745
+ return -1;
16746
+ }
16747
+ if (a.__quillRawDate > b.__quillRawDate) {
16748
+ return 1;
16749
+ }
16750
+ return 0;
16751
+ });
16752
+ }
16664
16753
  }
16754
+ columns?.forEach((column, index) => {
16755
+ if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
16756
+ column.label = "Count";
16757
+ }
16758
+ });
16759
+ const numericColumns = columns?.filter(
16760
+ (column) => column.format === "whole_number" || column.format === "percentage"
16761
+ );
16762
+ rows.forEach((row) => {
16763
+ numericColumns?.forEach((column) => {
16764
+ row[column.field] = row[column.field] ?? 0;
16765
+ });
16766
+ });
16767
+ return {
16768
+ rows,
16769
+ columns: columns ?? [],
16770
+ rowCount: rowCount || rows.length,
16771
+ pivotQuery: report?.queryString || "",
16772
+ comparisonPivotQuery: comparisonPivotQuery || ""
16773
+ };
16665
16774
  }
16666
- function dateTrunc(date, granularity = "day", databaseType) {
16667
- const weekStartsOn = databaseType === "mssql" ? 0 : 1;
16668
- const timeZone = "UTC";
16669
- const zonedDate = utcToZonedTime2(date, timeZone);
16670
- switch (granularity.toLowerCase()) {
16671
- case "week":
16672
- return startOfWeek3(zonedDate, { weekStartsOn });
16673
- case "month":
16674
- return startOfMonth(zonedDate);
16675
- case "day":
16676
- return startOfDay3(zonedDate);
16677
- case "year":
16678
- return startOfYear(zonedDate);
16679
- default:
16680
- throw new Error(`Unsupported granularity: ${granularity}`);
16775
+ function generatePivotTableYAxis(pivot, cols, yAxisField) {
16776
+ if (pivot?.aggregationType === "count") {
16777
+ return [
16778
+ {
16779
+ field: pivot.valueField ?? "count",
16780
+ label: yAxisField.label,
16781
+ format: yAxisField.format
16782
+ }
16783
+ ];
16681
16784
  }
16785
+ return [
16786
+ {
16787
+ field: pivot.valueField ?? "count",
16788
+ label: yAxisField.label,
16789
+ format: yAxisField.format
16790
+ }
16791
+ ];
16682
16792
  }
16683
- function mergeComparisonPivotColumns({
16684
- pivot,
16685
- rows,
16686
- compRows
16687
- }) {
16688
- if (!compRows || !compRows.length) return rows;
16689
- const mappedCompRows = compRows.filter((compRow) => compRow.name !== pivot.rowField).map((compRow) => ({ ...compRow, name: `comparison_${compRow.name}` }));
16690
- return rows.concat(mappedCompRows);
16793
+ function generatePivotTitle(pivot) {
16794
+ if (pivot.rowField && !pivot.valueField && pivot.aggregations?.[0]) {
16795
+ return snakeAndCamelCaseToTitleCase(
16796
+ `${pivot.aggregations[0].aggregationType} of ${pivot.rowField}${pivot.columnField ? ` by ${pivot.columnField}` : ""}
16797
+ `
16798
+ );
16799
+ } else if (!pivot.rowField && pivot.aggregations?.[0]?.valueField) {
16800
+ return snakeAndCamelCaseToTitleCase(
16801
+ `${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
16802
+ `
16803
+ );
16804
+ }
16805
+ return snakeAndCamelCaseToTitleCase(
16806
+ `${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
16807
+ );
16691
16808
  }
16692
- function mergeComparisonPivotRows({
16809
+ async function generatePivotTable({
16693
16810
  pivot,
16694
- rows,
16695
- compRows,
16696
- databaseType,
16697
16811
  dateBucket,
16698
- comparisonInterval,
16699
- columnFieldValues
16812
+ dateFilter,
16813
+ report,
16814
+ client,
16815
+ getToken,
16816
+ eventTracking,
16817
+ uniqueValues,
16818
+ dashboardName,
16819
+ tenants,
16820
+ additionalProcessing,
16821
+ caller,
16822
+ pivotQuery
16700
16823
  }) {
16701
- if (!compRows || !compRows.length) return rows;
16702
- if (pivot.columnField && columnFieldValues && columnFieldValues.length > 0) {
16703
- return merge2DPivotRows(
16704
- pivot,
16705
- rows,
16706
- compRows,
16707
- columnFieldValues,
16708
- databaseType,
16709
- dateBucket,
16710
- comparisonInterval
16711
- );
16712
- }
16713
- if (pivot.rowField) {
16714
- return merge1DPivotRows(
16715
- pivot,
16716
- rows,
16717
- compRows,
16718
- databaseType,
16719
- dateBucket,
16720
- comparisonInterval
16721
- );
16824
+ try {
16825
+ if (report && client) {
16826
+ const pivotTable = await generatePivotWithSQL({
16827
+ pivotQuery,
16828
+ pivot,
16829
+ report,
16830
+ client,
16831
+ dateBucket,
16832
+ dateFilter,
16833
+ dashboardName,
16834
+ tenants,
16835
+ additionalProcessing,
16836
+ caller,
16837
+ getToken
16838
+ });
16839
+ return pivotTable;
16840
+ }
16841
+ } catch (e) {
16842
+ eventTracking?.logError?.({
16843
+ type: "bug",
16844
+ // TODO: determine type
16845
+ severity: "high",
16846
+ message: "Error generating pivot table",
16847
+ errorMessage: e.message,
16848
+ errorStack: e.stack,
16849
+ errorData: {
16850
+ caller: "PivotModal",
16851
+ function: "generatePivotTable"
16852
+ }
16853
+ });
16854
+ throw Error(`Failed to generate pivot table with SQL: ${e}`);
16722
16855
  }
16723
- return mergeAggregatedRows(pivot, rows, compRows);
16856
+ throw Error("Failed to generate pivot table: invalid report");
16724
16857
  }
16725
- function merge2DPivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
16726
- if (!pivot || !pivot.columnField) {
16727
- return [];
16728
- }
16729
- if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
16730
- return merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues);
16858
+
16859
+ // src/utils/paginationProcessing.ts
16860
+ var DEFAULT_PAGINATION = {
16861
+ page: 0,
16862
+ rowsPerPage: 10,
16863
+ rowsPerRequest: 600
16864
+ };
16865
+ var DEFAULT_TABLE_PAGINATION = {
16866
+ page: 0,
16867
+ rowsPerPage: 10,
16868
+ rowsPerRequest: 50
16869
+ };
16870
+ function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
16871
+ if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
16872
+ return false;
16731
16873
  }
16732
- return merge2DDatePivotRows(
16733
- pivot,
16734
- rows,
16735
- compRows,
16736
- columnFieldValues,
16737
- databaseType,
16738
- dateBucket,
16739
- comparisonInterval
16874
+ const indexAdjustedPage = page;
16875
+ const pageInterval = Math.floor(
16876
+ indexAdjustedPage * pagination.rowsPerPage / pagination.rowsPerRequest
16877
+ );
16878
+ const indexAdjustedPreviousPage = maxPage;
16879
+ const previousPageInterval = Math.floor(
16880
+ indexAdjustedPreviousPage * pagination.rowsPerPage / pagination.rowsPerRequest
16740
16881
  );
16882
+ return pageInterval > previousPageInterval;
16741
16883
  }
16742
- function merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues) {
16743
- if (!pivot.rowField || !pivot.aggregations?.some((agg) => agg.valueField)) {
16744
- return rows;
16884
+ function shouldSortInMemory(pagination, rowCount) {
16885
+ if (!rowCount || rowCount < pagination.rowsPerRequest) {
16886
+ return true;
16745
16887
  }
16746
- return rows.map((row) => {
16747
- const matchingCompRow = compRows.find(
16748
- (compRow) => compRow[pivot.rowField] === row[pivot.rowField]
16749
- );
16750
- const comparisonFields = columnFieldValues.reduce(
16751
- (acc, fieldValue) => {
16752
- acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
16753
- return acc;
16754
- },
16755
- {}
16756
- );
16757
- return {
16758
- ...row,
16759
- ...comparisonFields
16760
- };
16761
- });
16888
+ return false;
16762
16889
  }
16763
- function merge2DDatePivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
16764
- if (!comparisonInterval || !pivot.rowField) {
16765
- return rows;
16766
- }
16767
- return rows.map((row) => {
16768
- const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
16769
- const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
16770
- const matchingCompRow = compRows.find((compRow) => {
16771
- const comparisonDateWithInterval = dateAdder(
16772
- compRow[pivot.rowField],
16773
- comparisonInterval
16774
- );
16775
- const truncatedCompRowDate = dateTrunc(
16776
- comparisonDateWithInterval,
16777
- dateBucket,
16778
- databaseType
16779
- );
16780
- return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
16781
- });
16782
- const comparisonFields = columnFieldValues.reduce(
16783
- (acc, fieldValue) => {
16784
- acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
16785
- return acc;
16786
- },
16787
- {}
16788
- );
16890
+
16891
+ // src/utils/dashboard.ts
16892
+ var defaultDashboardItem = {
16893
+ id: "",
16894
+ name: "",
16895
+ dashboardName: "",
16896
+ rows: [],
16897
+ compareRows: [],
16898
+ columns: [],
16899
+ chartType: "",
16900
+ pivot: null,
16901
+ yAxisFields: [],
16902
+ xAxisLabel: "",
16903
+ xAxisField: "",
16904
+ xAxisFormat: "string",
16905
+ order: -1,
16906
+ filtersApplied: [],
16907
+ queryString: "",
16908
+ rowCount: 0,
16909
+ columnInternal: []
16910
+ };
16911
+ async function cleanDashboardItem({
16912
+ item,
16913
+ dashboardFilters,
16914
+ getToken,
16915
+ eventTracking,
16916
+ client,
16917
+ dateBucket,
16918
+ additionalProcessing,
16919
+ customFields,
16920
+ skipPivotFetch,
16921
+ tenants
16922
+ }) {
16923
+ if (!item) return defaultDashboardItem;
16924
+ if (!item.rows) {
16789
16925
  return {
16790
- ...row,
16791
- ...comparisonFields
16926
+ ...defaultDashboardItem,
16927
+ id: item._id,
16928
+ name: item.name
16792
16929
  };
16793
- });
16794
- }
16795
- function merge1DPivotRows(pivot, rows, compRows, databaseType, dateBucket, comparisonInterval) {
16796
- if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
16797
- return merge1DStringPivotRows(pivot, rows, compRows);
16798
16930
  }
16799
- return merge1DDatePivotRows(
16800
- pivot,
16801
- rows,
16802
- compRows,
16803
- databaseType,
16804
- dateBucket,
16805
- comparisonInterval
16806
- );
16807
- }
16808
- function merge1DStringPivotRows(pivot, rows, compRows) {
16809
- if (!pivot.rowField || !pivot.valueField) {
16810
- return rows;
16931
+ const fields = item.fields || [];
16932
+ const columnsWithCustomFields = [...item.columns ?? []];
16933
+ if (item.includeCustomFields && item.rows?.length > 0) {
16934
+ const tables = item.referencedTables ?? [];
16935
+ tables.forEach((table) => {
16936
+ const _customFields = customFields?.[table] ?? [];
16937
+ _customFields.forEach((field) => {
16938
+ const isJsonCustomField = !!field.refColumn;
16939
+ if (item.rows[0][field.field] !== void 0 && !item.columns.some((col) => col.field === field.field)) {
16940
+ const result_field = fields.find((f) => f.name === field.field);
16941
+ const converted_field = convertPostgresColumn(result_field ?? {});
16942
+ columnsWithCustomFields.push({
16943
+ field: field.field,
16944
+ format: converted_field.format,
16945
+ label: snakeAndCamelCaseToTitleCase(field.field),
16946
+ fieldType: converted_field.fieldType,
16947
+ dataTypeID: converted_field.dataTypeID,
16948
+ jsType: converted_field.jsType,
16949
+ inferFormat: isJsonCustomField
16950
+ });
16951
+ }
16952
+ });
16953
+ });
16811
16954
  }
16812
- return rows.map((row) => {
16813
- const matchingCompRow = compRows.find(
16814
- (compRow) => compRow[pivot.rowField] === row[pivot.rowField]
16815
- );
16816
- let aggregationSuffix = "";
16817
- if (matchingCompRow && pivot.aggregationType === "percentage") {
16818
- if (matchingCompRow[`${pivot.valueField}_Percentage`]) {
16819
- aggregationSuffix = "_Percentage";
16820
- } else if (matchingCompRow[`${pivot.valueField}_PERCENTAGE`]) {
16821
- aggregationSuffix = "_PERCENTAGE";
16822
- } else {
16823
- aggregationSuffix = "_percentage";
16824
- }
16825
- }
16826
- return {
16827
- ...row,
16828
- [`comparison_${pivot.valueField}${aggregationSuffix}`]: matchingCompRow ? matchingCompRow[`${pivot.valueField}${aggregationSuffix}`] : null
16829
- };
16955
+ const processedColumns = item.columns.map((col) => {
16956
+ return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
16830
16957
  });
16831
- }
16832
- function merge1DDatePivotRows(pivot, rows, compRows, databaseType, dateBucket, comparisonInterval) {
16833
- if (!comparisonInterval || !pivot.rowField) {
16834
- return rows;
16835
- }
16836
- return rows.map((row) => {
16837
- const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
16838
- const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
16839
- const matchingCompRow = compRows.find((compRow) => {
16840
- const comparisonDateWithInterval = dateAdder(
16841
- compRow[`${pivot.rowField}`],
16842
- comparisonInterval
16843
- );
16844
- const truncatedCompRowDate = dateTrunc(
16845
- comparisonDateWithInterval,
16846
- dateBucket,
16847
- databaseType
16848
- );
16849
- return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
16850
- });
16851
- let aggregationSuffix = "";
16852
- if (matchingCompRow && pivot.aggregationType === "percentage") {
16853
- if (matchingCompRow[`${pivot.valueField}_Percentage`]) {
16854
- aggregationSuffix = "_Percentage";
16855
- } else if (matchingCompRow[`${pivot.valueField}_PERCENTAGE`]) {
16856
- aggregationSuffix = "_PERCENTAGE";
16857
- } else {
16858
- aggregationSuffix = "_percentage";
16859
- }
16860
- }
16958
+ const columnInternal = (item.includeCustomFields ? columnsWithCustomFields : item.columns).map((col) => {
16959
+ const field = item.fields?.find((f) => f.name === col.field);
16960
+ const converted_field = convertPostgresColumn(field ?? {});
16861
16961
  return {
16862
- ...row,
16863
- [`comparison_${pivot.valueField}${aggregationSuffix}`]: matchingCompRow?.[`${pivot.valueField}${aggregationSuffix}`] || null
16962
+ fieldType: converted_field.fieldType,
16963
+ dataTypeID: converted_field.dataTypeID,
16964
+ jsType: converted_field.jsType,
16965
+ ...col,
16966
+ label: snakeAndCamelCaseToTitleCase(col.label)
16864
16967
  };
16865
16968
  });
16866
- }
16867
- function mergeAggregatedRows(pivot, rows, compRows) {
16868
- return rows.map((row, i) => {
16869
- let aggregationSuffix = "";
16870
- if (compRows[i] && pivot.aggregationType === "percentage") {
16871
- if (compRows[i][`${pivot.valueField}_Percentage`]) {
16872
- aggregationSuffix = "_Percentage";
16873
- } else if (compRows[i][`${pivot.valueField}_PERCENTAGE`]) {
16874
- aggregationSuffix = "_PERCENTAGE";
16875
- } else {
16876
- aggregationSuffix = "_percentage";
16969
+ let pivotTable;
16970
+ let pivotError;
16971
+ try {
16972
+ const shouldPaginatePivotAsTable = item.chartType === "table";
16973
+ const pivotChartProcessing = {
16974
+ page: DEFAULT_PAGINATION
16975
+ };
16976
+ pivotTable = await getPivotTable(
16977
+ {
16978
+ ...item,
16979
+ pivot: item.pivot && !skipPivotFetch ? {
16980
+ ...item.pivot,
16981
+ aggregations: item.pivot.aggregations ?? [
16982
+ {
16983
+ valueField: item.pivot.valueField,
16984
+ valueFieldType: item.pivot.valueFieldType,
16985
+ valueField2: item.pivot.valueField2,
16986
+ valueField2Type: item.pivot.valueField2Type,
16987
+ aggregationType: item.pivot.aggregationType
16988
+ }
16989
+ ]
16990
+ } : void 0
16991
+ },
16992
+ dashboardFilters,
16993
+ item.dashboardName,
16994
+ getToken,
16995
+ client,
16996
+ eventTracking,
16997
+ dateBucket,
16998
+ shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
16999
+ tenants,
17000
+ customFields
17001
+ );
17002
+ } catch (e) {
17003
+ pivotTable = void 0;
17004
+ eventTracking?.logError?.({
17005
+ type: "bug",
17006
+ // TODO: determine type
17007
+ severity: "high",
17008
+ message: "Error fetching pivot table",
17009
+ errorMessage: e.message,
17010
+ errorStack: e.stack,
17011
+ errorData: {
17012
+ caller: "cleanDashboardItem",
17013
+ function: "cleanDashboardItem"
16877
17014
  }
17015
+ });
17016
+ console.error("Error fetching pivot table", e);
17017
+ pivotError = "Error fetching pivot table";
17018
+ }
17019
+ const referenceLineYValues = [];
17020
+ for (const key in item) {
17021
+ if (key.startsWith("referenceLine_")) {
17022
+ const field = key.slice(14);
17023
+ if (!item[key] || !item[key][0]) continue;
17024
+ const value = Object.values(item[key][0])[0];
17025
+ referenceLineYValues.push({ label: field, query: [value, value] });
16878
17026
  }
16879
- const compRow = {
16880
- [`comparison_${pivot.valueField}${aggregationSuffix}`]: compRows[i]?.[`${pivot.valueField}${aggregationSuffix}`]
16881
- };
16882
- return { ...row, ...compRow };
16883
- });
16884
- }
16885
-
16886
- // src/utils/queryConstructor.ts
16887
- function processSingleQuotes(value, databaseType) {
16888
- if (["postgresql", "snowflake", "clickhouse"].includes(
16889
- databaseType.toLowerCase()
16890
- )) {
16891
- return value.replaceAll("'", "''");
16892
17027
  }
16893
- return value.replaceAll("'", "\\'");
16894
- }
16895
- function processAggType(aggType, hasColumnField = false) {
16896
- if (aggType === "count" && hasColumnField) return "SUM";
16897
- return aggType?.toLowerCase() === "average" ? "AVG" : aggType?.toLowerCase();
16898
- }
16899
- function replaceBigQuerySpecialCharacters(column) {
16900
- return column.replaceAll("/", "quill_forward_slash");
16901
- }
16902
- function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
16903
- switch (databaseType.toLowerCase()) {
16904
- case "postgresql":
16905
- case "clickhouse": {
16906
- if (column === "") {
16907
- return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
16908
- }
16909
- if (isColumnFieldAlias) {
16910
- return `"${column.replaceAll('"', "")}"`;
16911
- }
16912
- const columnParts = column.split(".");
16913
- if (columnParts.length > 1) {
16914
- return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
17028
+ if (item.referenceLines) {
17029
+ for (const referenceLine of item.referenceLines) {
17030
+ if (Array.isArray(referenceLine.query)) {
17031
+ referenceLineYValues.push({
17032
+ label: referenceLine.label,
17033
+ query: referenceLine.query
17034
+ });
17035
+ } else if (referenceLine.query === "") {
17036
+ referenceLineYValues.push({
17037
+ label: referenceLine.label,
17038
+ query: (pivotTable?.rows ? pivotTable.rows : item.rows).map(
17039
+ (row) => Number(row[referenceLine.label]) || 0
17040
+ )
17041
+ });
16915
17042
  }
16916
- return `"${column.replaceAll('"', "")}"`;
16917
17043
  }
16918
- case "mysql": {
16919
- if (column === "") {
16920
- return fallbackOnNull ? `${fallbackOnNull}` : "_";
16921
- }
16922
- if (isColumnFieldAlias) {
17044
+ }
17045
+ return {
17046
+ id: item._id ?? item.id,
17047
+ name: item.name,
17048
+ dashboardName: item.dashboardName,
17049
+ // section: item.section,
17050
+ rows: item.rows,
17051
+ pivotRows: pivotTable ? pivotTable.rows : void 0,
17052
+ pivotColumns: pivotTable ? pivotTable.columns : void 0,
17053
+ compareRows: item.compareRows,
17054
+ columns: processedColumns.map((column) => {
17055
+ return {
17056
+ field: column.field,
17057
+ format: column.format,
17058
+ label: column.label,
17059
+ inferFormat: column.inferFormat
17060
+ };
17061
+ }),
17062
+ includeCustomFields: item.includeCustomFields,
17063
+ columnInternal,
17064
+ columnsWithCustomFields,
17065
+ chartType: item.chartType,
17066
+ dateField: item.dateField,
17067
+ pivot: pivotError ? void 0 : item.pivot ? {
17068
+ ...item.pivot,
17069
+ aggregations: item.pivot.aggregations ?? [
17070
+ {
17071
+ valueField: item.pivot.valueField,
17072
+ valueFieldType: item.pivot.valueFieldType,
17073
+ valueField2: item.pivot.valueField2,
17074
+ valueField2Type: item.pivot.valueField2Type,
17075
+ aggregationType: item.pivot.aggregationType
17076
+ }
17077
+ ],
17078
+ columnValues: item.distinctStrings
17079
+ } : void 0,
17080
+ yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
17081
+ xAxisLabel: item.xAxisLabel,
17082
+ xAxisField: item.xAxisField,
17083
+ xAxisFormat: item.xAxisFormat,
17084
+ order: item.order,
17085
+ filtersApplied: item.filtersApplied,
17086
+ filterMap: item.filterMap,
17087
+ flags: item.flags,
17088
+ rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
17089
+ pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
17090
+ template: item.template,
17091
+ sort: item.sort,
17092
+ itemQuery: item.itemQuery,
17093
+ queryString: item.queryString,
17094
+ pivotQuery: pivotTable?.pivotQuery,
17095
+ comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
17096
+ referencedTables: item?.referencedTables || [],
17097
+ referencedColumns: item?.referencedColumns || {},
17098
+ error: item.error ?? pivotError,
17099
+ referenceLineYValues,
17100
+ referenceLines: item.referenceLines
17101
+ };
17102
+ }
17103
+ async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
17104
+ if (!report) return void 0;
17105
+ const dateFilter = Object.values(dashboardFilters ?? {}).find(
17106
+ (filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
17107
+ );
17108
+ if (dateFilter?.operator === "BETWEEN") {
17109
+ dateFilter.startDate = dateFilter.value[0];
17110
+ dateFilter.endDate = dateFilter.value[1];
17111
+ }
17112
+ const pivot = report?.pivot;
17113
+ const data = report || {};
17114
+ if (pivot && client) {
17115
+ if (report.rowCount === 0 || report.rows.length === 0) {
17116
+ const columns = [];
17117
+ if (pivot.rowField) {
17118
+ columns.push({
17119
+ field: pivot.rowField,
17120
+ label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
17121
+ format: pivot.rowFieldType || "string",
17122
+ jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
17123
+ fieldType: pivot.rowFieldType || "string",
17124
+ dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
17125
+ });
17126
+ }
17127
+ for (const agg of pivot.aggregations ?? []) {
17128
+ if (agg.valueField) {
17129
+ columns.push({
17130
+ field: agg.valueField,
17131
+ label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
17132
+ //FIXME: valueFieldType is not always the same as the format
17133
+ format: agg.valueFieldType ?? "whole_number",
17134
+ jsType: agg.valueFieldType ?? "number",
17135
+ fieldType: agg.valueFieldType ?? "number",
17136
+ dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
17137
+ });
17138
+ }
17139
+ }
17140
+ return {
17141
+ rows: [],
17142
+ rowCount: 0,
17143
+ pivotQuery: report.queryString ?? "",
17144
+ columns
17145
+ };
17146
+ }
17147
+ try {
17148
+ let dateBucket = dateBucketInitial;
17149
+ let filterDateRange = void 0;
17150
+ if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
17151
+ filterDateRange = {
17152
+ start: dateFilter.startDate,
17153
+ end: dateFilter.endDate
17154
+ };
17155
+ } else if (report.dateRange) {
17156
+ filterDateRange = report.dateRange;
17157
+ }
17158
+ if (!dateBucket && filterDateRange) {
17159
+ dateBucket = getDateBucketFromRange(filterDateRange);
17160
+ }
17161
+ const pivotTable = await generatePivotWithSQL({
17162
+ pivot,
17163
+ report,
17164
+ client,
17165
+ dateBucket,
17166
+ dateFilter,
17167
+ dashboardName,
17168
+ tenants,
17169
+ additionalProcessing,
17170
+ getToken
17171
+ });
17172
+ return pivotTable;
17173
+ } catch (e) {
17174
+ eventTracking?.logError?.({
17175
+ type: "bug",
17176
+ // TODO: determine type
17177
+ severity: "high",
17178
+ message: "Error fetching pivot table",
17179
+ errorMessage: e.message,
17180
+ errorStack: e.stack,
17181
+ errorData: {
17182
+ caller: "getPivotTable",
17183
+ function: "getPivotTable"
17184
+ }
17185
+ });
17186
+ console.error("Error fetching pivot table", e);
17187
+ throw e;
17188
+ }
17189
+ }
17190
+ return pivot && data.rows ? generatePivotTable({
17191
+ pivot,
17192
+ report,
17193
+ client,
17194
+ uniqueValues: report.distinctStrings,
17195
+ dashboardName,
17196
+ tenants,
17197
+ dateFilter,
17198
+ additionalProcessing,
17199
+ getToken,
17200
+ eventTracking
17201
+ }) : void 0;
17202
+ }
17203
+ function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
17204
+ if (!pivotTable) return itemInfo?.yAxisFields ?? [];
17205
+ const pivot = itemInfo?.pivot || config?.pivot;
17206
+ if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
17207
+ const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
17208
+ return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
17209
+ }
17210
+ async function getDashboard(dashboardName, client, getToken, tenants, flags) {
17211
+ const { data: resp } = await quillFetch({
17212
+ client,
17213
+ task: "dashboard",
17214
+ metadata: {
17215
+ name: dashboardName,
17216
+ clientId: client.publicKey,
17217
+ databaseType: client.databaseType,
17218
+ useNewNodeSql: true,
17219
+ tenants,
17220
+ flags
17221
+ },
17222
+ getToken
17223
+ });
17224
+ return {
17225
+ ...resp,
17226
+ createdAt: resp.createdAt && new Date(resp.createdAt),
17227
+ dateFilter: resp.dateFilter ? {
17228
+ ...resp.dateFilter,
17229
+ presetOptions: resp.dateFilter.presetOptions?.map(
17230
+ (preset) => ({
17231
+ ...preset,
17232
+ loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
17233
+ loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
17234
+ })
17235
+ ),
17236
+ defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
17237
+ (preset) => ({
17238
+ ...preset,
17239
+ loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
17240
+ loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
17241
+ })
17242
+ )
17243
+ } : void 0
17244
+ };
17245
+ }
17246
+
17247
+ // src/utils/chartBuilder.ts
17248
+ var numberFormatOptions = [
17249
+ "whole_number",
17250
+ "one_decimal_place",
17251
+ "two_decimal_places",
17252
+ "dollar_amount",
17253
+ "dollar_cents",
17254
+ "percentage"
17255
+ ];
17256
+ var dateFormatOptions = [
17257
+ "MMM_yyyy",
17258
+ "MMM_dd",
17259
+ "MMM_dd_yyyy",
17260
+ "MMM_dd_hh:mm_ap_pm",
17261
+ "hh_ap_pm",
17262
+ "date",
17263
+ "timestamptz"
17264
+ ];
17265
+ var NUMBER_OPTIONS = [
17266
+ { value: "whole_number", label: "whole number" },
17267
+ { value: "one_decimal_place", label: "one decimal place" },
17268
+ { value: "two_decimal_places", label: "two decimal places" },
17269
+ { value: "dollar_amount", label: "dollar amount" },
17270
+ { value: "dollar_cents", label: "dollar and cent amount" },
17271
+ { value: "percent", label: "percentage" }
17272
+ ];
17273
+ var DATE_OPTIONS = [
17274
+ { value: "MMM_yyyy", label: "month" },
17275
+ { value: "MMM_dd", label: "day" },
17276
+ { value: "MMM_dd_yyyy", label: "day and year" },
17277
+ { value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
17278
+ { value: "hh_ap_pm", label: "hour" }
17279
+ ];
17280
+ var ALL_FORMAT_OPTIONS = [
17281
+ ...NUMBER_OPTIONS,
17282
+ ...DATE_OPTIONS,
17283
+ { value: "string", label: "string" }
17284
+ ];
17285
+ function createInitialFormData(columns) {
17286
+ const firstNumberColumn = columns?.find(
17287
+ (col) => numberFormatOptions.includes(col.format)
17288
+ );
17289
+ const firstStringColumn = columns?.find(
17290
+ (col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
17291
+ );
17292
+ const firstDateColumn = columns?.find(
17293
+ (col) => dateFormatOptions.includes(col.format)
17294
+ );
17295
+ const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
17296
+ const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
17297
+ const formEmptyState = {
17298
+ name: "",
17299
+ columns: columns.map((col) => {
17300
+ return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
17301
+ }),
17302
+ xAxisField,
17303
+ xAxisFormat,
17304
+ yAxisFields: [
17305
+ {
17306
+ field: firstNumberColumn?.field || columns?.[0]?.field || "",
17307
+ label: "",
17308
+ format: firstNumberColumn?.format || columns?.[0]?.format || "string"
17309
+ }
17310
+ ],
17311
+ xAxisLabel: "",
17312
+ chartType: firstNumberColumn ? "line" : "table",
17313
+ pivot: null,
17314
+ template: true,
17315
+ referenceLines: []
17316
+ };
17317
+ return formEmptyState;
17318
+ }
17319
+
17320
+ // src/utils/error.ts
17321
+ var DataLoadError = class extends Error {
17322
+ data;
17323
+ constructor(message, data) {
17324
+ super(message);
17325
+ this.name = "DataLoadError";
17326
+ this.data = data;
17327
+ }
17328
+ };
17329
+
17330
+ // src/utils/errorProcessing.ts
17331
+ function processFilterErrorList(resp) {
17332
+ if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
17333
+ return;
17334
+ }
17335
+ }
17336
+
17337
+ // src/utils/queryConstructor.ts
17338
+ function replaceBigQuerySpecialCharacters(column) {
17339
+ return column.replaceAll("/", "quill_forward_slash");
17340
+ }
17341
+ function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
17342
+ switch (databaseType.toLowerCase()) {
17343
+ case "postgresql":
17344
+ case "clickhouse": {
17345
+ if (column === "") {
17346
+ return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
17347
+ }
17348
+ if (isColumnFieldAlias) {
17349
+ return `"${column.replaceAll('"', "")}"`;
17350
+ }
17351
+ const columnParts = column.split(".");
17352
+ if (columnParts.length > 1) {
17353
+ return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
17354
+ }
17355
+ return `"${column.replaceAll('"', "")}"`;
17356
+ }
17357
+ case "mysql": {
17358
+ if (column === "") {
17359
+ return fallbackOnNull ? `${fallbackOnNull}` : "_";
17360
+ }
17361
+ if (isColumnFieldAlias) {
16923
17362
  return `\`${column.replaceAll(`\``, "").replaceAll(`"`, "")}\``;
16924
17363
  }
16925
17364
  const columnParts = column.split(".");
@@ -16987,51 +17426,6 @@ function processColumnReference(column, databaseType, fallbackOnNull, isColumnFi
16987
17426
  function replaceSpacesWithUnderscores(column) {
16988
17427
  return column.replaceAll(" ", "_");
16989
17428
  }
16990
- function processInterval(interval2, rowField, databaseType) {
16991
- if (["postgresql", "snowflake", "clickhouse"].includes(
16992
- databaseType.toLowerCase()
16993
- )) {
16994
- return `(${processColumnReference(rowField, databaseType)} + INTERVAL '${interval2}')`;
16995
- } else if (databaseType.toLowerCase() === "mysql") {
16996
- return `(${processColumnReference(rowField, databaseType)} + INTERVAL ${interval2})`;
16997
- }
16998
- return `TIMESTAMP_ADD(${processColumnReference(rowField, databaseType)}, INTERVAL ${interval2} )`;
16999
- }
17000
- function processDateTrunc(dateBucket, rowField, databaseType, comparisonInterval) {
17001
- const dateField = comparisonInterval ? processInterval(comparisonInterval, rowField, databaseType) : processColumnReference(rowField, databaseType);
17002
- if (["postgresql", "snowflake"].includes(databaseType.toLowerCase())) {
17003
- return `date_trunc('${dateBucket}', ${dateField})`;
17004
- }
17005
- if (["clickhouse"].includes(databaseType.toLowerCase())) {
17006
- return `dateTrunc('${dateBucket}', ${dateField})`;
17007
- }
17008
- if (["databricks"].includes(databaseType.toLowerCase())) {
17009
- return `DATE_TRUNC('${dateBucket}', ${dateField})`;
17010
- }
17011
- if (["mysql"].includes(databaseType.toLowerCase())) {
17012
- switch (dateBucket.toLowerCase()) {
17013
- case "year":
17014
- return `DATE_FORMAT(${dateField}, '%Y-01-01 00:00:00')`;
17015
- case "month":
17016
- return `DATE_FORMAT(${dateField}, '%Y-%m-01 00:00:00')`;
17017
- case "week":
17018
- return `DATE_FORMAT(${dateField}, '%Y-%U-1 00:00:00')`;
17019
- case "day":
17020
- default:
17021
- return `DATE(${dateField})`;
17022
- }
17023
- }
17024
- if (["mssql"].includes(databaseType.toLowerCase())) {
17025
- return `DATETRUNC(${dateBucket}, ${dateField})`;
17026
- }
17027
- return `TIMESTAMP_TRUNC(${dateField}, ${dateBucket})`;
17028
- }
17029
- function processValueField(aggType, databaseType, valueField) {
17030
- if (aggType === "min" || aggType === "max" || aggType?.toLowerCase() === "average")
17031
- return `${processColumnReference(valueField, databaseType)} ELSE null`;
17032
- if (aggType === "count") return `1 ELSE 0`;
17033
- return valueField ? `${processColumnReference(valueField, databaseType)} ELSE 0` : `1 ELSE 0`;
17034
- }
17035
17429
  function generateCountQuery(fields, query, databaseType) {
17036
17430
  let countQuery = [];
17037
17431
  let cteQuery = `WITH querytable AS (${query.replace(";", "")}) `;
@@ -17150,1123 +17544,12 @@ function generateMinMaxDateRangeQueries(columnFields, query, databaseType) {
17150
17544
  const distinctQueries = columnFields.map((field) => {
17151
17545
  const wrappedField = ["postgresql", "clickhouse"].includes(
17152
17546
  databaseType.toLowerCase()
17153
- ) ? `"${field}"` : field;
17154
- return `SELECT '${field}' AS field, ${min2}(${wrappedField})${cast} AS min_range, ${max2}(${wrappedField})${cast} AS max_range FROM querytable`;
17547
+ ) ? processColumnReference(field, databaseType) : field;
17548
+ return `SELECT '${field}' AS ${processColumnReference("field", databaseType)}, ${min2}(${wrappedField})${cast} AS ${processColumnReference("min_range", databaseType)}, ${max2}(${wrappedField})${cast} AS ${processColumnReference("max_range", databaseType)} FROM querytable`;
17155
17549
  });
17156
17550
  const distinctQuery = distinctQueries.join(" UNION ALL ");
17157
17551
  return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17158
17552
  }
17159
- function generatePivotQuery(pivot, itemQuery, databaseType, distinctStrings, dateBucket) {
17160
- if (!isValidPivot(pivot).valid) {
17161
- return void 0;
17162
- }
17163
- if (pivot.columnField && distinctStrings && distinctStrings.length > 0) {
17164
- return create2DPivotQuery(
17165
- pivot,
17166
- itemQuery,
17167
- databaseType,
17168
- distinctStrings,
17169
- dateBucket
17170
- );
17171
- }
17172
- if (pivot.rowField) {
17173
- return create1DPivotQuery(pivot, itemQuery, dateBucket, databaseType);
17174
- }
17175
- return createAggregationValuePivot(pivot, itemQuery, databaseType);
17176
- }
17177
- function create2DPivotQuery(pivot, itemQuery, databaseType, columnFieldValues, dateBucket) {
17178
- if (!pivot || !pivot.columnField) {
17179
- return void 0;
17180
- }
17181
- if (isStringType(pivot.rowFieldType ?? "") || !pivot.rowFieldType) {
17182
- return create2DStringPivotQuery(
17183
- pivot,
17184
- itemQuery,
17185
- columnFieldValues,
17186
- databaseType
17187
- );
17188
- }
17189
- return create2DDatePivotQuery(
17190
- pivot,
17191
- itemQuery,
17192
- columnFieldValues,
17193
- databaseType,
17194
- dateBucket
17195
- );
17196
- }
17197
- function create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType) {
17198
- const isValidBaseQuery = itemQuery.match(
17199
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17200
- );
17201
- if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField)
17202
- return void 0;
17203
- const rowField = pivot.rowField;
17204
- if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
17205
- throw new Error("No value field provided for pivot");
17206
- if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
17207
- throw new Error("No aggregation type provided for pivot");
17208
- const columnField = pivot.columnField;
17209
- const rowFieldAlias = processColumnReference(
17210
- rowField,
17211
- databaseType,
17212
- void 0,
17213
- false,
17214
- true
17215
- );
17216
- const columnFieldAlias = processColumnReference(
17217
- columnField,
17218
- databaseType,
17219
- void 0,
17220
- false,
17221
- true
17222
- );
17223
- let caseWhens = [];
17224
- let valueAliases = [];
17225
- const seenAggs = {};
17226
- pivot.aggregations?.forEach((currentAgg) => {
17227
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17228
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17229
- } else {
17230
- seenAggs[currentAgg.aggregationType ?? ""] = {
17231
- ...seenAggs[currentAgg.aggregationType ?? ""],
17232
- [currentAgg.valueField ?? ""]: 1
17233
- };
17234
- }
17235
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
17236
- if (disambiguationIndex === "1") disambiguationIndex = "";
17237
- const valueFieldAlias = processColumnReference(
17238
- currentAgg.valueField || rowField || "count",
17239
- databaseType,
17240
- void 0,
17241
- false,
17242
- true
17243
- );
17244
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17245
- let value2AliasSubstring = "";
17246
- const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
17247
- (acc, v) => acc + v
17248
- ) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
17249
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
17250
- const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
17251
- currentAgg.aggregationType,
17252
- databaseType,
17253
- valueFieldAlias
17254
- );
17255
- if (currentAgg.aggregationType === "percentage") {
17256
- if (!currentAgg.valueField)
17257
- throw new Error("No value field provided for pivot");
17258
- const valueField2Alias = processColumnReference(
17259
- currentAgg.valueField2 ?? currentAgg.valueField,
17260
- databaseType,
17261
- void 0,
17262
- false,
17263
- true
17264
- );
17265
- const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
17266
- if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
17267
- caseWhens = [
17268
- ...caseWhens,
17269
- ...columnFieldValues.map((column) => {
17270
- return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17271
- column,
17272
- databaseType
17273
- )}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
17274
- column + disambiguation,
17275
- databaseType,
17276
- "_",
17277
- true
17278
- )}`;
17279
- })
17280
- ];
17281
- } else {
17282
- value2AliasSubstring = `${processColumnReference(
17283
- currentAgg.valueField2 ?? currentAgg.valueField,
17284
- databaseType,
17285
- void 0,
17286
- true
17287
- )} AS ${valueField2Alias}`;
17288
- caseWhens = [
17289
- ...caseWhens,
17290
- ...columnFieldValues.map((column) => {
17291
- return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17292
- column,
17293
- databaseType
17294
- )}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17295
- column,
17296
- databaseType
17297
- )}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
17298
- column + disambiguation,
17299
- databaseType,
17300
- "_",
17301
- true
17302
- )}`;
17303
- })
17304
- ];
17305
- }
17306
- } else {
17307
- caseWhens = [
17308
- ...caseWhens,
17309
- ...columnFieldValues.map((column) => {
17310
- return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17311
- column,
17312
- databaseType
17313
- )}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
17314
- })
17315
- ];
17316
- }
17317
- if (valueAliasSubstring) valueAliases.push(valueAliasSubstring);
17318
- if (value2AliasSubstring) valueAliases.push(value2AliasSubstring);
17319
- });
17320
- valueAliases = [
17321
- `${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
17322
- ...valueAliases,
17323
- `${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
17324
- ];
17325
- valueAliases = Array.from(new Set(valueAliases));
17326
- const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
17327
- const pivotQuery = `
17328
- ,quill_alias AS (
17329
- SELECT ${valueAliases.length > 0 ? `${valueAliases.join(", ")}` : ""}
17330
- FROM quill_base_table
17331
- ),
17332
- quill_qt_cw AS (
17333
- SELECT ${rowFieldAlias}
17334
- ${caseWhens.length > 0 ? `, ${caseWhens.join(", ")}` : ""}
17335
- FROM quill_alias
17336
- GROUP BY ${rowFieldAlias}
17337
- ),
17338
- quill_base_pivot AS (
17339
- SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
17340
- FROM quill_qt_cw qt
17341
- ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
17342
- )
17343
- SELECT * FROM quill_base_pivot
17344
- `.replace(/\s+/g, " ").trim();
17345
- return itemQuery.replace(
17346
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17347
- pivotQuery
17348
- );
17349
- }
17350
- function create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseType, dateBucket = "month") {
17351
- const isValidBaseQuery = itemQuery.match(
17352
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17353
- );
17354
- if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField) {
17355
- return void 0;
17356
- }
17357
- if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
17358
- throw new Error("No value field provided for pivot");
17359
- if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
17360
- throw new Error("No aggregation type provided for pivot");
17361
- const rowField = pivot.rowField;
17362
- const columnField = pivot.columnField;
17363
- const rowFieldAlias = processColumnReference(
17364
- rowField,
17365
- databaseType,
17366
- void 0,
17367
- false,
17368
- true
17369
- );
17370
- const columnFieldAlias = processColumnReference(
17371
- columnField,
17372
- databaseType,
17373
- void 0,
17374
- false,
17375
- true
17376
- );
17377
- let caseWhens = [];
17378
- let valueFieldAliases = [];
17379
- const seenAggs = {};
17380
- pivot.aggregations?.forEach((currentAgg) => {
17381
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17382
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17383
- } else {
17384
- seenAggs[currentAgg.aggregationType ?? ""] = {
17385
- ...seenAggs[currentAgg.aggregationType ?? ""],
17386
- [currentAgg.valueField ?? ""]: 1
17387
- };
17388
- }
17389
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
17390
- if (disambiguationIndex === "1") disambiguationIndex = "";
17391
- const valueFieldAlias = processColumnReference(
17392
- currentAgg.valueField ?? rowField,
17393
- databaseType,
17394
- void 0,
17395
- false,
17396
- true
17397
- );
17398
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17399
- let value2AliasSubstring = "";
17400
- const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
17401
- (acc, v) => acc + v
17402
- ) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
17403
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
17404
- const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
17405
- currentAgg.aggregationType,
17406
- databaseType,
17407
- valueFieldAlias
17408
- );
17409
- if (currentAgg.aggregationType === "percentage") {
17410
- if (!currentAgg.valueField)
17411
- throw new Error("No value field provided for pivot");
17412
- const valueField2Alias = processColumnReference(
17413
- currentAgg.valueField2 ?? currentAgg.valueField,
17414
- databaseType,
17415
- void 0,
17416
- false,
17417
- true
17418
- );
17419
- const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
17420
- if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
17421
- caseWhens = [
17422
- ...caseWhens,
17423
- ...columnFieldValues.map((column) => {
17424
- return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17425
- column,
17426
- databaseType
17427
- )}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
17428
- column + disambiguation,
17429
- databaseType,
17430
- "_",
17431
- true
17432
- )}`;
17433
- })
17434
- ];
17435
- } else {
17436
- value2AliasSubstring = `${processColumnReference(
17437
- currentAgg.valueField2 ?? currentAgg.valueField,
17438
- databaseType,
17439
- void 0,
17440
- true
17441
- )} AS ${valueField2Alias}`;
17442
- caseWhens = [
17443
- ...caseWhens,
17444
- ...columnFieldValues.map((column) => {
17445
- return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17446
- column,
17447
- databaseType
17448
- )}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17449
- column,
17450
- databaseType
17451
- )}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
17452
- column + disambiguation,
17453
- databaseType,
17454
- "_",
17455
- true
17456
- )}`;
17457
- })
17458
- ];
17459
- }
17460
- } else {
17461
- caseWhens = [
17462
- ...caseWhens,
17463
- ...columnFieldValues.map((column) => {
17464
- return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17465
- column,
17466
- databaseType
17467
- )}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
17468
- })
17469
- ];
17470
- }
17471
- if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
17472
- if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
17473
- });
17474
- valueFieldAliases = [
17475
- `${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
17476
- ...valueFieldAliases,
17477
- `${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
17478
- ];
17479
- valueFieldAliases = Array.from(new Set(valueFieldAliases));
17480
- const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
17481
- const pivotQuery = `
17482
- , quill_alias AS (SELECT ${valueFieldAliases.length > 0 ? `${valueFieldAliases.join(", ")}` : ""} FROM quill_base_table),
17483
- quill_qt_agg AS (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(", ")}` : ""} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === "clickhouse" ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
17484
- quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
17485
- ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
17486
- SELECT * FROM quill_base_pivot
17487
- `.replace(/\s+/g, " ").trim();
17488
- return itemQuery.replace(
17489
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17490
- pivotQuery
17491
- );
17492
- }
17493
- function create1DPivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
17494
- if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
17495
- return create1DStringPivotQuery(pivot, itemQuery, databaseType);
17496
- }
17497
- return create1DDatePivotQuery(pivot, itemQuery, dateBucket, databaseType);
17498
- }
17499
- function create1DStringPivotQuery(pivot, itemQuery, databaseType) {
17500
- const isValidBaseQuery = itemQuery.match(
17501
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17502
- );
17503
- if (!isValidBaseQuery) return void 0;
17504
- const rowField = pivot.rowField;
17505
- const rowAlias = processColumnReference(
17506
- rowField,
17507
- databaseType,
17508
- void 0,
17509
- true
17510
- );
17511
- let quillAggSelects = [rowAlias];
17512
- let valueFieldAliases = [];
17513
- const seenAggs = {};
17514
- pivot.aggregations?.forEach((currentAgg) => {
17515
- if (!currentAgg.valueField) currentAgg.valueField = void 0;
17516
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17517
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17518
- } else {
17519
- seenAggs[currentAgg.aggregationType ?? ""] = {
17520
- ...seenAggs[currentAgg.aggregationType ?? ""],
17521
- [currentAgg.valueField ?? ""]: 1
17522
- };
17523
- }
17524
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
17525
- if (disambiguationIndex === "1") disambiguationIndex = "";
17526
- const valueFieldAlias = processColumnReference(
17527
- currentAgg.valueField || rowField || "count",
17528
- databaseType,
17529
- void 0,
17530
- false,
17531
- true
17532
- );
17533
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17534
- let value2AliasSubstring = "";
17535
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
17536
- let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
17537
- if (currentAgg.valueFieldType === "bool") {
17538
- valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
17539
- }
17540
- if (currentAgg.aggregationType === "percentage") {
17541
- let countPercentage = false;
17542
- if (!currentAgg.valueField) {
17543
- countPercentage = true;
17544
- }
17545
- const valueField2Alias = processColumnReference(
17546
- currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
17547
- databaseType,
17548
- void 0,
17549
- false,
17550
- true
17551
- );
17552
- let value2Expr = valueField2Alias;
17553
- if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
17554
- value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
17555
- }
17556
- value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
17557
- const percentageExpr = countPercentage ? "CAST(COUNT(*) AS FLOAT) / (SELECT COUNT(*) FROM quill_base_table)" : currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
17558
- quillAggSelects = [
17559
- ...quillAggSelects,
17560
- `${percentageExpr} as ${processColumnReference(
17561
- `${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
17562
- databaseType,
17563
- void 0,
17564
- false,
17565
- true
17566
- )}`
17567
- ];
17568
- } else {
17569
- quillAggSelects = [
17570
- ...quillAggSelects,
17571
- `${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
17572
- (currentAgg.valueField || "count") + disambiguation,
17573
- databaseType
17574
- )}`
17575
- ];
17576
- }
17577
- if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
17578
- if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
17579
- });
17580
- valueFieldAliases = Array.from(new Set(valueFieldAliases));
17581
- const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
17582
- const pivotQuery = `, quill_alias AS (
17583
- SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
17584
- FROM quill_base_table
17585
- ),
17586
- quill_qt_cw AS (
17587
- SELECT ${quillAggSelects.join(", ")} FROM quill_alias GROUP BY ${rowAlias}
17588
- ),
17589
- quill_base_pivot AS (
17590
- SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
17591
- FROM quill_qt_cw qt ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
17592
- )
17593
- SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
17594
- return itemQuery.replace(
17595
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17596
- pivotQuery
17597
- );
17598
- }
17599
- function create1DDatePivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
17600
- const isValidBaseQuery = itemQuery.match(
17601
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17602
- );
17603
- if (!isValidBaseQuery) {
17604
- return void 0;
17605
- }
17606
- const rowField = pivot.rowField || "";
17607
- const rowFieldAlias = processColumnReference(
17608
- rowField,
17609
- databaseType,
17610
- void 0
17611
- );
17612
- let quillAggSelects = [
17613
- `${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(rowField, databaseType)}`
17614
- ];
17615
- let valueFieldAliases = [];
17616
- const seenAggs = {};
17617
- pivot.aggregations?.forEach((currentAgg) => {
17618
- if (!currentAgg.valueField) currentAgg.valueField = void 0;
17619
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17620
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17621
- } else {
17622
- seenAggs[currentAgg.aggregationType ?? ""] = {
17623
- ...seenAggs[currentAgg.aggregationType ?? ""],
17624
- [currentAgg.valueField ?? ""]: 1
17625
- };
17626
- }
17627
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
17628
- if (disambiguationIndex === "1") disambiguationIndex = "";
17629
- const valueFieldAlias = processColumnReference(
17630
- currentAgg.valueField || rowField || "count",
17631
- databaseType,
17632
- void 0,
17633
- false,
17634
- true
17635
- );
17636
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17637
- let value2AliasSubstring = "";
17638
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
17639
- let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
17640
- if (currentAgg.valueFieldType === "bool") {
17641
- valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
17642
- }
17643
- if (currentAgg.aggregationType === "percentage") {
17644
- let countPercentage = false;
17645
- if (!currentAgg.valueField) {
17646
- countPercentage = true;
17647
- }
17648
- const valueField2Alias = processColumnReference(
17649
- currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
17650
- databaseType,
17651
- void 0,
17652
- false,
17653
- true
17654
- );
17655
- value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
17656
- let value2Expr = valueField2Alias;
17657
- if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
17658
- value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
17659
- }
17660
- const percentageExpr = countPercentage ? "CAST(COUNT(*) AS FLOAT) / (SELECT COUNT(*) FROM quill_base_table)" : currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
17661
- quillAggSelects = [
17662
- ...quillAggSelects,
17663
- `${percentageExpr} as ${processColumnReference(
17664
- `${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
17665
- databaseType,
17666
- void 0,
17667
- false,
17668
- true
17669
- )}`
17670
- ];
17671
- } else {
17672
- quillAggSelects = [
17673
- ...quillAggSelects,
17674
- `${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference((currentAgg.valueField || "count") + disambiguation, databaseType)}`
17675
- ];
17676
- }
17677
- if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
17678
- if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
17679
- });
17680
- valueFieldAliases = Array.from(new Set(valueFieldAliases));
17681
- const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
17682
- const pivotQuery = `, quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowFieldAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
17683
- FROM quill_base_table),
17684
- quill_qt_agg AS (SELECT ${quillAggSelects.join(", ")}
17685
- FROM quill_alias GROUP BY ${databaseType.toLowerCase() === "clickhouse" ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
17686
- quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
17687
- ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
17688
- SELECT * FROM quill_base_pivot
17689
- `.replace(/\s+/g, " ").trim();
17690
- return itemQuery.replace(
17691
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17692
- pivotQuery
17693
- );
17694
- }
17695
- function createAggregationValuePivot(pivot, itemQuery, databaseType) {
17696
- const isValidBaseQuery = itemQuery.match(
17697
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17698
- );
17699
- if (!isValidBaseQuery) return void 0;
17700
- let quillAggSelects = [];
17701
- let valueFieldAliases = [];
17702
- const seenAggs = {};
17703
- pivot.aggregations?.forEach((currentAgg) => {
17704
- if (!currentAgg.valueField) currentAgg.valueField = void 0;
17705
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17706
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17707
- } else {
17708
- seenAggs[currentAgg.aggregationType ?? ""] = {
17709
- ...seenAggs[currentAgg.aggregationType ?? ""],
17710
- [currentAgg.valueField ?? ""]: 1
17711
- };
17712
- }
17713
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
17714
- if (disambiguationIndex === "1") disambiguationIndex = "";
17715
- const valueFieldAlias = processColumnReference(
17716
- currentAgg.valueField || "count",
17717
- databaseType,
17718
- void 0,
17719
- false,
17720
- true
17721
- );
17722
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17723
- let value2AliasSubstring = "";
17724
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}_${currentAgg.aggregationType}` : "";
17725
- let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
17726
- valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : valueExpr;
17727
- if (currentAgg.aggregationType === "percentage") {
17728
- if (!currentAgg.valueField) {
17729
- throw new Error("No value field provided for percentage aggregation");
17730
- }
17731
- const valueField2Alias = processColumnReference(
17732
- currentAgg.valueField2 ?? currentAgg.valueField,
17733
- databaseType,
17734
- void 0,
17735
- false,
17736
- true
17737
- );
17738
- const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
17739
- value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
17740
- const percentageExpr = currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
17741
- quillAggSelects = [
17742
- ...quillAggSelects,
17743
- `${percentageExpr} as ${processColumnReference(
17744
- `${currentAgg.valueField ?? ""}${disambiguation}`,
17745
- databaseType,
17746
- void 0,
17747
- false,
17748
- true
17749
- )}`
17750
- ];
17751
- } else {
17752
- quillAggSelects = [
17753
- ...quillAggSelects,
17754
- `${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
17755
- (currentAgg.valueField || "count") + disambiguation,
17756
- databaseType
17757
- )}`
17758
- ];
17759
- }
17760
- if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
17761
- if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
17762
- });
17763
- valueFieldAliases = Array.from(new Set(valueFieldAliases));
17764
- if (valueFieldAliases.length === 0) {
17765
- valueFieldAliases = ["*"];
17766
- }
17767
- const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
17768
- const pivotQuery = `, quill_alias AS (
17769
- SELECT ${valueFieldAliases.join(", ")} FROM quill_base_table
17770
- ),
17771
- quill_qt_agg AS (
17772
- SELECT ${quillAggSelects.join(", ")} FROM quill_alias
17773
- ),
17774
- quill_base_pivot AS (
17775
- SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
17776
- ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
17777
- )
17778
- SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
17779
- return itemQuery.replace(
17780
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17781
- pivotQuery
17782
- );
17783
- }
17784
- function additionalProcessingOnPivotQuery(pivot, query, additionalProcessing, databaseType = "postgresql") {
17785
- if (!additionalProcessing || !query) return query;
17786
- const isValidBaseQuery = query.match(
17787
- /SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
17788
- );
17789
- if (!isValidBaseQuery) {
17790
- return void 0;
17791
- }
17792
- if (!pivot.aggregations || pivot.aggregations.length === 0) {
17793
- if (pivot.aggregationType) {
17794
- pivot.aggregations = [
17795
- {
17796
- aggregationType: pivot.aggregationType,
17797
- valueField: pivot.valueField,
17798
- valueField2: pivot.valueField2
17799
- }
17800
- ];
17801
- } else {
17802
- throw new Error("No aggregations provided for pivot");
17803
- }
17804
- }
17805
- let rowsPerPage = 0;
17806
- let currentInterval = 0;
17807
- let offset = 0;
17808
- let limit = 1e3;
17809
- let sortQuery = "";
17810
- if (additionalProcessing.page) {
17811
- const page = additionalProcessing.page.page || 0;
17812
- if (additionalProcessing.page.rowsPerRequest) {
17813
- limit = additionalProcessing.page.rowsPerRequest;
17814
- }
17815
- rowsPerPage = additionalProcessing.page.rowsPerPage || 0;
17816
- currentInterval = page ? Math.floor(page / (limit / rowsPerPage)) : 0;
17817
- offset = currentInterval * limit;
17818
- }
17819
- const disambiguation = pivot.aggregations.length > 1 ? `_${matchCasing(pivot.aggregations?.[0]?.aggregationType, pivot.aggregations?.[0]?.valueField)}` : "";
17820
- if (additionalProcessing.sort) {
17821
- sortQuery = `ORDER BY ${processColumnReference(additionalProcessing.sort.field, databaseType, void 0, true)} ${additionalProcessing.sort.direction || ""}`;
17822
- } else {
17823
- const valueFieldAlias = processColumnReference(
17824
- (pivot.aggregations?.[0]?.valueField ?? "") + disambiguation,
17825
- databaseType,
17826
- void 0,
17827
- false,
17828
- true
17829
- );
17830
- const defaultSortField = pivot.sortField || pivot.rowField || valueFieldAlias;
17831
- const defaultSortDirection = pivot.sortDirection || "";
17832
- if (defaultSortField !== `"_"`) {
17833
- sortQuery = `ORDER BY ${processColumnReference(defaultSortField, databaseType, void 0, true)} ${defaultSortDirection}`;
17834
- } else {
17835
- sortQuery = "";
17836
- }
17837
- }
17838
- const additionalProcessingQuery = `
17839
- SELECT *
17840
- FROM quill_base_pivot ${sortQuery}${databaseType.toLowerCase() === "mssql" ? ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY` : ` LIMIT ${limit} OFFSET ${offset}`}
17841
- `.replace(/\s+/g, " ").trim();
17842
- return query.replace(
17843
- /SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
17844
- additionalProcessingQuery
17845
- );
17846
- }
17847
- function generateRowCountQuery(query, databaseType) {
17848
- if (!query) return query;
17849
- const isValidBaseQuery = query.match(
17850
- /SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
17851
- );
17852
- if (!isValidBaseQuery) {
17853
- return void 0;
17854
- }
17855
- const rowCountQuery = `, subview_row_count_cte AS (SELECT * FROM quill_base_pivot)
17856
- SELECT count(*) as ${processColumnReference("row_count", databaseType || "postgresql", void 0, true)} FROM subview_row_count_cte
17857
- `.replace(/\s+/g, " ").trim();
17858
- return query.replace(
17859
- /SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
17860
- rowCountQuery
17861
- );
17862
- }
17863
-
17864
- // src/utils/pivotConstructor.ts
17865
- async function generatePivotWithSQL({
17866
- pivot,
17867
- report,
17868
- client,
17869
- dateBucket,
17870
- dateFilter,
17871
- distinctStrings,
17872
- dashboardName,
17873
- tenants,
17874
- additionalProcessing,
17875
- pivotQuery,
17876
- comparisonPivotQuery,
17877
- getPivotRowCount = true,
17878
- caller,
17879
- getToken
17880
- }) {
17881
- let sqlQuery = pivotQuery;
17882
- let comparisonPivotSql = comparisonPivotQuery;
17883
- const databaseType = client.databaseType || "postgresql";
17884
- if (!pivotQuery && pivot.columnField && !pivot.columnValues && !distinctStrings) {
17885
- if (!report?.rows) {
17886
- throw new Error("No distinct strings provided for column field");
17887
- } else {
17888
- distinctStrings = Array.from(
17889
- new Set(
17890
- report.rows.map((row) => row[pivot.columnField]).filter((value) => value !== null && value !== void 0)
17891
- )
17892
- );
17893
- }
17894
- }
17895
- if (!pivot.aggregations?.length && pivot.aggregationType) {
17896
- pivot.aggregations = [
17897
- {
17898
- aggregationType: pivot.aggregationType,
17899
- valueField: pivot.valueField,
17900
- valueFieldType: pivot.valueFieldType,
17901
- valueField2: pivot.valueField2,
17902
- valueField2Type: pivot.valueField2Type
17903
- }
17904
- ];
17905
- }
17906
- let comparisonInterval = void 0;
17907
- if (dateFilter && dateFilter.comparisonRange) {
17908
- comparisonInterval = getComparisonInterval(
17909
- {
17910
- startDate: dateFilter.comparisonRange.startDate,
17911
- endDate: dateFilter.comparisonRange.endDate
17912
- },
17913
- dateBucket
17914
- );
17915
- }
17916
- if (pivot.rowField && !pivot.rowFieldType) {
17917
- const rowColumn = report?.columns.find(
17918
- (column) => column.field === pivot.rowField
17919
- );
17920
- pivot.rowFieldType = rowColumn?.format || "string";
17921
- }
17922
- const filteredDistinctStrings = distinctStrings?.filter(
17923
- (value) => value !== null && value !== void 0 && value !== ""
17924
- );
17925
- const pivotColumnFields = filteredDistinctStrings?.slice(
17926
- 0,
17927
- MAX_PIVOT_UNIQUE_VALUES
17928
- );
17929
- if (!pivotQuery && report) {
17930
- if (!report.itemQuery) {
17931
- throw Error("No item query found in report");
17932
- }
17933
- const itemQuery = report.itemQuery[0];
17934
- const comparisonQuery = report.itemQuery[1];
17935
- if (!itemQuery) {
17936
- throw Error("No item query found in report");
17937
- }
17938
- sqlQuery = generatePivotQuery(
17939
- pivot,
17940
- itemQuery,
17941
- databaseType,
17942
- pivotColumnFields,
17943
- dateBucket
17944
- );
17945
- comparisonPivotSql = comparisonQuery ? generatePivotQuery(
17946
- pivot,
17947
- comparisonQuery,
17948
- databaseType,
17949
- pivotColumnFields,
17950
- dateBucket
17951
- ) : "";
17952
- }
17953
- if (!sqlQuery) {
17954
- throw "Error generating pivot query";
17955
- }
17956
- const paginatedSqlQuery = additionalProcessingOnPivotQuery(
17957
- pivot,
17958
- sqlQuery,
17959
- additionalProcessing,
17960
- client.databaseType
17961
- );
17962
- const paginatedComparisonQuery = comparisonPivotSql ? additionalProcessingOnPivotQuery(
17963
- pivot,
17964
- comparisonPivotSql,
17965
- additionalProcessing,
17966
- client.databaseType
17967
- ) : "";
17968
- const preQueries = [paginatedSqlQuery];
17969
- getPivotRowCount = getPivotRowCount && (report?.chartType === "table" || caller === "ReportBuilder");
17970
- if (getPivotRowCount) {
17971
- const pivotRowCountQuery = generateRowCountQuery(
17972
- sqlQuery,
17973
- client.databaseType
17974
- );
17975
- preQueries.push(pivotRowCountQuery);
17976
- }
17977
- if (paginatedComparisonQuery) {
17978
- preQueries.push(paginatedComparisonQuery);
17979
- }
17980
- const { data: resp } = await quillFetch({
17981
- client,
17982
- task: "query",
17983
- metadata: {
17984
- preQueries,
17985
- clientId: client.publicKey,
17986
- databaseType,
17987
- runQueryConfig: {
17988
- overridePost: true,
17989
- convertDatatypes: true
17990
- },
17991
- useNewNodeSql: true,
17992
- dashboardName,
17993
- tenants
17994
- },
17995
- urlParameters: `caller=generatePivot&task=query`,
17996
- credentials: "same-origin",
17997
- getToken
17998
- });
17999
- if (resp.success === false) {
18000
- throw resp.errorMessage;
18001
- }
18002
- const queryResponseRows = resp?.queryResults?.[0]?.rows || [];
18003
- const queryResponseFields = resp?.queryResults?.[0]?.fields || [];
18004
- const queryComparisonResponseRows = (getPivotRowCount ? resp?.queryResults?.[2]?.rows : resp?.queryResults?.[1]?.rows) || [];
18005
- const queryComparisonResponseFields = (getPivotRowCount ? resp?.queryResults?.[2]?.fields : resp?.queryResults?.[1]?.fields) || [];
18006
- parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
18007
- parseValueFromBigQueryDates(
18008
- queryComparisonResponseRows,
18009
- queryComparisonResponseFields
18010
- );
18011
- const responseRows = mergeComparisonPivotRows({
18012
- pivot,
18013
- rows: queryResponseRows,
18014
- compRows: queryComparisonResponseRows,
18015
- databaseType,
18016
- dateBucket,
18017
- comparisonInterval,
18018
- columnFieldValues: pivotColumnFields
18019
- });
18020
- const responseFields = mergeComparisonPivotColumns({
18021
- pivot,
18022
- rows: queryResponseFields,
18023
- compRows: queryComparisonResponseFields
18024
- });
18025
- const rows = pivot.rowField ? responseRows.map(
18026
- (row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
18027
- ) : responseRows;
18028
- if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
18029
- rows.forEach((row) => {
18030
- Object.keys(row).forEach((key) => {
18031
- const processedKey = processColumnName(key);
18032
- if (processedKey !== key) {
18033
- row[processedKey] = row[key];
18034
- delete row[key];
18035
- }
18036
- });
18037
- });
18038
- }
18039
- const columns = responseFields?.map((field) => ({
18040
- field: processColumnName(field.name),
18041
- label: snakeCaseToTitleCase(
18042
- processColumnName(field.name.replace("comparison_", "comparison "))
18043
- ),
18044
- format: field.name === pivot.rowField ? "string" : (
18045
- // This scary equation is calculating which aggregation a column is associated with.
18046
- // Eg you have 7 columns and 2 aggregations, you can assume column 0 is the row field, 1-3 is aggregation 0, and 4-6 is aggregation 1.
18047
- // pivot.aggregations?.[
18048
- // Math.floor(
18049
- // (index - 1) /
18050
- // Math.floor(
18051
- // (responseFields.length - 1) /
18052
- // (pivot.aggregations?.length ?? 1),
18053
- // ),
18054
- // )
18055
- // ]?.aggregationType === 'percentage'
18056
- pivot.aggregations?.find(
18057
- (agg) => agg.valueField === field.name || `${agg.valueField}_percentage` === field.name || !agg.valueField && agg.aggregationType === "percentage" && field.name.endsWith("percentage")
18058
- )?.aggregationType === "percentage" ? "percent" : "whole_number"
18059
- ),
18060
- fieldType: field.fieldType,
18061
- jsType: field.jsType,
18062
- dataTypeID: field.dataTypeID
18063
- })).filter(
18064
- (field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
18065
- ).sort((a, b) => {
18066
- if (a.field === pivot.rowField) {
18067
- return -1;
18068
- }
18069
- if (b.field === pivot.rowField) {
18070
- return 1;
18071
- }
18072
- return 0;
18073
- });
18074
- if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
18075
- rows.forEach((row) => {
18076
- row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
18077
- let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
18078
- if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
18079
- const rowDate = new Date(value);
18080
- if (rowDate < dateFilter.startDate) {
18081
- value = dateFilter.startDate.toISOString();
18082
- } else if (rowDate > dateFilter.endDate) {
18083
- value = dateFilter.endDate.toISOString();
18084
- }
18085
- }
18086
- const dateString = getDateString(
18087
- value,
18088
- dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
18089
- dateBucket,
18090
- databaseType
18091
- );
18092
- row[pivot.rowField || ""] = dateString;
18093
- });
18094
- if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
18095
- const dateSet = new Set(
18096
- rows.map((row) => row[pivot.rowField || ""])
18097
- );
18098
- for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
18099
- const formattedDate = getDateString(
18100
- date.toISOString(),
18101
- { start: dateFilter.startDate, end: dateFilter.endDate },
18102
- dateBucket,
18103
- databaseType
18104
- );
18105
- if (!dateSet.has(formattedDate)) {
18106
- const newRow = {};
18107
- newRow[pivot.rowField] = formattedDate;
18108
- newRow.__quillRawDate = date.toISOString();
18109
- rows.push(newRow);
18110
- dateSet.add(formattedDate);
18111
- }
18112
- }
18113
- }
18114
- if (!pivot.sort) {
18115
- rows.sort((a, b) => {
18116
- if (a.__quillRawDate < b.__quillRawDate) {
18117
- return -1;
18118
- }
18119
- if (a.__quillRawDate > b.__quillRawDate) {
18120
- return 1;
18121
- }
18122
- return 0;
18123
- });
18124
- }
18125
- }
18126
- columns?.forEach((column, index) => {
18127
- if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
18128
- column.label = "Count";
18129
- }
18130
- });
18131
- const numericColumns = columns?.filter(
18132
- (column) => column.format === "whole_number" || column.format === "percentage"
18133
- );
18134
- rows.forEach((row) => {
18135
- numericColumns?.forEach((column) => {
18136
- row[column.field] = row[column.field] ?? 0;
18137
- });
18138
- });
18139
- return {
18140
- rows,
18141
- columns: columns ?? [],
18142
- rowCount: getPivotRowCount ? Number(resp?.queryResults?.[1]?.rows?.[0]?.["row_count"]) ?? rows.length : 0,
18143
- pivotQuery: sqlQuery,
18144
- comparisonPivotQuery: comparisonPivotSql
18145
- };
18146
- }
18147
- function generatePivotTableYAxis(pivot, cols, yAxisField) {
18148
- if (pivot?.aggregationType === "count") {
18149
- return [
18150
- {
18151
- field: pivot.valueField ?? "count",
18152
- label: yAxisField.label,
18153
- format: yAxisField.format
18154
- }
18155
- ];
18156
- }
18157
- return [
18158
- {
18159
- field: pivot.valueField ?? "count",
18160
- label: yAxisField.label,
18161
- format: yAxisField.format
18162
- }
18163
- ];
18164
- }
18165
- function generatePivotTitle(pivot) {
18166
- if (pivot.rowField && !pivot.valueField && pivot.aggregations?.[0]) {
18167
- return snakeAndCamelCaseToTitleCase(
18168
- `${pivot.aggregations[0].aggregationType} of ${pivot.rowField}${pivot.columnField ? ` by ${pivot.columnField}` : ""}
18169
- `
18170
- );
18171
- } else if (!pivot.rowField && pivot.aggregations?.[0]?.valueField) {
18172
- return snakeAndCamelCaseToTitleCase(
18173
- `${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
18174
- `
18175
- );
18176
- }
18177
- return snakeAndCamelCaseToTitleCase(
18178
- `${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
18179
- );
18180
- }
18181
- async function generatePivotTable({
18182
- pivot,
18183
- dateBucket,
18184
- dateFilter,
18185
- report,
18186
- client,
18187
- getToken,
18188
- eventTracking,
18189
- uniqueValues,
18190
- dashboardName,
18191
- tenants,
18192
- additionalProcessing,
18193
- caller,
18194
- pivotQuery
18195
- }) {
18196
- try {
18197
- if (report && client) {
18198
- const pivotTable = await generatePivotWithSQL({
18199
- pivotQuery,
18200
- pivot,
18201
- report,
18202
- client,
18203
- dateBucket,
18204
- dateFilter,
18205
- distinctStrings: pivot.columnField && uniqueValues?.[pivot.columnField] ? uniqueValues[pivot.columnField] : [],
18206
- dashboardName,
18207
- tenants,
18208
- additionalProcessing,
18209
- caller,
18210
- getToken
18211
- });
18212
- return pivotTable;
18213
- }
18214
- } catch (e) {
18215
- eventTracking?.logError?.({
18216
- type: "bug",
18217
- // TODO: determine type
18218
- severity: "high",
18219
- message: "Error generating pivot table",
18220
- errorMessage: e.message,
18221
- errorStack: e.stack,
18222
- errorData: {
18223
- caller: "PivotModal",
18224
- function: "generatePivotTable"
18225
- }
18226
- });
18227
- throw Error(`Failed to generate pivot table with SQL: ${e}`);
18228
- }
18229
- throw Error("Failed to generate pivot table: invalid report");
18230
- }
18231
-
18232
- // src/utils/errorProcessing.ts
18233
- function processFilterErrorList(resp) {
18234
- if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
18235
- return;
18236
- }
18237
- }
18238
-
18239
- // src/utils/paginationProcessing.ts
18240
- var DEFAULT_PAGINATION = {
18241
- page: 0,
18242
- rowsPerPage: 10,
18243
- rowsPerRequest: 600
18244
- };
18245
- var DEFAULT_TABLE_PAGINATION = {
18246
- page: 0,
18247
- rowsPerPage: 10,
18248
- rowsPerRequest: 50
18249
- };
18250
- function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
18251
- if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
18252
- return false;
18253
- }
18254
- const indexAdjustedPage = page;
18255
- const pageInterval = Math.floor(
18256
- indexAdjustedPage * pagination.rowsPerPage / pagination.rowsPerRequest
18257
- );
18258
- const indexAdjustedPreviousPage = maxPage;
18259
- const previousPageInterval = Math.floor(
18260
- indexAdjustedPreviousPage * pagination.rowsPerPage / pagination.rowsPerRequest
18261
- );
18262
- return pageInterval > previousPageInterval;
18263
- }
18264
- function shouldSortInMemory(pagination, rowCount) {
18265
- if (!rowCount || rowCount < pagination.rowsPerRequest) {
18266
- return true;
18267
- }
18268
- return false;
18269
- }
18270
17553
 
18271
17554
  // src/utils/tableProcessing.ts
18272
17555
  var getUniqueValuesByQuery = async ({
@@ -19008,491 +18291,6 @@ var fetchTableByAST = async (ast, client, getToken, tenants, eventTracking, dash
19008
18291
  return { rows, columns, rowCount, error, itemQuery, referencedTables };
19009
18292
  };
19010
18293
 
19011
- // src/utils/dashboard.ts
19012
- var defaultDashboardItem = {
19013
- id: "",
19014
- name: "",
19015
- dashboardName: "",
19016
- rows: [],
19017
- compareRows: [],
19018
- columns: [],
19019
- chartType: "",
19020
- pivot: null,
19021
- yAxisFields: [],
19022
- xAxisLabel: "",
19023
- xAxisField: "",
19024
- xAxisFormat: "string",
19025
- order: -1,
19026
- filtersApplied: [],
19027
- queryString: "",
19028
- rowCount: 0,
19029
- columnInternal: []
19030
- };
19031
- async function cleanDashboardItem({
19032
- item,
19033
- dashboardFilters,
19034
- getToken,
19035
- eventTracking,
19036
- client,
19037
- dateBucket,
19038
- additionalProcessing,
19039
- customFields,
19040
- skipPivotFetch,
19041
- tenants
19042
- }) {
19043
- if (!item) return defaultDashboardItem;
19044
- if (!item.rows) {
19045
- return {
19046
- ...defaultDashboardItem,
19047
- id: item._id,
19048
- name: item.name
19049
- };
19050
- }
19051
- const fields = item.fields || [];
19052
- const columnsWithCustomFields = [...item.columns ?? []];
19053
- if (item.includeCustomFields && item.rows?.length > 0) {
19054
- const tables = item.referencedTables ?? [];
19055
- tables.forEach((table) => {
19056
- const _customFields = customFields?.[table] ?? [];
19057
- _customFields.forEach((field) => {
19058
- const isJsonCustomField = !!field.refColumn;
19059
- if (item.rows[0][field.field] !== void 0 && !item.columns.some((col) => col.field === field.field)) {
19060
- const result_field = fields.find((f) => f.name === field.field);
19061
- const converted_field = convertPostgresColumn(result_field ?? {});
19062
- columnsWithCustomFields.push({
19063
- field: field.field,
19064
- format: converted_field.format,
19065
- label: snakeAndCamelCaseToTitleCase(field.field),
19066
- fieldType: converted_field.fieldType,
19067
- dataTypeID: converted_field.dataTypeID,
19068
- jsType: converted_field.jsType,
19069
- inferFormat: isJsonCustomField
19070
- });
19071
- }
19072
- });
19073
- });
19074
- }
19075
- const processedColumns = item.columns.map((col) => {
19076
- return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
19077
- });
19078
- const columnInternal = (item.includeCustomFields ? columnsWithCustomFields : item.columns).map((col) => {
19079
- const field = item.fields?.find((f) => f.name === col.field);
19080
- const converted_field = convertPostgresColumn(field ?? {});
19081
- return {
19082
- fieldType: converted_field.fieldType,
19083
- dataTypeID: converted_field.dataTypeID,
19084
- jsType: converted_field.jsType,
19085
- ...col,
19086
- label: snakeAndCamelCaseToTitleCase(col.label)
19087
- };
19088
- });
19089
- let pivotTable;
19090
- let pivotError;
19091
- try {
19092
- const shouldPaginatePivotAsTable = item.chartType === "table";
19093
- const pivotChartProcessing = {
19094
- page: DEFAULT_PAGINATION
19095
- };
19096
- pivotTable = await getPivotTable(
19097
- {
19098
- ...item,
19099
- pivot: item.pivot && !skipPivotFetch ? {
19100
- ...item.pivot,
19101
- aggregations: item.pivot.aggregations ?? [
19102
- {
19103
- valueField: item.pivot.valueField,
19104
- valueFieldType: item.pivot.valueFieldType,
19105
- valueField2: item.pivot.valueField2,
19106
- valueField2Type: item.pivot.valueField2Type,
19107
- aggregationType: item.pivot.aggregationType
19108
- }
19109
- ]
19110
- } : void 0
19111
- },
19112
- dashboardFilters,
19113
- item.dashboardName,
19114
- getToken,
19115
- client,
19116
- eventTracking,
19117
- dateBucket,
19118
- shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
19119
- tenants,
19120
- customFields
19121
- );
19122
- } catch (e) {
19123
- pivotTable = void 0;
19124
- eventTracking?.logError?.({
19125
- type: "bug",
19126
- // TODO: determine type
19127
- severity: "high",
19128
- message: "Error fetching pivot table",
19129
- errorMessage: e.message,
19130
- errorStack: e.stack,
19131
- errorData: {
19132
- caller: "cleanDashboardItem",
19133
- function: "cleanDashboardItem"
19134
- }
19135
- });
19136
- console.error("Error fetching pivot table", e);
19137
- pivotError = "Error fetching pivot table";
19138
- }
19139
- const referenceLineYValues = [];
19140
- for (const key in item) {
19141
- if (key.startsWith("referenceLine_")) {
19142
- const field = key.slice(14);
19143
- if (!item[key] || !item[key][0]) continue;
19144
- const value = Object.values(item[key][0])[0];
19145
- referenceLineYValues.push({ label: field, query: [value, value] });
19146
- }
19147
- }
19148
- if (item.referenceLines) {
19149
- for (const referenceLine of item.referenceLines) {
19150
- if (Array.isArray(referenceLine.query)) {
19151
- referenceLineYValues.push({
19152
- label: referenceLine.label,
19153
- query: referenceLine.query
19154
- });
19155
- } else if (referenceLine.query === "") {
19156
- referenceLineYValues.push({
19157
- label: referenceLine.label,
19158
- query: (pivotTable?.rows ? pivotTable.rows : item.rows).map(
19159
- (row) => Number(row[referenceLine.label]) || 0
19160
- )
19161
- });
19162
- }
19163
- }
19164
- }
19165
- return {
19166
- id: item._id ?? item.id,
19167
- name: item.name,
19168
- dashboardName: item.dashboardName,
19169
- // section: item.section,
19170
- rows: item.rows,
19171
- pivotRows: pivotTable ? pivotTable.rows : void 0,
19172
- pivotColumns: pivotTable ? pivotTable.columns : void 0,
19173
- compareRows: item.compareRows,
19174
- columns: processedColumns.map((column) => {
19175
- return {
19176
- field: column.field,
19177
- format: column.format,
19178
- label: column.label,
19179
- inferFormat: column.inferFormat
19180
- };
19181
- }),
19182
- includeCustomFields: item.includeCustomFields,
19183
- columnInternal,
19184
- columnsWithCustomFields,
19185
- chartType: item.chartType,
19186
- dateField: item.dateField,
19187
- pivot: pivotError ? void 0 : item.pivot ? {
19188
- ...item.pivot,
19189
- aggregations: item.pivot.aggregations ?? [
19190
- {
19191
- valueField: item.pivot.valueField,
19192
- valueFieldType: item.pivot.valueFieldType,
19193
- valueField2: item.pivot.valueField2,
19194
- valueField2Type: item.pivot.valueField2Type,
19195
- aggregationType: item.pivot.aggregationType
19196
- }
19197
- ],
19198
- columnValues: item.distinctStrings
19199
- } : void 0,
19200
- yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
19201
- xAxisLabel: item.xAxisLabel,
19202
- xAxisField: item.xAxisField,
19203
- xAxisFormat: item.xAxisFormat,
19204
- order: item.order,
19205
- filtersApplied: item.filtersApplied,
19206
- filterMap: item.filterMap,
19207
- flags: item.flags,
19208
- rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
19209
- pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
19210
- template: item.template,
19211
- sort: item.sort,
19212
- itemQuery: item.itemQuery,
19213
- queryString: item.queryString,
19214
- pivotQuery: pivotTable?.pivotQuery,
19215
- comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
19216
- referencedTables: item?.referencedTables || [],
19217
- referencedColumns: item?.referencedColumns || {},
19218
- error: item.error ?? pivotError,
19219
- referenceLineYValues,
19220
- referenceLines: item.referenceLines
19221
- };
19222
- }
19223
- async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
19224
- if (!report) return void 0;
19225
- const dateFilter = Object.values(dashboardFilters ?? {}).find(
19226
- (filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
19227
- );
19228
- if (dateFilter?.operator === "BETWEEN") {
19229
- dateFilter.startDate = dateFilter.value[0];
19230
- dateFilter.endDate = dateFilter.value[1];
19231
- }
19232
- const pivot = report?.pivot;
19233
- const data = report || {};
19234
- if (pivot && client) {
19235
- if (report.rowCount === 0 || report.rows.length === 0) {
19236
- const columns = [];
19237
- if (pivot.rowField) {
19238
- columns.push({
19239
- field: pivot.rowField,
19240
- label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
19241
- format: pivot.rowFieldType || "string",
19242
- jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
19243
- fieldType: pivot.rowFieldType || "string",
19244
- dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
19245
- });
19246
- }
19247
- for (const agg of pivot.aggregations ?? []) {
19248
- if (agg.valueField) {
19249
- columns.push({
19250
- field: agg.valueField,
19251
- label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
19252
- //FIXME: valueFieldType is not always the same as the format
19253
- format: agg.valueFieldType ?? "whole_number",
19254
- jsType: agg.valueFieldType ?? "number",
19255
- fieldType: agg.valueFieldType ?? "number",
19256
- dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
19257
- });
19258
- }
19259
- }
19260
- const pivotQuery = generatePivotQuery(
19261
- pivot,
19262
- report.itemQuery?.[0],
19263
- client.databaseType
19264
- );
19265
- return {
19266
- rows: [],
19267
- rowCount: 0,
19268
- pivotQuery: pivotQuery ?? "",
19269
- columns
19270
- };
19271
- }
19272
- try {
19273
- let dateBucket = dateBucketInitial;
19274
- let filterDateRange = void 0;
19275
- if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
19276
- filterDateRange = {
19277
- start: dateFilter.startDate,
19278
- end: dateFilter.endDate
19279
- };
19280
- } else if (report.dateRange) {
19281
- filterDateRange = report.dateRange;
19282
- }
19283
- if (!dateBucket && filterDateRange) {
19284
- dateBucket = getDateBucketFromRange(filterDateRange);
19285
- }
19286
- if (pivot.columnField && !report.distinctStrings) {
19287
- const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
19288
- if (!columnFieldColumn) {
19289
- console.error(
19290
- "could not find pivot column field on report",
19291
- pivot.columnField
19292
- );
19293
- }
19294
- const unique = await getUniqueValuesByQuery({
19295
- columns: [columnFieldColumn],
19296
- query: report.queryString,
19297
- client,
19298
- getToken,
19299
- dashboardName,
19300
- tenants,
19301
- customFields: customFields ?? {},
19302
- eventTracking
19303
- });
19304
- report.distinctStrings = unique?.[pivot.columnField] ?? [];
19305
- }
19306
- if (pivot.columnField && !report.distinctStrings) {
19307
- const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
19308
- if (!columnFieldColumn) {
19309
- console.error(
19310
- "could not find pivot column field on report",
19311
- pivot.columnField
19312
- );
19313
- }
19314
- const unique = await getUniqueValuesByQuery({
19315
- columns: [columnFieldColumn],
19316
- query: report.queryString,
19317
- client,
19318
- getToken,
19319
- dashboardName,
19320
- tenants,
19321
- customFields: customFields ?? {},
19322
- eventTracking
19323
- });
19324
- report.distinctStrings = unique?.[pivot.columnField] ?? [];
19325
- }
19326
- const pivotTable = await generatePivotWithSQL({
19327
- pivot,
19328
- report,
19329
- client,
19330
- dateBucket,
19331
- dateFilter,
19332
- distinctStrings: report.distinctStrings,
19333
- dashboardName,
19334
- tenants,
19335
- additionalProcessing,
19336
- getToken
19337
- });
19338
- return pivotTable;
19339
- } catch (e) {
19340
- eventTracking?.logError?.({
19341
- type: "bug",
19342
- // TODO: determine type
19343
- severity: "high",
19344
- message: "Error fetching pivot table",
19345
- errorMessage: e.message,
19346
- errorStack: e.stack,
19347
- errorData: {
19348
- caller: "getPivotTable",
19349
- function: "getPivotTable"
19350
- }
19351
- });
19352
- console.error("Error fetching pivot table", e);
19353
- throw e;
19354
- }
19355
- }
19356
- return pivot && data.rows ? generatePivotTable({
19357
- pivot,
19358
- report,
19359
- client,
19360
- uniqueValues: report.distinctStrings,
19361
- dashboardName,
19362
- tenants,
19363
- dateFilter,
19364
- additionalProcessing,
19365
- getToken,
19366
- eventTracking
19367
- }) : void 0;
19368
- }
19369
- function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
19370
- if (!pivotTable) return itemInfo?.yAxisFields ?? [];
19371
- const pivot = itemInfo?.pivot || config?.pivot;
19372
- if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
19373
- const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
19374
- return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
19375
- }
19376
- async function getDashboard(dashboardName, client, getToken, tenants, flags) {
19377
- const { data: resp } = await quillFetch({
19378
- client,
19379
- task: "dashboard",
19380
- metadata: {
19381
- name: dashboardName,
19382
- clientId: client.publicKey,
19383
- databaseType: client.databaseType,
19384
- useNewNodeSql: true,
19385
- tenants,
19386
- flags
19387
- },
19388
- getToken
19389
- });
19390
- return {
19391
- ...resp,
19392
- createdAt: resp.createdAt && new Date(resp.createdAt),
19393
- dateFilter: resp.dateFilter ? {
19394
- ...resp.dateFilter,
19395
- presetOptions: resp.dateFilter.presetOptions?.map(
19396
- (preset) => ({
19397
- ...preset,
19398
- loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
19399
- loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
19400
- })
19401
- ),
19402
- defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
19403
- (preset) => ({
19404
- ...preset,
19405
- loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
19406
- loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
19407
- })
19408
- )
19409
- } : void 0
19410
- };
19411
- }
19412
-
19413
- // src/utils/chartBuilder.ts
19414
- var numberFormatOptions = [
19415
- "whole_number",
19416
- "one_decimal_place",
19417
- "two_decimal_places",
19418
- "dollar_amount",
19419
- "dollar_cents",
19420
- "percentage"
19421
- ];
19422
- var dateFormatOptions = [
19423
- "MMM_yyyy",
19424
- "MMM_dd",
19425
- "MMM_dd_yyyy",
19426
- "MMM_dd_hh:mm_ap_pm",
19427
- "hh_ap_pm",
19428
- "date",
19429
- "timestamptz"
19430
- ];
19431
- var NUMBER_OPTIONS = [
19432
- { value: "whole_number", label: "whole number" },
19433
- { value: "one_decimal_place", label: "one decimal place" },
19434
- { value: "two_decimal_places", label: "two decimal places" },
19435
- { value: "dollar_amount", label: "dollar amount" },
19436
- { value: "dollar_cents", label: "dollar and cent amount" },
19437
- { value: "percent", label: "percentage" }
19438
- ];
19439
- var DATE_OPTIONS = [
19440
- { value: "MMM_yyyy", label: "month" },
19441
- { value: "MMM_dd", label: "day" },
19442
- { value: "MMM_dd_yyyy", label: "day and year" },
19443
- { value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
19444
- { value: "hh_ap_pm", label: "hour" }
19445
- ];
19446
- var ALL_FORMAT_OPTIONS = [
19447
- ...NUMBER_OPTIONS,
19448
- ...DATE_OPTIONS,
19449
- { value: "string", label: "string" }
19450
- ];
19451
- function createInitialFormData(columns) {
19452
- const firstNumberColumn = columns?.find(
19453
- (col) => numberFormatOptions.includes(col.format)
19454
- );
19455
- const firstStringColumn = columns?.find(
19456
- (col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
19457
- );
19458
- const firstDateColumn = columns?.find(
19459
- (col) => dateFormatOptions.includes(col.format)
19460
- );
19461
- const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
19462
- const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
19463
- const formEmptyState = {
19464
- name: "",
19465
- columns: columns.map((col) => {
19466
- return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
19467
- }),
19468
- xAxisField,
19469
- xAxisFormat,
19470
- yAxisFields: [
19471
- {
19472
- field: firstNumberColumn?.field || columns?.[0]?.field || "",
19473
- label: "",
19474
- format: firstNumberColumn?.format || columns?.[0]?.format || "string"
19475
- }
19476
- ],
19477
- xAxisLabel: "",
19478
- chartType: firstNumberColumn ? "line" : "table",
19479
- pivot: null,
19480
- template: true,
19481
- referenceLines: []
19482
- };
19483
- return formEmptyState;
19484
- }
19485
-
19486
- // src/utils/error.ts
19487
- var DataLoadError = class extends Error {
19488
- data;
19489
- constructor(message, data) {
19490
- super(message);
19491
- this.name = "DataLoadError";
19492
- this.data = data;
19493
- }
19494
- };
19495
-
19496
18294
  // src/components/ReportBuilder/convert.ts
19497
18295
  import { isValid as isValid3, parseISO as parseISO2 } from "date-fns";
19498
18296
  function recursiveSearchAndReplace(node, search, replace) {
@@ -23144,6 +21942,35 @@ import jsPDF from "jspdf";
23144
21942
 
23145
21943
  // src/hooks/useDashboard.ts
23146
21944
  import { useContext, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState as useState2 } from "react";
21945
+
21946
+ // src/utils/merge.ts
21947
+ import {
21948
+ add,
21949
+ startOfDay as startOfDay3,
21950
+ startOfMonth,
21951
+ startOfWeek as startOfWeek3,
21952
+ startOfYear
21953
+ } from "date-fns";
21954
+ import { utcToZonedTime as utcToZonedTime2 } from "date-fns-tz";
21955
+ function mergeComparisonRange(resp) {
21956
+ if (resp.chartType === "table") return resp;
21957
+ const compRows = resp.compareRows;
21958
+ if (!compRows) return resp;
21959
+ const newRows = resp.rows.map((row, i) => {
21960
+ if (i < compRows.length) {
21961
+ const compRow = compRows[i];
21962
+ const newRow = { ...row };
21963
+ for (const [key, value] of Object.entries(compRow)) {
21964
+ newRow[`comparison_${key}`] = value;
21965
+ }
21966
+ return newRow;
21967
+ }
21968
+ return row;
21969
+ });
21970
+ return { ...resp, rows: newRows };
21971
+ }
21972
+
21973
+ // src/hooks/useDashboard.ts
23147
21974
  var useDashboardInternal = (dashboardName, customFilters) => {
23148
21975
  const [dashboard] = useContext(DashboardContext);
23149
21976
  const {
@@ -39043,6 +37870,22 @@ import {
39043
37870
  useContext as useContext26,
39044
37871
  useMemo as useMemo21
39045
37872
  } from "react";
37873
+ import {
37874
+ closestCenter,
37875
+ DndContext,
37876
+ KeyboardSensor,
37877
+ PointerSensor,
37878
+ useSensor,
37879
+ useSensors
37880
+ } from "@dnd-kit/core";
37881
+ import {
37882
+ arrayMove,
37883
+ SortableContext,
37884
+ sortableKeyboardCoordinates,
37885
+ verticalListSortingStrategy,
37886
+ useSortable
37887
+ } from "@dnd-kit/sortable";
37888
+ import { CSS as DND_CSS } from "@dnd-kit/utilities";
39046
37889
 
39047
37890
  // src/internals/ReportBuilder/PivotModal.tsx
39048
37891
  import {
@@ -42312,6 +41155,173 @@ var CHART_TO_LABELS = {
42312
41155
  "World map": { xAxisLabel: "Country", yAxisLabel: "Value" },
42313
41156
  gauge: { xAxisLabel: "Value" }
42314
41157
  };
41158
+ function SortableColumnItem({
41159
+ column,
41160
+ index,
41161
+ rows,
41162
+ columns,
41163
+ handleChange,
41164
+ deleteRef,
41165
+ deleteButtonMargin,
41166
+ handleRemoveField,
41167
+ SelectComponent,
41168
+ TextInputComponent,
41169
+ DeleteButtonComponent
41170
+ }) {
41171
+ const { attributes, listeners, setNodeRef, transform, transition: transition2 } = useSortable({ id: column.field });
41172
+ const style2 = {
41173
+ transform: DND_CSS.Transform.toString(transform),
41174
+ transition: transition2
41175
+ };
41176
+ return /* @__PURE__ */ jsx65("div", { style: style2, ref: setNodeRef, children: /* @__PURE__ */ jsxs47(
41177
+ "div",
41178
+ {
41179
+ style: {
41180
+ display: "flex",
41181
+ alignItems: "center",
41182
+ gap: 4
41183
+ },
41184
+ children: [
41185
+ /* @__PURE__ */ jsxs47(
41186
+ "div",
41187
+ {
41188
+ style: {
41189
+ cursor: "grab",
41190
+ display: "flex",
41191
+ gap: 2,
41192
+ flexDirection: "row",
41193
+ paddingTop: 8,
41194
+ paddingBottom: 8,
41195
+ paddingLeft: 8,
41196
+ paddingRight: 8,
41197
+ borderRadius: 4
41198
+ },
41199
+ className: "handle",
41200
+ ...attributes,
41201
+ ...listeners,
41202
+ children: [
41203
+ /* @__PURE__ */ jsx65("style", { children: `.handle{background:white;} .handle:hover{background:rgba(0,0,0,0.03);}` }),
41204
+ /* @__PURE__ */ jsxs47("div", { style: { display: "flex", gap: 2, flexDirection: "column" }, children: [
41205
+ /* @__PURE__ */ jsx65(
41206
+ "div",
41207
+ {
41208
+ style: {
41209
+ width: 3,
41210
+ height: 3,
41211
+ borderRadius: 3,
41212
+ background: "#9CA0A7"
41213
+ }
41214
+ }
41215
+ ),
41216
+ /* @__PURE__ */ jsx65(
41217
+ "div",
41218
+ {
41219
+ style: {
41220
+ width: 3,
41221
+ height: 3,
41222
+ borderRadius: 3,
41223
+ background: "#9CA0A7"
41224
+ }
41225
+ }
41226
+ ),
41227
+ /* @__PURE__ */ jsx65(
41228
+ "div",
41229
+ {
41230
+ style: {
41231
+ width: 3,
41232
+ height: 3,
41233
+ borderRadius: 3,
41234
+ background: "#9CA0A7"
41235
+ }
41236
+ }
41237
+ )
41238
+ ] }),
41239
+ /* @__PURE__ */ jsxs47("div", { style: { display: "flex", gap: 2, flexDirection: "column" }, children: [
41240
+ /* @__PURE__ */ jsx65(
41241
+ "div",
41242
+ {
41243
+ style: {
41244
+ width: 3,
41245
+ height: 3,
41246
+ borderRadius: 3,
41247
+ background: "#9CA0A7"
41248
+ }
41249
+ }
41250
+ ),
41251
+ /* @__PURE__ */ jsx65(
41252
+ "div",
41253
+ {
41254
+ style: {
41255
+ width: 3,
41256
+ height: 3,
41257
+ borderRadius: 3,
41258
+ background: "#9CA0A7"
41259
+ }
41260
+ }
41261
+ ),
41262
+ /* @__PURE__ */ jsx65(
41263
+ "div",
41264
+ {
41265
+ style: {
41266
+ width: 3,
41267
+ height: 3,
41268
+ borderRadius: 3,
41269
+ background: "#9CA0A7"
41270
+ }
41271
+ }
41272
+ )
41273
+ ] })
41274
+ ]
41275
+ }
41276
+ ),
41277
+ /* @__PURE__ */ jsxs47("div", { style: { flex: 1, display: "flex", gap: 12 }, children: [
41278
+ /* @__PURE__ */ jsx65(
41279
+ SelectComponent,
41280
+ {
41281
+ value: column.field,
41282
+ onChange: (e) => handleChange(e.target.value, "columns.field", index),
41283
+ options: rows[0] ? Object.keys(rows[0]).map((elem) => ({
41284
+ label: elem,
41285
+ value: elem
41286
+ })) : columns.map((elem) => ({
41287
+ label: elem.field,
41288
+ value: elem.field
41289
+ })),
41290
+ width: 200,
41291
+ hideEmptyOption: true
41292
+ }
41293
+ ),
41294
+ /* @__PURE__ */ jsx65(
41295
+ TextInputComponent,
41296
+ {
41297
+ id: `chart-builder-column-label-${index}`,
41298
+ width: 200,
41299
+ value: column.label,
41300
+ placeholder: "Column Label",
41301
+ onChange: (e) => handleChange(e.target.value, "columns.label", index)
41302
+ }
41303
+ ),
41304
+ /* @__PURE__ */ jsx65(
41305
+ SelectComponent,
41306
+ {
41307
+ value: column.format,
41308
+ onChange: (e) => handleChange(e.target.value, "columns.format", index),
41309
+ options: ALL_FORMAT_OPTIONS,
41310
+ width: 200,
41311
+ hideEmptyOption: true
41312
+ }
41313
+ ),
41314
+ /* @__PURE__ */ jsx65("div", { ref: deleteRef, style: { marginLeft: deleteButtonMargin }, children: /* @__PURE__ */ jsx65(
41315
+ DeleteButtonComponent,
41316
+ {
41317
+ onClick: () => handleRemoveField("columns", index)
41318
+ }
41319
+ ) })
41320
+ ] })
41321
+ ]
41322
+ }
41323
+ ) });
41324
+ }
42315
41325
  function getPivotMetricOptions(pivot, selectedPivotTable, chartType) {
42316
41326
  if (["metric", "gauge"].includes(chartType) && selectedPivotTable) {
42317
41327
  return selectedPivotTable.columns.map((elem) => ({
@@ -42520,7 +41530,6 @@ function ChartBuilder({
42520
41530
  }, [reportId]);
42521
41531
  const [windowWidth, setWindowWidth] = useState28(1200);
42522
41532
  const [rows, setRows] = useState28(report?.rows ?? []);
42523
- const [itemQuery, setItemQuery] = useState28(report?.itemQuery);
42524
41533
  const [rowCount, setRowCount] = useState28(report?.rowCount ?? 0);
42525
41534
  const [maxPage, setMaxPage] = useState28(0);
42526
41535
  const [isLoading, setIsLoading] = useState28(false);
@@ -43250,7 +42259,7 @@ function ChartBuilder({
43250
42259
  pivot,
43251
42260
  dateBucket,
43252
42261
  dateFilter,
43253
- report: report ? { ...report, ...tableInfo ?? { itemQuery } } : void 0,
42262
+ report: report ? { ...report, ...tableInfo } : void 0,
43254
42263
  client,
43255
42264
  uniqueValues,
43256
42265
  dashboardName: destinationDashboardName,
@@ -43411,7 +42420,6 @@ function ChartBuilder({
43411
42420
  setCurrentProcessing(processing);
43412
42421
  setRows(tableInfo.rows);
43413
42422
  setProcessedColumns(processColumns(tableInfo.columns));
43414
- setItemQuery(tableInfo.itemQuery);
43415
42423
  fetchRowCount(processing, overrideFilters);
43416
42424
  if (formData.pivot) {
43417
42425
  try {
@@ -43777,6 +42785,26 @@ function ChartBuilder({
43777
42785
  );
43778
42786
  setFormData({ ...formData, [fieldName]: updatedArray });
43779
42787
  };
42788
+ const columnDragSensors = useSensors(
42789
+ useSensor(PointerSensor),
42790
+ useSensor(KeyboardSensor, {
42791
+ coordinateGetter: sortableKeyboardCoordinates
42792
+ })
42793
+ );
42794
+ const handleColumnDragEnd = (event) => {
42795
+ const { active, over } = event;
42796
+ if (!active || !over) return;
42797
+ if (active.id !== over.id) {
42798
+ const oldIndex = formData.columns.findIndex(
42799
+ (col) => col.field === active.id
42800
+ );
42801
+ const newIndex = formData.columns.findIndex(
42802
+ (col) => col.field === over.id
42803
+ );
42804
+ const newColumns = arrayMove(formData.columns, oldIndex, newIndex);
42805
+ setFormData({ ...formData, columns: newColumns });
42806
+ }
42807
+ };
43780
42808
  const handleSubmit = (event) => {
43781
42809
  event.preventDefault();
43782
42810
  };
@@ -44297,7 +43325,7 @@ function ChartBuilder({
44297
43325
  uniqueValuesIsLoading: initialUniqueValuesIsLoading,
44298
43326
  initialSelectedPivotTable: selectedPivotTable,
44299
43327
  pivotRecommendationsEnabled,
44300
- report: report ? { ...report, ...{ itemQuery } } : void 0,
43328
+ report,
44301
43329
  dashboardName: destinationDashboardName || "",
44302
43330
  dateFilter: filtersEnabled ? currentDashboardFilters?.find(
44303
43331
  (f) => f.filterType === "date_range"
@@ -44685,141 +43713,98 @@ function ChartBuilder({
44685
43713
  formData.pivot && selectedPivotTable && selectedPivotTable.columns && formData.chartType === "table" ? (
44686
43714
  // THIS CASE IF FOR PIVOT TABLES ONLY
44687
43715
  selectedPivotTable.columns.map(
44688
- (column, index) => /* @__PURE__ */ jsxs47(
44689
- ChartBuilderInputRowContainer,
44690
- {
44691
- children: [
44692
- /* @__PURE__ */ jsx65(
44693
- SelectComponent,
44694
- {
44695
- value: column.field,
44696
- onChange: (e) => handleChange(
44697
- e.target.value,
44698
- "pivot.field",
44699
- index
44700
- ),
44701
- options: selectedPivotTable.columns.map(
44702
- (elem) => ({
44703
- label: elem.field,
44704
- value: elem.field
44705
- })
44706
- ),
44707
- disabled: index === 0,
44708
- width: 200,
44709
- hideEmptyOption: true
44710
- }
43716
+ (column, index) => /* @__PURE__ */ jsxs47(ChartBuilderInputRowContainer, { children: [
43717
+ /* @__PURE__ */ jsx65(
43718
+ SelectComponent,
43719
+ {
43720
+ value: column.field,
43721
+ onChange: (e) => handleChange(
43722
+ e.target.value,
43723
+ "pivot.field",
43724
+ index
44711
43725
  ),
44712
- /* @__PURE__ */ jsx65(
44713
- TextInputComponent,
44714
- {
44715
- id: `chart-builder-column-label-${index}`,
44716
- width: 200,
44717
- value: column.label,
44718
- placeholder: "Column Label",
44719
- onChange: (e) => handleChange(
44720
- e.target.value,
44721
- "pivot.label",
44722
- index
44723
- )
44724
- }
43726
+ options: selectedPivotTable.columns.map(
43727
+ (elem) => ({
43728
+ label: elem.field,
43729
+ value: elem.field
43730
+ })
44725
43731
  ),
44726
- /* @__PURE__ */ jsx65(
44727
- SelectComponent,
44728
- {
44729
- value: (
44730
- // The first index use rowField for the rest of them use value fields
44731
- column.format
44732
- ),
44733
- onChange: (e) => handleChange(
44734
- e.target.value,
44735
- "pivot.format",
44736
- index
44737
- ),
44738
- options: formData.pivot && index === 0 && selectedPivotTable?.columns.length > 1 ? isDateField(
44739
- formData.pivot.rowFieldType || ""
44740
- ) ? [{ label: "date", value: "string" }] : [{ label: "string", value: "string" }] : [
44741
- ...NUMBER_OPTIONS,
44742
- { label: "string", value: "string" }
44743
- ],
44744
- width: 200,
44745
- hideEmptyOption: true
44746
- }
43732
+ disabled: index === 0,
43733
+ width: 200,
43734
+ hideEmptyOption: true
43735
+ }
43736
+ ),
43737
+ /* @__PURE__ */ jsx65(
43738
+ TextInputComponent,
43739
+ {
43740
+ id: `chart-builder-column-label-${index}`,
43741
+ width: 200,
43742
+ value: column.label,
43743
+ placeholder: "Column Label",
43744
+ onChange: (e) => handleChange(
43745
+ e.target.value,
43746
+ "pivot.label",
43747
+ index
44747
43748
  )
44748
- ]
44749
- },
44750
- "column" + index
44751
- )
43749
+ }
43750
+ ),
43751
+ /* @__PURE__ */ jsx65(
43752
+ SelectComponent,
43753
+ {
43754
+ value: (
43755
+ // The first index use rowField for the rest of them use value fields
43756
+ column.format
43757
+ ),
43758
+ onChange: (e) => handleChange(
43759
+ e.target.value,
43760
+ "pivot.format",
43761
+ index
43762
+ ),
43763
+ options: formData.pivot && index === 0 && selectedPivotTable?.columns.length > 1 ? isDateField(
43764
+ formData.pivot.rowFieldType || ""
43765
+ ) ? [{ label: "date", value: "string" }] : [{ label: "string", value: "string" }] : [
43766
+ ...NUMBER_OPTIONS,
43767
+ { label: "string", value: "string" }
43768
+ ],
43769
+ width: 200,
43770
+ hideEmptyOption: true
43771
+ }
43772
+ )
43773
+ ] }, "column" + index)
44752
43774
  )
44753
- ) : formData.columns.map(
44754
- (column, index) => /* @__PURE__ */ jsxs47(
44755
- ChartBuilderInputRowContainer,
44756
- {
44757
- children: [
44758
- /* @__PURE__ */ jsx65(
44759
- SelectComponent,
44760
- {
44761
- value: column.field,
44762
- onChange: (e) => handleChange(
44763
- e.target.value,
44764
- "columns.field",
44765
- index
44766
- ),
44767
- options: rows[0] ? Object.keys(rows[0]).map((elem) => ({
44768
- label: elem,
44769
- value: elem
44770
- })) : columns.map((elem) => ({
44771
- label: elem.field,
44772
- value: elem.field
44773
- })),
44774
- width: 200,
44775
- hideEmptyOption: true
44776
- }
44777
- ),
44778
- /* @__PURE__ */ jsx65(
44779
- TextInputComponent,
44780
- {
44781
- id: `chart-builder-column-label-${index}`,
44782
- width: 200,
44783
- value: column.label,
44784
- placeholder: "Column Label",
44785
- onChange: (e) => handleChange(
44786
- e.target.value,
44787
- "columns.label",
44788
- index
44789
- )
44790
- }
44791
- ),
44792
- /* @__PURE__ */ jsx65(
44793
- SelectComponent,
44794
- {
44795
- value: column.format,
44796
- onChange: (e) => handleChange(
44797
- e.target.value,
44798
- "columns.format",
44799
- index
44800
- ),
44801
- options: ALL_FORMAT_OPTIONS,
44802
- width: 200,
44803
- hideEmptyOption: true
44804
- }
44805
- ),
44806
- /* @__PURE__ */ jsx65(
44807
- "div",
44808
- {
44809
- ref: deleteRef,
44810
- style: { marginLeft: deleteButtonMargin },
44811
- children: /* @__PURE__ */ jsx65(
44812
- DeleteButtonComponent,
44813
- {
44814
- onClick: () => handleRemoveField("columns", index)
44815
- }
44816
- )
44817
- }
43775
+ ) : /* @__PURE__ */ jsx65(
43776
+ DndContext,
43777
+ {
43778
+ sensors: columnDragSensors,
43779
+ collisionDetection: closestCenter,
43780
+ onDragEnd: handleColumnDragEnd,
43781
+ children: /* @__PURE__ */ jsx65(
43782
+ SortableContext,
43783
+ {
43784
+ items: formData.columns.map((col) => col.field),
43785
+ strategy: verticalListSortingStrategy,
43786
+ children: formData.columns.map(
43787
+ (column, index) => /* @__PURE__ */ jsx65(
43788
+ SortableColumnItem,
43789
+ {
43790
+ column,
43791
+ index,
43792
+ rows,
43793
+ columns,
43794
+ handleChange,
43795
+ deleteRef,
43796
+ deleteButtonMargin,
43797
+ handleRemoveField,
43798
+ SelectComponent,
43799
+ TextInputComponent,
43800
+ DeleteButtonComponent
43801
+ },
43802
+ column.field
43803
+ )
44818
43804
  )
44819
- ]
44820
- },
44821
- "column" + index
44822
- )
43805
+ }
43806
+ )
43807
+ }
44823
43808
  ),
44824
43809
  /* @__PURE__ */ jsx65("div", { children: !// hide when pivoted and chartType === 'table'
44825
43810
  (formData.pivot && selectedPivotTable && selectedPivotTable.columns && formData.chartType === "table") && /* @__PURE__ */ jsxs47(
@@ -48994,21 +47979,21 @@ var useReportBuilder = ({
48994
47979
  // src/components/ReportBuilder/AddColumnModal.tsx
48995
47980
  import { useState as useState32, useRef as useRef19, useMemo as useMemo24, useEffect as useEffect26, useContext as useContext30 } from "react";
48996
47981
  import {
48997
- DndContext,
48998
- closestCenter,
48999
- KeyboardSensor,
49000
- PointerSensor,
49001
- useSensor,
49002
- useSensors
47982
+ DndContext as DndContext2,
47983
+ closestCenter as closestCenter2,
47984
+ KeyboardSensor as KeyboardSensor2,
47985
+ PointerSensor as PointerSensor2,
47986
+ useSensor as useSensor2,
47987
+ useSensors as useSensors2
49003
47988
  } from "@dnd-kit/core";
49004
47989
  import {
49005
- arrayMove,
49006
- SortableContext,
49007
- sortableKeyboardCoordinates,
49008
- verticalListSortingStrategy,
49009
- useSortable
47990
+ arrayMove as arrayMove2,
47991
+ SortableContext as SortableContext2,
47992
+ sortableKeyboardCoordinates as sortableKeyboardCoordinates2,
47993
+ verticalListSortingStrategy as verticalListSortingStrategy2,
47994
+ useSortable as useSortable2
49010
47995
  } from "@dnd-kit/sortable";
49011
- import { CSS as DND_CSS } from "@dnd-kit/utilities";
47996
+ import { CSS as DND_CSS2 } from "@dnd-kit/utilities";
49012
47997
  import { jsx as jsx67, jsxs as jsxs49 } from "react/jsx-runtime";
49013
47998
  function AddColumnModal({
49014
47999
  onSave,
@@ -49077,10 +48062,10 @@ function AddColumnModal({
49077
48062
  setTimeout(() => setInitialLoad(false), 200);
49078
48063
  }
49079
48064
  }, [schemaLoading]);
49080
- const sensors = useSensors(
49081
- useSensor(PointerSensor),
49082
- useSensor(KeyboardSensor, {
49083
- coordinateGetter: sortableKeyboardCoordinates
48065
+ const sensors = useSensors2(
48066
+ useSensor2(PointerSensor2),
48067
+ useSensor2(KeyboardSensor2, {
48068
+ coordinateGetter: sortableKeyboardCoordinates2
49084
48069
  })
49085
48070
  );
49086
48071
  function handleDragEnd(event) {
@@ -49090,7 +48075,7 @@ function AddColumnModal({
49090
48075
  setOrderedColumnNames((orderedColumnNames2) => {
49091
48076
  const oldIndex = orderedColumnNames2.indexOf(active.id);
49092
48077
  const newIndex = orderedColumnNames2.indexOf(over.id);
49093
- return arrayMove(orderedColumnNames2, oldIndex, newIndex);
48078
+ return arrayMove2(orderedColumnNames2, oldIndex, newIndex);
49094
48079
  });
49095
48080
  }
49096
48081
  }
@@ -49134,16 +48119,16 @@ function AddColumnModal({
49134
48119
  }
49135
48120
  ),
49136
48121
  schemaLoading || initialLoad ? /* @__PURE__ */ jsx67(LoadingComponent, {}) : schema.length > 0 ? /* @__PURE__ */ jsx67(
49137
- DndContext,
48122
+ DndContext2,
49138
48123
  {
49139
48124
  sensors,
49140
- collisionDetection: closestCenter,
48125
+ collisionDetection: closestCenter2,
49141
48126
  onDragEnd: handleDragEnd,
49142
48127
  children: /* @__PURE__ */ jsx67(
49143
- SortableContext,
48128
+ SortableContext2,
49144
48129
  {
49145
48130
  items: orderedColumnNames,
49146
- strategy: verticalListSortingStrategy,
48131
+ strategy: verticalListSortingStrategy2,
49147
48132
  children: /* @__PURE__ */ jsxs49(
49148
48133
  "div",
49149
48134
  {
@@ -49351,9 +48336,9 @@ var SortableItem = ({
49351
48336
  selectedColumns,
49352
48337
  SelectColumn
49353
48338
  }) => {
49354
- const { attributes, listeners, setNodeRef, transform, transition: transition2 } = useSortable({ id: id2 });
48339
+ const { attributes, listeners, setNodeRef, transform, transition: transition2 } = useSortable2({ id: id2 });
49355
48340
  const style2 = {
49356
- transform: DND_CSS.Transform.toString(transform),
48341
+ transform: DND_CSS2.Transform.toString(transform),
49357
48342
  transition: transition2
49358
48343
  };
49359
48344
  const handleSelect = () => {
@@ -49383,17 +48368,17 @@ var SortableItem = ({
49383
48368
 
49384
48369
  // src/components/ReportBuilder/DraggableColumns.tsx
49385
48370
  import {
49386
- closestCenter as closestCenter2,
49387
- DndContext as DndContext2,
49388
- KeyboardSensor as KeyboardSensor2,
49389
- PointerSensor as PointerSensor2,
49390
- useSensor as useSensor2,
49391
- useSensors as useSensors2
48371
+ closestCenter as closestCenter3,
48372
+ DndContext as DndContext3,
48373
+ KeyboardSensor as KeyboardSensor3,
48374
+ PointerSensor as PointerSensor3,
48375
+ useSensor as useSensor3,
48376
+ useSensors as useSensors3
49392
48377
  } from "@dnd-kit/core";
49393
48378
 
49394
48379
  // src/components/ReportBuilder/DraggableItem.tsx
49395
- import { useSortable as useSortable2 } from "@dnd-kit/sortable";
49396
- import { CSS as DND_CSS2 } from "@dnd-kit/utilities";
48380
+ import { useSortable as useSortable3 } from "@dnd-kit/sortable";
48381
+ import { CSS as DND_CSS3 } from "@dnd-kit/utilities";
49397
48382
  import { jsx as jsx68 } from "react/jsx-runtime";
49398
48383
  function DraggableItem({
49399
48384
  id: id2,
@@ -49402,9 +48387,9 @@ function DraggableItem({
49402
48387
  DraggableColumnComponent,
49403
48388
  loading
49404
48389
  }) {
49405
- const { attributes, listeners, setNodeRef, transform, transition: transition2 } = useSortable2({ id: id2 });
48390
+ const { attributes, listeners, setNodeRef, transform, transition: transition2 } = useSortable3({ id: id2 });
49406
48391
  const style2 = {
49407
- transform: DND_CSS2.Transform.toString(transform),
48392
+ transform: DND_CSS3.Transform.toString(transform),
49408
48393
  transition: transition2
49409
48394
  };
49410
48395
  return /* @__PURE__ */ jsx68("div", { style: { ...style2 }, ref: setNodeRef, children: /* @__PURE__ */ jsx68(
@@ -49430,10 +48415,10 @@ function DraggableItem({
49430
48415
 
49431
48416
  // src/components/ReportBuilder/DraggableColumns.tsx
49432
48417
  import {
49433
- arrayMove as arrayMove2,
49434
- SortableContext as SortableContext2,
49435
- sortableKeyboardCoordinates as sortableKeyboardCoordinates2,
49436
- verticalListSortingStrategy as verticalListSortingStrategy2
48418
+ arrayMove as arrayMove3,
48419
+ SortableContext as SortableContext3,
48420
+ sortableKeyboardCoordinates as sortableKeyboardCoordinates3,
48421
+ verticalListSortingStrategy as verticalListSortingStrategy3
49437
48422
  } from "@dnd-kit/sortable";
49438
48423
  import { useMemo as useMemo25 } from "react";
49439
48424
  import { jsx as jsx69, jsxs as jsxs50 } from "react/jsx-runtime";
@@ -49443,10 +48428,10 @@ function DraggableColumns({
49443
48428
  DraggableColumnComponent,
49444
48429
  loading
49445
48430
  }) {
49446
- const sensors = useSensors2(
49447
- useSensor2(PointerSensor2),
49448
- useSensor2(KeyboardSensor2, {
49449
- coordinateGetter: sortableKeyboardCoordinates2
48431
+ const sensors = useSensors3(
48432
+ useSensor3(PointerSensor3),
48433
+ useSensor3(KeyboardSensor3, {
48434
+ coordinateGetter: sortableKeyboardCoordinates3
49450
48435
  })
49451
48436
  );
49452
48437
  const columnNames = useMemo25(() => {
@@ -49463,7 +48448,7 @@ function DraggableColumns({
49463
48448
  if (active.id !== over.id) {
49464
48449
  const oldIndex = columnNames.findIndex((c) => c.endsWith(active.id));
49465
48450
  const newIndex = columnNames.findIndex((c) => c.endsWith(over.id));
49466
- const newOrder = arrayMove2(columnNames, oldIndex, newIndex);
48451
+ const newOrder = arrayMove3(columnNames, oldIndex, newIndex);
49467
48452
  const orderToColumns = newOrder.map((name2) => {
49468
48453
  const [table, field] = name2.split(".");
49469
48454
  return columns.find(
@@ -49480,16 +48465,16 @@ function DraggableColumns({
49480
48465
  onColumnOrderChange(newColumns);
49481
48466
  }
49482
48467
  return /* @__PURE__ */ jsx69(
49483
- DndContext2,
48468
+ DndContext3,
49484
48469
  {
49485
48470
  sensors,
49486
- collisionDetection: closestCenter2,
48471
+ collisionDetection: closestCenter3,
49487
48472
  onDragEnd: handleDragEnd,
49488
48473
  children: /* @__PURE__ */ jsx69(
49489
- SortableContext2,
48474
+ SortableContext3,
49490
48475
  {
49491
48476
  items: columnNames,
49492
- strategy: verticalListSortingStrategy2,
48477
+ strategy: verticalListSortingStrategy3,
49493
48478
  children: /* @__PURE__ */ jsxs50(
49494
48479
  "div",
49495
48480
  {