@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.cjs CHANGED
@@ -14781,21 +14781,6 @@ function isDateFormat(xAxisFormat) {
14781
14781
  const isDate = DATE_FORMATS.includes(xAxisFormat);
14782
14782
  return isDate;
14783
14783
  }
14784
- function getComparisonInterval(comparisonRange, dateBucket) {
14785
- const dayCount = (0, import_date_fns5.differenceInDays)(
14786
- comparisonRange.endDate,
14787
- comparisonRange.startDate
14788
- );
14789
- if (!isNaN(dayCount)) {
14790
- if (dateBucket === "month") {
14791
- return Math.floor(dayCount / 30) + " month";
14792
- } else if (dateBucket === "year") {
14793
- return Math.floor(dayCount / 365) + " year";
14794
- } else {
14795
- return dayCount + " day";
14796
- }
14797
- }
14798
- }
14799
14784
  function getDateBucketFromRange(dateRange) {
14800
14785
  const difference = (0, import_date_fns5.differenceInDays)(dateRange.end, dateRange.start);
14801
14786
  if (difference < 14) {
@@ -16609,311 +16594,771 @@ function parseValueFromBigQueryDates(rows, columns) {
16609
16594
  });
16610
16595
  }
16611
16596
 
16612
- // src/utils/merge.ts
16613
- var import_date_fns7 = require("date-fns");
16614
- var import_date_fns_tz2 = require("date-fns-tz");
16615
- function mergeComparisonRange(resp) {
16616
- if (resp.chartType === "table") return resp;
16617
- const compRows = resp.compareRows;
16618
- if (!compRows) return resp;
16619
- const newRows = resp.rows.map((row, i) => {
16620
- if (i < compRows.length) {
16621
- const compRow = compRows[i];
16622
- const newRow = { ...row };
16623
- for (const [key, value] of Object.entries(compRow)) {
16624
- newRow[`comparison_${key}`] = value;
16597
+ // src/utils/pivotConstructor.ts
16598
+ async function generatePivotWithSQL({
16599
+ pivot,
16600
+ report,
16601
+ client,
16602
+ dateBucket,
16603
+ dateFilter,
16604
+ distinctStrings,
16605
+ dashboardName,
16606
+ tenants,
16607
+ additionalProcessing,
16608
+ pivotQuery,
16609
+ comparisonPivotQuery,
16610
+ getPivotRowCount = true,
16611
+ caller,
16612
+ getToken
16613
+ }) {
16614
+ const databaseType = client.databaseType || "postgresql";
16615
+ if (!pivot.aggregations?.length && pivot.aggregationType) {
16616
+ pivot.aggregations = [
16617
+ {
16618
+ aggregationType: pivot.aggregationType,
16619
+ valueField: pivot.valueField,
16620
+ valueFieldType: pivot.valueFieldType,
16621
+ valueField2: pivot.valueField2,
16622
+ valueField2Type: pivot.valueField2Type
16625
16623
  }
16626
- return newRow;
16627
- }
16628
- return row;
16624
+ ];
16625
+ }
16626
+ const pivotConfig = {
16627
+ rowField: pivot.rowField,
16628
+ rowFieldType: pivot.rowFieldType,
16629
+ columnField: pivot.columnField,
16630
+ aggregations: pivot.aggregations?.map((agg) => ({
16631
+ aggregationType: agg.aggregationType,
16632
+ valueField: agg.valueField,
16633
+ valueFieldType: agg.valueFieldType
16634
+ }))
16635
+ };
16636
+ const resp = await quillFetch({
16637
+ client,
16638
+ task: "pivot-template",
16639
+ metadata: {
16640
+ clientId: client.clientId,
16641
+ pivot: pivotConfig,
16642
+ itemQuery: report?.queryString,
16643
+ dashboardName,
16644
+ tenants
16645
+ },
16646
+ credentials: "same-origin",
16647
+ getToken
16629
16648
  });
16630
- return { ...resp, rows: newRows };
16631
- }
16632
- function dateAdder(date, interval2) {
16633
- const match = interval2.match(/^(\d+)\s+(day|month|year)$/);
16634
- if (!match) {
16635
- throw new Error(`Invalid interval format: ${interval2}`);
16649
+ if (resp.data?.success === false) {
16650
+ throw resp.data.errorMessage;
16636
16651
  }
16637
- const [, valueStr, unit] = match;
16638
- if (!valueStr || !unit) {
16639
- throw new Error("Could not parse interval");
16652
+ const queryResponseRows = resp.data?.rows || resp.queries?.queryResults?.[0]?.rows || [];
16653
+ const queryResponseFields = resp.data?.fields || resp.queries?.queryResults?.[0]?.fields || [];
16654
+ const rowCount = resp.queries?.queryResults?.[1]?.rows?.[0]?.row_count || 0;
16655
+ parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
16656
+ const responseRows = queryResponseRows;
16657
+ const responseFields = queryResponseFields;
16658
+ const rows = pivot.rowField ? responseRows.map(
16659
+ (row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
16660
+ ) : responseRows;
16661
+ if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
16662
+ rows.forEach((row) => {
16663
+ Object.keys(row).forEach((key) => {
16664
+ const processedKey = processColumnName(key);
16665
+ if (processedKey !== key) {
16666
+ row[processedKey] = row[key];
16667
+ delete row[key];
16668
+ }
16669
+ });
16670
+ });
16640
16671
  }
16641
- const value = parseInt(valueStr, 10);
16642
- const parsedDate = typeof date === "string" ? new Date(date) : date;
16643
- switch (unit) {
16644
- case "day":
16645
- return (0, import_date_fns7.add)(parsedDate, { days: value });
16646
- case "month":
16647
- return (0, import_date_fns7.add)(parsedDate, { months: value });
16648
- case "year":
16649
- return (0, import_date_fns7.add)(parsedDate, { years: value });
16650
- default:
16651
- throw new Error(`Unsupported interval unit: ${unit}`);
16672
+ const columns = responseFields?.map((field) => ({
16673
+ field: processColumnName(field.field || field.name),
16674
+ label: snakeCaseToTitleCase(
16675
+ processColumnName(
16676
+ (field.field || field.name).replace("comparison_", "comparison ")
16677
+ )
16678
+ ),
16679
+ format: (field.field || field.name) === pivot.rowField ? "string" : pivot.aggregations?.find(
16680
+ (agg) => agg.valueField === (field.field || field.name) || `${agg.valueField}_percentage` === (field.field || field.name) || !agg.valueField && agg.aggregationType === "percentage" && (field.field || field.name)?.endsWith("percentage")
16681
+ )?.aggregationType === "percentage" ? "percent" : "whole_number",
16682
+ fieldType: field.fieldType,
16683
+ jsType: field.jsType,
16684
+ dataTypeID: field.dataTypeID
16685
+ })).filter(
16686
+ (field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
16687
+ ).sort((a, b) => {
16688
+ if (a.field === pivot.rowField) {
16689
+ return -1;
16690
+ }
16691
+ if (b.field === pivot.rowField) {
16692
+ return 1;
16693
+ }
16694
+ return 0;
16695
+ });
16696
+ if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
16697
+ rows.forEach((row) => {
16698
+ row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
16699
+ let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
16700
+ if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
16701
+ const rowDate = new Date(value);
16702
+ if (rowDate < dateFilter.startDate) {
16703
+ value = dateFilter.startDate.toISOString();
16704
+ } else if (rowDate > dateFilter.endDate) {
16705
+ value = dateFilter.endDate.toISOString();
16706
+ }
16707
+ }
16708
+ const dateString = getDateString(
16709
+ value,
16710
+ dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
16711
+ dateBucket,
16712
+ databaseType
16713
+ );
16714
+ row[pivot.rowField || ""] = dateString;
16715
+ });
16716
+ if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
16717
+ const dateSet = new Set(
16718
+ rows.map((row) => row[pivot.rowField || ""])
16719
+ );
16720
+ for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
16721
+ const formattedDate = getDateString(
16722
+ date.toISOString(),
16723
+ { start: dateFilter.startDate, end: dateFilter.endDate },
16724
+ dateBucket,
16725
+ databaseType
16726
+ );
16727
+ if (!dateSet.has(formattedDate)) {
16728
+ const newRow = {};
16729
+ newRow[pivot.rowField] = formattedDate;
16730
+ newRow.__quillRawDate = date.toISOString();
16731
+ rows.push(newRow);
16732
+ dateSet.add(formattedDate);
16733
+ }
16734
+ }
16735
+ }
16736
+ if (!pivot.sort) {
16737
+ rows.sort((a, b) => {
16738
+ if (a.__quillRawDate < b.__quillRawDate) {
16739
+ return -1;
16740
+ }
16741
+ if (a.__quillRawDate > b.__quillRawDate) {
16742
+ return 1;
16743
+ }
16744
+ return 0;
16745
+ });
16746
+ }
16652
16747
  }
16748
+ columns?.forEach((column, index) => {
16749
+ if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
16750
+ column.label = "Count";
16751
+ }
16752
+ });
16753
+ const numericColumns = columns?.filter(
16754
+ (column) => column.format === "whole_number" || column.format === "percentage"
16755
+ );
16756
+ rows.forEach((row) => {
16757
+ numericColumns?.forEach((column) => {
16758
+ row[column.field] = row[column.field] ?? 0;
16759
+ });
16760
+ });
16761
+ return {
16762
+ rows,
16763
+ columns: columns ?? [],
16764
+ rowCount: rowCount || rows.length,
16765
+ pivotQuery: report?.queryString || "",
16766
+ comparisonPivotQuery: comparisonPivotQuery || ""
16767
+ };
16653
16768
  }
16654
- function dateTrunc(date, granularity = "day", databaseType) {
16655
- const weekStartsOn = databaseType === "mssql" ? 0 : 1;
16656
- const timeZone = "UTC";
16657
- const zonedDate = (0, import_date_fns_tz2.utcToZonedTime)(date, timeZone);
16658
- switch (granularity.toLowerCase()) {
16659
- case "week":
16660
- return (0, import_date_fns7.startOfWeek)(zonedDate, { weekStartsOn });
16661
- case "month":
16662
- return (0, import_date_fns7.startOfMonth)(zonedDate);
16663
- case "day":
16664
- return (0, import_date_fns7.startOfDay)(zonedDate);
16665
- case "year":
16666
- return (0, import_date_fns7.startOfYear)(zonedDate);
16667
- default:
16668
- throw new Error(`Unsupported granularity: ${granularity}`);
16769
+ function generatePivotTableYAxis(pivot, cols, yAxisField) {
16770
+ if (pivot?.aggregationType === "count") {
16771
+ return [
16772
+ {
16773
+ field: pivot.valueField ?? "count",
16774
+ label: yAxisField.label,
16775
+ format: yAxisField.format
16776
+ }
16777
+ ];
16669
16778
  }
16779
+ return [
16780
+ {
16781
+ field: pivot.valueField ?? "count",
16782
+ label: yAxisField.label,
16783
+ format: yAxisField.format
16784
+ }
16785
+ ];
16670
16786
  }
16671
- function mergeComparisonPivotColumns({
16672
- pivot,
16673
- rows,
16674
- compRows
16675
- }) {
16676
- if (!compRows || !compRows.length) return rows;
16677
- const mappedCompRows = compRows.filter((compRow) => compRow.name !== pivot.rowField).map((compRow) => ({ ...compRow, name: `comparison_${compRow.name}` }));
16678
- return rows.concat(mappedCompRows);
16787
+ function generatePivotTitle(pivot) {
16788
+ if (pivot.rowField && !pivot.valueField && pivot.aggregations?.[0]) {
16789
+ return snakeAndCamelCaseToTitleCase(
16790
+ `${pivot.aggregations[0].aggregationType} of ${pivot.rowField}${pivot.columnField ? ` by ${pivot.columnField}` : ""}
16791
+ `
16792
+ );
16793
+ } else if (!pivot.rowField && pivot.aggregations?.[0]?.valueField) {
16794
+ return snakeAndCamelCaseToTitleCase(
16795
+ `${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
16796
+ `
16797
+ );
16798
+ }
16799
+ return snakeAndCamelCaseToTitleCase(
16800
+ `${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
16801
+ );
16679
16802
  }
16680
- function mergeComparisonPivotRows({
16803
+ async function generatePivotTable({
16681
16804
  pivot,
16682
- rows,
16683
- compRows,
16684
- databaseType,
16685
16805
  dateBucket,
16686
- comparisonInterval,
16687
- columnFieldValues
16806
+ dateFilter,
16807
+ report,
16808
+ client,
16809
+ getToken,
16810
+ eventTracking,
16811
+ uniqueValues,
16812
+ dashboardName,
16813
+ tenants,
16814
+ additionalProcessing,
16815
+ caller,
16816
+ pivotQuery
16688
16817
  }) {
16689
- if (!compRows || !compRows.length) return rows;
16690
- if (pivot.columnField && columnFieldValues && columnFieldValues.length > 0) {
16691
- return merge2DPivotRows(
16692
- pivot,
16693
- rows,
16694
- compRows,
16695
- columnFieldValues,
16696
- databaseType,
16697
- dateBucket,
16698
- comparisonInterval
16699
- );
16700
- }
16701
- if (pivot.rowField) {
16702
- return merge1DPivotRows(
16703
- pivot,
16704
- rows,
16705
- compRows,
16706
- databaseType,
16707
- dateBucket,
16708
- comparisonInterval
16709
- );
16818
+ try {
16819
+ if (report && client) {
16820
+ const pivotTable = await generatePivotWithSQL({
16821
+ pivotQuery,
16822
+ pivot,
16823
+ report,
16824
+ client,
16825
+ dateBucket,
16826
+ dateFilter,
16827
+ dashboardName,
16828
+ tenants,
16829
+ additionalProcessing,
16830
+ caller,
16831
+ getToken
16832
+ });
16833
+ return pivotTable;
16834
+ }
16835
+ } catch (e) {
16836
+ eventTracking?.logError?.({
16837
+ type: "bug",
16838
+ // TODO: determine type
16839
+ severity: "high",
16840
+ message: "Error generating pivot table",
16841
+ errorMessage: e.message,
16842
+ errorStack: e.stack,
16843
+ errorData: {
16844
+ caller: "PivotModal",
16845
+ function: "generatePivotTable"
16846
+ }
16847
+ });
16848
+ throw Error(`Failed to generate pivot table with SQL: ${e}`);
16710
16849
  }
16711
- return mergeAggregatedRows(pivot, rows, compRows);
16850
+ throw Error("Failed to generate pivot table: invalid report");
16712
16851
  }
16713
- function merge2DPivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
16714
- if (!pivot || !pivot.columnField) {
16715
- return [];
16716
- }
16717
- if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
16718
- return merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues);
16852
+
16853
+ // src/utils/paginationProcessing.ts
16854
+ var DEFAULT_PAGINATION = {
16855
+ page: 0,
16856
+ rowsPerPage: 10,
16857
+ rowsPerRequest: 600
16858
+ };
16859
+ var DEFAULT_TABLE_PAGINATION = {
16860
+ page: 0,
16861
+ rowsPerPage: 10,
16862
+ rowsPerRequest: 50
16863
+ };
16864
+ function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
16865
+ if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
16866
+ return false;
16719
16867
  }
16720
- return merge2DDatePivotRows(
16721
- pivot,
16722
- rows,
16723
- compRows,
16724
- columnFieldValues,
16725
- databaseType,
16726
- dateBucket,
16727
- comparisonInterval
16868
+ const indexAdjustedPage = page;
16869
+ const pageInterval = Math.floor(
16870
+ indexAdjustedPage * pagination.rowsPerPage / pagination.rowsPerRequest
16871
+ );
16872
+ const indexAdjustedPreviousPage = maxPage;
16873
+ const previousPageInterval = Math.floor(
16874
+ indexAdjustedPreviousPage * pagination.rowsPerPage / pagination.rowsPerRequest
16728
16875
  );
16876
+ return pageInterval > previousPageInterval;
16729
16877
  }
16730
- function merge2DStringPivotRows(pivot, rows, compRows, columnFieldValues) {
16731
- if (!pivot.rowField || !pivot.aggregations?.some((agg) => agg.valueField)) {
16732
- return rows;
16878
+ function shouldSortInMemory(pagination, rowCount) {
16879
+ if (!rowCount || rowCount < pagination.rowsPerRequest) {
16880
+ return true;
16733
16881
  }
16734
- return rows.map((row) => {
16735
- const matchingCompRow = compRows.find(
16736
- (compRow) => compRow[pivot.rowField] === row[pivot.rowField]
16737
- );
16738
- const comparisonFields = columnFieldValues.reduce(
16739
- (acc, fieldValue) => {
16740
- acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
16741
- return acc;
16742
- },
16743
- {}
16744
- );
16745
- return {
16746
- ...row,
16747
- ...comparisonFields
16748
- };
16749
- });
16882
+ return false;
16750
16883
  }
16751
- function merge2DDatePivotRows(pivot, rows, compRows, columnFieldValues, databaseType, dateBucket, comparisonInterval) {
16752
- if (!comparisonInterval || !pivot.rowField) {
16753
- return rows;
16754
- }
16755
- return rows.map((row) => {
16756
- const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
16757
- const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
16758
- const matchingCompRow = compRows.find((compRow) => {
16759
- const comparisonDateWithInterval = dateAdder(
16760
- compRow[pivot.rowField],
16761
- comparisonInterval
16762
- );
16763
- const truncatedCompRowDate = dateTrunc(
16764
- comparisonDateWithInterval,
16765
- dateBucket,
16766
- databaseType
16767
- );
16768
- return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
16769
- });
16770
- const comparisonFields = columnFieldValues.reduce(
16771
- (acc, fieldValue) => {
16772
- acc[`comparison_${fieldValue}`] = matchingCompRow ? matchingCompRow[fieldValue] || null : null;
16773
- return acc;
16774
- },
16775
- {}
16776
- );
16884
+
16885
+ // src/utils/dashboard.ts
16886
+ var defaultDashboardItem = {
16887
+ id: "",
16888
+ name: "",
16889
+ dashboardName: "",
16890
+ rows: [],
16891
+ compareRows: [],
16892
+ columns: [],
16893
+ chartType: "",
16894
+ pivot: null,
16895
+ yAxisFields: [],
16896
+ xAxisLabel: "",
16897
+ xAxisField: "",
16898
+ xAxisFormat: "string",
16899
+ order: -1,
16900
+ filtersApplied: [],
16901
+ queryString: "",
16902
+ rowCount: 0,
16903
+ columnInternal: []
16904
+ };
16905
+ async function cleanDashboardItem({
16906
+ item,
16907
+ dashboardFilters,
16908
+ getToken,
16909
+ eventTracking,
16910
+ client,
16911
+ dateBucket,
16912
+ additionalProcessing,
16913
+ customFields,
16914
+ skipPivotFetch,
16915
+ tenants
16916
+ }) {
16917
+ if (!item) return defaultDashboardItem;
16918
+ if (!item.rows) {
16777
16919
  return {
16778
- ...row,
16779
- ...comparisonFields
16920
+ ...defaultDashboardItem,
16921
+ id: item._id,
16922
+ name: item.name
16780
16923
  };
16781
- });
16782
- }
16783
- function merge1DPivotRows(pivot, rows, compRows, databaseType, dateBucket, comparisonInterval) {
16784
- if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
16785
- return merge1DStringPivotRows(pivot, rows, compRows);
16786
16924
  }
16787
- return merge1DDatePivotRows(
16788
- pivot,
16789
- rows,
16790
- compRows,
16791
- databaseType,
16792
- dateBucket,
16793
- comparisonInterval
16794
- );
16795
- }
16796
- function merge1DStringPivotRows(pivot, rows, compRows) {
16797
- if (!pivot.rowField || !pivot.valueField) {
16798
- return rows;
16925
+ const fields = item.fields || [];
16926
+ const columnsWithCustomFields = [...item.columns ?? []];
16927
+ if (item.includeCustomFields && item.rows?.length > 0) {
16928
+ const tables = item.referencedTables ?? [];
16929
+ tables.forEach((table) => {
16930
+ const _customFields = customFields?.[table] ?? [];
16931
+ _customFields.forEach((field) => {
16932
+ const isJsonCustomField = !!field.refColumn;
16933
+ if (item.rows[0][field.field] !== void 0 && !item.columns.some((col) => col.field === field.field)) {
16934
+ const result_field = fields.find((f) => f.name === field.field);
16935
+ const converted_field = convertPostgresColumn(result_field ?? {});
16936
+ columnsWithCustomFields.push({
16937
+ field: field.field,
16938
+ format: converted_field.format,
16939
+ label: snakeAndCamelCaseToTitleCase(field.field),
16940
+ fieldType: converted_field.fieldType,
16941
+ dataTypeID: converted_field.dataTypeID,
16942
+ jsType: converted_field.jsType,
16943
+ inferFormat: isJsonCustomField
16944
+ });
16945
+ }
16946
+ });
16947
+ });
16799
16948
  }
16800
- return rows.map((row) => {
16801
- const matchingCompRow = compRows.find(
16802
- (compRow) => compRow[pivot.rowField] === row[pivot.rowField]
16803
- );
16804
- let aggregationSuffix = "";
16805
- if (matchingCompRow && pivot.aggregationType === "percentage") {
16806
- if (matchingCompRow[`${pivot.valueField}_Percentage`]) {
16807
- aggregationSuffix = "_Percentage";
16808
- } else if (matchingCompRow[`${pivot.valueField}_PERCENTAGE`]) {
16809
- aggregationSuffix = "_PERCENTAGE";
16810
- } else {
16811
- aggregationSuffix = "_percentage";
16812
- }
16813
- }
16814
- return {
16815
- ...row,
16816
- [`comparison_${pivot.valueField}${aggregationSuffix}`]: matchingCompRow ? matchingCompRow[`${pivot.valueField}${aggregationSuffix}`] : null
16817
- };
16949
+ const processedColumns = item.columns.map((col) => {
16950
+ return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
16818
16951
  });
16819
- }
16820
- function merge1DDatePivotRows(pivot, rows, compRows, databaseType, dateBucket, comparisonInterval) {
16821
- if (!comparisonInterval || !pivot.rowField) {
16822
- return rows;
16823
- }
16824
- return rows.map((row) => {
16825
- const rowDate = typeof row[pivot.rowField] === "string" ? new Date(row[pivot.rowField]) : row[pivot.rowField];
16826
- const truncatedRowDate = dateTrunc(rowDate, dateBucket, databaseType);
16827
- const matchingCompRow = compRows.find((compRow) => {
16828
- const comparisonDateWithInterval = dateAdder(
16829
- compRow[`${pivot.rowField}`],
16830
- comparisonInterval
16831
- );
16832
- const truncatedCompRowDate = dateTrunc(
16833
- comparisonDateWithInterval,
16834
- dateBucket,
16835
- databaseType
16836
- );
16837
- return truncatedRowDate.toISOString() === truncatedCompRowDate.toISOString();
16838
- });
16839
- let aggregationSuffix = "";
16840
- if (matchingCompRow && pivot.aggregationType === "percentage") {
16841
- if (matchingCompRow[`${pivot.valueField}_Percentage`]) {
16842
- aggregationSuffix = "_Percentage";
16843
- } else if (matchingCompRow[`${pivot.valueField}_PERCENTAGE`]) {
16844
- aggregationSuffix = "_PERCENTAGE";
16845
- } else {
16846
- aggregationSuffix = "_percentage";
16847
- }
16848
- }
16952
+ const columnInternal = (item.includeCustomFields ? columnsWithCustomFields : item.columns).map((col) => {
16953
+ const field = item.fields?.find((f) => f.name === col.field);
16954
+ const converted_field = convertPostgresColumn(field ?? {});
16849
16955
  return {
16850
- ...row,
16851
- [`comparison_${pivot.valueField}${aggregationSuffix}`]: matchingCompRow?.[`${pivot.valueField}${aggregationSuffix}`] || null
16956
+ fieldType: converted_field.fieldType,
16957
+ dataTypeID: converted_field.dataTypeID,
16958
+ jsType: converted_field.jsType,
16959
+ ...col,
16960
+ label: snakeAndCamelCaseToTitleCase(col.label)
16852
16961
  };
16853
16962
  });
16854
- }
16855
- function mergeAggregatedRows(pivot, rows, compRows) {
16856
- return rows.map((row, i) => {
16857
- let aggregationSuffix = "";
16858
- if (compRows[i] && pivot.aggregationType === "percentage") {
16859
- if (compRows[i][`${pivot.valueField}_Percentage`]) {
16860
- aggregationSuffix = "_Percentage";
16861
- } else if (compRows[i][`${pivot.valueField}_PERCENTAGE`]) {
16862
- aggregationSuffix = "_PERCENTAGE";
16863
- } else {
16864
- aggregationSuffix = "_percentage";
16963
+ let pivotTable;
16964
+ let pivotError;
16965
+ try {
16966
+ const shouldPaginatePivotAsTable = item.chartType === "table";
16967
+ const pivotChartProcessing = {
16968
+ page: DEFAULT_PAGINATION
16969
+ };
16970
+ pivotTable = await getPivotTable(
16971
+ {
16972
+ ...item,
16973
+ pivot: item.pivot && !skipPivotFetch ? {
16974
+ ...item.pivot,
16975
+ aggregations: item.pivot.aggregations ?? [
16976
+ {
16977
+ valueField: item.pivot.valueField,
16978
+ valueFieldType: item.pivot.valueFieldType,
16979
+ valueField2: item.pivot.valueField2,
16980
+ valueField2Type: item.pivot.valueField2Type,
16981
+ aggregationType: item.pivot.aggregationType
16982
+ }
16983
+ ]
16984
+ } : void 0
16985
+ },
16986
+ dashboardFilters,
16987
+ item.dashboardName,
16988
+ getToken,
16989
+ client,
16990
+ eventTracking,
16991
+ dateBucket,
16992
+ shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
16993
+ tenants,
16994
+ customFields
16995
+ );
16996
+ } catch (e) {
16997
+ pivotTable = void 0;
16998
+ eventTracking?.logError?.({
16999
+ type: "bug",
17000
+ // TODO: determine type
17001
+ severity: "high",
17002
+ message: "Error fetching pivot table",
17003
+ errorMessage: e.message,
17004
+ errorStack: e.stack,
17005
+ errorData: {
17006
+ caller: "cleanDashboardItem",
17007
+ function: "cleanDashboardItem"
16865
17008
  }
17009
+ });
17010
+ console.error("Error fetching pivot table", e);
17011
+ pivotError = "Error fetching pivot table";
17012
+ }
17013
+ const referenceLineYValues = [];
17014
+ for (const key in item) {
17015
+ if (key.startsWith("referenceLine_")) {
17016
+ const field = key.slice(14);
17017
+ if (!item[key] || !item[key][0]) continue;
17018
+ const value = Object.values(item[key][0])[0];
17019
+ referenceLineYValues.push({ label: field, query: [value, value] });
16866
17020
  }
16867
- const compRow = {
16868
- [`comparison_${pivot.valueField}${aggregationSuffix}`]: compRows[i]?.[`${pivot.valueField}${aggregationSuffix}`]
16869
- };
16870
- return { ...row, ...compRow };
16871
- });
16872
- }
16873
-
16874
- // src/utils/queryConstructor.ts
16875
- function processSingleQuotes(value, databaseType) {
16876
- if (["postgresql", "snowflake", "clickhouse"].includes(
16877
- databaseType.toLowerCase()
16878
- )) {
16879
- return value.replaceAll("'", "''");
16880
17021
  }
16881
- return value.replaceAll("'", "\\'");
16882
- }
16883
- function processAggType(aggType, hasColumnField = false) {
16884
- if (aggType === "count" && hasColumnField) return "SUM";
16885
- return aggType?.toLowerCase() === "average" ? "AVG" : aggType?.toLowerCase();
16886
- }
16887
- function replaceBigQuerySpecialCharacters(column) {
16888
- return column.replaceAll("/", "quill_forward_slash");
16889
- }
16890
- function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
16891
- switch (databaseType.toLowerCase()) {
16892
- case "postgresql":
16893
- case "clickhouse": {
16894
- if (column === "") {
16895
- return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
16896
- }
16897
- if (isColumnFieldAlias) {
16898
- return `"${column.replaceAll('"', "")}"`;
16899
- }
16900
- const columnParts = column.split(".");
16901
- if (columnParts.length > 1) {
16902
- return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
17022
+ if (item.referenceLines) {
17023
+ for (const referenceLine of item.referenceLines) {
17024
+ if (Array.isArray(referenceLine.query)) {
17025
+ referenceLineYValues.push({
17026
+ label: referenceLine.label,
17027
+ query: referenceLine.query
17028
+ });
17029
+ } else if (referenceLine.query === "") {
17030
+ referenceLineYValues.push({
17031
+ label: referenceLine.label,
17032
+ query: (pivotTable?.rows ? pivotTable.rows : item.rows).map(
17033
+ (row) => Number(row[referenceLine.label]) || 0
17034
+ )
17035
+ });
16903
17036
  }
16904
- return `"${column.replaceAll('"', "")}"`;
16905
17037
  }
16906
- case "mysql": {
16907
- if (column === "") {
16908
- return fallbackOnNull ? `${fallbackOnNull}` : "_";
16909
- }
16910
- if (isColumnFieldAlias) {
16911
- return `\`${column.replaceAll(`\``, "").replaceAll(`"`, "")}\``;
16912
- }
16913
- const columnParts = column.split(".");
16914
- if (columnParts.length > 1) {
16915
- return `\`` + columnParts.map((part) => part.replaceAll(`\``, "")).join("`.`") + `\``;
16916
- }
17038
+ }
17039
+ return {
17040
+ id: item._id ?? item.id,
17041
+ name: item.name,
17042
+ dashboardName: item.dashboardName,
17043
+ // section: item.section,
17044
+ rows: item.rows,
17045
+ pivotRows: pivotTable ? pivotTable.rows : void 0,
17046
+ pivotColumns: pivotTable ? pivotTable.columns : void 0,
17047
+ compareRows: item.compareRows,
17048
+ columns: processedColumns.map((column) => {
17049
+ return {
17050
+ field: column.field,
17051
+ format: column.format,
17052
+ label: column.label,
17053
+ inferFormat: column.inferFormat
17054
+ };
17055
+ }),
17056
+ includeCustomFields: item.includeCustomFields,
17057
+ columnInternal,
17058
+ columnsWithCustomFields,
17059
+ chartType: item.chartType,
17060
+ dateField: item.dateField,
17061
+ pivot: pivotError ? void 0 : item.pivot ? {
17062
+ ...item.pivot,
17063
+ aggregations: item.pivot.aggregations ?? [
17064
+ {
17065
+ valueField: item.pivot.valueField,
17066
+ valueFieldType: item.pivot.valueFieldType,
17067
+ valueField2: item.pivot.valueField2,
17068
+ valueField2Type: item.pivot.valueField2Type,
17069
+ aggregationType: item.pivot.aggregationType
17070
+ }
17071
+ ],
17072
+ columnValues: item.distinctStrings
17073
+ } : void 0,
17074
+ yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
17075
+ xAxisLabel: item.xAxisLabel,
17076
+ xAxisField: item.xAxisField,
17077
+ xAxisFormat: item.xAxisFormat,
17078
+ order: item.order,
17079
+ filtersApplied: item.filtersApplied,
17080
+ filterMap: item.filterMap,
17081
+ flags: item.flags,
17082
+ rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
17083
+ pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
17084
+ template: item.template,
17085
+ sort: item.sort,
17086
+ itemQuery: item.itemQuery,
17087
+ queryString: item.queryString,
17088
+ pivotQuery: pivotTable?.pivotQuery,
17089
+ comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
17090
+ referencedTables: item?.referencedTables || [],
17091
+ referencedColumns: item?.referencedColumns || {},
17092
+ error: item.error ?? pivotError,
17093
+ referenceLineYValues,
17094
+ referenceLines: item.referenceLines
17095
+ };
17096
+ }
17097
+ async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
17098
+ if (!report) return void 0;
17099
+ const dateFilter = Object.values(dashboardFilters ?? {}).find(
17100
+ (filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
17101
+ );
17102
+ if (dateFilter?.operator === "BETWEEN") {
17103
+ dateFilter.startDate = dateFilter.value[0];
17104
+ dateFilter.endDate = dateFilter.value[1];
17105
+ }
17106
+ const pivot = report?.pivot;
17107
+ const data = report || {};
17108
+ if (pivot && client) {
17109
+ if (report.rowCount === 0 || report.rows.length === 0) {
17110
+ const columns = [];
17111
+ if (pivot.rowField) {
17112
+ columns.push({
17113
+ field: pivot.rowField,
17114
+ label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
17115
+ format: pivot.rowFieldType || "string",
17116
+ jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
17117
+ fieldType: pivot.rowFieldType || "string",
17118
+ dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
17119
+ });
17120
+ }
17121
+ for (const agg of pivot.aggregations ?? []) {
17122
+ if (agg.valueField) {
17123
+ columns.push({
17124
+ field: agg.valueField,
17125
+ label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
17126
+ //FIXME: valueFieldType is not always the same as the format
17127
+ format: agg.valueFieldType ?? "whole_number",
17128
+ jsType: agg.valueFieldType ?? "number",
17129
+ fieldType: agg.valueFieldType ?? "number",
17130
+ dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
17131
+ });
17132
+ }
17133
+ }
17134
+ return {
17135
+ rows: [],
17136
+ rowCount: 0,
17137
+ pivotQuery: report.queryString ?? "",
17138
+ columns
17139
+ };
17140
+ }
17141
+ try {
17142
+ let dateBucket = dateBucketInitial;
17143
+ let filterDateRange = void 0;
17144
+ if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
17145
+ filterDateRange = {
17146
+ start: dateFilter.startDate,
17147
+ end: dateFilter.endDate
17148
+ };
17149
+ } else if (report.dateRange) {
17150
+ filterDateRange = report.dateRange;
17151
+ }
17152
+ if (!dateBucket && filterDateRange) {
17153
+ dateBucket = getDateBucketFromRange(filterDateRange);
17154
+ }
17155
+ const pivotTable = await generatePivotWithSQL({
17156
+ pivot,
17157
+ report,
17158
+ client,
17159
+ dateBucket,
17160
+ dateFilter,
17161
+ dashboardName,
17162
+ tenants,
17163
+ additionalProcessing,
17164
+ getToken
17165
+ });
17166
+ return pivotTable;
17167
+ } catch (e) {
17168
+ eventTracking?.logError?.({
17169
+ type: "bug",
17170
+ // TODO: determine type
17171
+ severity: "high",
17172
+ message: "Error fetching pivot table",
17173
+ errorMessage: e.message,
17174
+ errorStack: e.stack,
17175
+ errorData: {
17176
+ caller: "getPivotTable",
17177
+ function: "getPivotTable"
17178
+ }
17179
+ });
17180
+ console.error("Error fetching pivot table", e);
17181
+ throw e;
17182
+ }
17183
+ }
17184
+ return pivot && data.rows ? generatePivotTable({
17185
+ pivot,
17186
+ report,
17187
+ client,
17188
+ uniqueValues: report.distinctStrings,
17189
+ dashboardName,
17190
+ tenants,
17191
+ dateFilter,
17192
+ additionalProcessing,
17193
+ getToken,
17194
+ eventTracking
17195
+ }) : void 0;
17196
+ }
17197
+ function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
17198
+ if (!pivotTable) return itemInfo?.yAxisFields ?? [];
17199
+ const pivot = itemInfo?.pivot || config?.pivot;
17200
+ if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
17201
+ const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
17202
+ return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
17203
+ }
17204
+ async function getDashboard(dashboardName, client, getToken, tenants, flags) {
17205
+ const { data: resp } = await quillFetch({
17206
+ client,
17207
+ task: "dashboard",
17208
+ metadata: {
17209
+ name: dashboardName,
17210
+ clientId: client.publicKey,
17211
+ databaseType: client.databaseType,
17212
+ useNewNodeSql: true,
17213
+ tenants,
17214
+ flags
17215
+ },
17216
+ getToken
17217
+ });
17218
+ return {
17219
+ ...resp,
17220
+ createdAt: resp.createdAt && new Date(resp.createdAt),
17221
+ dateFilter: resp.dateFilter ? {
17222
+ ...resp.dateFilter,
17223
+ presetOptions: resp.dateFilter.presetOptions?.map(
17224
+ (preset) => ({
17225
+ ...preset,
17226
+ loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
17227
+ loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
17228
+ })
17229
+ ),
17230
+ defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
17231
+ (preset) => ({
17232
+ ...preset,
17233
+ loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
17234
+ loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
17235
+ })
17236
+ )
17237
+ } : void 0
17238
+ };
17239
+ }
17240
+
17241
+ // src/utils/chartBuilder.ts
17242
+ var numberFormatOptions = [
17243
+ "whole_number",
17244
+ "one_decimal_place",
17245
+ "two_decimal_places",
17246
+ "dollar_amount",
17247
+ "dollar_cents",
17248
+ "percentage"
17249
+ ];
17250
+ var dateFormatOptions = [
17251
+ "MMM_yyyy",
17252
+ "MMM_dd",
17253
+ "MMM_dd_yyyy",
17254
+ "MMM_dd_hh:mm_ap_pm",
17255
+ "hh_ap_pm",
17256
+ "date",
17257
+ "timestamptz"
17258
+ ];
17259
+ var NUMBER_OPTIONS = [
17260
+ { value: "whole_number", label: "whole number" },
17261
+ { value: "one_decimal_place", label: "one decimal place" },
17262
+ { value: "two_decimal_places", label: "two decimal places" },
17263
+ { value: "dollar_amount", label: "dollar amount" },
17264
+ { value: "dollar_cents", label: "dollar and cent amount" },
17265
+ { value: "percent", label: "percentage" }
17266
+ ];
17267
+ var DATE_OPTIONS = [
17268
+ { value: "MMM_yyyy", label: "month" },
17269
+ { value: "MMM_dd", label: "day" },
17270
+ { value: "MMM_dd_yyyy", label: "day and year" },
17271
+ { value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
17272
+ { value: "hh_ap_pm", label: "hour" }
17273
+ ];
17274
+ var ALL_FORMAT_OPTIONS = [
17275
+ ...NUMBER_OPTIONS,
17276
+ ...DATE_OPTIONS,
17277
+ { value: "string", label: "string" }
17278
+ ];
17279
+ function createInitialFormData(columns) {
17280
+ const firstNumberColumn = columns?.find(
17281
+ (col) => numberFormatOptions.includes(col.format)
17282
+ );
17283
+ const firstStringColumn = columns?.find(
17284
+ (col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
17285
+ );
17286
+ const firstDateColumn = columns?.find(
17287
+ (col) => dateFormatOptions.includes(col.format)
17288
+ );
17289
+ const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
17290
+ const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
17291
+ const formEmptyState = {
17292
+ name: "",
17293
+ columns: columns.map((col) => {
17294
+ return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
17295
+ }),
17296
+ xAxisField,
17297
+ xAxisFormat,
17298
+ yAxisFields: [
17299
+ {
17300
+ field: firstNumberColumn?.field || columns?.[0]?.field || "",
17301
+ label: "",
17302
+ format: firstNumberColumn?.format || columns?.[0]?.format || "string"
17303
+ }
17304
+ ],
17305
+ xAxisLabel: "",
17306
+ chartType: firstNumberColumn ? "line" : "table",
17307
+ pivot: null,
17308
+ template: true,
17309
+ referenceLines: []
17310
+ };
17311
+ return formEmptyState;
17312
+ }
17313
+
17314
+ // src/utils/error.ts
17315
+ var DataLoadError = class extends Error {
17316
+ data;
17317
+ constructor(message, data) {
17318
+ super(message);
17319
+ this.name = "DataLoadError";
17320
+ this.data = data;
17321
+ }
17322
+ };
17323
+
17324
+ // src/utils/errorProcessing.ts
17325
+ function processFilterErrorList(resp) {
17326
+ if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
17327
+ return;
17328
+ }
17329
+ }
17330
+
17331
+ // src/utils/queryConstructor.ts
17332
+ function replaceBigQuerySpecialCharacters(column) {
17333
+ return column.replaceAll("/", "quill_forward_slash");
17334
+ }
17335
+ function processColumnReference(column, databaseType, fallbackOnNull, isColumnFieldAlias, isValueFieldAlias) {
17336
+ switch (databaseType.toLowerCase()) {
17337
+ case "postgresql":
17338
+ case "clickhouse": {
17339
+ if (column === "") {
17340
+ return fallbackOnNull ? `"${fallbackOnNull}"` : `"_"`;
17341
+ }
17342
+ if (isColumnFieldAlias) {
17343
+ return `"${column.replaceAll('"', "")}"`;
17344
+ }
17345
+ const columnParts = column.split(".");
17346
+ if (columnParts.length > 1) {
17347
+ return `"` + columnParts.map((part) => part.replaceAll('"', "")).join('"."') + `"`;
17348
+ }
17349
+ return `"${column.replaceAll('"', "")}"`;
17350
+ }
17351
+ case "mysql": {
17352
+ if (column === "") {
17353
+ return fallbackOnNull ? `${fallbackOnNull}` : "_";
17354
+ }
17355
+ if (isColumnFieldAlias) {
17356
+ return `\`${column.replaceAll(`\``, "").replaceAll(`"`, "")}\``;
17357
+ }
17358
+ const columnParts = column.split(".");
17359
+ if (columnParts.length > 1) {
17360
+ return `\`` + columnParts.map((part) => part.replaceAll(`\``, "")).join("`.`") + `\``;
17361
+ }
16917
17362
  return `\`${column.replaceAll(`\``, "")}\``;
16918
17363
  }
16919
17364
  case "snowflake": {
@@ -16975,51 +17420,6 @@ function processColumnReference(column, databaseType, fallbackOnNull, isColumnFi
16975
17420
  function replaceSpacesWithUnderscores(column) {
16976
17421
  return column.replaceAll(" ", "_");
16977
17422
  }
16978
- function processInterval(interval2, rowField, databaseType) {
16979
- if (["postgresql", "snowflake", "clickhouse"].includes(
16980
- databaseType.toLowerCase()
16981
- )) {
16982
- return `(${processColumnReference(rowField, databaseType)} + INTERVAL '${interval2}')`;
16983
- } else if (databaseType.toLowerCase() === "mysql") {
16984
- return `(${processColumnReference(rowField, databaseType)} + INTERVAL ${interval2})`;
16985
- }
16986
- return `TIMESTAMP_ADD(${processColumnReference(rowField, databaseType)}, INTERVAL ${interval2} )`;
16987
- }
16988
- function processDateTrunc(dateBucket, rowField, databaseType, comparisonInterval) {
16989
- const dateField = comparisonInterval ? processInterval(comparisonInterval, rowField, databaseType) : processColumnReference(rowField, databaseType);
16990
- if (["postgresql", "snowflake"].includes(databaseType.toLowerCase())) {
16991
- return `date_trunc('${dateBucket}', ${dateField})`;
16992
- }
16993
- if (["clickhouse"].includes(databaseType.toLowerCase())) {
16994
- return `dateTrunc('${dateBucket}', ${dateField})`;
16995
- }
16996
- if (["databricks"].includes(databaseType.toLowerCase())) {
16997
- return `DATE_TRUNC('${dateBucket}', ${dateField})`;
16998
- }
16999
- if (["mysql"].includes(databaseType.toLowerCase())) {
17000
- switch (dateBucket.toLowerCase()) {
17001
- case "year":
17002
- return `DATE_FORMAT(${dateField}, '%Y-01-01 00:00:00')`;
17003
- case "month":
17004
- return `DATE_FORMAT(${dateField}, '%Y-%m-01 00:00:00')`;
17005
- case "week":
17006
- return `DATE_FORMAT(${dateField}, '%Y-%U-1 00:00:00')`;
17007
- case "day":
17008
- default:
17009
- return `DATE(${dateField})`;
17010
- }
17011
- }
17012
- if (["mssql"].includes(databaseType.toLowerCase())) {
17013
- return `DATETRUNC(${dateBucket}, ${dateField})`;
17014
- }
17015
- return `TIMESTAMP_TRUNC(${dateField}, ${dateBucket})`;
17016
- }
17017
- function processValueField(aggType, databaseType, valueField) {
17018
- if (aggType === "min" || aggType === "max" || aggType?.toLowerCase() === "average")
17019
- return `${processColumnReference(valueField, databaseType)} ELSE null`;
17020
- if (aggType === "count") return `1 ELSE 0`;
17021
- return valueField ? `${processColumnReference(valueField, databaseType)} ELSE 0` : `1 ELSE 0`;
17022
- }
17023
17423
  function generateCountQuery(fields, query, databaseType) {
17024
17424
  let countQuery = [];
17025
17425
  let cteQuery = `WITH querytable AS (${query.replace(";", "")}) `;
@@ -17054,1206 +17454,95 @@ function generateDistinctQuery(stringFields, query, databaseType) {
17054
17454
  case "mssql":
17055
17455
  return generateDistinctQueryMSSQL(stringFields, query);
17056
17456
  case "databricks":
17057
- return generateDistinctQueryDatabricks(stringFields, query);
17058
- case "clickhouse":
17059
- // works with default for now
17060
- default:
17061
- return generateDistinctQueryDefault(stringFields, query, databaseType);
17062
- }
17063
- }
17064
- function generateDistinctQueryDefault(stringFields, query, databaseType) {
17065
- const distinctQueries = stringFields.map((field) => {
17066
- return `SELECT '${field}' AS ${processColumnReference("field", databaseType)}, ARRAY_AGG(DISTINCT ${field}) AS ${processColumnReference("string_values", databaseType)} FROM querytable`;
17067
- });
17068
- const distinctQuery = distinctQueries.join(" UNION ALL ");
17069
- return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17070
- }
17071
- function generateDistinctQueryMySQL(stringFields, query) {
17072
- const distinctQueries = stringFields.map((field) => {
17073
- return `
17074
- SELECT '${field}' AS ${processColumnReference("field", "mysql")},
17075
- JSON_ARRAYAGG(\`${field}\`) AS ${processColumnReference("string_values", "mysql")}
17076
- FROM (SELECT DISTINCT \`${field}\` FROM querytable) AS distinct_${replaceSpacesWithUnderscores(field)}`;
17077
- });
17078
- const distinctQuery = distinctQueries.join(" UNION ALL ");
17079
- return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17080
- }
17081
- function generateDistinctQueryBigQuery(stringFields, query) {
17082
- const distinctQueries = stringFields.map((field) => {
17083
- return `
17084
- SELECT '${field}' AS ${processColumnReference("field", "bigquery")},
17085
- ARRAY_AGG(\`${field}\`) AS ${processColumnReference("string_values", "bigquery")}
17086
- FROM (SELECT \`${field}\` FROM querytable WHERE \`${field}\` IS NOT NULL GROUP BY \`${field}\`) AS distinct_${replaceSpacesWithUnderscores(field)}`;
17087
- });
17088
- const distinctQuery = distinctQueries.join(" UNION ALL ");
17089
- return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17090
- }
17091
- function generateDistinctQueryPostgres(stringFields, query) {
17092
- const distinctQueries = stringFields.map((field) => {
17093
- return `SELECT '${field}' AS ${processColumnReference("field", "postgresql")}, to_json(ARRAY_AGG(DISTINCT "${field}")) AS ${processColumnReference("string_values", "postgresql")} FROM querytable`;
17094
- });
17095
- const distinctQuery = distinctQueries.join(" UNION ALL ");
17096
- return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17097
- }
17098
- function generateDistinctQuerySnowflake(stringFields, query) {
17099
- const distinctQueries = stringFields.map((field) => {
17100
- return `SELECT '${field}' AS "field", ARRAY_AGG(DISTINCT "${field}") AS "string_values" FROM querytable`;
17101
- });
17102
- const distinctQuery = distinctQueries.join(" UNION ALL ");
17103
- return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17104
- }
17105
- function generateDistinctQueryMSSQL(stringFields, query) {
17106
- const escapeFieldName = (field) => field.replace(/'/g, "''");
17107
- const distinctQueries = stringFields.map((field) => {
17108
- return `
17109
- SELECT
17110
- '${escapeFieldName(field)}' AS field,
17111
- STRING_AGG(${field}, ',') AS string_values
17112
- FROM (
17113
- SELECT ${field}
17114
- FROM querytable
17115
- WHERE ${field} IS NOT NULL
17116
- GROUP BY ${field}
17117
- ) AS grouped
17118
- `.replace(/\s+/g, " ").trim();
17119
- });
17120
- const distinctQuery = distinctQueries.join(" UNION ALL ");
17121
- return `
17122
- WITH querytable AS (
17123
- ${query.replace(";", "")}
17124
- )
17125
- ${distinctQuery}`.replace(/\s+/g, " ").trim();
17126
- }
17127
- function generateDistinctQueryDatabricks(stringFields, query) {
17128
- const distinctQueries = stringFields.map((field) => {
17129
- return `SELECT '${field}' AS ${processColumnReference("field", "databricks")}, collect_set(\`${field}\`) AS ${processColumnReference("string_values", "databricks")} FROM querytable`;
17130
- });
17131
- const distinctQuery = distinctQueries.join(" UNION ALL ");
17132
- return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17133
- }
17134
- function generateMinMaxDateRangeQueries(columnFields, query, databaseType) {
17135
- const max2 = "MAX";
17136
- const min2 = "MIN";
17137
- const cast = databaseType.toLowerCase() === "snowflake" ? "::TIMESTAMP_TZ" : "";
17138
- const distinctQueries = columnFields.map((field) => {
17139
- const wrappedField = ["postgresql", "clickhouse"].includes(
17140
- databaseType.toLowerCase()
17141
- ) ? `"${field}"` : field;
17142
- return `SELECT '${field}' AS field, ${min2}(${wrappedField})${cast} AS min_range, ${max2}(${wrappedField})${cast} AS max_range FROM querytable`;
17143
- });
17144
- const distinctQuery = distinctQueries.join(" UNION ALL ");
17145
- return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17146
- }
17147
- function generatePivotQuery(pivot, itemQuery, databaseType, distinctStrings, dateBucket) {
17148
- if (!isValidPivot(pivot).valid) {
17149
- return void 0;
17150
- }
17151
- if (pivot.columnField && distinctStrings && distinctStrings.length > 0) {
17152
- return create2DPivotQuery(
17153
- pivot,
17154
- itemQuery,
17155
- databaseType,
17156
- distinctStrings,
17157
- dateBucket
17158
- );
17159
- }
17160
- if (pivot.rowField) {
17161
- return create1DPivotQuery(pivot, itemQuery, dateBucket, databaseType);
17162
- }
17163
- return createAggregationValuePivot(pivot, itemQuery, databaseType);
17164
- }
17165
- function create2DPivotQuery(pivot, itemQuery, databaseType, columnFieldValues, dateBucket) {
17166
- if (!pivot || !pivot.columnField) {
17167
- return void 0;
17168
- }
17169
- if (isStringType(pivot.rowFieldType ?? "") || !pivot.rowFieldType) {
17170
- return create2DStringPivotQuery(
17171
- pivot,
17172
- itemQuery,
17173
- columnFieldValues,
17174
- databaseType
17175
- );
17176
- }
17177
- return create2DDatePivotQuery(
17178
- pivot,
17179
- itemQuery,
17180
- columnFieldValues,
17181
- databaseType,
17182
- dateBucket
17183
- );
17184
- }
17185
- function create2DStringPivotQuery(pivot, itemQuery, columnFieldValues, databaseType) {
17186
- const isValidBaseQuery = itemQuery.match(
17187
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17188
- );
17189
- if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField)
17190
- return void 0;
17191
- const rowField = pivot.rowField;
17192
- if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
17193
- throw new Error("No value field provided for pivot");
17194
- if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
17195
- throw new Error("No aggregation type provided for pivot");
17196
- const columnField = pivot.columnField;
17197
- const rowFieldAlias = processColumnReference(
17198
- rowField,
17199
- databaseType,
17200
- void 0,
17201
- false,
17202
- true
17203
- );
17204
- const columnFieldAlias = processColumnReference(
17205
- columnField,
17206
- databaseType,
17207
- void 0,
17208
- false,
17209
- true
17210
- );
17211
- let caseWhens = [];
17212
- let valueAliases = [];
17213
- const seenAggs = {};
17214
- pivot.aggregations?.forEach((currentAgg) => {
17215
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17216
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17217
- } else {
17218
- seenAggs[currentAgg.aggregationType ?? ""] = {
17219
- ...seenAggs[currentAgg.aggregationType ?? ""],
17220
- [currentAgg.valueField ?? ""]: 1
17221
- };
17222
- }
17223
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
17224
- if (disambiguationIndex === "1") disambiguationIndex = "";
17225
- const valueFieldAlias = processColumnReference(
17226
- currentAgg.valueField || rowField || "count",
17227
- databaseType,
17228
- void 0,
17229
- false,
17230
- true
17231
- );
17232
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17233
- let value2AliasSubstring = "";
17234
- const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
17235
- (acc, v) => acc + v
17236
- ) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
17237
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
17238
- const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
17239
- currentAgg.aggregationType,
17240
- databaseType,
17241
- valueFieldAlias
17242
- );
17243
- if (currentAgg.aggregationType === "percentage") {
17244
- if (!currentAgg.valueField)
17245
- throw new Error("No value field provided for pivot");
17246
- const valueField2Alias = processColumnReference(
17247
- currentAgg.valueField2 ?? currentAgg.valueField,
17248
- databaseType,
17249
- void 0,
17250
- false,
17251
- true
17252
- );
17253
- const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
17254
- if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
17255
- caseWhens = [
17256
- ...caseWhens,
17257
- ...columnFieldValues.map((column) => {
17258
- return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17259
- column,
17260
- databaseType
17261
- )}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
17262
- column + disambiguation,
17263
- databaseType,
17264
- "_",
17265
- true
17266
- )}`;
17267
- })
17268
- ];
17269
- } else {
17270
- value2AliasSubstring = `${processColumnReference(
17271
- currentAgg.valueField2 ?? currentAgg.valueField,
17272
- databaseType,
17273
- void 0,
17274
- true
17275
- )} AS ${valueField2Alias}`;
17276
- caseWhens = [
17277
- ...caseWhens,
17278
- ...columnFieldValues.map((column) => {
17279
- return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17280
- column,
17281
- databaseType
17282
- )}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17283
- column,
17284
- databaseType
17285
- )}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
17286
- column + disambiguation,
17287
- databaseType,
17288
- "_",
17289
- true
17290
- )}`;
17291
- })
17292
- ];
17293
- }
17294
- } else {
17295
- caseWhens = [
17296
- ...caseWhens,
17297
- ...columnFieldValues.map((column) => {
17298
- return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17299
- column,
17300
- databaseType
17301
- )}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
17302
- })
17303
- ];
17304
- }
17305
- if (valueAliasSubstring) valueAliases.push(valueAliasSubstring);
17306
- if (value2AliasSubstring) valueAliases.push(value2AliasSubstring);
17307
- });
17308
- valueAliases = [
17309
- `${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
17310
- ...valueAliases,
17311
- `${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
17312
- ];
17313
- valueAliases = Array.from(new Set(valueAliases));
17314
- const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
17315
- const pivotQuery = `
17316
- ,quill_alias AS (
17317
- SELECT ${valueAliases.length > 0 ? `${valueAliases.join(", ")}` : ""}
17318
- FROM quill_base_table
17319
- ),
17320
- quill_qt_cw AS (
17321
- SELECT ${rowFieldAlias}
17322
- ${caseWhens.length > 0 ? `, ${caseWhens.join(", ")}` : ""}
17323
- FROM quill_alias
17324
- GROUP BY ${rowFieldAlias}
17325
- ),
17326
- quill_base_pivot AS (
17327
- SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
17328
- FROM quill_qt_cw qt
17329
- ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
17330
- )
17331
- SELECT * FROM quill_base_pivot
17332
- `.replace(/\s+/g, " ").trim();
17333
- return itemQuery.replace(
17334
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17335
- pivotQuery
17336
- );
17337
- }
17338
- function create2DDatePivotQuery(pivot, itemQuery, columnFieldValues, databaseType, dateBucket = "month") {
17339
- const isValidBaseQuery = itemQuery.match(
17340
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17341
- );
17342
- if (!isValidBaseQuery || !pivot.columnField || !pivot.rowField) {
17343
- return void 0;
17344
- }
17345
- if (!pivot.aggregations?.[0]?.valueField && pivot.aggregations?.[0]?.aggregationType !== "count" && !pivot.valueField && pivot.aggregationType !== "count")
17346
- throw new Error("No value field provided for pivot");
17347
- if (!pivot.aggregations?.[0]?.aggregationType && !pivot.aggregationType)
17348
- throw new Error("No aggregation type provided for pivot");
17349
- const rowField = pivot.rowField;
17350
- const columnField = pivot.columnField;
17351
- const rowFieldAlias = processColumnReference(
17352
- rowField,
17353
- databaseType,
17354
- void 0,
17355
- false,
17356
- true
17357
- );
17358
- const columnFieldAlias = processColumnReference(
17359
- columnField,
17360
- databaseType,
17361
- void 0,
17362
- false,
17363
- true
17364
- );
17365
- let caseWhens = [];
17366
- let valueFieldAliases = [];
17367
- const seenAggs = {};
17368
- pivot.aggregations?.forEach((currentAgg) => {
17369
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17370
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17371
- } else {
17372
- seenAggs[currentAgg.aggregationType ?? ""] = {
17373
- ...seenAggs[currentAgg.aggregationType ?? ""],
17374
- [currentAgg.valueField ?? ""]: 1
17375
- };
17376
- }
17377
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString();
17378
- if (disambiguationIndex === "1") disambiguationIndex = "";
17379
- const valueFieldAlias = processColumnReference(
17380
- currentAgg.valueField ?? rowField,
17381
- databaseType,
17382
- void 0,
17383
- false,
17384
- true
17385
- );
17386
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17387
- let value2AliasSubstring = "";
17388
- const disambiguationField = Object.values(seenAggs[currentAgg.aggregationType ?? ""] ?? {}).reduce(
17389
- (acc, v) => acc + v
17390
- ) > 1 ? `_${currentAgg.valueField}${disambiguationIndex}` : "";
17391
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationField}_${disambiguationField ? matchCasing(currentAgg.aggregationType, currentAgg.valueField) : currentAgg.aggregationType}` : "";
17392
- const valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : processValueField(
17393
- currentAgg.aggregationType,
17394
- databaseType,
17395
- valueFieldAlias
17396
- );
17397
- if (currentAgg.aggregationType === "percentage") {
17398
- if (!currentAgg.valueField)
17399
- throw new Error("No value field provided for pivot");
17400
- const valueField2Alias = processColumnReference(
17401
- currentAgg.valueField2 ?? currentAgg.valueField,
17402
- databaseType,
17403
- void 0,
17404
- false,
17405
- true
17406
- );
17407
- const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
17408
- if (currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2) {
17409
- caseWhens = [
17410
- ...caseWhens,
17411
- ...columnFieldValues.map((column) => {
17412
- return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17413
- column,
17414
- databaseType
17415
- )}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(${value2Expr}), 1) AS ${processColumnReference(
17416
- column + disambiguation,
17417
- databaseType,
17418
- "_",
17419
- true
17420
- )}`;
17421
- })
17422
- ];
17423
- } else {
17424
- value2AliasSubstring = `${processColumnReference(
17425
- currentAgg.valueField2 ?? currentAgg.valueField,
17426
- databaseType,
17427
- void 0,
17428
- true
17429
- )} AS ${valueField2Alias}`;
17430
- caseWhens = [
17431
- ...caseWhens,
17432
- ...columnFieldValues.map((column) => {
17433
- return `CAST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17434
- column,
17435
- databaseType
17436
- )}' THEN ${valueExpr} END) AS FLOAT) / GREATEST(sum(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17437
- column,
17438
- databaseType
17439
- )}' THEN ${value2Expr} END), 1) AS ${processColumnReference(
17440
- column + disambiguation,
17441
- databaseType,
17442
- "_",
17443
- true
17444
- )}`;
17445
- })
17446
- ];
17447
- }
17448
- } else {
17449
- caseWhens = [
17450
- ...caseWhens,
17451
- ...columnFieldValues.map((column) => {
17452
- return `${processAggType(currentAgg.aggregationType, true)}(CASE WHEN ${columnFieldAlias} = '${processSingleQuotes(
17453
- column,
17454
- databaseType
17455
- )}' THEN ${valueExpr} END) AS ${processColumnReference(column + disambiguation, databaseType, "_", true)}`;
17456
- })
17457
- ];
17458
- }
17459
- if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
17460
- if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
17461
- });
17462
- valueFieldAliases = [
17463
- `${processColumnReference(rowField, databaseType, void 0, true)} AS ${rowFieldAlias}`,
17464
- ...valueFieldAliases,
17465
- `${processColumnReference(columnField, databaseType, void 0, true)} AS ${columnFieldAlias}`
17466
- ];
17467
- valueFieldAliases = Array.from(new Set(valueFieldAliases));
17468
- const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
17469
- const pivotQuery = `
17470
- , quill_alias AS (SELECT ${valueFieldAliases.length > 0 ? `${valueFieldAliases.join(", ")}` : ""} FROM quill_base_table),
17471
- quill_qt_agg AS (SELECT ${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${rowFieldAlias}${caseWhens.length > 0 ? `, ${caseWhens.join(", ")}` : ""} FROM quill_alias GROUP BY ${databaseType.toLowerCase() === "clickhouse" ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
17472
- quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
17473
- ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
17474
- SELECT * FROM quill_base_pivot
17475
- `.replace(/\s+/g, " ").trim();
17476
- return itemQuery.replace(
17477
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17478
- pivotQuery
17479
- );
17480
- }
17481
- function create1DPivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
17482
- if (isStringType(pivot.rowFieldType || "") || !pivot.rowFieldType) {
17483
- return create1DStringPivotQuery(pivot, itemQuery, databaseType);
17484
- }
17485
- return create1DDatePivotQuery(pivot, itemQuery, dateBucket, databaseType);
17486
- }
17487
- function create1DStringPivotQuery(pivot, itemQuery, databaseType) {
17488
- const isValidBaseQuery = itemQuery.match(
17489
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17490
- );
17491
- if (!isValidBaseQuery) return void 0;
17492
- const rowField = pivot.rowField;
17493
- const rowAlias = processColumnReference(
17494
- rowField,
17495
- databaseType,
17496
- void 0,
17497
- true
17498
- );
17499
- let quillAggSelects = [rowAlias];
17500
- let valueFieldAliases = [];
17501
- const seenAggs = {};
17502
- pivot.aggregations?.forEach((currentAgg) => {
17503
- if (!currentAgg.valueField) currentAgg.valueField = void 0;
17504
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17505
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17506
- } else {
17507
- seenAggs[currentAgg.aggregationType ?? ""] = {
17508
- ...seenAggs[currentAgg.aggregationType ?? ""],
17509
- [currentAgg.valueField ?? ""]: 1
17510
- };
17511
- }
17512
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
17513
- if (disambiguationIndex === "1") disambiguationIndex = "";
17514
- const valueFieldAlias = processColumnReference(
17515
- currentAgg.valueField || rowField || "count",
17516
- databaseType,
17517
- void 0,
17518
- false,
17519
- true
17520
- );
17521
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17522
- let value2AliasSubstring = "";
17523
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
17524
- let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
17525
- if (currentAgg.valueFieldType === "bool") {
17526
- valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
17527
- }
17528
- if (currentAgg.aggregationType === "percentage") {
17529
- let countPercentage = false;
17530
- if (!currentAgg.valueField) {
17531
- countPercentage = true;
17532
- }
17533
- const valueField2Alias = processColumnReference(
17534
- currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
17535
- databaseType,
17536
- void 0,
17537
- false,
17538
- true
17539
- );
17540
- let value2Expr = valueField2Alias;
17541
- if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
17542
- value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
17543
- }
17544
- value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
17545
- const percentageExpr = countPercentage ? "CAST(COUNT(*) AS FLOAT) / (SELECT COUNT(*) FROM quill_base_table)" : currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
17546
- quillAggSelects = [
17547
- ...quillAggSelects,
17548
- `${percentageExpr} as ${processColumnReference(
17549
- `${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
17550
- databaseType,
17551
- void 0,
17552
- false,
17553
- true
17554
- )}`
17555
- ];
17556
- } else {
17557
- quillAggSelects = [
17558
- ...quillAggSelects,
17559
- `${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
17560
- (currentAgg.valueField || "count") + disambiguation,
17561
- databaseType
17562
- )}`
17563
- ];
17564
- }
17565
- if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
17566
- if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
17567
- });
17568
- valueFieldAliases = Array.from(new Set(valueFieldAliases));
17569
- const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
17570
- const pivotQuery = `, quill_alias AS (
17571
- SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
17572
- FROM quill_base_table
17573
- ),
17574
- quill_qt_cw AS (
17575
- SELECT ${quillAggSelects.join(", ")} FROM quill_alias GROUP BY ${rowAlias}
17576
- ),
17577
- quill_base_pivot AS (
17578
- SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} *
17579
- FROM quill_qt_cw qt ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
17580
- )
17581
- SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
17582
- return itemQuery.replace(
17583
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17584
- pivotQuery
17585
- );
17586
- }
17587
- function create1DDatePivotQuery(pivot, itemQuery, dateBucket = "month", databaseType) {
17588
- const isValidBaseQuery = itemQuery.match(
17589
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17590
- );
17591
- if (!isValidBaseQuery) {
17592
- return void 0;
17593
- }
17594
- const rowField = pivot.rowField || "";
17595
- const rowFieldAlias = processColumnReference(
17596
- rowField,
17597
- databaseType,
17598
- void 0
17599
- );
17600
- let quillAggSelects = [
17601
- `${processDateTrunc(dateBucket, rowFieldAlias, databaseType)} as ${processColumnReference(rowField, databaseType)}`
17602
- ];
17603
- let valueFieldAliases = [];
17604
- const seenAggs = {};
17605
- pivot.aggregations?.forEach((currentAgg) => {
17606
- if (!currentAgg.valueField) currentAgg.valueField = void 0;
17607
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17608
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17609
- } else {
17610
- seenAggs[currentAgg.aggregationType ?? ""] = {
17611
- ...seenAggs[currentAgg.aggregationType ?? ""],
17612
- [currentAgg.valueField ?? ""]: 1
17613
- };
17614
- }
17615
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
17616
- if (disambiguationIndex === "1") disambiguationIndex = "";
17617
- const valueFieldAlias = processColumnReference(
17618
- currentAgg.valueField || rowField || "count",
17619
- databaseType,
17620
- void 0,
17621
- false,
17622
- true
17623
- );
17624
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17625
- let value2AliasSubstring = "";
17626
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}` + (currentAgg.aggregationType !== "count" ? `_${currentAgg.aggregationType}` : "") : "";
17627
- let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
17628
- if (currentAgg.valueFieldType === "bool") {
17629
- valueExpr = `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END`;
17630
- }
17631
- if (currentAgg.aggregationType === "percentage") {
17632
- let countPercentage = false;
17633
- if (!currentAgg.valueField) {
17634
- countPercentage = true;
17635
- }
17636
- const valueField2Alias = processColumnReference(
17637
- currentAgg.valueField2 ?? currentAgg.valueField ?? "count",
17638
- databaseType,
17639
- void 0,
17640
- false,
17641
- true
17642
- );
17643
- value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
17644
- let value2Expr = valueField2Alias;
17645
- if ((currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool") {
17646
- value2Expr = `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END`;
17647
- }
17648
- const percentageExpr = countPercentage ? "CAST(COUNT(*) AS FLOAT) / (SELECT COUNT(*) FROM quill_base_table)" : currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
17649
- quillAggSelects = [
17650
- ...quillAggSelects,
17651
- `${percentageExpr} as ${processColumnReference(
17652
- `${currentAgg.valueField ?? (disambiguation ? "count" : "percentage")}${disambiguation}`,
17653
- databaseType,
17654
- void 0,
17655
- false,
17656
- true
17657
- )}`
17658
- ];
17659
- } else {
17660
- quillAggSelects = [
17661
- ...quillAggSelects,
17662
- `${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference((currentAgg.valueField || "count") + disambiguation, databaseType)}`
17663
- ];
17664
- }
17665
- if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
17666
- if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
17667
- });
17668
- valueFieldAliases = Array.from(new Set(valueFieldAliases));
17669
- const sortQuery = `${pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : ""}`;
17670
- const pivotQuery = `, quill_alias AS (SELECT ${processColumnReference(`${rowField}`, databaseType, void 0, true)} AS ${rowFieldAlias}${valueFieldAliases.length > 0 ? `, ${valueFieldAliases.join(", ")}` : ""}
17671
- FROM quill_base_table),
17672
- quill_qt_agg AS (SELECT ${quillAggSelects.join(", ")}
17673
- FROM quill_alias GROUP BY ${databaseType.toLowerCase() === "clickhouse" ? processColumnReference(`${rowField}`, databaseType) : processDateTrunc(dateBucket, rowFieldAlias, databaseType)}),
17674
- quill_base_pivot AS (SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
17675
- ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""})
17676
- SELECT * FROM quill_base_pivot
17677
- `.replace(/\s+/g, " ").trim();
17678
- return itemQuery.replace(
17679
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17680
- pivotQuery
17681
- );
17682
- }
17683
- function createAggregationValuePivot(pivot, itemQuery, databaseType) {
17684
- const isValidBaseQuery = itemQuery.match(
17685
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/
17686
- );
17687
- if (!isValidBaseQuery) return void 0;
17688
- let quillAggSelects = [];
17689
- let valueFieldAliases = [];
17690
- const seenAggs = {};
17691
- pivot.aggregations?.forEach((currentAgg) => {
17692
- if (!currentAgg.valueField) currentAgg.valueField = void 0;
17693
- if (seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]) {
17694
- seenAggs[currentAgg.aggregationType ?? ""][currentAgg.valueField ?? ""] += 1;
17695
- } else {
17696
- seenAggs[currentAgg.aggregationType ?? ""] = {
17697
- ...seenAggs[currentAgg.aggregationType ?? ""],
17698
- [currentAgg.valueField ?? ""]: 1
17699
- };
17700
- }
17701
- let disambiguationIndex = seenAggs[currentAgg.aggregationType ?? ""]?.[currentAgg.valueField ?? ""]?.toString() ?? "";
17702
- if (disambiguationIndex === "1") disambiguationIndex = "";
17703
- const valueFieldAlias = processColumnReference(
17704
- currentAgg.valueField || "count",
17705
- databaseType,
17706
- void 0,
17707
- false,
17708
- true
17709
- );
17710
- const valueAliasSubstring = currentAgg.valueField ? `${processColumnReference(currentAgg.valueField, databaseType, void 0, true)} AS ${valueFieldAlias}` : "";
17711
- let value2AliasSubstring = "";
17712
- const disambiguation = pivot.aggregations?.length > 1 ? `${disambiguationIndex}_${currentAgg.aggregationType}` : "";
17713
- let valueExpr = !currentAgg.valueField ? "*" : valueFieldAlias;
17714
- valueExpr = currentAgg.valueFieldType === "bool" ? `CASE WHEN ${valueFieldAlias} THEN 1 ELSE 0 END` : valueExpr;
17715
- if (currentAgg.aggregationType === "percentage") {
17716
- if (!currentAgg.valueField) {
17717
- throw new Error("No value field provided for percentage aggregation");
17718
- }
17719
- const valueField2Alias = processColumnReference(
17720
- currentAgg.valueField2 ?? currentAgg.valueField,
17721
- databaseType,
17722
- void 0,
17723
- false,
17724
- true
17725
- );
17726
- const value2Expr = (currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? `CASE WHEN ${valueField2Alias} THEN 1 ELSE 0 END` : valueField2Alias;
17727
- value2AliasSubstring = currentAgg.valueField2 && currentAgg.valueField !== currentAgg.valueField2 ? `${processColumnReference(currentAgg.valueField2, databaseType, void 0, true)} AS ${valueField2Alias}` : "";
17728
- const percentageExpr = currentAgg.valueField === currentAgg.valueField2 || !currentAgg.valueField2 ? `CAST(sum(${valueExpr}) AS FLOAT) / ${(currentAgg.valueField2Type ?? currentAgg.valueFieldType) === "bool" ? "COUNT(*)" : "SUM(sum(" + valueExpr + ")) OVER ()"}` : `CAST(sum(${valueExpr}) AS FLOAT) / GREATEST(sum(${value2Expr}), 1)`;
17729
- quillAggSelects = [
17730
- ...quillAggSelects,
17731
- `${percentageExpr} as ${processColumnReference(
17732
- `${currentAgg.valueField ?? ""}${disambiguation}`,
17733
- databaseType,
17734
- void 0,
17735
- false,
17736
- true
17737
- )}`
17738
- ];
17739
- } else {
17740
- quillAggSelects = [
17741
- ...quillAggSelects,
17742
- `${processAggType(currentAgg.aggregationType)}(${valueExpr}) AS ${processColumnReference(
17743
- (currentAgg.valueField || "count") + disambiguation,
17744
- databaseType
17745
- )}`
17746
- ];
17747
- }
17748
- if (valueAliasSubstring) valueFieldAliases.push(valueAliasSubstring);
17749
- if (value2AliasSubstring) valueFieldAliases.push(value2AliasSubstring);
17750
- });
17751
- valueFieldAliases = Array.from(new Set(valueFieldAliases));
17752
- if (valueFieldAliases.length === 0) {
17753
- valueFieldAliases = ["*"];
17754
- }
17755
- const sortQuery = pivot.sort && pivot.sortField && pivot.rowLimit ? ` ORDER BY ${processColumnReference(pivot.sortField, databaseType, void 0, true)} ${pivot.sortDirection || ""} ` : "";
17756
- const pivotQuery = `, quill_alias AS (
17757
- SELECT ${valueFieldAliases.join(", ")} FROM quill_base_table
17758
- ),
17759
- quill_qt_agg AS (
17760
- SELECT ${quillAggSelects.join(", ")} FROM quill_alias
17761
- ),
17762
- quill_base_pivot AS (
17763
- SELECT ${pivot.rowLimit && databaseType.toLowerCase() === "mssql" ? `TOP ${pivot.rowLimit}` : ""} * FROM quill_qt_agg qt
17764
- ${sortQuery}${pivot.rowLimit && databaseType.toLowerCase() !== "mssql" ? ` LIMIT ${pivot.rowLimit}` : ""}
17765
- )
17766
- SELECT * FROM quill_base_pivot`.replace(/\s+/g, " ").trim();
17767
- return itemQuery.replace(
17768
- /SELECT \* FROM\s+["'[`]?quill_base_table["'\]`]?\s*$/,
17769
- pivotQuery
17770
- );
17771
- }
17772
- function additionalProcessingOnPivotQuery(pivot, query, additionalProcessing, databaseType = "postgresql") {
17773
- if (!additionalProcessing || !query) return query;
17774
- const isValidBaseQuery = query.match(
17775
- /SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
17776
- );
17777
- if (!isValidBaseQuery) {
17778
- return void 0;
17779
- }
17780
- if (!pivot.aggregations || pivot.aggregations.length === 0) {
17781
- if (pivot.aggregationType) {
17782
- pivot.aggregations = [
17783
- {
17784
- aggregationType: pivot.aggregationType,
17785
- valueField: pivot.valueField,
17786
- valueField2: pivot.valueField2
17787
- }
17788
- ];
17789
- } else {
17790
- throw new Error("No aggregations provided for pivot");
17791
- }
17792
- }
17793
- let rowsPerPage = 0;
17794
- let currentInterval = 0;
17795
- let offset = 0;
17796
- let limit = 1e3;
17797
- let sortQuery = "";
17798
- if (additionalProcessing.page) {
17799
- const page = additionalProcessing.page.page || 0;
17800
- if (additionalProcessing.page.rowsPerRequest) {
17801
- limit = additionalProcessing.page.rowsPerRequest;
17802
- }
17803
- rowsPerPage = additionalProcessing.page.rowsPerPage || 0;
17804
- currentInterval = page ? Math.floor(page / (limit / rowsPerPage)) : 0;
17805
- offset = currentInterval * limit;
17806
- }
17807
- const disambiguation = pivot.aggregations.length > 1 ? `_${matchCasing(pivot.aggregations?.[0]?.aggregationType, pivot.aggregations?.[0]?.valueField)}` : "";
17808
- if (additionalProcessing.sort) {
17809
- sortQuery = `ORDER BY ${processColumnReference(additionalProcessing.sort.field, databaseType, void 0, true)} ${additionalProcessing.sort.direction || ""}`;
17810
- } else {
17811
- const valueFieldAlias = processColumnReference(
17812
- (pivot.aggregations?.[0]?.valueField ?? "") + disambiguation,
17813
- databaseType,
17814
- void 0,
17815
- false,
17816
- true
17817
- );
17818
- const defaultSortField = pivot.sortField || pivot.rowField || valueFieldAlias;
17819
- const defaultSortDirection = pivot.sortDirection || "";
17820
- if (defaultSortField !== `"_"`) {
17821
- sortQuery = `ORDER BY ${processColumnReference(defaultSortField, databaseType, void 0, true)} ${defaultSortDirection}`;
17822
- } else {
17823
- sortQuery = "";
17824
- }
17825
- }
17826
- const additionalProcessingQuery = `
17827
- SELECT *
17828
- FROM quill_base_pivot ${sortQuery}${databaseType.toLowerCase() === "mssql" ? ` OFFSET ${offset} ROWS FETCH NEXT ${limit} ROWS ONLY` : ` LIMIT ${limit} OFFSET ${offset}`}
17829
- `.replace(/\s+/g, " ").trim();
17830
- return query.replace(
17831
- /SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
17832
- additionalProcessingQuery
17833
- );
17834
- }
17835
- function generateRowCountQuery(query, databaseType) {
17836
- if (!query) return query;
17837
- const isValidBaseQuery = query.match(
17838
- /SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/
17839
- );
17840
- if (!isValidBaseQuery) {
17841
- return void 0;
17842
- }
17843
- const rowCountQuery = `, subview_row_count_cte AS (SELECT * FROM quill_base_pivot)
17844
- SELECT count(*) as ${processColumnReference("row_count", databaseType || "postgresql", void 0, true)} FROM subview_row_count_cte
17845
- `.replace(/\s+/g, " ").trim();
17846
- return query.replace(
17847
- /SELECT \* FROM\s+["'[`]?quill_base_pivot["'\]`]?\s*$/,
17848
- rowCountQuery
17849
- );
17850
- }
17851
-
17852
- // src/utils/pivotConstructor.ts
17853
- async function generatePivotWithSQL({
17854
- pivot,
17855
- report,
17856
- client,
17857
- dateBucket,
17858
- dateFilter,
17859
- distinctStrings,
17860
- dashboardName,
17861
- tenants,
17862
- additionalProcessing,
17863
- pivotQuery,
17864
- comparisonPivotQuery,
17865
- getPivotRowCount = true,
17866
- caller,
17867
- getToken
17868
- }) {
17869
- let sqlQuery = pivotQuery;
17870
- let comparisonPivotSql = comparisonPivotQuery;
17871
- const databaseType = client.databaseType || "postgresql";
17872
- if (!pivotQuery && pivot.columnField && !pivot.columnValues && !distinctStrings) {
17873
- if (!report?.rows) {
17874
- throw new Error("No distinct strings provided for column field");
17875
- } else {
17876
- distinctStrings = Array.from(
17877
- new Set(
17878
- report.rows.map((row) => row[pivot.columnField]).filter((value) => value !== null && value !== void 0)
17879
- )
17880
- );
17881
- }
17882
- }
17883
- if (!pivot.aggregations?.length && pivot.aggregationType) {
17884
- pivot.aggregations = [
17885
- {
17886
- aggregationType: pivot.aggregationType,
17887
- valueField: pivot.valueField,
17888
- valueFieldType: pivot.valueFieldType,
17889
- valueField2: pivot.valueField2,
17890
- valueField2Type: pivot.valueField2Type
17891
- }
17892
- ];
17893
- }
17894
- let comparisonInterval = void 0;
17895
- if (dateFilter && dateFilter.comparisonRange) {
17896
- comparisonInterval = getComparisonInterval(
17897
- {
17898
- startDate: dateFilter.comparisonRange.startDate,
17899
- endDate: dateFilter.comparisonRange.endDate
17900
- },
17901
- dateBucket
17902
- );
17903
- }
17904
- if (pivot.rowField && !pivot.rowFieldType) {
17905
- const rowColumn = report?.columns.find(
17906
- (column) => column.field === pivot.rowField
17907
- );
17908
- pivot.rowFieldType = rowColumn?.format || "string";
17909
- }
17910
- const filteredDistinctStrings = distinctStrings?.filter(
17911
- (value) => value !== null && value !== void 0 && value !== ""
17912
- );
17913
- const pivotColumnFields = filteredDistinctStrings?.slice(
17914
- 0,
17915
- MAX_PIVOT_UNIQUE_VALUES
17916
- );
17917
- if (!pivotQuery && report) {
17918
- if (!report.itemQuery) {
17919
- throw Error("No item query found in report");
17920
- }
17921
- const itemQuery = report.itemQuery[0];
17922
- const comparisonQuery = report.itemQuery[1];
17923
- if (!itemQuery) {
17924
- throw Error("No item query found in report");
17925
- }
17926
- sqlQuery = generatePivotQuery(
17927
- pivot,
17928
- itemQuery,
17929
- databaseType,
17930
- pivotColumnFields,
17931
- dateBucket
17932
- );
17933
- comparisonPivotSql = comparisonQuery ? generatePivotQuery(
17934
- pivot,
17935
- comparisonQuery,
17936
- databaseType,
17937
- pivotColumnFields,
17938
- dateBucket
17939
- ) : "";
17940
- }
17941
- if (!sqlQuery) {
17942
- throw "Error generating pivot query";
17943
- }
17944
- const paginatedSqlQuery = additionalProcessingOnPivotQuery(
17945
- pivot,
17946
- sqlQuery,
17947
- additionalProcessing,
17948
- client.databaseType
17949
- );
17950
- const paginatedComparisonQuery = comparisonPivotSql ? additionalProcessingOnPivotQuery(
17951
- pivot,
17952
- comparisonPivotSql,
17953
- additionalProcessing,
17954
- client.databaseType
17955
- ) : "";
17956
- const preQueries = [paginatedSqlQuery];
17957
- getPivotRowCount = getPivotRowCount && (report?.chartType === "table" || caller === "ReportBuilder");
17958
- if (getPivotRowCount) {
17959
- const pivotRowCountQuery = generateRowCountQuery(
17960
- sqlQuery,
17961
- client.databaseType
17962
- );
17963
- preQueries.push(pivotRowCountQuery);
17964
- }
17965
- if (paginatedComparisonQuery) {
17966
- preQueries.push(paginatedComparisonQuery);
17967
- }
17968
- const { data: resp } = await quillFetch({
17969
- client,
17970
- task: "query",
17971
- metadata: {
17972
- preQueries,
17973
- clientId: client.publicKey,
17974
- databaseType,
17975
- runQueryConfig: {
17976
- overridePost: true,
17977
- convertDatatypes: true
17978
- },
17979
- useNewNodeSql: true,
17980
- dashboardName,
17981
- tenants
17982
- },
17983
- urlParameters: `caller=generatePivot&task=query`,
17984
- credentials: "same-origin",
17985
- getToken
17986
- });
17987
- if (resp.success === false) {
17988
- throw resp.errorMessage;
17989
- }
17990
- const queryResponseRows = resp?.queryResults?.[0]?.rows || [];
17991
- const queryResponseFields = resp?.queryResults?.[0]?.fields || [];
17992
- const queryComparisonResponseRows = (getPivotRowCount ? resp?.queryResults?.[2]?.rows : resp?.queryResults?.[1]?.rows) || [];
17993
- const queryComparisonResponseFields = (getPivotRowCount ? resp?.queryResults?.[2]?.fields : resp?.queryResults?.[1]?.fields) || [];
17994
- parseValueFromBigQueryDates(queryResponseRows, queryResponseFields);
17995
- parseValueFromBigQueryDates(
17996
- queryComparisonResponseRows,
17997
- queryComparisonResponseFields
17998
- );
17999
- const responseRows = mergeComparisonPivotRows({
18000
- pivot,
18001
- rows: queryResponseRows,
18002
- compRows: queryComparisonResponseRows,
18003
- databaseType,
18004
- dateBucket,
18005
- comparisonInterval,
18006
- columnFieldValues: pivotColumnFields
18007
- });
18008
- const responseFields = mergeComparisonPivotColumns({
18009
- pivot,
18010
- rows: queryResponseFields,
18011
- compRows: queryComparisonResponseFields
18012
- });
18013
- const rows = pivot.rowField ? responseRows.map(
18014
- (row) => !row[pivot.rowField] ? { ...row, [pivot.rowField]: "-" } : row
18015
- ) : responseRows;
18016
- if (pivot.columnField && client.databaseType?.toLowerCase() === "bigquery") {
18017
- rows.forEach((row) => {
18018
- Object.keys(row).forEach((key) => {
18019
- const processedKey = processColumnName(key);
18020
- if (processedKey !== key) {
18021
- row[processedKey] = row[key];
18022
- delete row[key];
18023
- }
18024
- });
18025
- });
18026
- }
18027
- const columns = responseFields?.map((field) => ({
18028
- field: processColumnName(field.name),
18029
- label: snakeCaseToTitleCase(
18030
- processColumnName(field.name.replace("comparison_", "comparison "))
18031
- ),
18032
- format: field.name === pivot.rowField ? "string" : (
18033
- // This scary equation is calculating which aggregation a column is associated with.
18034
- // Eg you have 7 columns and 2 aggregations, you can assume column 0 is the row field, 1-3 is aggregation 0, and 4-6 is aggregation 1.
18035
- // pivot.aggregations?.[
18036
- // Math.floor(
18037
- // (index - 1) /
18038
- // Math.floor(
18039
- // (responseFields.length - 1) /
18040
- // (pivot.aggregations?.length ?? 1),
18041
- // ),
18042
- // )
18043
- // ]?.aggregationType === 'percentage'
18044
- pivot.aggregations?.find(
18045
- (agg) => agg.valueField === field.name || `${agg.valueField}_percentage` === field.name || !agg.valueField && agg.aggregationType === "percentage" && field.name.endsWith("percentage")
18046
- )?.aggregationType === "percentage" ? "percent" : "whole_number"
18047
- ),
18048
- fieldType: field.fieldType,
18049
- jsType: field.jsType,
18050
- dataTypeID: field.dataTypeID
18051
- })).filter(
18052
- (field, index) => field.field !== "comparison_" + pivot.rowField || index === 0
18053
- ).sort((a, b) => {
18054
- if (a.field === pivot.rowField) {
18055
- return -1;
18056
- }
18057
- if (b.field === pivot.rowField) {
18058
- return 1;
18059
- }
18060
- return 0;
18061
- });
18062
- if (pivot.rowField && !isStringType(pivot.rowFieldType || "")) {
18063
- rows.forEach((row) => {
18064
- row.__quillRawDate = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
18065
- let value = typeof row[pivot.rowField || ""] === "object" ? row[pivot.rowField || ""].value : row[pivot.rowField || ""];
18066
- if (dateBucket === "week" && dateFilter?.startDate && dateFilter?.endDate) {
18067
- const rowDate = new Date(value);
18068
- if (rowDate < dateFilter.startDate) {
18069
- value = dateFilter.startDate.toISOString();
18070
- } else if (rowDate > dateFilter.endDate) {
18071
- value = dateFilter.endDate.toISOString();
18072
- }
18073
- }
18074
- const dateString = getDateString(
18075
- value,
18076
- dateFilter?.startDate && dateFilter?.endDate ? { start: dateFilter.startDate, end: dateFilter.endDate } : void 0,
18077
- dateBucket,
18078
- databaseType
18079
- );
18080
- row[pivot.rowField || ""] = dateString;
18081
- });
18082
- if (pivot.rowField && pivot.rowFieldType && !isStringType(pivot.rowFieldType) && dateFilter?.startDate && dateFilter?.endDate) {
18083
- const dateSet = new Set(
18084
- rows.map((row) => row[pivot.rowField || ""])
18085
- );
18086
- for (let date = dateFilter.startDate; date <= dateFilter.endDate; date = new Date(date.getTime() + 24 * 60 * 60 * 1e3)) {
18087
- const formattedDate = getDateString(
18088
- date.toISOString(),
18089
- { start: dateFilter.startDate, end: dateFilter.endDate },
18090
- dateBucket,
18091
- databaseType
18092
- );
18093
- if (!dateSet.has(formattedDate)) {
18094
- const newRow = {};
18095
- newRow[pivot.rowField] = formattedDate;
18096
- newRow.__quillRawDate = date.toISOString();
18097
- rows.push(newRow);
18098
- dateSet.add(formattedDate);
18099
- }
18100
- }
18101
- }
18102
- if (!pivot.sort) {
18103
- rows.sort((a, b) => {
18104
- if (a.__quillRawDate < b.__quillRawDate) {
18105
- return -1;
18106
- }
18107
- if (a.__quillRawDate > b.__quillRawDate) {
18108
- return 1;
18109
- }
18110
- return 0;
18111
- });
18112
- }
18113
- }
18114
- columns?.forEach((column, index) => {
18115
- if (column.label && ["null", "undefined"].includes(column.label.toLowerCase()) && !pivot.columnField && !pivot.aggregations?.[index]?.valueField && pivot.aggregations?.[index]?.aggregationType === "count") {
18116
- column.label = "Count";
18117
- }
18118
- });
18119
- const numericColumns = columns?.filter(
18120
- (column) => column.format === "whole_number" || column.format === "percentage"
18121
- );
18122
- rows.forEach((row) => {
18123
- numericColumns?.forEach((column) => {
18124
- row[column.field] = row[column.field] ?? 0;
18125
- });
18126
- });
18127
- return {
18128
- rows,
18129
- columns: columns ?? [],
18130
- rowCount: getPivotRowCount ? Number(resp?.queryResults?.[1]?.rows?.[0]?.["row_count"]) ?? rows.length : 0,
18131
- pivotQuery: sqlQuery,
18132
- comparisonPivotQuery: comparisonPivotSql
18133
- };
18134
- }
18135
- function generatePivotTableYAxis(pivot, cols, yAxisField) {
18136
- if (pivot?.aggregationType === "count") {
18137
- return [
18138
- {
18139
- field: pivot.valueField ?? "count",
18140
- label: yAxisField.label,
18141
- format: yAxisField.format
18142
- }
18143
- ];
18144
- }
18145
- return [
18146
- {
18147
- field: pivot.valueField ?? "count",
18148
- label: yAxisField.label,
18149
- format: yAxisField.format
18150
- }
18151
- ];
18152
- }
18153
- function generatePivotTitle(pivot) {
18154
- if (pivot.rowField && !pivot.valueField && pivot.aggregations?.[0]) {
18155
- return snakeAndCamelCaseToTitleCase(
18156
- `${pivot.aggregations[0].aggregationType} of ${pivot.rowField}${pivot.columnField ? ` by ${pivot.columnField}` : ""}
18157
- `
18158
- );
18159
- } else if (!pivot.rowField && pivot.aggregations?.[0]?.valueField) {
18160
- return snakeAndCamelCaseToTitleCase(
18161
- `${pivot.aggregations[0].aggregationType} of ${pivot.aggregations[0].valueField}
18162
- `
18163
- );
18164
- }
18165
- return snakeAndCamelCaseToTitleCase(
18166
- `${pivot.aggregations?.[0]?.aggregationType ?? "Aggregation"} of ${pivot.aggregations?.[0]?.valueField ?? "value"}${pivot.rowField ? ` by ${pivot.rowField}` : ""}${pivot.columnField ? ` and ${pivot.columnField}` : ""}`
18167
- );
18168
- }
18169
- async function generatePivotTable({
18170
- pivot,
18171
- dateBucket,
18172
- dateFilter,
18173
- report,
18174
- client,
18175
- getToken,
18176
- eventTracking,
18177
- uniqueValues,
18178
- dashboardName,
18179
- tenants,
18180
- additionalProcessing,
18181
- caller,
18182
- pivotQuery
18183
- }) {
18184
- try {
18185
- if (report && client) {
18186
- const pivotTable = await generatePivotWithSQL({
18187
- pivotQuery,
18188
- pivot,
18189
- report,
18190
- client,
18191
- dateBucket,
18192
- dateFilter,
18193
- distinctStrings: pivot.columnField && uniqueValues?.[pivot.columnField] ? uniqueValues[pivot.columnField] : [],
18194
- dashboardName,
18195
- tenants,
18196
- additionalProcessing,
18197
- caller,
18198
- getToken
18199
- });
18200
- return pivotTable;
18201
- }
18202
- } catch (e) {
18203
- eventTracking?.logError?.({
18204
- type: "bug",
18205
- // TODO: determine type
18206
- severity: "high",
18207
- message: "Error generating pivot table",
18208
- errorMessage: e.message,
18209
- errorStack: e.stack,
18210
- errorData: {
18211
- caller: "PivotModal",
18212
- function: "generatePivotTable"
18213
- }
18214
- });
18215
- throw Error(`Failed to generate pivot table with SQL: ${e}`);
17457
+ return generateDistinctQueryDatabricks(stringFields, query);
17458
+ case "clickhouse":
17459
+ // works with default for now
17460
+ default:
17461
+ return generateDistinctQueryDefault(stringFields, query, databaseType);
18216
17462
  }
18217
- throw Error("Failed to generate pivot table: invalid report");
18218
17463
  }
18219
-
18220
- // src/utils/errorProcessing.ts
18221
- function processFilterErrorList(resp) {
18222
- if (!resp || !resp.filterErrorList || !Array.isArray(resp.filterErrorList)) {
18223
- return;
18224
- }
17464
+ function generateDistinctQueryDefault(stringFields, query, databaseType) {
17465
+ const distinctQueries = stringFields.map((field) => {
17466
+ return `SELECT '${field}' AS ${processColumnReference("field", databaseType)}, ARRAY_AGG(DISTINCT ${field}) AS ${processColumnReference("string_values", databaseType)} FROM querytable`;
17467
+ });
17468
+ const distinctQuery = distinctQueries.join(" UNION ALL ");
17469
+ return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
18225
17470
  }
18226
-
18227
- // src/utils/paginationProcessing.ts
18228
- var DEFAULT_PAGINATION = {
18229
- page: 0,
18230
- rowsPerPage: 10,
18231
- rowsPerRequest: 600
18232
- };
18233
- var DEFAULT_TABLE_PAGINATION = {
18234
- page: 0,
18235
- rowsPerPage: 10,
18236
- rowsPerRequest: 50
18237
- };
18238
- function shouldFetchMore(pagination, page, maxPage, currentRowCount) {
18239
- if (!pagination || currentRowCount && currentRowCount >= pagination.rowsPerPage * (page + 1)) {
18240
- return false;
18241
- }
18242
- const indexAdjustedPage = page;
18243
- const pageInterval = Math.floor(
18244
- indexAdjustedPage * pagination.rowsPerPage / pagination.rowsPerRequest
18245
- );
18246
- const indexAdjustedPreviousPage = maxPage;
18247
- const previousPageInterval = Math.floor(
18248
- indexAdjustedPreviousPage * pagination.rowsPerPage / pagination.rowsPerRequest
18249
- );
18250
- return pageInterval > previousPageInterval;
17471
+ function generateDistinctQueryMySQL(stringFields, query) {
17472
+ const distinctQueries = stringFields.map((field) => {
17473
+ return `
17474
+ SELECT '${field}' AS ${processColumnReference("field", "mysql")},
17475
+ JSON_ARRAYAGG(\`${field}\`) AS ${processColumnReference("string_values", "mysql")}
17476
+ FROM (SELECT DISTINCT \`${field}\` FROM querytable) AS distinct_${replaceSpacesWithUnderscores(field)}`;
17477
+ });
17478
+ const distinctQuery = distinctQueries.join(" UNION ALL ");
17479
+ return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
18251
17480
  }
18252
- function shouldSortInMemory(pagination, rowCount) {
18253
- if (!rowCount || rowCount < pagination.rowsPerRequest) {
18254
- return true;
18255
- }
18256
- return false;
17481
+ function generateDistinctQueryBigQuery(stringFields, query) {
17482
+ const distinctQueries = stringFields.map((field) => {
17483
+ return `
17484
+ SELECT '${field}' AS ${processColumnReference("field", "bigquery")},
17485
+ ARRAY_AGG(\`${field}\`) AS ${processColumnReference("string_values", "bigquery")}
17486
+ FROM (SELECT \`${field}\` FROM querytable WHERE \`${field}\` IS NOT NULL GROUP BY \`${field}\`) AS distinct_${replaceSpacesWithUnderscores(field)}`;
17487
+ });
17488
+ const distinctQuery = distinctQueries.join(" UNION ALL ");
17489
+ return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17490
+ }
17491
+ function generateDistinctQueryPostgres(stringFields, query) {
17492
+ const distinctQueries = stringFields.map((field) => {
17493
+ return `SELECT '${field}' AS ${processColumnReference("field", "postgresql")}, to_json(ARRAY_AGG(DISTINCT "${field}")) AS ${processColumnReference("string_values", "postgresql")} FROM querytable`;
17494
+ });
17495
+ const distinctQuery = distinctQueries.join(" UNION ALL ");
17496
+ return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17497
+ }
17498
+ function generateDistinctQuerySnowflake(stringFields, query) {
17499
+ const distinctQueries = stringFields.map((field) => {
17500
+ return `SELECT '${field}' AS "field", ARRAY_AGG(DISTINCT "${field}") AS "string_values" FROM querytable`;
17501
+ });
17502
+ const distinctQuery = distinctQueries.join(" UNION ALL ");
17503
+ return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17504
+ }
17505
+ function generateDistinctQueryMSSQL(stringFields, query) {
17506
+ const escapeFieldName = (field) => field.replace(/'/g, "''");
17507
+ const distinctQueries = stringFields.map((field) => {
17508
+ return `
17509
+ SELECT
17510
+ '${escapeFieldName(field)}' AS field,
17511
+ STRING_AGG(${field}, ',') AS string_values
17512
+ FROM (
17513
+ SELECT ${field}
17514
+ FROM querytable
17515
+ WHERE ${field} IS NOT NULL
17516
+ GROUP BY ${field}
17517
+ ) AS grouped
17518
+ `.replace(/\s+/g, " ").trim();
17519
+ });
17520
+ const distinctQuery = distinctQueries.join(" UNION ALL ");
17521
+ return `
17522
+ WITH querytable AS (
17523
+ ${query.replace(";", "")}
17524
+ )
17525
+ ${distinctQuery}`.replace(/\s+/g, " ").trim();
17526
+ }
17527
+ function generateDistinctQueryDatabricks(stringFields, query) {
17528
+ const distinctQueries = stringFields.map((field) => {
17529
+ return `SELECT '${field}' AS ${processColumnReference("field", "databricks")}, collect_set(\`${field}\`) AS ${processColumnReference("string_values", "databricks")} FROM querytable`;
17530
+ });
17531
+ const distinctQuery = distinctQueries.join(" UNION ALL ");
17532
+ return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
17533
+ }
17534
+ function generateMinMaxDateRangeQueries(columnFields, query, databaseType) {
17535
+ const max2 = "MAX";
17536
+ const min2 = "MIN";
17537
+ const cast = databaseType.toLowerCase() === "snowflake" ? "::TIMESTAMP_TZ" : "";
17538
+ const distinctQueries = columnFields.map((field) => {
17539
+ const wrappedField = ["postgresql", "clickhouse"].includes(
17540
+ databaseType.toLowerCase()
17541
+ ) ? processColumnReference(field, databaseType) : field;
17542
+ return `SELECT '${field}' AS ${processColumnReference("field", databaseType)}, ${min2}(${wrappedField})${cast} AS ${processColumnReference("min_range", databaseType)}, ${max2}(${wrappedField})${cast} AS ${processColumnReference("max_range", databaseType)} FROM querytable`;
17543
+ });
17544
+ const distinctQuery = distinctQueries.join(" UNION ALL ");
17545
+ return `WITH querytable AS (${query.replace(";", "")}) ` + distinctQuery;
18257
17546
  }
18258
17547
 
18259
17548
  // src/utils/tableProcessing.ts
@@ -18894,595 +18183,110 @@ var fetchResultsByReport = async ({
18894
18183
  if (e instanceof Error && e.name === "AbortError") {
18895
18184
  throw e;
18896
18185
  }
18897
- eventTracking?.logError?.({
18898
- type: "bug",
18899
- // TODO: determine type
18900
- severity: "high",
18901
- message: "Error fetching results by report",
18902
- errorMessage: e.message,
18903
- errorStack: e.stack,
18904
- errorData: {
18905
- caller: "fetchResultsByReport",
18906
- function: "fetchResultsByReport"
18907
- }
18908
- });
18909
- rows = [];
18910
- columns = [];
18911
- rowCount = 0;
18912
- error = e.message;
18913
- }
18914
- if (client.databaseType && client.databaseType.toLowerCase() === "bigquery") {
18915
- parseValueFromBigQueryDates(rows, columns);
18916
- }
18917
- return { rows, columns, rowCount, error };
18918
- };
18919
- var fetchTableByAST = async (ast, client, getToken, tenants, eventTracking, dashboardName, processing, customFields, rowsOnly, rowCountOnly) => {
18920
- let rows = [];
18921
- let columns = [];
18922
- let rowCount;
18923
- let error;
18924
- let itemQuery;
18925
- let referencedTables;
18926
- try {
18927
- const fetchResp = await quillFetch({
18928
- client,
18929
- task: "patterns",
18930
- metadata: {
18931
- clientId: client.publicKey,
18932
- ast,
18933
- customFields,
18934
- additionalProcessing: processing,
18935
- useUpdatedDataGathering: true,
18936
- useNewNodeSql: true,
18937
- rowsOnly,
18938
- rowCountOnly,
18939
- dashboardName,
18940
- tenants
18941
- },
18942
- getToken
18943
- });
18944
- const resp = await parseFetchResponse(
18945
- client,
18946
- "patterns",
18947
- fetchResp,
18948
- getToken
18949
- );
18950
- if (resp.errorMessage || resp.name === "error") {
18951
- throw new Error(resp.errorMessage);
18952
- }
18953
- processFilterErrorList(resp);
18954
- if (resp.rowCount !== void 0) {
18955
- rowCount = resp.rowCount;
18956
- }
18957
- const gatheredRows = resp.rows && resp.rows.length ? resp.rows : [];
18958
- columns = resp.fields.map((elem) => convertPostgresColumn(elem));
18959
- rows = gatheredRows;
18960
- itemQuery = resp.itemQuery;
18961
- referencedTables = resp.referencedTables;
18962
- if (customFields) {
18963
- const tables = referencedTables ?? [];
18964
- tables.forEach((table) => {
18965
- const _customFields = customFields?.[table] ?? [];
18966
- columns.forEach((col) => {
18967
- if (_customFields.some((field) => {
18968
- return field.field === col.field;
18969
- })) {
18970
- col.inferFormat = true;
18971
- }
18972
- });
18973
- });
18974
- }
18975
- } catch (e) {
18976
- eventTracking?.logError?.({
18977
- type: "bug",
18978
- // TODO: determine type
18979
- severity: "high",
18980
- message: "Error fetching table by AST",
18981
- errorMessage: e.message,
18982
- errorStack: e.stack,
18983
- errorData: {
18984
- caller: "fetchTableByAST",
18985
- function: "fetchTableByAST"
18986
- }
18987
- });
18988
- rows = [];
18989
- columns = [];
18990
- rowCount = 0;
18991
- error = e.message;
18992
- }
18993
- if (client.databaseType && client.databaseType.toLowerCase() === "bigquery") {
18994
- parseValueFromBigQueryDates(rows, columns);
18995
- }
18996
- return { rows, columns, rowCount, error, itemQuery, referencedTables };
18997
- };
18998
-
18999
- // src/utils/dashboard.ts
19000
- var defaultDashboardItem = {
19001
- id: "",
19002
- name: "",
19003
- dashboardName: "",
19004
- rows: [],
19005
- compareRows: [],
19006
- columns: [],
19007
- chartType: "",
19008
- pivot: null,
19009
- yAxisFields: [],
19010
- xAxisLabel: "",
19011
- xAxisField: "",
19012
- xAxisFormat: "string",
19013
- order: -1,
19014
- filtersApplied: [],
19015
- queryString: "",
19016
- rowCount: 0,
19017
- columnInternal: []
19018
- };
19019
- async function cleanDashboardItem({
19020
- item,
19021
- dashboardFilters,
19022
- getToken,
19023
- eventTracking,
19024
- client,
19025
- dateBucket,
19026
- additionalProcessing,
19027
- customFields,
19028
- skipPivotFetch,
19029
- tenants
19030
- }) {
19031
- if (!item) return defaultDashboardItem;
19032
- if (!item.rows) {
19033
- return {
19034
- ...defaultDashboardItem,
19035
- id: item._id,
19036
- name: item.name
19037
- };
19038
- }
19039
- const fields = item.fields || [];
19040
- const columnsWithCustomFields = [...item.columns ?? []];
19041
- if (item.includeCustomFields && item.rows?.length > 0) {
19042
- const tables = item.referencedTables ?? [];
19043
- tables.forEach((table) => {
19044
- const _customFields = customFields?.[table] ?? [];
19045
- _customFields.forEach((field) => {
19046
- const isJsonCustomField = !!field.refColumn;
19047
- if (item.rows[0][field.field] !== void 0 && !item.columns.some((col) => col.field === field.field)) {
19048
- const result_field = fields.find((f) => f.name === field.field);
19049
- const converted_field = convertPostgresColumn(result_field ?? {});
19050
- columnsWithCustomFields.push({
19051
- field: field.field,
19052
- format: converted_field.format,
19053
- label: snakeAndCamelCaseToTitleCase(field.field),
19054
- fieldType: converted_field.fieldType,
19055
- dataTypeID: converted_field.dataTypeID,
19056
- jsType: converted_field.jsType,
19057
- inferFormat: isJsonCustomField
19058
- });
19059
- }
19060
- });
19061
- });
19062
- }
19063
- const processedColumns = item.columns.map((col) => {
19064
- return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
19065
- });
19066
- const columnInternal = (item.includeCustomFields ? columnsWithCustomFields : item.columns).map((col) => {
19067
- const field = item.fields?.find((f) => f.name === col.field);
19068
- const converted_field = convertPostgresColumn(field ?? {});
19069
- return {
19070
- fieldType: converted_field.fieldType,
19071
- dataTypeID: converted_field.dataTypeID,
19072
- jsType: converted_field.jsType,
19073
- ...col,
19074
- label: snakeAndCamelCaseToTitleCase(col.label)
19075
- };
19076
- });
19077
- let pivotTable;
19078
- let pivotError;
19079
- try {
19080
- const shouldPaginatePivotAsTable = item.chartType === "table";
19081
- const pivotChartProcessing = {
19082
- page: DEFAULT_PAGINATION
19083
- };
19084
- pivotTable = await getPivotTable(
19085
- {
19086
- ...item,
19087
- pivot: item.pivot && !skipPivotFetch ? {
19088
- ...item.pivot,
19089
- aggregations: item.pivot.aggregations ?? [
19090
- {
19091
- valueField: item.pivot.valueField,
19092
- valueFieldType: item.pivot.valueFieldType,
19093
- valueField2: item.pivot.valueField2,
19094
- valueField2Type: item.pivot.valueField2Type,
19095
- aggregationType: item.pivot.aggregationType
19096
- }
19097
- ]
19098
- } : void 0
19099
- },
19100
- dashboardFilters,
19101
- item.dashboardName,
19102
- getToken,
19103
- client,
19104
- eventTracking,
19105
- dateBucket,
19106
- shouldPaginatePivotAsTable ? additionalProcessing : pivotChartProcessing,
19107
- tenants,
19108
- customFields
19109
- );
19110
- } catch (e) {
19111
- pivotTable = void 0;
19112
- eventTracking?.logError?.({
19113
- type: "bug",
19114
- // TODO: determine type
19115
- severity: "high",
19116
- message: "Error fetching pivot table",
19117
- errorMessage: e.message,
19118
- errorStack: e.stack,
19119
- errorData: {
19120
- caller: "cleanDashboardItem",
19121
- function: "cleanDashboardItem"
19122
- }
19123
- });
19124
- console.error("Error fetching pivot table", e);
19125
- pivotError = "Error fetching pivot table";
19126
- }
19127
- const referenceLineYValues = [];
19128
- for (const key in item) {
19129
- if (key.startsWith("referenceLine_")) {
19130
- const field = key.slice(14);
19131
- if (!item[key] || !item[key][0]) continue;
19132
- const value = Object.values(item[key][0])[0];
19133
- referenceLineYValues.push({ label: field, query: [value, value] });
19134
- }
19135
- }
19136
- if (item.referenceLines) {
19137
- for (const referenceLine of item.referenceLines) {
19138
- if (Array.isArray(referenceLine.query)) {
19139
- referenceLineYValues.push({
19140
- label: referenceLine.label,
19141
- query: referenceLine.query
19142
- });
19143
- } else if (referenceLine.query === "") {
19144
- referenceLineYValues.push({
19145
- label: referenceLine.label,
19146
- query: (pivotTable?.rows ? pivotTable.rows : item.rows).map(
19147
- (row) => Number(row[referenceLine.label]) || 0
19148
- )
19149
- });
19150
- }
19151
- }
19152
- }
19153
- return {
19154
- id: item._id ?? item.id,
19155
- name: item.name,
19156
- dashboardName: item.dashboardName,
19157
- // section: item.section,
19158
- rows: item.rows,
19159
- pivotRows: pivotTable ? pivotTable.rows : void 0,
19160
- pivotColumns: pivotTable ? pivotTable.columns : void 0,
19161
- compareRows: item.compareRows,
19162
- columns: processedColumns.map((column) => {
19163
- return {
19164
- field: column.field,
19165
- format: column.format,
19166
- label: column.label,
19167
- inferFormat: column.inferFormat
19168
- };
19169
- }),
19170
- includeCustomFields: item.includeCustomFields,
19171
- columnInternal,
19172
- columnsWithCustomFields,
19173
- chartType: item.chartType,
19174
- dateField: item.dateField,
19175
- pivot: pivotError ? void 0 : item.pivot ? {
19176
- ...item.pivot,
19177
- aggregations: item.pivot.aggregations ?? [
19178
- {
19179
- valueField: item.pivot.valueField,
19180
- valueFieldType: item.pivot.valueFieldType,
19181
- valueField2: item.pivot.valueField2,
19182
- valueField2Type: item.pivot.valueField2Type,
19183
- aggregationType: item.pivot.aggregationType
19184
- }
19185
- ],
19186
- columnValues: item.distinctStrings
19187
- } : void 0,
19188
- yAxisFields: pivotTable ? extractPivotedYAxis(pivotTable, item) : item.yAxisFields,
19189
- xAxisLabel: item.xAxisLabel,
19190
- xAxisField: item.xAxisField,
19191
- xAxisFormat: item.xAxisFormat,
19192
- order: item.order,
19193
- filtersApplied: item.filtersApplied,
19194
- filterMap: item.filterMap,
19195
- flags: item.flags,
19196
- rowCount: item.rowCount ? parseInt(item.rowCount) : item.rows.length,
19197
- pivotRowCount: pivotTable ? pivotTable.rowCount : void 0,
19198
- template: item.template,
19199
- sort: item.sort,
19200
- itemQuery: item.itemQuery,
19201
- queryString: item.queryString,
19202
- pivotQuery: pivotTable?.pivotQuery,
19203
- comparisonPivotQuery: pivotTable?.comparisonPivotQuery,
19204
- referencedTables: item?.referencedTables || [],
19205
- referencedColumns: item?.referencedColumns || {},
19206
- error: item.error ?? pivotError,
19207
- referenceLineYValues,
19208
- referenceLines: item.referenceLines
19209
- };
19210
- }
19211
- async function getPivotTable(report, dashboardFilters, dashboardName, getToken, client, eventTracking, dateBucketInitial, additionalProcessing, tenants, customFields) {
19212
- if (!report) return void 0;
19213
- const dateFilter = Object.values(dashboardFilters ?? {}).find(
19214
- (filter) => filter.filterType === "date_range" || filter.operator === "BETWEEN"
19215
- );
19216
- if (dateFilter?.operator === "BETWEEN") {
19217
- dateFilter.startDate = dateFilter.value[0];
19218
- dateFilter.endDate = dateFilter.value[1];
19219
- }
19220
- const pivot = report?.pivot;
19221
- const data = report || {};
19222
- if (pivot && client) {
19223
- if (report.rowCount === 0 || report.rows.length === 0) {
19224
- const columns = [];
19225
- if (pivot.rowField) {
19226
- columns.push({
19227
- field: pivot.rowField,
19228
- label: snakeCaseToTitleCase(processColumnName(pivot.rowField)),
19229
- format: pivot.rowFieldType || "string",
19230
- jsType: convertFieldTypeToJSType(pivot.rowFieldType || "string"),
19231
- fieldType: pivot.rowFieldType || "string",
19232
- dataTypeID: fieldTypeToDataTypeID(pivot.rowFieldType || "string")
19233
- });
19234
- }
19235
- for (const agg of pivot.aggregations ?? []) {
19236
- if (agg.valueField) {
19237
- columns.push({
19238
- field: agg.valueField,
19239
- label: snakeCaseToTitleCase(processColumnName(agg.valueField)),
19240
- //FIXME: valueFieldType is not always the same as the format
19241
- format: agg.valueFieldType ?? "whole_number",
19242
- jsType: agg.valueFieldType ?? "number",
19243
- fieldType: agg.valueFieldType ?? "number",
19244
- dataTypeID: fieldTypeToDataTypeID(agg.valueFieldType ?? "number")
19245
- });
19246
- }
19247
- }
19248
- const pivotQuery = generatePivotQuery(
19249
- pivot,
19250
- report.itemQuery?.[0],
19251
- client.databaseType
19252
- );
19253
- return {
19254
- rows: [],
19255
- rowCount: 0,
19256
- pivotQuery: pivotQuery ?? "",
19257
- columns
19258
- };
19259
- }
19260
- try {
19261
- let dateBucket = dateBucketInitial;
19262
- let filterDateRange = void 0;
19263
- if (dateFilter && dateFilter.startDate && dateFilter.endDate) {
19264
- filterDateRange = {
19265
- start: dateFilter.startDate,
19266
- end: dateFilter.endDate
19267
- };
19268
- } else if (report.dateRange) {
19269
- filterDateRange = report.dateRange;
19270
- }
19271
- if (!dateBucket && filterDateRange) {
19272
- dateBucket = getDateBucketFromRange(filterDateRange);
19273
- }
19274
- if (pivot.columnField && !report.distinctStrings) {
19275
- const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
19276
- if (!columnFieldColumn) {
19277
- console.error(
19278
- "could not find pivot column field on report",
19279
- pivot.columnField
19280
- );
19281
- }
19282
- const unique = await getUniqueValuesByQuery({
19283
- columns: [columnFieldColumn],
19284
- query: report.queryString,
19285
- client,
19286
- getToken,
19287
- dashboardName,
19288
- tenants,
19289
- customFields: customFields ?? {},
19290
- eventTracking
19291
- });
19292
- report.distinctStrings = unique?.[pivot.columnField] ?? [];
19293
- }
19294
- if (pivot.columnField && !report.distinctStrings) {
19295
- const columnFieldColumn = (report.columnsWithCustomFields ?? report.columns).find((col) => col.field === pivot.columnField);
19296
- if (!columnFieldColumn) {
19297
- console.error(
19298
- "could not find pivot column field on report",
19299
- pivot.columnField
19300
- );
19301
- }
19302
- const unique = await getUniqueValuesByQuery({
19303
- columns: [columnFieldColumn],
19304
- query: report.queryString,
19305
- client,
19306
- getToken,
19307
- dashboardName,
19308
- tenants,
19309
- customFields: customFields ?? {},
19310
- eventTracking
19311
- });
19312
- report.distinctStrings = unique?.[pivot.columnField] ?? [];
18186
+ eventTracking?.logError?.({
18187
+ type: "bug",
18188
+ // TODO: determine type
18189
+ severity: "high",
18190
+ message: "Error fetching results by report",
18191
+ errorMessage: e.message,
18192
+ errorStack: e.stack,
18193
+ errorData: {
18194
+ caller: "fetchResultsByReport",
18195
+ function: "fetchResultsByReport"
19313
18196
  }
19314
- const pivotTable = await generatePivotWithSQL({
19315
- pivot,
19316
- report,
19317
- client,
19318
- dateBucket,
19319
- dateFilter,
19320
- distinctStrings: report.distinctStrings,
18197
+ });
18198
+ rows = [];
18199
+ columns = [];
18200
+ rowCount = 0;
18201
+ error = e.message;
18202
+ }
18203
+ if (client.databaseType && client.databaseType.toLowerCase() === "bigquery") {
18204
+ parseValueFromBigQueryDates(rows, columns);
18205
+ }
18206
+ return { rows, columns, rowCount, error };
18207
+ };
18208
+ var fetchTableByAST = async (ast, client, getToken, tenants, eventTracking, dashboardName, processing, customFields, rowsOnly, rowCountOnly) => {
18209
+ let rows = [];
18210
+ let columns = [];
18211
+ let rowCount;
18212
+ let error;
18213
+ let itemQuery;
18214
+ let referencedTables;
18215
+ try {
18216
+ const fetchResp = await quillFetch({
18217
+ client,
18218
+ task: "patterns",
18219
+ metadata: {
18220
+ clientId: client.publicKey,
18221
+ ast,
18222
+ customFields,
18223
+ additionalProcessing: processing,
18224
+ useUpdatedDataGathering: true,
18225
+ useNewNodeSql: true,
18226
+ rowsOnly,
18227
+ rowCountOnly,
19321
18228
  dashboardName,
19322
- tenants,
19323
- additionalProcessing,
19324
- getToken
19325
- });
19326
- return pivotTable;
19327
- } catch (e) {
19328
- eventTracking?.logError?.({
19329
- type: "bug",
19330
- // TODO: determine type
19331
- severity: "high",
19332
- message: "Error fetching pivot table",
19333
- errorMessage: e.message,
19334
- errorStack: e.stack,
19335
- errorData: {
19336
- caller: "getPivotTable",
19337
- function: "getPivotTable"
19338
- }
18229
+ tenants
18230
+ },
18231
+ getToken
18232
+ });
18233
+ const resp = await parseFetchResponse(
18234
+ client,
18235
+ "patterns",
18236
+ fetchResp,
18237
+ getToken
18238
+ );
18239
+ if (resp.errorMessage || resp.name === "error") {
18240
+ throw new Error(resp.errorMessage);
18241
+ }
18242
+ processFilterErrorList(resp);
18243
+ if (resp.rowCount !== void 0) {
18244
+ rowCount = resp.rowCount;
18245
+ }
18246
+ const gatheredRows = resp.rows && resp.rows.length ? resp.rows : [];
18247
+ columns = resp.fields.map((elem) => convertPostgresColumn(elem));
18248
+ rows = gatheredRows;
18249
+ itemQuery = resp.itemQuery;
18250
+ referencedTables = resp.referencedTables;
18251
+ if (customFields) {
18252
+ const tables = referencedTables ?? [];
18253
+ tables.forEach((table) => {
18254
+ const _customFields = customFields?.[table] ?? [];
18255
+ columns.forEach((col) => {
18256
+ if (_customFields.some((field) => {
18257
+ return field.field === col.field;
18258
+ })) {
18259
+ col.inferFormat = true;
18260
+ }
18261
+ });
19339
18262
  });
19340
- console.error("Error fetching pivot table", e);
19341
- throw e;
19342
18263
  }
19343
- }
19344
- return pivot && data.rows ? generatePivotTable({
19345
- pivot,
19346
- report,
19347
- client,
19348
- uniqueValues: report.distinctStrings,
19349
- dashboardName,
19350
- tenants,
19351
- dateFilter,
19352
- additionalProcessing,
19353
- getToken,
19354
- eventTracking
19355
- }) : void 0;
19356
- }
19357
- function extractPivotedYAxis(pivotTable, itemInfo, config = void 0) {
19358
- if (!pivotTable) return itemInfo?.yAxisFields ?? [];
19359
- const pivot = itemInfo?.pivot || config?.pivot;
19360
- if (!pivot.columnField && !pivot.rowField) return itemInfo?.yAxisFields ?? [];
19361
- const yAxisFields = config ? config.yAxisFields : itemInfo?.yAxisFields;
19362
- return yAxisFields && yAxisFields.length > 0 ? generatePivotTableYAxis(pivot, pivotTable.columns, yAxisFields[0]) : yAxisFields;
19363
- }
19364
- async function getDashboard(dashboardName, client, getToken, tenants, flags) {
19365
- const { data: resp } = await quillFetch({
19366
- client,
19367
- task: "dashboard",
19368
- metadata: {
19369
- name: dashboardName,
19370
- clientId: client.publicKey,
19371
- databaseType: client.databaseType,
19372
- useNewNodeSql: true,
19373
- tenants,
19374
- flags
19375
- },
19376
- getToken
19377
- });
19378
- return {
19379
- ...resp,
19380
- createdAt: resp.createdAt && new Date(resp.createdAt),
19381
- dateFilter: resp.dateFilter ? {
19382
- ...resp.dateFilter,
19383
- presetOptions: resp.dateFilter.presetOptions?.map(
19384
- (preset) => ({
19385
- ...preset,
19386
- loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
19387
- loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
19388
- })
19389
- ),
19390
- defaultPresetRanges: resp.dateFilter.defaultPresetRanges?.map(
19391
- (preset) => ({
19392
- ...preset,
19393
- loopStart: preset.loopStart ? new Date(preset.loopStart) : void 0,
19394
- loopEnd: preset.loopEnd ? new Date(preset.loopEnd) : void 0
19395
- })
19396
- )
19397
- } : void 0
19398
- };
19399
- }
19400
-
19401
- // src/utils/chartBuilder.ts
19402
- var numberFormatOptions = [
19403
- "whole_number",
19404
- "one_decimal_place",
19405
- "two_decimal_places",
19406
- "dollar_amount",
19407
- "dollar_cents",
19408
- "percentage"
19409
- ];
19410
- var dateFormatOptions = [
19411
- "MMM_yyyy",
19412
- "MMM_dd",
19413
- "MMM_dd_yyyy",
19414
- "MMM_dd_hh:mm_ap_pm",
19415
- "hh_ap_pm",
19416
- "date",
19417
- "timestamptz"
19418
- ];
19419
- var NUMBER_OPTIONS = [
19420
- { value: "whole_number", label: "whole number" },
19421
- { value: "one_decimal_place", label: "one decimal place" },
19422
- { value: "two_decimal_places", label: "two decimal places" },
19423
- { value: "dollar_amount", label: "dollar amount" },
19424
- { value: "dollar_cents", label: "dollar and cent amount" },
19425
- { value: "percent", label: "percentage" }
19426
- ];
19427
- var DATE_OPTIONS = [
19428
- { value: "MMM_yyyy", label: "month" },
19429
- { value: "MMM_dd", label: "day" },
19430
- { value: "MMM_dd_yyyy", label: "day and year" },
19431
- { value: "MMM_dd_hh:mm_ap_pm", label: "day and time" },
19432
- { value: "hh_ap_pm", label: "hour" }
19433
- ];
19434
- var ALL_FORMAT_OPTIONS = [
19435
- ...NUMBER_OPTIONS,
19436
- ...DATE_OPTIONS,
19437
- { value: "string", label: "string" }
19438
- ];
19439
- function createInitialFormData(columns) {
19440
- const firstNumberColumn = columns?.find(
19441
- (col) => numberFormatOptions.includes(col.format)
19442
- );
19443
- const firstStringColumn = columns?.find(
19444
- (col) => !numberFormatOptions.includes(col.format) && !dateFormatOptions.includes(col.format)
19445
- );
19446
- const firstDateColumn = columns?.find(
19447
- (col) => dateFormatOptions.includes(col.format)
19448
- );
19449
- const xAxisField = firstStringColumn?.field || firstDateColumn?.field || firstNumberColumn?.field || columns?.[0]?.field || "";
19450
- const xAxisFormat = firstStringColumn?.format || firstDateColumn?.format || firstNumberColumn?.format || columns?.[0]?.format || "string";
19451
- const formEmptyState = {
19452
- name: "",
19453
- columns: columns.map((col) => {
19454
- return { ...col, label: snakeAndCamelCaseToTitleCase(col.label) };
19455
- }),
19456
- xAxisField,
19457
- xAxisFormat,
19458
- yAxisFields: [
19459
- {
19460
- field: firstNumberColumn?.field || columns?.[0]?.field || "",
19461
- label: "",
19462
- format: firstNumberColumn?.format || columns?.[0]?.format || "string"
18264
+ } catch (e) {
18265
+ eventTracking?.logError?.({
18266
+ type: "bug",
18267
+ // TODO: determine type
18268
+ severity: "high",
18269
+ message: "Error fetching table by AST",
18270
+ errorMessage: e.message,
18271
+ errorStack: e.stack,
18272
+ errorData: {
18273
+ caller: "fetchTableByAST",
18274
+ function: "fetchTableByAST"
19463
18275
  }
19464
- ],
19465
- xAxisLabel: "",
19466
- chartType: firstNumberColumn ? "line" : "table",
19467
- pivot: null,
19468
- template: true,
19469
- referenceLines: []
19470
- };
19471
- return formEmptyState;
19472
- }
19473
-
19474
- // src/utils/error.ts
19475
- var DataLoadError = class extends Error {
19476
- data;
19477
- constructor(message, data) {
19478
- super(message);
19479
- this.name = "DataLoadError";
19480
- this.data = data;
18276
+ });
18277
+ rows = [];
18278
+ columns = [];
18279
+ rowCount = 0;
18280
+ error = e.message;
19481
18281
  }
18282
+ if (client.databaseType && client.databaseType.toLowerCase() === "bigquery") {
18283
+ parseValueFromBigQueryDates(rows, columns);
18284
+ }
18285
+ return { rows, columns, rowCount, error, itemQuery, referencedTables };
19482
18286
  };
19483
18287
 
19484
18288
  // src/components/ReportBuilder/convert.ts
19485
- var import_date_fns8 = require("date-fns");
18289
+ var import_date_fns7 = require("date-fns");
19486
18290
  function recursiveSearchAndReplace(node, search, replace) {
19487
18291
  if (typeof node !== "object") {
19488
18292
  return;
@@ -19791,7 +18595,7 @@ function convertStringComparison(node, databaseType) {
19791
18595
  searchAndReplace(element);
19792
18596
  });
19793
18597
  } else if (typeof obj === "object" && obj !== null) {
19794
- if (obj.type === "binary_expr" && (obj.operator === "=" && !(0, import_date_fns8.isValid)((0, import_date_fns8.parseISO)(obj.right.value)) || // don't do it on date objects
18598
+ if (obj.type === "binary_expr" && (obj.operator === "=" && !(0, import_date_fns7.isValid)((0, import_date_fns7.parseISO)(obj.right.value)) || // don't do it on date objects
19795
18599
  obj.operator === "LIKE" || obj.operator === "ILIKE") && obj.left && (obj.left.type === "column_ref" || obj.left.type === "double_quote_string") && obj.right && obj.right.type === "single_quote_string") {
19796
18600
  obj.operator = "LIKE";
19797
18601
  obj.left = {
@@ -23132,6 +21936,29 @@ var import_jspdf = __toESM(require("jspdf"), 1);
23132
21936
 
23133
21937
  // src/hooks/useDashboard.ts
23134
21938
  var import_react2 = require("react");
21939
+
21940
+ // src/utils/merge.ts
21941
+ var import_date_fns8 = require("date-fns");
21942
+ var import_date_fns_tz2 = require("date-fns-tz");
21943
+ function mergeComparisonRange(resp) {
21944
+ if (resp.chartType === "table") return resp;
21945
+ const compRows = resp.compareRows;
21946
+ if (!compRows) return resp;
21947
+ const newRows = resp.rows.map((row, i) => {
21948
+ if (i < compRows.length) {
21949
+ const compRow = compRows[i];
21950
+ const newRow = { ...row };
21951
+ for (const [key, value] of Object.entries(compRow)) {
21952
+ newRow[`comparison_${key}`] = value;
21953
+ }
21954
+ return newRow;
21955
+ }
21956
+ return row;
21957
+ });
21958
+ return { ...resp, rows: newRows };
21959
+ }
21960
+
21961
+ // src/hooks/useDashboard.ts
23135
21962
  var useDashboardInternal = (dashboardName, customFilters) => {
23136
21963
  const [dashboard] = (0, import_react2.useContext)(DashboardContext);
23137
21964
  const {
@@ -38940,6 +37767,9 @@ var import_react46 = __toESM(require("@monaco-editor/react"), 1);
38940
37767
 
38941
37768
  // src/ChartBuilder.tsx
38942
37769
  var import_react43 = require("react");
37770
+ var import_core = require("@dnd-kit/core");
37771
+ var import_sortable = require("@dnd-kit/sortable");
37772
+ var import_utilities = require("@dnd-kit/utilities");
38943
37773
 
38944
37774
  // src/internals/ReportBuilder/PivotModal.tsx
38945
37775
  var import_react40 = require("react");
@@ -42182,6 +41012,173 @@ var CHART_TO_LABELS = {
42182
41012
  "World map": { xAxisLabel: "Country", yAxisLabel: "Value" },
42183
41013
  gauge: { xAxisLabel: "Value" }
42184
41014
  };
41015
+ function SortableColumnItem({
41016
+ column,
41017
+ index,
41018
+ rows,
41019
+ columns,
41020
+ handleChange,
41021
+ deleteRef,
41022
+ deleteButtonMargin,
41023
+ handleRemoveField,
41024
+ SelectComponent,
41025
+ TextInputComponent,
41026
+ DeleteButtonComponent
41027
+ }) {
41028
+ const { attributes, listeners, setNodeRef, transform, transition: transition2 } = (0, import_sortable.useSortable)({ id: column.field });
41029
+ const style2 = {
41030
+ transform: import_utilities.CSS.Transform.toString(transform),
41031
+ transition: transition2
41032
+ };
41033
+ return /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { style: style2, ref: setNodeRef, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
41034
+ "div",
41035
+ {
41036
+ style: {
41037
+ display: "flex",
41038
+ alignItems: "center",
41039
+ gap: 4
41040
+ },
41041
+ children: [
41042
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
41043
+ "div",
41044
+ {
41045
+ style: {
41046
+ cursor: "grab",
41047
+ display: "flex",
41048
+ gap: 2,
41049
+ flexDirection: "row",
41050
+ paddingTop: 8,
41051
+ paddingBottom: 8,
41052
+ paddingLeft: 8,
41053
+ paddingRight: 8,
41054
+ borderRadius: 4
41055
+ },
41056
+ className: "handle",
41057
+ ...attributes,
41058
+ ...listeners,
41059
+ children: [
41060
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("style", { children: `.handle{background:white;} .handle:hover{background:rgba(0,0,0,0.03);}` }),
41061
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { style: { display: "flex", gap: 2, flexDirection: "column" }, children: [
41062
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41063
+ "div",
41064
+ {
41065
+ style: {
41066
+ width: 3,
41067
+ height: 3,
41068
+ borderRadius: 3,
41069
+ background: "#9CA0A7"
41070
+ }
41071
+ }
41072
+ ),
41073
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41074
+ "div",
41075
+ {
41076
+ style: {
41077
+ width: 3,
41078
+ height: 3,
41079
+ borderRadius: 3,
41080
+ background: "#9CA0A7"
41081
+ }
41082
+ }
41083
+ ),
41084
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41085
+ "div",
41086
+ {
41087
+ style: {
41088
+ width: 3,
41089
+ height: 3,
41090
+ borderRadius: 3,
41091
+ background: "#9CA0A7"
41092
+ }
41093
+ }
41094
+ )
41095
+ ] }),
41096
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { style: { display: "flex", gap: 2, flexDirection: "column" }, children: [
41097
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41098
+ "div",
41099
+ {
41100
+ style: {
41101
+ width: 3,
41102
+ height: 3,
41103
+ borderRadius: 3,
41104
+ background: "#9CA0A7"
41105
+ }
41106
+ }
41107
+ ),
41108
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41109
+ "div",
41110
+ {
41111
+ style: {
41112
+ width: 3,
41113
+ height: 3,
41114
+ borderRadius: 3,
41115
+ background: "#9CA0A7"
41116
+ }
41117
+ }
41118
+ ),
41119
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41120
+ "div",
41121
+ {
41122
+ style: {
41123
+ width: 3,
41124
+ height: 3,
41125
+ borderRadius: 3,
41126
+ background: "#9CA0A7"
41127
+ }
41128
+ }
41129
+ )
41130
+ ] })
41131
+ ]
41132
+ }
41133
+ ),
41134
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)("div", { style: { flex: 1, display: "flex", gap: 12 }, children: [
41135
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41136
+ SelectComponent,
41137
+ {
41138
+ value: column.field,
41139
+ onChange: (e) => handleChange(e.target.value, "columns.field", index),
41140
+ options: rows[0] ? Object.keys(rows[0]).map((elem) => ({
41141
+ label: elem,
41142
+ value: elem
41143
+ })) : columns.map((elem) => ({
41144
+ label: elem.field,
41145
+ value: elem.field
41146
+ })),
41147
+ width: 200,
41148
+ hideEmptyOption: true
41149
+ }
41150
+ ),
41151
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41152
+ TextInputComponent,
41153
+ {
41154
+ id: `chart-builder-column-label-${index}`,
41155
+ width: 200,
41156
+ value: column.label,
41157
+ placeholder: "Column Label",
41158
+ onChange: (e) => handleChange(e.target.value, "columns.label", index)
41159
+ }
41160
+ ),
41161
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41162
+ SelectComponent,
41163
+ {
41164
+ value: column.format,
41165
+ onChange: (e) => handleChange(e.target.value, "columns.format", index),
41166
+ options: ALL_FORMAT_OPTIONS,
41167
+ width: 200,
41168
+ hideEmptyOption: true
41169
+ }
41170
+ ),
41171
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { ref: deleteRef, style: { marginLeft: deleteButtonMargin }, children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
41172
+ DeleteButtonComponent,
41173
+ {
41174
+ onClick: () => handleRemoveField("columns", index)
41175
+ }
41176
+ ) })
41177
+ ] })
41178
+ ]
41179
+ }
41180
+ ) });
41181
+ }
42185
41182
  function getPivotMetricOptions(pivot, selectedPivotTable, chartType) {
42186
41183
  if (["metric", "gauge"].includes(chartType) && selectedPivotTable) {
42187
41184
  return selectedPivotTable.columns.map((elem) => ({
@@ -42390,7 +41387,6 @@ function ChartBuilder({
42390
41387
  }, [reportId]);
42391
41388
  const [windowWidth, setWindowWidth] = (0, import_react43.useState)(1200);
42392
41389
  const [rows, setRows] = (0, import_react43.useState)(report?.rows ?? []);
42393
- const [itemQuery, setItemQuery] = (0, import_react43.useState)(report?.itemQuery);
42394
41390
  const [rowCount, setRowCount] = (0, import_react43.useState)(report?.rowCount ?? 0);
42395
41391
  const [maxPage, setMaxPage] = (0, import_react43.useState)(0);
42396
41392
  const [isLoading, setIsLoading] = (0, import_react43.useState)(false);
@@ -43120,7 +42116,7 @@ function ChartBuilder({
43120
42116
  pivot,
43121
42117
  dateBucket,
43122
42118
  dateFilter,
43123
- report: report ? { ...report, ...tableInfo ?? { itemQuery } } : void 0,
42119
+ report: report ? { ...report, ...tableInfo } : void 0,
43124
42120
  client,
43125
42121
  uniqueValues,
43126
42122
  dashboardName: destinationDashboardName,
@@ -43281,7 +42277,6 @@ function ChartBuilder({
43281
42277
  setCurrentProcessing(processing);
43282
42278
  setRows(tableInfo.rows);
43283
42279
  setProcessedColumns(processColumns(tableInfo.columns));
43284
- setItemQuery(tableInfo.itemQuery);
43285
42280
  fetchRowCount(processing, overrideFilters);
43286
42281
  if (formData.pivot) {
43287
42282
  try {
@@ -43647,6 +42642,26 @@ function ChartBuilder({
43647
42642
  );
43648
42643
  setFormData({ ...formData, [fieldName]: updatedArray });
43649
42644
  };
42645
+ const columnDragSensors = (0, import_core.useSensors)(
42646
+ (0, import_core.useSensor)(import_core.PointerSensor),
42647
+ (0, import_core.useSensor)(import_core.KeyboardSensor, {
42648
+ coordinateGetter: import_sortable.sortableKeyboardCoordinates
42649
+ })
42650
+ );
42651
+ const handleColumnDragEnd = (event) => {
42652
+ const { active, over } = event;
42653
+ if (!active || !over) return;
42654
+ if (active.id !== over.id) {
42655
+ const oldIndex = formData.columns.findIndex(
42656
+ (col) => col.field === active.id
42657
+ );
42658
+ const newIndex = formData.columns.findIndex(
42659
+ (col) => col.field === over.id
42660
+ );
42661
+ const newColumns = (0, import_sortable.arrayMove)(formData.columns, oldIndex, newIndex);
42662
+ setFormData({ ...formData, columns: newColumns });
42663
+ }
42664
+ };
43650
42665
  const handleSubmit = (event) => {
43651
42666
  event.preventDefault();
43652
42667
  };
@@ -44167,7 +43182,7 @@ function ChartBuilder({
44167
43182
  uniqueValuesIsLoading: initialUniqueValuesIsLoading,
44168
43183
  initialSelectedPivotTable: selectedPivotTable,
44169
43184
  pivotRecommendationsEnabled,
44170
- report: report ? { ...report, ...{ itemQuery } } : void 0,
43185
+ report,
44171
43186
  dashboardName: destinationDashboardName || "",
44172
43187
  dateFilter: filtersEnabled ? currentDashboardFilters?.find(
44173
43188
  (f) => f.filterType === "date_range"
@@ -44555,141 +43570,98 @@ function ChartBuilder({
44555
43570
  formData.pivot && selectedPivotTable && selectedPivotTable.columns && formData.chartType === "table" ? (
44556
43571
  // THIS CASE IF FOR PIVOT TABLES ONLY
44557
43572
  selectedPivotTable.columns.map(
44558
- (column, index) => /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
44559
- ChartBuilderInputRowContainer,
44560
- {
44561
- children: [
44562
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
44563
- SelectComponent,
44564
- {
44565
- value: column.field,
44566
- onChange: (e) => handleChange(
44567
- e.target.value,
44568
- "pivot.field",
44569
- index
44570
- ),
44571
- options: selectedPivotTable.columns.map(
44572
- (elem) => ({
44573
- label: elem.field,
44574
- value: elem.field
44575
- })
44576
- ),
44577
- disabled: index === 0,
44578
- width: 200,
44579
- hideEmptyOption: true
44580
- }
43573
+ (column, index) => /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(ChartBuilderInputRowContainer, { children: [
43574
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
43575
+ SelectComponent,
43576
+ {
43577
+ value: column.field,
43578
+ onChange: (e) => handleChange(
43579
+ e.target.value,
43580
+ "pivot.field",
43581
+ index
44581
43582
  ),
44582
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
44583
- TextInputComponent,
44584
- {
44585
- id: `chart-builder-column-label-${index}`,
44586
- width: 200,
44587
- value: column.label,
44588
- placeholder: "Column Label",
44589
- onChange: (e) => handleChange(
44590
- e.target.value,
44591
- "pivot.label",
44592
- index
44593
- )
44594
- }
43583
+ options: selectedPivotTable.columns.map(
43584
+ (elem) => ({
43585
+ label: elem.field,
43586
+ value: elem.field
43587
+ })
44595
43588
  ),
44596
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
44597
- SelectComponent,
44598
- {
44599
- value: (
44600
- // The first index use rowField for the rest of them use value fields
44601
- column.format
44602
- ),
44603
- onChange: (e) => handleChange(
44604
- e.target.value,
44605
- "pivot.format",
44606
- index
44607
- ),
44608
- options: formData.pivot && index === 0 && selectedPivotTable?.columns.length > 1 ? isDateField(
44609
- formData.pivot.rowFieldType || ""
44610
- ) ? [{ label: "date", value: "string" }] : [{ label: "string", value: "string" }] : [
44611
- ...NUMBER_OPTIONS,
44612
- { label: "string", value: "string" }
44613
- ],
44614
- width: 200,
44615
- hideEmptyOption: true
44616
- }
43589
+ disabled: index === 0,
43590
+ width: 200,
43591
+ hideEmptyOption: true
43592
+ }
43593
+ ),
43594
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
43595
+ TextInputComponent,
43596
+ {
43597
+ id: `chart-builder-column-label-${index}`,
43598
+ width: 200,
43599
+ value: column.label,
43600
+ placeholder: "Column Label",
43601
+ onChange: (e) => handleChange(
43602
+ e.target.value,
43603
+ "pivot.label",
43604
+ index
44617
43605
  )
44618
- ]
44619
- },
44620
- "column" + index
44621
- )
43606
+ }
43607
+ ),
43608
+ /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
43609
+ SelectComponent,
43610
+ {
43611
+ value: (
43612
+ // The first index use rowField for the rest of them use value fields
43613
+ column.format
43614
+ ),
43615
+ onChange: (e) => handleChange(
43616
+ e.target.value,
43617
+ "pivot.format",
43618
+ index
43619
+ ),
43620
+ options: formData.pivot && index === 0 && selectedPivotTable?.columns.length > 1 ? isDateField(
43621
+ formData.pivot.rowFieldType || ""
43622
+ ) ? [{ label: "date", value: "string" }] : [{ label: "string", value: "string" }] : [
43623
+ ...NUMBER_OPTIONS,
43624
+ { label: "string", value: "string" }
43625
+ ],
43626
+ width: 200,
43627
+ hideEmptyOption: true
43628
+ }
43629
+ )
43630
+ ] }, "column" + index)
44622
43631
  )
44623
- ) : formData.columns.map(
44624
- (column, index) => /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
44625
- ChartBuilderInputRowContainer,
44626
- {
44627
- children: [
44628
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
44629
- SelectComponent,
44630
- {
44631
- value: column.field,
44632
- onChange: (e) => handleChange(
44633
- e.target.value,
44634
- "columns.field",
44635
- index
44636
- ),
44637
- options: rows[0] ? Object.keys(rows[0]).map((elem) => ({
44638
- label: elem,
44639
- value: elem
44640
- })) : columns.map((elem) => ({
44641
- label: elem.field,
44642
- value: elem.field
44643
- })),
44644
- width: 200,
44645
- hideEmptyOption: true
44646
- }
44647
- ),
44648
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
44649
- TextInputComponent,
44650
- {
44651
- id: `chart-builder-column-label-${index}`,
44652
- width: 200,
44653
- value: column.label,
44654
- placeholder: "Column Label",
44655
- onChange: (e) => handleChange(
44656
- e.target.value,
44657
- "columns.label",
44658
- index
44659
- )
44660
- }
44661
- ),
44662
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
44663
- SelectComponent,
44664
- {
44665
- value: column.format,
44666
- onChange: (e) => handleChange(
44667
- e.target.value,
44668
- "columns.format",
44669
- index
44670
- ),
44671
- options: ALL_FORMAT_OPTIONS,
44672
- width: 200,
44673
- hideEmptyOption: true
44674
- }
44675
- ),
44676
- /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
44677
- "div",
44678
- {
44679
- ref: deleteRef,
44680
- style: { marginLeft: deleteButtonMargin },
44681
- children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
44682
- DeleteButtonComponent,
44683
- {
44684
- onClick: () => handleRemoveField("columns", index)
44685
- }
44686
- )
44687
- }
43632
+ ) : /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
43633
+ import_core.DndContext,
43634
+ {
43635
+ sensors: columnDragSensors,
43636
+ collisionDetection: import_core.closestCenter,
43637
+ onDragEnd: handleColumnDragEnd,
43638
+ children: /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
43639
+ import_sortable.SortableContext,
43640
+ {
43641
+ items: formData.columns.map((col) => col.field),
43642
+ strategy: import_sortable.verticalListSortingStrategy,
43643
+ children: formData.columns.map(
43644
+ (column, index) => /* @__PURE__ */ (0, import_jsx_runtime65.jsx)(
43645
+ SortableColumnItem,
43646
+ {
43647
+ column,
43648
+ index,
43649
+ rows,
43650
+ columns,
43651
+ handleChange,
43652
+ deleteRef,
43653
+ deleteButtonMargin,
43654
+ handleRemoveField,
43655
+ SelectComponent,
43656
+ TextInputComponent,
43657
+ DeleteButtonComponent
43658
+ },
43659
+ column.field
43660
+ )
44688
43661
  )
44689
- ]
44690
- },
44691
- "column" + index
44692
- )
43662
+ }
43663
+ )
43664
+ }
44693
43665
  ),
44694
43666
  /* @__PURE__ */ (0, import_jsx_runtime65.jsx)("div", { children: !// hide when pivoted and chartType === 'table'
44695
43667
  (formData.pivot && selectedPivotTable && selectedPivotTable.columns && formData.chartType === "table") && /* @__PURE__ */ (0, import_jsx_runtime65.jsxs)(
@@ -48858,9 +47830,9 @@ var useReportBuilder = ({
48858
47830
 
48859
47831
  // src/components/ReportBuilder/AddColumnModal.tsx
48860
47832
  var import_react48 = require("react");
48861
- var import_core = require("@dnd-kit/core");
48862
- var import_sortable = require("@dnd-kit/sortable");
48863
- var import_utilities = require("@dnd-kit/utilities");
47833
+ var import_core2 = require("@dnd-kit/core");
47834
+ var import_sortable2 = require("@dnd-kit/sortable");
47835
+ var import_utilities2 = require("@dnd-kit/utilities");
48864
47836
  var import_jsx_runtime67 = require("react/jsx-runtime");
48865
47837
  function AddColumnModal({
48866
47838
  onSave,
@@ -48929,10 +47901,10 @@ function AddColumnModal({
48929
47901
  setTimeout(() => setInitialLoad(false), 200);
48930
47902
  }
48931
47903
  }, [schemaLoading]);
48932
- const sensors = (0, import_core.useSensors)(
48933
- (0, import_core.useSensor)(import_core.PointerSensor),
48934
- (0, import_core.useSensor)(import_core.KeyboardSensor, {
48935
- coordinateGetter: import_sortable.sortableKeyboardCoordinates
47904
+ const sensors = (0, import_core2.useSensors)(
47905
+ (0, import_core2.useSensor)(import_core2.PointerSensor),
47906
+ (0, import_core2.useSensor)(import_core2.KeyboardSensor, {
47907
+ coordinateGetter: import_sortable2.sortableKeyboardCoordinates
48936
47908
  })
48937
47909
  );
48938
47910
  function handleDragEnd(event) {
@@ -48942,7 +47914,7 @@ function AddColumnModal({
48942
47914
  setOrderedColumnNames((orderedColumnNames2) => {
48943
47915
  const oldIndex = orderedColumnNames2.indexOf(active.id);
48944
47916
  const newIndex = orderedColumnNames2.indexOf(over.id);
48945
- return (0, import_sortable.arrayMove)(orderedColumnNames2, oldIndex, newIndex);
47917
+ return (0, import_sortable2.arrayMove)(orderedColumnNames2, oldIndex, newIndex);
48946
47918
  });
48947
47919
  }
48948
47920
  }
@@ -48986,16 +47958,16 @@ function AddColumnModal({
48986
47958
  }
48987
47959
  ),
48988
47960
  schemaLoading || initialLoad ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(LoadingComponent, {}) : schema.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
48989
- import_core.DndContext,
47961
+ import_core2.DndContext,
48990
47962
  {
48991
47963
  sensors,
48992
- collisionDetection: import_core.closestCenter,
47964
+ collisionDetection: import_core2.closestCenter,
48993
47965
  onDragEnd: handleDragEnd,
48994
47966
  children: /* @__PURE__ */ (0, import_jsx_runtime67.jsx)(
48995
- import_sortable.SortableContext,
47967
+ import_sortable2.SortableContext,
48996
47968
  {
48997
47969
  items: orderedColumnNames,
48998
- strategy: import_sortable.verticalListSortingStrategy,
47970
+ strategy: import_sortable2.verticalListSortingStrategy,
48999
47971
  children: /* @__PURE__ */ (0, import_jsx_runtime67.jsxs)(
49000
47972
  "div",
49001
47973
  {
@@ -49203,9 +48175,9 @@ var SortableItem = ({
49203
48175
  selectedColumns,
49204
48176
  SelectColumn
49205
48177
  }) => {
49206
- const { attributes, listeners, setNodeRef, transform, transition: transition2 } = (0, import_sortable.useSortable)({ id: id2 });
48178
+ const { attributes, listeners, setNodeRef, transform, transition: transition2 } = (0, import_sortable2.useSortable)({ id: id2 });
49207
48179
  const style2 = {
49208
- transform: import_utilities.CSS.Transform.toString(transform),
48180
+ transform: import_utilities2.CSS.Transform.toString(transform),
49209
48181
  transition: transition2
49210
48182
  };
49211
48183
  const handleSelect = () => {
@@ -49234,11 +48206,11 @@ var SortableItem = ({
49234
48206
  };
49235
48207
 
49236
48208
  // src/components/ReportBuilder/DraggableColumns.tsx
49237
- var import_core2 = require("@dnd-kit/core");
48209
+ var import_core3 = require("@dnd-kit/core");
49238
48210
 
49239
48211
  // src/components/ReportBuilder/DraggableItem.tsx
49240
- var import_sortable2 = require("@dnd-kit/sortable");
49241
- var import_utilities2 = require("@dnd-kit/utilities");
48212
+ var import_sortable3 = require("@dnd-kit/sortable");
48213
+ var import_utilities3 = require("@dnd-kit/utilities");
49242
48214
  var import_jsx_runtime68 = require("react/jsx-runtime");
49243
48215
  function DraggableItem({
49244
48216
  id: id2,
@@ -49247,9 +48219,9 @@ function DraggableItem({
49247
48219
  DraggableColumnComponent,
49248
48220
  loading
49249
48221
  }) {
49250
- const { attributes, listeners, setNodeRef, transform, transition: transition2 } = (0, import_sortable2.useSortable)({ id: id2 });
48222
+ const { attributes, listeners, setNodeRef, transform, transition: transition2 } = (0, import_sortable3.useSortable)({ id: id2 });
49251
48223
  const style2 = {
49252
- transform: import_utilities2.CSS.Transform.toString(transform),
48224
+ transform: import_utilities3.CSS.Transform.toString(transform),
49253
48225
  transition: transition2
49254
48226
  };
49255
48227
  return /* @__PURE__ */ (0, import_jsx_runtime68.jsx)("div", { style: { ...style2 }, ref: setNodeRef, children: /* @__PURE__ */ (0, import_jsx_runtime68.jsx)(
@@ -49274,7 +48246,7 @@ function DraggableItem({
49274
48246
  }
49275
48247
 
49276
48248
  // src/components/ReportBuilder/DraggableColumns.tsx
49277
- var import_sortable3 = require("@dnd-kit/sortable");
48249
+ var import_sortable4 = require("@dnd-kit/sortable");
49278
48250
  var import_react49 = require("react");
49279
48251
  var import_jsx_runtime69 = require("react/jsx-runtime");
49280
48252
  function DraggableColumns({
@@ -49283,10 +48255,10 @@ function DraggableColumns({
49283
48255
  DraggableColumnComponent,
49284
48256
  loading
49285
48257
  }) {
49286
- const sensors = (0, import_core2.useSensors)(
49287
- (0, import_core2.useSensor)(import_core2.PointerSensor),
49288
- (0, import_core2.useSensor)(import_core2.KeyboardSensor, {
49289
- coordinateGetter: import_sortable3.sortableKeyboardCoordinates
48258
+ const sensors = (0, import_core3.useSensors)(
48259
+ (0, import_core3.useSensor)(import_core3.PointerSensor),
48260
+ (0, import_core3.useSensor)(import_core3.KeyboardSensor, {
48261
+ coordinateGetter: import_sortable4.sortableKeyboardCoordinates
49290
48262
  })
49291
48263
  );
49292
48264
  const columnNames = (0, import_react49.useMemo)(() => {
@@ -49303,7 +48275,7 @@ function DraggableColumns({
49303
48275
  if (active.id !== over.id) {
49304
48276
  const oldIndex = columnNames.findIndex((c) => c.endsWith(active.id));
49305
48277
  const newIndex = columnNames.findIndex((c) => c.endsWith(over.id));
49306
- const newOrder = (0, import_sortable3.arrayMove)(columnNames, oldIndex, newIndex);
48278
+ const newOrder = (0, import_sortable4.arrayMove)(columnNames, oldIndex, newIndex);
49307
48279
  const orderToColumns = newOrder.map((name2) => {
49308
48280
  const [table, field] = name2.split(".");
49309
48281
  return columns.find(
@@ -49320,16 +48292,16 @@ function DraggableColumns({
49320
48292
  onColumnOrderChange(newColumns);
49321
48293
  }
49322
48294
  return /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
49323
- import_core2.DndContext,
48295
+ import_core3.DndContext,
49324
48296
  {
49325
48297
  sensors,
49326
- collisionDetection: import_core2.closestCenter,
48298
+ collisionDetection: import_core3.closestCenter,
49327
48299
  onDragEnd: handleDragEnd,
49328
48300
  children: /* @__PURE__ */ (0, import_jsx_runtime69.jsx)(
49329
- import_sortable3.SortableContext,
48301
+ import_sortable4.SortableContext,
49330
48302
  {
49331
48303
  items: columnNames,
49332
- strategy: import_sortable3.verticalListSortingStrategy,
48304
+ strategy: import_sortable4.verticalListSortingStrategy,
49333
48305
  children: /* @__PURE__ */ (0, import_jsx_runtime69.jsxs)(
49334
48306
  "div",
49335
48307
  {