Skip to content

Commit eafaa51

Browse files
committed
[IMP] pivot: use NA() for a missing value
1 parent 358b858 commit eafaa51

File tree

8 files changed

+49
-14
lines changed

8 files changed

+49
-14
lines changed

src/functions/module_lookup.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -698,7 +698,7 @@ export const PIVOT_VALUE = {
698698
arg("pivot_id (number,string)", _t("ID of the pivot.")),
699699
arg("measure_name (string)", _t("Name of the measure.")),
700700
arg("domain_field_name (string,optional,repeating)", _t("Field name.")),
701-
arg("domain_value (number,string,boolean,optional,repeating)", _t("Value.")),
701+
arg("domain_value (number,string,boolean,any,optional,repeating)", _t("Value.")),
702702
],
703703
compute: function (
704704
formulaId: Maybe<FunctionResultObject>,
@@ -746,7 +746,7 @@ export const PIVOT_HEADER = {
746746
args: [
747747
arg("pivot_id (number,string)", _t("ID of the pivot.")),
748748
arg("domain_field_name (string,optional,repeating)", _t("Field name.")),
749-
arg("domain_value (number,string,value,optional,repeating)", _t("Value.")),
749+
arg("domain_value (number,string,any,optional,repeating)", _t("Value.")),
750750
],
751751
compute: function (
752752
pivotId: Maybe<FunctionResultObject>,

src/helpers/pivot/pivot_helpers.ts

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import {
1212
Matrix,
1313
Pivot,
1414
} from "../../types";
15-
import { EvaluationError } from "../../types/errors";
15+
import { CellErrorType, EvaluationError } from "../../types/errors";
1616
import {
1717
Granularity,
1818
PivotCoreDimension,
@@ -195,16 +195,18 @@ export function toNormalizedPivotValue(
195195
dimension: Pick<PivotDimension, "type" | "displayName" | "granularity">,
196196
groupValue
197197
) {
198-
if (groupValue === null || groupValue === "null") {
198+
if (
199+
groupValue === null ||
200+
groupValue?.value === null ||
201+
groupValue === CellErrorType.NotAvailable ||
202+
groupValue?.value === CellErrorType.NotAvailable
203+
) {
199204
return null;
200205
}
201206
const groupValueString =
202207
typeof groupValue === "boolean"
203208
? toString(groupValue).toLocaleLowerCase()
204209
: toString(groupValue);
205-
if (groupValueString === "null") {
206-
return null;
207-
}
208210
if (!pivotNormalizationValueRegistry.contains(dimension.type)) {
209211
throw new EvaluationError(
210212
_t("Field %(field)s is not supported because of its type (%(type)s)", {
@@ -233,7 +235,7 @@ export function toFunctionPivotValue(
233235
dimension: Pick<PivotDimension, "type" | "granularity">
234236
) {
235237
if (value === null) {
236-
return `"null"`;
238+
return "NA()";
237239
}
238240
if (!pivotToFunctionValueRegistry.contains(dimension.type)) {
239241
return `"${value}"`;

src/helpers/pivot/spreadsheet_pivot/data_entry_spreadsheet_pivot.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { CellValue, EvaluatedCell } from "../../../types";
2+
import { CellErrorType } from "../../../types/errors";
23
import {
34
DimensionTree,
45
PivotDimension,
@@ -220,7 +221,7 @@ export function groupPivotDataEntriesBy(dataEntries: DataEntries, dimension: Piv
220221
function keySelector(dimension: PivotDimension): (item: DataEntry, index: number) => string {
221222
const name = dimension.nameWithGranularity;
222223
return (item) => {
223-
return `${item[name]?.value ?? null}`;
224+
return `${item[name]?.value ?? CellErrorType.NotAvailable}`;
224225
};
225226
}
226227

@@ -245,10 +246,10 @@ export function orderDataEntriesKeys(
245246
* Used to order two values
246247
*/
247248
function compareDimensionValues(dimension: PivotDimension, a: string, b: string): number {
248-
if (a === "null") {
249+
if (a === CellErrorType.NotAvailable) {
249250
return dimension.order === "asc" ? 1 : -1;
250251
}
251-
if (b === "null") {
252+
if (b === CellErrorType.NotAvailable) {
252253
return dimension.order === "asc" ? -1 : 1;
253254
}
254255
if (dimension.type === "integer" || dimension.type === "datetime") {

src/migrations/data.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { migrationStepRegistry } from "./migration_steps";
1919
* a breaking change is made in the way the state is handled, and an upgrade
2020
* function should be defined
2121
*/
22-
export const CURRENT_VERSION = 24;
22+
export const CURRENT_VERSION = 25;
2323
const INITIAL_SHEET_ID = "Sheet1";
2424

2525
/**

src/migrations/migration_steps.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,25 @@ migrationStepRegistry
446446
}
447447
return data;
448448
},
449+
})
450+
.add("migration_24", {
451+
// convert "null" in pivot formulas to NA()
452+
versionFrom: "24",
453+
migrate(data: WorkbookData): any {
454+
for (const sheet of data.sheets || []) {
455+
for (const xc in sheet.cells || []) {
456+
const cellLowerCased = sheet.cells[xc]?.toLowerCase();
457+
if (
458+
cellLowerCased?.startsWith("=") &&
459+
cellLowerCased.includes("pivot") &&
460+
cellLowerCased.includes('"null"')
461+
) {
462+
sheet.cells[xc] = sheet.cells[xc]?.replace(/"null"/g, "NA()");
463+
}
464+
}
465+
}
466+
return data;
467+
},
449468
});
450469

451470
function fixOverlappingFilters(data: any): any {

tests/clipboard/clipboard_plugin.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2114,7 +2114,7 @@ describe("clipboard", () => {
21142114
["", "=PIVOT.HEADER(1)"],
21152115
["", '=PIVOT.HEADER(1,"measure","Price:sum")'],
21162116
['=PIVOT.HEADER(1,"Customer","Alice")', '=PIVOT.VALUE(1,"Price:sum","Customer","Alice")'],
2117-
['=PIVOT.HEADER(1,"Customer","null")', '=PIVOT.VALUE(1,"Price:sum","Customer","null")'],
2117+
['=PIVOT.HEADER(1,"Customer",NA())', '=PIVOT.VALUE(1,"Price:sum","Customer",NA())'],
21182118
]);
21192119
});
21202120

tests/model/model_import_export.test.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -586,6 +586,19 @@ describe("Migrations", () => {
586586
});
587587
expect(getCellContent(model, "A1")).toBe("Hello");
588588
});
589+
590+
test("migrate version 25: flatten cell object", () => {
591+
const model = new Model({
592+
version: 24,
593+
sheets: [
594+
{
595+
id: "1",
596+
cells: { A1: '=PIVOT.VALUE(1, "revenue", "customer", "null")' },
597+
},
598+
],
599+
});
600+
expect(getCell(model, "A1")?.content).toBe('=PIVOT.VALUE(1, "revenue", "customer", NA())');
601+
});
589602
});
590603

591604
describe("Import", () => {

tests/pivots/pivot_menu_items.test.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ describe("Pivot fix formula menu item", () => {
216216
model.dispatch("SET_FORMULA_VISIBILITY", { show: true });
217217
expect(getEvaluatedGrid(model, "C3:D4")).toEqual([
218218
[`=PIVOT.HEADER(1,"Customer","Alice")`, `=PIVOT.VALUE(1,"Amount:sum","Customer","Alice")`],
219-
[`=PIVOT.HEADER(1,"Customer","null")`, `=PIVOT.VALUE(1,"Amount:sum","Customer","null")`],
219+
[`=PIVOT.HEADER(1,"Customer",NA())`, `=PIVOT.VALUE(1,"Amount:sum","Customer",NA())`],
220220
]);
221221
});
222222

0 commit comments

Comments
 (0)