diff --git a/components/Main.tsx b/components/Main.tsx
index d2c08a9..4133547 100644
--- a/components/Main.tsx
+++ b/components/Main.tsx
@@ -97,28 +97,47 @@ export default function Main() {
aggregation.name &&
(rows.length > 0 || columns.length > 0)
) {
- const row_list = rows.map((row) => row.name);
- const column_list = columns.map((column) => column.name);
- const all_fields = [...new Set([...row_list, ...column_list])];
+ const generateFieldExpression = (
+ field: (typeof rows)[0] | (typeof columns)[0]
+ ) => {
+ if (field.dateExtract) {
+ // Extract the original field name by removing the dateExtract prefix
+ const originalField = field.name
+ .replace(`${field.dateExtract}(`, "")
+ .replace(")", "");
+ return `CAST(EXTRACT(${field.dateExtract} FROM CAST("${originalField}" AS DATE)) AS VARCHAR) AS "${field.name}"`;
+ }
+ return `CAST("${field.name}" AS ${
+ getTypeForColumn(queryFields, field.table, field.name) === "Utf8"
+ ? "VARCHAR"
+ : "DOUBLE"
+ }) AS "${field.name}"`;
+ };
+
+ const generateGroupByExpression = (
+ field: (typeof rows)[0] | (typeof columns)[0]
+ ) => {
+ if (field.dateExtract) {
+ // Extract the original field name by removing the dateExtract prefix
+ const originalField = field.name
+ .replace(`${field.dateExtract}(`, "")
+ .replace(")", "");
+ return `EXTRACT(${field.dateExtract} FROM CAST("${originalField}" AS DATE))`;
+ }
+ return `CAST("${field.name}" AS ${
+ getTypeForColumn(queryFields, field.table, field.name) === "Utf8"
+ ? "VARCHAR"
+ : "DOUBLE"
+ })`;
+ };
+
+ const all_fields = [...rows, ...columns];
const all_fields_string = all_fields
- .map(
- (field) =>
- `CAST("${field}" AS ${
- getTypeForColumn(queryFields, files[0].name, field) === "Utf8"
- ? "VARCHAR"
- : "DOUBLE"
- }) AS "${field}"`
- )
+ .map((field) => generateFieldExpression(field))
.join(", ");
+
const all_fields_string_groupby = all_fields
- .map(
- (field) =>
- `CAST("${field}" AS ${
- getTypeForColumn(queryFields, files[0].name, field) === "Utf8"
- ? "VARCHAR"
- : "DOUBLE"
- })`
- )
+ .map((field) => generateGroupByExpression(field))
.join(", ");
return `
@@ -134,12 +153,21 @@ export default function Main() {
${
filters.length > 0
? `WHERE ${filters
- .map(
- (filter) =>
- `"${filter.field}" IN (${filter.values
+ .map((filter) => {
+ if (filter.dateExtract) {
+ const originalField = filter.field
+ .replace(`${filter.dateExtract}(`, "")
+ .replace(")", "");
+ return `CAST(EXTRACT(${
+ filter.dateExtract
+ } FROM CAST("${originalField}" AS DATE)) AS VARCHAR) IN (${filter.values
.map((value) => `'${value}'`)
- .join(", ")})`
- )
+ .join(", ")})`;
+ }
+ return `"${filter.field}" IN (${filter.values
+ .map((value) => `'${value}'`)
+ .join(", ")})`;
+ })
.join(" AND ")}`
: ""
}
@@ -150,35 +178,58 @@ export default function Main() {
aggregation.name &&
(rows.length > 0 || columns.length > 0)
) {
- const fields = [...rows, ...columns];
+ const generateFieldExpression = (
+ field: (typeof rows)[0] | (typeof columns)[0]
+ ) => {
+ if (field.dateExtract) {
+ const originalField = field.name
+ .replace(`${field.dateExtract}(`, "")
+ .replace(")", "");
+ return `CAST(EXTRACT(${
+ field.dateExtract
+ } FROM CAST(TABLE${files.findIndex(
+ (file) => file.name === field.table
+ )}."${originalField}" AS DATE)) AS VARCHAR) AS "${field.name}"`;
+ }
+ return `CAST(TABLE${files.findIndex(
+ (file) => file.name === field.table
+ )}."${field.name}" AS ${
+ getTypeForColumn(queryFields, field.table, field.name) === "Utf8"
+ ? "VARCHAR"
+ : "DOUBLE"
+ }) AS "${field.name}"`;
+ };
+
+ const generateGroupByExpression = (
+ field: (typeof rows)[0] | (typeof columns)[0]
+ ) => {
+ if (field.dateExtract) {
+ const originalField = field.name
+ .replace(`${field.dateExtract}(`, "")
+ .replace(")", "");
+ return `EXTRACT(${
+ field.dateExtract
+ } FROM CAST(TABLE${files.findIndex(
+ (file) => file.name === field.table
+ )}."${originalField}" AS DATE))`;
+ }
+ return `CAST(TABLE${files.findIndex(
+ (file) => file.name === field.table
+ )}."${field.name}" AS ${
+ getTypeForColumn(queryFields, field.table, field.name) === "Utf8"
+ ? "VARCHAR"
+ : "DOUBLE"
+ })`;
+ };
+ const fields = [...rows, ...columns];
const uniqueFields = [
...new Set(fields.map((field) => JSON.stringify(field))),
].map((str) => JSON.parse(str));
- const all_fields_string = uniqueFields.map(
- (field) =>
- `CAST(TABLE${files.findIndex(
- (file) => file.name === field.table
- )}."${field.name}" AS ${
- getTypeForColumn(queryFields, field.table, field.name) === "Utf8"
- ? "VARCHAR"
- : "DOUBLE"
- }) AS "${field.name}"`
- );
-
+ const all_fields_string = uniqueFields.map(generateFieldExpression);
const all_fields_string_groupby = uniqueFields
- .map(
- (field) =>
- `CAST(TABLE${files.findIndex(
- (file) => file.name === field.table
- )}."${field.name}" AS ${
- getTypeForColumn(queryFields, field.table, field.name) ===
- "Utf8"
- ? "VARCHAR"
- : "DOUBLE"
- })`
- )
+ .map(generateGroupByExpression)
.join(", ");
const relationship_list = relationships.map((relationship) => {
@@ -240,14 +291,25 @@ export default function Main() {
${
filters.length > 0
? `WHERE ${filters
- .map(
- (filter) =>
- `TABLE${files.findIndex(
+ .map((filter) => {
+ if (filter.dateExtract) {
+ const originalField = filter.field
+ .replace(`${filter.dateExtract}(`, "")
+ .replace(")", "");
+ return `CAST(EXTRACT(${
+ filter.dateExtract
+ } FROM CAST(TABLE${files.findIndex(
(file) => file.name === filter.table
- )}."${filter.field}" IN (${filter.values
+ )}."${originalField}" AS DATE)) AS VARCHAR) IN (${filter.values
.map((value) => `'${value}'`)
- .join(", ")})`
- )
+ .join(", ")})`;
+ }
+ return `TABLE${files.findIndex(
+ (file) => file.name === filter.table
+ )}."${filter.field}" IN (${filter.values
+ .map((value) => `'${value}'`)
+ .join(", ")})`;
+ })
.join(" AND ")}`
: ""
}
diff --git a/stores/usePivotStore.ts b/stores/usePivotStore.ts
index c6240f7..4d09726 100644
--- a/stores/usePivotStore.ts
+++ b/stores/usePivotStore.ts
@@ -3,11 +3,13 @@ import { create } from "zustand";
type rowType = {
name: string;
table: string;
+ dateExtract?: "YEAR" | "MONTH" | "QUARTER";
};
type columnType = {
name: string;
table: string;
+ dateExtract?: "YEAR" | "MONTH" | "QUARTER";
};
type aggregationType = {
@@ -20,18 +22,27 @@ export type filterType = {
table: string;
field: string;
values: string[];
+ dateExtract?: "YEAR" | "MONTH" | "QUARTER";
};
export type PivotState = {
rows: rowType[];
setRows: (table: string, rows: string[]) => void;
- addRow: (table: string, row: string) => void;
+ addRow: (
+ table: string,
+ row: string,
+ dateExtract?: "YEAR" | "MONTH" | "QUARTER"
+ ) => void;
clearRow: (table: string, row: string) => void;
clearRows: () => void;
clearFileRows: (table?: string) => void;
columns: columnType[];
setColumns: (table: string, columns: string[]) => void;
- addColumn: (table: string, column: string) => void;
+ addColumn: (
+ table: string,
+ column: string,
+ dateExtract?: "YEAR" | "MONTH" | "QUARTER"
+ ) => void;
clearColumn: (table: string, column: string) => void;
clearColumns: () => void;
clearFileColumns: (table?: string) => void;
@@ -44,7 +55,12 @@ export type PivotState = {
clearAggregation: () => void;
clearFileAggregation: (table?: string) => void;
filters: filterType[];
- addFilter: (table: string, field: string, values: string[]) => void;
+ addFilter: (
+ table: string,
+ field: string,
+ values: string[],
+ dateExtract?: "YEAR" | "MONTH" | "QUARTER"
+ ) => void;
clearFilter: (table: string, field: string) => void;
clearFilters: () => void;
clearFileFilters: (table?: string) => void;
@@ -64,13 +80,14 @@ export const usePivotStore = create
((set) => ({
.map((row) => ({ name: row, table })),
],
})),
- addRow: (table, row) => {
+ addRow: (table, row, dateExtract) => {
set((state) => {
- if (state.rows.some((r) => r.table === table && r.name === row)) {
+ const fieldId = dateExtract ? `${dateExtract}(${row})` : row;
+ if (state.rows.some((r) => r.table === table && r.name === fieldId)) {
return { rows: state.rows };
}
return {
- rows: [...state.rows, { name: row, table: table }],
+ rows: [...state.rows, { name: fieldId, table, dateExtract }],
};
});
},
@@ -97,13 +114,14 @@ export const usePivotStore = create((set) => ({
.map((column) => ({ name: column, table })),
],
})),
- addColumn: (table, column) => {
+ addColumn: (table, column, dateExtract) => {
set((state) => {
- if (state.columns.some((c) => c.table === table && c.name === column)) {
+ const fieldId = dateExtract ? `${dateExtract}(${column})` : column;
+ if (state.columns.some((c) => c.table === table && c.name === fieldId)) {
return { columns: state.columns };
}
return {
- columns: [...state.columns, { name: column, table: table }],
+ columns: [...state.columns, { name: fieldId, table, dateExtract }],
};
});
},
@@ -136,13 +154,17 @@ export const usePivotStore = create((set) => ({
table && state.aggregation.table === table ? {} : state.aggregation,
})),
filters: [],
- addFilter: (table, field, values) => {
+ addFilter: (table, field, values, dateExtract) => {
set((state) => {
+ const fieldId = dateExtract ? `${dateExtract}(${field})` : field;
const filteredFilters = state.filters.filter(
- (f) => !(f.table === table && f.field === field)
+ (f) => !(f.table === table && f.field === fieldId)
);
return {
- filters: [...filteredFilters, { table, field, values }],
+ filters: [
+ ...filteredFilters,
+ { table, field: fieldId, values, dateExtract },
+ ],
};
});
},