Skip to content

Commit 6220c2b

Browse files
committed
evaluationBus
1 parent e3abf1d commit 6220c2b

File tree

9 files changed

+99
-53
lines changed

9 files changed

+99
-53
lines changed

packages/o-spreadsheet-engine/src/functions/module_lookup.ts

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -787,11 +787,9 @@ export const XLOOKUP = {
787787
//--------------------------------------------------------------------------
788788

789789
function addPivotMetaDataToContext(context: EvalContext, item: PivotCacheItem) {
790-
const { __originCellPosition: position, cellPositionMetaData: positionMap } = context;
790+
const { __originCellPosition: position } = context;
791791
if (position) {
792-
const existingData = positionMap.get(position) || {};
793-
existingData["pivot"] = item;
794-
positionMap.set(position, existingData);
792+
context.sendEvaluationMessage({ type: "addPivotToPosition", position, item });
795793
}
796794
}
797795

packages/o-spreadsheet-engine/src/functions/module_math.ts

Lines changed: 3 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ import { DivisionByZeroError, EvaluationError } from "../types/errors";
66
import { AddFunctionDescription } from "../types/functions";
77
import {
88
Arg,
9-
CellPosition,
109
FunctionResultNumber,
1110
FunctionResultObject,
1211
Matrix,
@@ -1387,18 +1386,11 @@ export const SUBTOTAL = {
13871386
acceptHiddenCells = false;
13881387
}
13891388

1390-
const { __originCellPosition: position, cellPositionMetaData: positionMap } = this;
1389+
const { __originCellPosition: position } = this;
13911390
if (position) {
1392-
const existingData = positionMap.get(position) || {};
1393-
existingData["subtotal"] = true;
1394-
positionMap.set(position, existingData);
1391+
this.sendEvaluationMessage({ type: "addSubTotalToPosition", position });
13951392
}
13961393

1397-
const isSubtotalCell = (cellPosition: CellPosition) => {
1398-
const cellMeta = positionMap.get(cellPosition);
1399-
return cellMeta?.subtotal === true;
1400-
};
1401-
14021394
if (code < 1 || code > 11) {
14031395
return new EvaluationError(
14041396
_t("The function code (%s) must be between 1 to 11 or 101 to 111.", code)
@@ -1423,7 +1415,7 @@ export const SUBTOTAL = {
14231415

14241416
for (let col = left; col <= right; col++) {
14251417
const cell = this.getters.getCell({ sheetId, col, row });
1426-
if (!cell || !isSubtotalCell({ sheetId, col, row })) {
1418+
if (!cell || !this.getters.isSubtotalCell({ sheetId, col, row })) {
14271419
evaluatedCellToKeep.push(this.getters.getEvaluatedCell({ sheetId, col, row }));
14281420
}
14291421
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import { CellPosition } from "../..";
2+
import { Registry } from "../../registry";
3+
4+
export type EvaluationMessage =
5+
| { type: "invalidateCell"; position: CellPosition }
6+
| { type: "invalidateAllCells" }
7+
| { type: string; [key: string]: any };
8+
9+
export interface EvaluationListener {
10+
handleEvaluationMessage(message: EvaluationMessage): void;
11+
}
12+
13+
export const evaluationListenerRegistry = new Registry<EvaluationListener>();

packages/o-spreadsheet-engine/src/plugins/ui_core_views/cell_evaluation/evaluation_plugin.ts

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import { isExportableToExcel } from "../../../formulas/helpers";
22
import { matrixMap } from "../../../functions/helpers";
3-
import { PositionMap } from "../../../helpers/cells/position_map";
43
import { toXC } from "../../../helpers/coordinates";
54
import { getItemId } from "../../../helpers/data_normalization";
65
import { cellPositions, positions } from "../../../helpers/zones";
@@ -160,8 +159,6 @@ export class EvaluationPlugin extends CoreViewPlugin {
160159
"getSpreadZone",
161160
"getArrayFormulaSpreadingOn",
162161
"isEmpty",
163-
"getEvaluatedCellMetaDataMap",
164-
"getEvaluatedCellMetaData",
165162
] as const;
166163

167164
private shouldRebuildDependenciesGraph = true;
@@ -427,17 +424,4 @@ export class EvaluationPlugin extends CoreViewPlugin {
427424
}
428425
return undefined;
429426
}
430-
431-
getEvaluatedCellMetaDataMap(): PositionMap<{ [metaDataKey: string]: any }> {
432-
return this.evaluator.getCellPositionMetaDataMap();
433-
}
434-
435-
getEvaluatedCellMetaData(position: CellPosition) {
436-
const cachedAtPosition = this.evaluator.getCellPositionMetaDataMap().get(position);
437-
if (cachedAtPosition) {
438-
return cachedAtPosition;
439-
}
440-
const mainPosition = this.getArrayFormulaSpreadingOn(position);
441-
return mainPosition ? this.evaluator.getCellPositionMetaDataMap().get(mainPosition) : undefined;
442-
}
443427
}

packages/o-spreadsheet-engine/src/plugins/ui_core_views/cell_evaluation/evaluator.ts

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ import { matrixMap } from "../../../functions/helpers";
2424
import { PositionMap } from "../../../helpers/cells/position_map";
2525
import { toXC } from "../../../helpers/coordinates";
2626
import { lazy } from "../../../helpers/misc";
27+
import {
28+
evaluationListenerRegistry,
29+
EvaluationMessage,
30+
} from "../../../helpers/pivot/evaluation_listener_registry";
2731
import { excludeTopLeft, positionToZone, union } from "../../../helpers/zones";
2832
import { onIterationEndEvaluationRegistry } from "../../../registries/evaluation_registry";
2933
import { _t } from "../../../translation";
@@ -34,7 +38,6 @@ import {
3438
GetSymbolValue,
3539
isMatrix,
3640
Matrix,
37-
PivotCacheItem,
3841
RangeCompiledFormula,
3942
UID,
4043
Zone,
@@ -57,8 +60,6 @@ export class Evaluator {
5760
private blockedArrayFormulas = new PositionSet({});
5861
private spreadingRelations = new SpreadingRelation();
5962

60-
private cellPositionMetaData = new PositionMap<{ [metaDataKey: string]: any }>();
61-
6263
constructor(private readonly context: ModelConfig["custom"], getters: Getters) {
6364
this.getters = getters;
6465
this.compilationParams = buildCompilationParameters(
@@ -142,7 +143,14 @@ export class Evaluator {
142143
forwardSearch: new Map(),
143144
reverseSearch: new Map(),
144145
};
145-
this.compilationParams.evalContext.cellPositionMetaData = this.cellPositionMetaData;
146+
this.compilationParams.evalContext.sendEvaluationMessage = (message: EvaluationMessage) =>
147+
this.sendToListeners(message);
148+
}
149+
150+
private sendToListeners(message: EvaluationMessage) {
151+
for (const listener of evaluationListenerRegistry.getAll()) {
152+
listener.handleEvaluationMessage(message);
153+
}
146154
}
147155

148156
private createEmptyPositionSet() {
@@ -222,7 +230,7 @@ export class Evaluator {
222230
evaluateAllCells() {
223231
const start = performance.now();
224232
this.evaluatedCells = new PositionMap();
225-
this.cellPositionMetaData = new PositionMap<PivotCacheItem>();
233+
this.sendToListeners({ type: "invalidateAllCells" });
226234
const ranges: BoundedRange[] = [];
227235
for (const sheetId of this.getters.getSheetIds()) {
228236
const zone = this.getters.getSheetZone(sheetId);
@@ -270,10 +278,6 @@ export class Evaluator {
270278
}
271279
}
272280

273-
getCellPositionMetaDataMap(): PositionMap<{ [metaDataKey: string]: any }> {
274-
return this.cellPositionMetaData;
275-
}
276-
277281
/**
278282
* Return the position of formulas blocked by the given positions
279283
* as well as all their dependencies.
@@ -335,7 +339,7 @@ export class Evaluator {
335339
for (let col = left; col <= right; col++) {
336340
for (let row = top; row <= bottom; row++) {
337341
const position = { sheetId: range.sheetId, col, row };
338-
this.cellPositionMetaData.delete(position);
342+
this.sendToListeners({ type: "invalidateCell", position });
339343
this.evaluatedCells.delete(position);
340344
}
341345
}
@@ -556,7 +560,7 @@ export class Evaluator {
556560
continue;
557561
}
558562
this.evaluatedCells.delete(resultPosition);
559-
this.cellPositionMetaData.delete(resultPosition);
563+
this.sendToListeners({ type: "invalidateCell", position: resultPosition });
560564
}
561565
}
562566
const sheetId = position.sheetId;

packages/o-spreadsheet-engine/src/plugins/ui_core_views/pivot_ui.ts

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
import { astToFormula } from "../../formulas/formula_formatter";
22
import { Token } from "../../formulas/tokenizer";
3+
import { PositionMap } from "../../helpers/cells/position_map";
34
import { deepEquals, getUniqueText } from "../../helpers/misc";
5+
import {
6+
evaluationListenerRegistry,
7+
EvaluationMessage,
8+
} from "../../helpers/pivot/evaluation_listener_registry";
49
import { getFirstPivotFunction } from "../../helpers/pivot/pivot_composer_helpers";
510
import { domainToColRowDomain } from "../../helpers/pivot/pivot_domain_helpers";
611
import withPivotPresentationLayer from "../../helpers/pivot/pivot_presentation";
@@ -44,9 +49,14 @@ export class PivotUIPlugin extends CoreViewPlugin {
4449
private unusedPivotsInFormulas?: UID[];
4550
private custom: UIPluginConfig["custom"];
4651

52+
private pivotCellsCache = new PositionMap<PivotCacheItem>();
53+
4754
constructor(config: CoreViewPluginConfig) {
4855
super(config);
4956
this.custom = config.custom;
57+
evaluationListenerRegistry.replace("PivotUIPlugin", {
58+
handleEvaluationMessage: this.handleEvaluationMessage.bind(this),
59+
});
5060
}
5161

5262
beforeHandle(cmd: Command) {
@@ -112,12 +122,27 @@ export class PivotUIPlugin extends CoreViewPlugin {
112122
}
113123
}
114124

125+
handleEvaluationMessage(message: EvaluationMessage) {
126+
if (message.type === "invalidateAllCells") {
127+
this.pivotCellsCache = new PositionMap<PivotCacheItem>();
128+
} else if (message.type === "invalidateCell") {
129+
this.pivotCellsCache.delete(message.position);
130+
} else if (message.type === "addPivotToPosition") {
131+
this.pivotCellsCache.set(message.position, message.item);
132+
}
133+
}
134+
115135
// ---------------------------------------------------------------------
116136
// Getters
117137
// ---------------------------------------------------------------------
118138

119139
getPivotInfoAtPosition(position: CellPosition): PivotCacheItem | undefined {
120-
return this.getters.getEvaluatedCellMetaData(position)?.pivot;
140+
const cachedAtPosition = this.pivotCellsCache.get(position);
141+
if (cachedAtPosition) {
142+
return cachedAtPosition;
143+
}
144+
const mainPosition = this.getters.getArrayFormulaSpreadingOn(position);
145+
return mainPosition ? this.pivotCellsCache.get(mainPosition) : undefined;
121146
}
122147

123148
/**

packages/o-spreadsheet-engine/src/plugins/ui_feature/subtotal_evaluation.ts

Lines changed: 36 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,24 @@
1+
import { CellPosition } from "../..";
2+
import { PositionMap } from "../../helpers/cells/position_map";
3+
import {
4+
evaluationListenerRegistry,
5+
EvaluationMessage,
6+
} from "../../helpers/pivot/evaluation_listener_registry";
17
import { Command, invalidSubtotalFormulasCommands } from "../../types/commands";
2-
import { UIPlugin } from "../ui_plugin";
8+
import { UIPlugin, UIPluginConfig } from "../ui_plugin";
39

410
export class SubtotalEvaluationPlugin extends UIPlugin {
11+
static getters = ["isSubtotalCell"] as const;
12+
13+
private subtotalPositions = new PositionMap<boolean>();
14+
15+
constructor(config: UIPluginConfig) {
16+
super(config);
17+
evaluationListenerRegistry.replace("SubtotalEvaluationPlugin", {
18+
handleEvaluationMessage: this.handleEvaluationMessage.bind(this),
19+
});
20+
}
21+
522
handle(cmd: Command) {
623
if (invalidSubtotalFormulasCommands.has(cmd.type)) {
724
this.dispatch("EVALUATE_CELLS", {
@@ -10,14 +27,26 @@ export class SubtotalEvaluationPlugin extends UIPlugin {
1027
}
1128
}
1229

30+
handleEvaluationMessage(message: EvaluationMessage) {
31+
if (message.type === "invalidateAllCells") {
32+
this.subtotalPositions = new PositionMap<boolean>();
33+
} else if (message.type === "invalidateCell") {
34+
this.subtotalPositions.delete(message.position);
35+
} else if (message.type === "addSubTotalToPosition") {
36+
this.subtotalPositions.set(message.position, true);
37+
}
38+
}
39+
40+
isSubtotalCell(position: CellPosition): boolean {
41+
return this.subtotalPositions.has(position);
42+
}
43+
1344
private getSubtotalCellIds(): string[] {
1445
const cellIds: string[] = [];
15-
const metaData = this.getters.getEvaluatedCellMetaDataMap();
16-
for (const position of metaData.keys()) {
17-
const data = metaData.get(position);
18-
if (data?.subtotal) {
19-
const cellId = this.getters.getCell(position)?.id;
20-
if (cellId) cellIds.push(cellId);
46+
for (const position of this.subtotalPositions.keys()) {
47+
const cellId = this.getters.getCell(position)?.id;
48+
if (cellId) {
49+
cellIds.push(cellId);
2150
}
2251
}
2352
return cellIds;

packages/o-spreadsheet-engine/src/types/functions.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { PositionMap } from "../helpers/cells/position_map";
1+
import { EvaluationMessage } from "../helpers/pivot/evaluation_listener_registry";
22
import { CellValue } from "./cells";
33
import { Getters } from "./getters";
44
import { Locale } from "./locale";
@@ -67,7 +67,7 @@ export type EvalContext = {
6767
addDependencies?: (position: CellPosition, ranges: Range[]) => void;
6868
debug?: boolean;
6969
lookupCaches?: LookupCaches;
70-
cellPositionMetaData: PositionMap<{ [metaDataKey: string]: any }>;
70+
sendEvaluationMessage: (message: EvaluationMessage) => void;
7171
};
7272

7373
/**

packages/o-spreadsheet-engine/src/types/getters.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,4 +72,5 @@ export type Getters = {
7272
PluginGetters<typeof CheckboxTogglePlugin> &
7373
PluginGetters<typeof CellIconPlugin> &
7474
PluginGetters<typeof DynamicTranslate> &
75-
PluginGetters<typeof CarouselUIPlugin>;
75+
PluginGetters<typeof CarouselUIPlugin> &
76+
PluginGetters<typeof SubtotalEvaluationPlugin>;

0 commit comments

Comments
 (0)