Skip to content

Commit

Permalink
[IMP] pivot: add support for date(time) measures
Browse files Browse the repository at this point in the history
With this commit, date and datetime fields are now supported as measures
for pivots.

closes #5302

Task: 3989393
Signed-off-by: Pierre Rousseau (pro) <[email protected]>
  • Loading branch information
LucasLefevre committed Jan 17, 2025
1 parent 361330e commit 4240bc5
Show file tree
Hide file tree
Showing 5 changed files with 55 additions and 7 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -263,11 +263,14 @@ export class PivotSidePanelStore extends SpreadsheetStore {
fields: PivotFields,
definition: PivotCoreDefinition
): Record<string, Set<string>> {
const { columns, rows } = definition;
const dateFields = columns.concat(rows).filter((dimension) => {
const fieldType = fields[dimension.fieldName]?.type;
return fieldType === "date" || fieldType === "datetime";
});
const { columns, rows, measures } = definition;
const dateFields = columns
.concat(rows)
.concat(measures)
.filter((dimension) => {
const fieldType = fields[dimension.fieldName]?.type;
return fieldType === "date" || fieldType === "datetime";
});
const granularitiesPerFields = {};
for (const field of dateFields) {
granularitiesPerFields[field.fieldName] = new Set(
Expand Down
1 change: 1 addition & 0 deletions src/helpers/pivot/pivot_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const AGGREGATORS_BY_FIELD_TYPE = {
integer: NUMBER_CHAR_AGGREGATORS,
char: NUMBER_CHAR_AGGREGATORS,
boolean: ["count_distinct", "count", "bool_and", "bool_or"],
datetime: ["max", "min", "count_distinct", "count"],
};

export const AGGREGATORS = {};
Expand Down
2 changes: 1 addition & 1 deletion src/helpers/pivot/pivot_registry.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,6 @@ pivotRegistry.add("SPREADSHEET", {
onIterationEndEvaluation: (pivot: SpreadsheetPivot) => pivot.markAsDirtyForEvaluation(),
dateGranularities: [...dateGranularities],
datetimeGranularities: [...dateGranularities, "hour_number", "minute_number", "second_number"],
isMeasureCandidate: (field: PivotField) => !["datetime", "boolean"].includes(field.type),
isMeasureCandidate: (field: PivotField) => field.type !== "boolean",
isGroupable: () => true,
});
29 changes: 29 additions & 0 deletions tests/pivots/spreadsheet_pivot/spreadsheet_pivot.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1615,6 +1615,35 @@ describe("Spreadsheet Pivot", () => {
);
});

test("Pivot with date and datetime measures", () => {
const model = createModelFromGrid({
A1: "Date",
B1: "Datetime",
A2: "2024/02/03",
B2: "2024/02/03 12:34:56",
A3: "2022/04/14",
B3: "2022/04/14 01:02:03",
});
addPivot(model, "A1:B3", {
columns: [],
rows: [],
measures: [
{ id: "Date:max", fieldName: "Date", aggregator: "max" },
{ id: "Datetime:max", fieldName: "Datetime", aggregator: "max" },
{ id: "Date:min", fieldName: "Date", aggregator: "min" },
{ id: "Datetime:min", fieldName: "Datetime", aggregator: "min" },
],
});
setCellContent(model, "A26", '=PIVOT.VALUE(1,"Date:max")');
setCellContent(model, "B26", '=PIVOT.VALUE(1,"Datetime:max")');
setCellContent(model, "A27", '=PIVOT.VALUE(1,"Date:min")');
setCellContent(model, "B27", '=PIVOT.VALUE(1,"Datetime:min")');
expect(getEvaluatedCell(model, "A26").formattedValue).toBe("2024/02/03");
expect(getEvaluatedCell(model, "B26").formattedValue).toBe("2024/02/03 12:34:56");
expect(getEvaluatedCell(model, "A27").formattedValue).toBe("2022/04/14");
expect(getEvaluatedCell(model, "B27").formattedValue).toBe("2022/04/14 01:02:03");
});

test("Pivot with measure AVG on text values does not crash", () => {
const model = createModelFromGrid({ A1: "Customer", A2: "Jean", A3: "Marc" });
addPivot(model, "A1:A3", {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,7 @@ describe("Spreadsheet pivot side panel", () => {
const measures = [...fixture.querySelectorAll(".o-autocomplete-value")].map(
(el) => el.textContent
);
expect(measures).toEqual(["Count", "float", "integer", "text"]);
expect(measures).toEqual(["Count", "date", "datetime", "float", "integer", "text"]);
});

test("defer update option is persistent", async () => {
Expand Down Expand Up @@ -431,6 +431,21 @@ describe("Spreadsheet pivot side panel", () => {
]);
});

test("can add a datetime measure", async () => {
setCellContent(model, "A1", "name");
setCellContent(model, "A2", "Alice");
setCellContent(model, "B1", "birthdate");
setCellContent(model, "B2", "1995/12/15");
addPivot(model, "A1:B2", {}, "3");
env.openSidePanel("PivotSidePanel", { pivotId: "3" });
await nextTick();
await click(fixture.querySelector(".o-pivot-measure .add-dimension")!);
await click(fixture.querySelectorAll(".o-autocomplete-value")[0]);
expect(model.getters.getPivotCoreDefinition("3").measures).toEqual([
{ id: "birthdate:count", fieldName: "birthdate", aggregator: "count" },
]);
});

test("should preserve the sorting of the dimension after ordering is changed", async () => {
mockGetBoundingClientRect({
/**
Expand Down

0 comments on commit 4240bc5

Please sign in to comment.