mirror of
https://github.com/dream-num/univer.git
synced 2026-08-28 23:01:30 +08:00
feat(formula): add formula dependency api 2 (#6277)
This commit is contained in:
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { IExecutionOptions, IMutation, Nullable } from '@univerjs/core';
|
||||
import type { IExecutionOptions, IMutation, IUnitRange, Nullable } from '@univerjs/core';
|
||||
import type {
|
||||
IFormulaExecuteResultMap,
|
||||
IFormulaStringMap,
|
||||
@@ -58,6 +58,15 @@ export interface ISetCellFormulaDependencyCalculationResultMutation {
|
||||
result: IFormulaDependencyTreeFullJson | undefined;
|
||||
}
|
||||
|
||||
export interface ISetQueryFormulaDependencyMutation {
|
||||
unitRanges: IUnitRange[];
|
||||
isInRange?: boolean;
|
||||
}
|
||||
|
||||
export interface ISetQueryFormulaDependencyResultMutation {
|
||||
result: IFormulaDependencyTreeJson[];
|
||||
}
|
||||
|
||||
/**
|
||||
* TODO: @DR-Univer
|
||||
* Trigger the calculation of the formula and stop the formula
|
||||
@@ -134,3 +143,15 @@ export const SetCellFormulaDependencyCalculationResultMutation: IMutation<ISetCe
|
||||
type: CommandType.MUTATION,
|
||||
handler: () => true,
|
||||
};
|
||||
|
||||
export const SetQueryFormulaDependencyMutation: IMutation<ISetQueryFormulaDependencyMutation> = {
|
||||
id: 'formula.mutation.set-query-formula-dependency',
|
||||
type: CommandType.MUTATION,
|
||||
handler: () => true,
|
||||
};
|
||||
|
||||
export const SetQueryFormulaDependencyResultMutation: IMutation<ISetQueryFormulaDependencyResultMutation> = {
|
||||
id: 'formula.mutation.set-query-formula-dependency-result',
|
||||
type: CommandType.MUTATION,
|
||||
handler: () => true,
|
||||
};
|
||||
|
||||
@@ -16,7 +16,8 @@
|
||||
|
||||
import type { ICommandInfo } from '@univerjs/core';
|
||||
import type { ISetArrayFormulaDataMutationParams } from '../commands/mutations/set-array-formula-data.mutation';
|
||||
import type { ISetFormulaCalculationStartMutation, ISetFormulaDependencyCalculationMutation, ISetFormulaStringBatchCalculationMutation } from '../commands/mutations/set-formula-calculation.mutation';
|
||||
import type { ISetFormulaCalculationStartMutation, ISetFormulaDependencyCalculationMutation, ISetFormulaStringBatchCalculationMutation, ISetQueryFormulaDependencyMutation } from '../commands/mutations/set-formula-calculation.mutation';
|
||||
import type { IFormulaDependencyTreeJson } from '../engine/dependency/dependency-tree';
|
||||
import type { IFormulaDirtyData } from '../services/current-data.service';
|
||||
import type { IAllRuntimeData } from '../services/runtime.service';
|
||||
import { Disposable, ICommandService, Inject } from '@univerjs/core';
|
||||
@@ -33,6 +34,8 @@ import {
|
||||
SetFormulaDependencyCalculationResultMutation,
|
||||
SetFormulaStringBatchCalculationMutation,
|
||||
SetFormulaStringBatchCalculationResultMutation,
|
||||
SetQueryFormulaDependencyMutation,
|
||||
SetQueryFormulaDependencyResultMutation,
|
||||
} from '../commands/mutations/set-formula-calculation.mutation';
|
||||
import { SetImageFormulaDataMutation } from '../commands/mutations/set-image-formula-data.mutation';
|
||||
import { FormulaDataModel } from '../models/formula-data.model';
|
||||
@@ -79,6 +82,9 @@ export class CalculateController extends Disposable {
|
||||
this._generateAllDependencyTreeJson();
|
||||
} else if (command.id === SetCellFormulaDependencyCalculationMutation.id) {
|
||||
this._generateCellDependencyTreeJson(command.params as ISetFormulaDependencyCalculationMutation);
|
||||
} else if (command.id === SetQueryFormulaDependencyMutation.id) {
|
||||
const params = command.params as ISetQueryFormulaDependencyMutation;
|
||||
this._queryFormulaDependencyJson(params);
|
||||
}
|
||||
})
|
||||
);
|
||||
@@ -110,6 +116,26 @@ export class CalculateController extends Disposable {
|
||||
});
|
||||
}
|
||||
|
||||
private async _queryFormulaDependencyJson(param: ISetQueryFormulaDependencyMutation) {
|
||||
const { unitRanges, isInRange } = param;
|
||||
let result: IFormulaDependencyTreeJson[] = [];
|
||||
if (isInRange) {
|
||||
result = await this._calculateFormulaService.getInRangeFormulas(unitRanges);
|
||||
} else {
|
||||
result = await this._calculateFormulaService.getRangeDependents(unitRanges);
|
||||
}
|
||||
|
||||
this._commandService.executeCommand(
|
||||
SetQueryFormulaDependencyResultMutation.id,
|
||||
{
|
||||
result,
|
||||
},
|
||||
{
|
||||
onlyLocal: true,
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private async _generateAllDependencyTreeJson() {
|
||||
const result = await this._calculateFormulaService.getAllDependencyJson();
|
||||
|
||||
@@ -139,20 +165,10 @@ export class CalculateController extends Disposable {
|
||||
);
|
||||
}
|
||||
|
||||
private async _calculateFormulaString(params: ISetFormulaStringBatchCalculationMutation) {
|
||||
const formulaData = this._formulaDataModel.getFormulaData();
|
||||
const arrayFormulaCellData = this._formulaDataModel.getArrayFormulaCellData();
|
||||
// array formula range is used to check whether the newly added array formula conflicts with the existing array formula
|
||||
const arrayFormulaRange = this._formulaDataModel.getArrayFormulaRange();
|
||||
|
||||
const rowData = this._formulaDataModel.getHiddenRowsFiltered();
|
||||
|
||||
private async _calculateFormulaString(param: ISetFormulaStringBatchCalculationMutation) {
|
||||
const { formulas } = param;
|
||||
const result = await this._calculateFormulaService.executeFormulas(
|
||||
params.formulas,
|
||||
formulaData,
|
||||
arrayFormulaCellData,
|
||||
arrayFormulaRange,
|
||||
rowData
|
||||
formulas
|
||||
);
|
||||
|
||||
this._commandService.executeCommand(
|
||||
|
||||
@@ -35,6 +35,8 @@ import {
|
||||
SetFormulaDependencyCalculationResultMutation,
|
||||
SetFormulaStringBatchCalculationMutation,
|
||||
SetFormulaStringBatchCalculationResultMutation,
|
||||
SetQueryFormulaDependencyMutation,
|
||||
SetQueryFormulaDependencyResultMutation,
|
||||
} from '../commands/mutations/set-formula-calculation.mutation';
|
||||
import { SetFormulaDataMutation } from '../commands/mutations/set-formula-data.mutation';
|
||||
import { SetImageFormulaDataMutation } from '../commands/mutations/set-image-formula-data.mutation';
|
||||
@@ -84,6 +86,8 @@ export class FormulaController extends Disposable {
|
||||
SetFormulaCalculationStartMutation,
|
||||
SetFormulaStringBatchCalculationMutation,
|
||||
SetFormulaStringBatchCalculationResultMutation,
|
||||
SetQueryFormulaDependencyMutation,
|
||||
SetQueryFormulaDependencyResultMutation,
|
||||
SetFormulaCalculationStopMutation,
|
||||
SetFormulaCalculationNotificationMutation,
|
||||
SetFormulaCalculationResultMutation,
|
||||
|
||||
@@ -59,6 +59,8 @@ export interface IFormulaDependencyGenerator {
|
||||
generate(): Promise<IFormulaDependencyTree[]>;
|
||||
getAllDependencyJson(): Promise<IFormulaDependencyTreeJson[]>;
|
||||
getCellDependencyJson(unitId: string, sheetId: string, row: number, column: number): Promise<IFormulaDependencyTreeFullJson | undefined>;
|
||||
getRangeDependents(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]>;
|
||||
getInRangeFormulas(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]>;
|
||||
}
|
||||
|
||||
export const IFormulaDependencyGenerator = createIdentifier<IFormulaDependencyGenerator>('engine-formula.dependency-generator');
|
||||
@@ -1411,26 +1413,28 @@ export class FormulaDependencyGenerator extends Disposable {
|
||||
this._startFormulaDependencyTreeModel();
|
||||
|
||||
const treeModel = this._getFormulaDependencyTreeModel(tree);
|
||||
const formula = this._lexerTreeBuilder.moveFormulaRefOffset(
|
||||
tree.formula,
|
||||
tree.refOffsetX,
|
||||
tree.refOffsetY
|
||||
);
|
||||
treeModel.formula = formula;
|
||||
|
||||
const childIds = this._getDependencyTreeChildrenIds(tree);
|
||||
for (const childId of childIds) {
|
||||
const childTreeModel = this._getTreeModel(childId);
|
||||
const tree = this._getTreeById(treeId);
|
||||
if (!tree) {
|
||||
continue;
|
||||
}
|
||||
if (tree.isVirtual) {
|
||||
const formula = this._lexerTreeBuilder.moveFormulaRefOffset(
|
||||
tree.formula,
|
||||
tree.refOffsetX,
|
||||
tree.refOffsetY
|
||||
);
|
||||
childTreeModel.formula = formula;
|
||||
treeModel.formula = formula;
|
||||
}
|
||||
|
||||
const childIds = this._getDependencyTreeChildrenIds(tree);
|
||||
for (const childId of childIds) {
|
||||
const childTreeModel = this._getTreeModel(childId);
|
||||
const tree = this._getTreeById(childId);
|
||||
if (tree && tree.isVirtual) {
|
||||
const formula = this._lexerTreeBuilder.moveFormulaRefOffset(
|
||||
tree.formula,
|
||||
tree.refOffsetX,
|
||||
tree.refOffsetY
|
||||
);
|
||||
childTreeModel.formula = formula;
|
||||
}
|
||||
|
||||
treeModel.addChild(childTreeModel);
|
||||
}
|
||||
|
||||
@@ -1438,4 +1442,88 @@ export class FormulaDependencyGenerator extends Disposable {
|
||||
|
||||
return treeModel.toFullJson();
|
||||
}
|
||||
|
||||
async getRangeDependents(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]> {
|
||||
await this._initializeGenerateTreeList();
|
||||
|
||||
this._startFormulaDependencyTreeModel();
|
||||
|
||||
const treeIds = this._dependencyManagerService.searchDependency(unitRanges);
|
||||
const treeList: FormulaDependencyTreeModel[] = [];
|
||||
for (const treeId of treeIds) {
|
||||
const tree = this._getTreeById(treeId);
|
||||
if (!tree) {
|
||||
continue;
|
||||
}
|
||||
const treeModel = this._getFormulaDependencyTreeModel(tree);
|
||||
if (tree.isVirtual) {
|
||||
const formula = this._lexerTreeBuilder.moveFormulaRefOffset(
|
||||
tree.formula,
|
||||
tree.refOffsetX,
|
||||
tree.refOffsetY
|
||||
);
|
||||
treeModel.formula = formula;
|
||||
}
|
||||
treeList.push(treeModel);
|
||||
}
|
||||
|
||||
const resultsJson: IFormulaDependencyTreeJson[] = [];
|
||||
for (const result of treeList) {
|
||||
if (result) {
|
||||
resultsJson.push(result.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
this._endFormulaDependencyTreeModel();
|
||||
|
||||
return resultsJson;
|
||||
}
|
||||
|
||||
async getInRangeFormulas(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]> {
|
||||
const treeList = await this._getAllTreeList();
|
||||
const matchTreeList: IFormulaDependencyTree[] = [];
|
||||
for (const dependencyTree of treeList) {
|
||||
for (const unitRange of unitRanges) {
|
||||
const unitId = unitRange.unitId;
|
||||
const sheetId = unitRange.sheetId;
|
||||
if (dependencyTree.unitId !== unitId || dependencyTree.subUnitId !== sheetId) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const range = unitRange.range;
|
||||
|
||||
if (dependencyTree.inRangeData(unitRange.range)) {
|
||||
matchTreeList.push(dependencyTree);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
this._startFormulaDependencyTreeModel();
|
||||
|
||||
const results: FormulaDependencyTreeModel[] = [];
|
||||
for (const tree of matchTreeList) {
|
||||
const treeModel = this._getFormulaDependencyTreeModel(tree);
|
||||
if (tree.isVirtual) {
|
||||
const formula = this._lexerTreeBuilder.moveFormulaRefOffset(
|
||||
tree.formula,
|
||||
tree.refOffsetX,
|
||||
tree.refOffsetY
|
||||
);
|
||||
treeModel.formula = formula;
|
||||
}
|
||||
results[tree.treeId] = treeModel;
|
||||
}
|
||||
|
||||
const resultsJson: IFormulaDependencyTreeJson[] = [];
|
||||
for (const result of results) {
|
||||
if (result) {
|
||||
resultsJson.push(result.toJson());
|
||||
}
|
||||
}
|
||||
|
||||
this._endFormulaDependencyTreeModel();
|
||||
|
||||
return resultsJson;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type { ICommandInfo, IDisposable } from '@univerjs/core';
|
||||
import type { FormulaExecutedStateType, IExecutionInProgressParams, IFormulaDependencyTreeFullJson, IFormulaDependencyTreeJson, IFormulaExecuteResultMap, IFormulaStringMap, ISequenceNode, ISetCellFormulaDependencyCalculationResultMutation, ISetFormulaCalculationNotificationMutation, ISetFormulaCalculationStartMutation, ISetFormulaDependencyCalculationResultMutation, ISetFormulaStringBatchCalculationResultMutation } from '@univerjs/engine-formula';
|
||||
import type { ICommandInfo, IDisposable, IUnitRange } from '@univerjs/core';
|
||||
import type { FormulaExecutedStateType, IExecutionInProgressParams, IFormulaDependencyTreeFullJson, IFormulaDependencyTreeJson, IFormulaExecuteResultMap, IFormulaStringMap, ISequenceNode, ISetCellFormulaDependencyCalculationResultMutation, ISetFormulaCalculationNotificationMutation, ISetFormulaCalculationResultMutation, ISetFormulaCalculationStartMutation, ISetFormulaDependencyCalculationResultMutation, ISetFormulaStringBatchCalculationResultMutation } from '@univerjs/engine-formula';
|
||||
import { ICommandService, IConfigService, Inject, Injector } from '@univerjs/core';
|
||||
import { FBase } from '@univerjs/core/facade';
|
||||
import { ENGINE_FORMULA_CYCLE_REFERENCE_COUNT, GlobalComputingStatusService, LexerTreeBuilder, SetCellFormulaDependencyCalculationMutation, SetCellFormulaDependencyCalculationResultMutation, SetFormulaCalculationNotificationMutation, SetFormulaCalculationStartMutation, SetFormulaCalculationStopMutation, SetFormulaDependencyCalculationMutation, SetFormulaDependencyCalculationResultMutation, SetFormulaStringBatchCalculationMutation, SetFormulaStringBatchCalculationResultMutation } from '@univerjs/engine-formula';
|
||||
import { ENGINE_FORMULA_CYCLE_REFERENCE_COUNT, GlobalComputingStatusService, LexerTreeBuilder, SetCellFormulaDependencyCalculationMutation, SetCellFormulaDependencyCalculationResultMutation, SetFormulaCalculationNotificationMutation, SetFormulaCalculationResultMutation, SetFormulaCalculationStartMutation, SetFormulaCalculationStopMutation, SetFormulaDependencyCalculationMutation, SetFormulaDependencyCalculationResultMutation, SetFormulaStringBatchCalculationMutation, SetFormulaStringBatchCalculationResultMutation, SetQueryFormulaDependencyMutation, SetQueryFormulaDependencyResultMutation } from '@univerjs/engine-formula';
|
||||
import { filter, firstValueFrom, map, race, timer } from 'rxjs';
|
||||
|
||||
/**
|
||||
@@ -249,6 +249,120 @@ export class FFormula extends FBase {
|
||||
this._configService.setConfig(ENGINE_FORMULA_CYCLE_REFERENCE_COUNT, maxIteration);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listens for the moment when formula-calculation results are applied.
|
||||
*
|
||||
* This event fires after the engine completes a calculation cycle and
|
||||
* dispatches a `SetFormulaCalculationResultMutation`.
|
||||
* The callback is invoked during an idle frame to avoid blocking UI updates.
|
||||
*
|
||||
* @param {Function} callback - A function called with the calculation result payload
|
||||
* once the result-application mutation is emitted.
|
||||
* @returns {IDisposable} A disposable used to unsubscribe from the event.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const formulaEngine = univerAPI.getFormula();
|
||||
*
|
||||
* const dispose = formulaEngine.calculationResultApplied((result) => {
|
||||
* console.log('Calculation results applied:', result);
|
||||
* });
|
||||
*
|
||||
* // Later…
|
||||
* dispose.dispose();
|
||||
* ```
|
||||
*/
|
||||
calculationResultApplied(callback: (result: ISetFormulaCalculationResultMutation) => void): IDisposable {
|
||||
return this._commandService.onCommandExecuted((command: ICommandInfo) => {
|
||||
if (command.id !== SetFormulaCalculationResultMutation.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = command.params as ISetFormulaCalculationResultMutation;
|
||||
|
||||
if (params !== undefined) {
|
||||
requestIdleCallback(() => {
|
||||
callback(params);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits for formula-calculation results to be applied.
|
||||
*
|
||||
* This method resolves under three conditions:
|
||||
* 1. A real calculation runs and the engine emits a "calculation started" signal,
|
||||
* followed by a "calculation result applied" signal.
|
||||
* 2. No calculation actually starts within 500 ms — the method assumes there is
|
||||
* nothing to wait for and resolves automatically.
|
||||
* 3. A global 30 s timeout triggers, in which case the promise rejects.
|
||||
*
|
||||
* The API internally listens to both “calculation in progress” events and
|
||||
* “calculation result applied” events, ensuring it behaves correctly whether
|
||||
* formulas are recalculated or skipped due to cache/state.
|
||||
*
|
||||
* @returns {Promise<void>} A promise that resolves when calculation results are applied
|
||||
* or when no calculation occurs within the start-detection window.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const formulaEngine = univerAPI.getFormula();
|
||||
*
|
||||
* // Wait for formula updates to apply before reading values.
|
||||
* await formulaEngine.onCalculationResultApplied();
|
||||
*
|
||||
* const value = sheet.getRange("C24").getValue();
|
||||
* console.log("Updated value:", value);
|
||||
* ```
|
||||
*/
|
||||
onCalculationResultApplied(): Promise<void> {
|
||||
return new Promise((resolve, reject) => {
|
||||
let started = false;
|
||||
let finished = false;
|
||||
|
||||
// Global timeout: reject if the whole calculation hangs
|
||||
const mainTimer = setTimeout(() => {
|
||||
cleanup();
|
||||
reject(new Error('Calculation end timeout'));
|
||||
}, 30_000);
|
||||
|
||||
// Watchdog: if no "calculation started" signal is received within 500ms,
|
||||
// assume there is no real calculation running and resolve immediately.
|
||||
const startWatchdog = setTimeout(() => {
|
||||
if (!started) {
|
||||
cleanup();
|
||||
resolve();
|
||||
}
|
||||
}, 500);
|
||||
|
||||
// Listen for "calculation in progress" signal (stageInfo)
|
||||
const processingDisposable = this.calculationProcessing(() => {
|
||||
if (started) return;
|
||||
started = true;
|
||||
|
||||
// A start signal is received → no need for the watchdog anymore
|
||||
clearTimeout(startWatchdog);
|
||||
});
|
||||
|
||||
// Listen for the "calculation completed" signal
|
||||
const endDisposable = this.calculationResultApplied(() => {
|
||||
if (finished) return;
|
||||
finished = true;
|
||||
|
||||
cleanup();
|
||||
resolve();
|
||||
});
|
||||
|
||||
function cleanup(): void {
|
||||
clearTimeout(mainTimer);
|
||||
clearTimeout(startWatchdog);
|
||||
processingDisposable.dispose();
|
||||
endDisposable.dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a batch of formulas asynchronously and receive computed results.
|
||||
*
|
||||
@@ -417,4 +531,99 @@ export class FFormula extends FBase {
|
||||
disposable.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the full dependency trees for all formulas that *depend on* the
|
||||
* specified ranges. This triggers a local dependency-calculation command and
|
||||
* invokes the callback once the calculation completes.
|
||||
*
|
||||
* @param unitRanges An array of workbook/sheet ranges to query. Each range
|
||||
* includes:
|
||||
* - `unitId` The workbook ID.
|
||||
* - `sheetId` The sheet ID.
|
||||
* - `range` The row/column boundaries.
|
||||
*
|
||||
* @param callback A function invoked with an array of `IFormulaDependencyTreeJson`
|
||||
* results. Each entry represents a formula node and its parent/child
|
||||
* relationships within the dependency graph.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const formulaEngine = univerAPI.getFormula();
|
||||
*
|
||||
* // Query all formulas that depend on A1:B10 in Sheet1.
|
||||
* formulaEngine.getRangeDependents(
|
||||
* [{ unitId: 'workbook1', sheetId: 'sheet1', range: { startRow: 0, endRow: 9, startColumn: 0, endColumn: 1 } }],
|
||||
* (result) => {
|
||||
* console.log('Dependent formulas:', result);
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
getRangeDependents(unitRanges: IUnitRange[], callback: (result: IFormulaDependencyTreeJson[]) => void): void {
|
||||
this._commandService.executeCommand(SetQueryFormulaDependencyMutation.id, { unitRanges }, { onlyLocal: true });
|
||||
|
||||
const disposable = this._commandService.onCommandExecuted((command: ICommandInfo) => {
|
||||
if (command.id !== SetQueryFormulaDependencyResultMutation.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = command.params as ISetFormulaDependencyCalculationResultMutation;
|
||||
|
||||
if (params.result != null) {
|
||||
callback(params.result);
|
||||
}
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the dependency trees of all formulas *inside* the specified ranges.
|
||||
* Unlike `getRangeDependents`, this API only returns formulas whose definitions
|
||||
* physically reside within the queried ranges.
|
||||
*
|
||||
* Internally this triggers the same dependency-calculation command but with
|
||||
* `isInRange = true`, and the callback is invoked when the results are ready.
|
||||
*
|
||||
* @param unitRanges An array of workbook/sheet ranges defining the lookup
|
||||
* boundaries:
|
||||
* - `unitId` The workbook ID.
|
||||
* - `sheetId` The sheet ID.
|
||||
* - `range` The zero-based grid range.
|
||||
*
|
||||
* @param callback Receives an array of `IFormulaDependencyTreeJson` describing
|
||||
* every formula found in the provided ranges along with their parent/child
|
||||
* relationships.
|
||||
*
|
||||
* @example
|
||||
* ```ts
|
||||
* const formulaEngine = univerAPI.getFormula();
|
||||
*
|
||||
* // Query all formulas that lie within A1:D20 in Sheet1.
|
||||
* formulaEngine.getInRangeFormulas(
|
||||
* [{ unitId: 'workbook1', sheetId: 'sheet1', range: { startRow: 0, endRow: 19, startColumn: 0, endColumn: 3 } }],
|
||||
* (result) => {
|
||||
* console.log('Formulas inside range:', result);
|
||||
* }
|
||||
* );
|
||||
* ```
|
||||
*/
|
||||
getInRangeFormulas(unitRanges: IUnitRange[], callback: (result: IFormulaDependencyTreeJson[]) => void): void {
|
||||
this._commandService.executeCommand(SetQueryFormulaDependencyMutation.id, { unitRanges, isInRange: true }, { onlyLocal: true });
|
||||
|
||||
const disposable = this._commandService.onCommandExecuted((command: ICommandInfo) => {
|
||||
if (command.id !== SetQueryFormulaDependencyResultMutation.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
const params = command.params as ISetFormulaDependencyCalculationResultMutation;
|
||||
|
||||
if (params.result != null) {
|
||||
callback(params.result);
|
||||
}
|
||||
|
||||
disposable.dispose();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ export {
|
||||
type ISetFormulaDependencyCalculationMutation,
|
||||
type ISetFormulaDependencyCalculationResultMutation,
|
||||
type ISetFormulaStringBatchCalculationResultMutation,
|
||||
type ISetQueryFormulaDependencyResultMutation,
|
||||
SetCellFormulaDependencyCalculationMutation,
|
||||
SetCellFormulaDependencyCalculationResultMutation,
|
||||
SetFormulaCalculationNotificationMutation,
|
||||
@@ -72,6 +73,8 @@ export {
|
||||
SetFormulaDependencyCalculationResultMutation,
|
||||
SetFormulaStringBatchCalculationMutation,
|
||||
SetFormulaStringBatchCalculationResultMutation,
|
||||
SetQueryFormulaDependencyMutation,
|
||||
SetQueryFormulaDependencyResultMutation,
|
||||
} from './commands/mutations/set-formula-calculation.mutation';
|
||||
export { type ISetFormulaDataMutationParams, SetFormulaDataMutation } from './commands/mutations/set-formula-data.mutation';
|
||||
export { type ISetImageFormulaDataMutationParams, SetImageFormulaDataMutation } from './commands/mutations/set-image-formula-data.mutation';
|
||||
|
||||
@@ -18,9 +18,7 @@ import type { IUnitRange } from '@univerjs/core';
|
||||
import type { Observable } from 'rxjs';
|
||||
import type {
|
||||
IArrayFormulaRangeType,
|
||||
IArrayFormulaUnitCellType,
|
||||
IFeatureDirtyRangeType,
|
||||
IFormulaData,
|
||||
IFormulaDatasetConfig,
|
||||
IFormulaExecuteResultItem,
|
||||
IFormulaExecuteResultMap,
|
||||
@@ -74,9 +72,11 @@ export interface ICalculateFormulaService {
|
||||
execute(formulaDatasetConfig: IFormulaDatasetConfig): Promise<void>;
|
||||
stopFormulaExecution(): void;
|
||||
calculate(formulaString: string, transformSuffix?: boolean): void;
|
||||
executeFormulas(formulas: IFormulaStringMap, formulaData: IFormulaData, arrayFormulaCellData: IArrayFormulaUnitCellType, arrayFormulaRange: IArrayFormulaRangeType, rowData: IUnitRowData): Promise<IFormulaExecuteResultMap>;
|
||||
getAllDependencyJson(): Promise<IFormulaDependencyTreeJson[]>;
|
||||
getCellDependencyJson(unitId: string, sheetId: string, row: number, column: number): Promise<IFormulaDependencyTreeFullJson | undefined>;
|
||||
executeFormulas(formulas: IFormulaStringMap, rowData?: IUnitRowData): Promise<IFormulaExecuteResultMap>;
|
||||
getAllDependencyJson(rowData?: IUnitRowData): Promise<IFormulaDependencyTreeJson[]>;
|
||||
getCellDependencyJson(unitId: string, sheetId: string, row: number, column: number, rowData?: IUnitRowData): Promise<IFormulaDependencyTreeFullJson | undefined>;
|
||||
getRangeDependents(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]>;
|
||||
getInRangeFormulas(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]>;
|
||||
}
|
||||
|
||||
export const ICalculateFormulaService = createIdentifier<ICalculateFormulaService>('engine-formula.calculate-formula.service');
|
||||
@@ -378,11 +378,8 @@ export class CalculateFormulaService extends Disposable implements ICalculateFor
|
||||
return this._runtimeService.getAllRuntimeData();
|
||||
}
|
||||
|
||||
async executeFormulas(formulas: IFormulaStringMap, formulaData: IFormulaData, arrayFormulaCellData: IArrayFormulaUnitCellType, arrayFormulaRange: IArrayFormulaRangeType, rowData?: IUnitRowData) {
|
||||
async executeFormulas(formulas: IFormulaStringMap, rowData?: IUnitRowData) {
|
||||
this._currentConfigService.loadDataLite(
|
||||
formulaData,
|
||||
arrayFormulaCellData,
|
||||
arrayFormulaRange,
|
||||
rowData
|
||||
);
|
||||
|
||||
@@ -515,10 +512,22 @@ export class CalculateFormulaService extends Disposable implements ICalculateFor
|
||||
}
|
||||
|
||||
async getAllDependencyJson(): Promise<IFormulaDependencyTreeJson[]> {
|
||||
this._currentConfigService.loadDataLite();
|
||||
return this._formulaDependencyGenerator.getAllDependencyJson();
|
||||
}
|
||||
|
||||
async getCellDependencyJson(unitId: string, sheetId: string, row: number, column: number): Promise<IFormulaDependencyTreeFullJson | undefined> {
|
||||
this._currentConfigService.loadDataLite();
|
||||
return this._formulaDependencyGenerator.getCellDependencyJson(unitId, sheetId, row, column);
|
||||
}
|
||||
|
||||
async getRangeDependents(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]> {
|
||||
this._currentConfigService.loadDataLite();
|
||||
return this._formulaDependencyGenerator.getRangeDependents(unitRanges);
|
||||
}
|
||||
|
||||
async getInRangeFormulas(unitRanges: IUnitRange[]): Promise<IFormulaDependencyTreeJson[]> {
|
||||
this._currentConfigService.loadDataLite();
|
||||
return this._formulaDependencyGenerator.getInRangeFormulas(unitRanges);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
import type { IUnitRange, LocaleType, Nullable, Workbook } from '@univerjs/core';
|
||||
import type {
|
||||
IArrayFormulaRangeType,
|
||||
IArrayFormulaUnitCellType,
|
||||
IDirtyUnitFeatureMap,
|
||||
IDirtyUnitOtherFormulaMap,
|
||||
IDirtyUnitSheetDefinedNameMap,
|
||||
@@ -115,7 +114,7 @@ export interface IFormulaCurrentConfigService {
|
||||
|
||||
setSheetNameMap(sheetIdToNameMap: IUnitSheetIdToNameMap): void;
|
||||
|
||||
loadDataLite(formulaData: IFormulaData, arrayFormulaCellData: IArrayFormulaUnitCellType, arrayFormulaRange: IArrayFormulaRangeType, rowData?: IUnitRowData): void;
|
||||
loadDataLite(rowData?: IUnitRowData): void;
|
||||
}
|
||||
|
||||
export class FormulaCurrentConfigService extends Disposable implements IFormulaCurrentConfigService {
|
||||
@@ -348,7 +347,7 @@ export class FormulaCurrentConfigService extends Disposable implements IFormulaC
|
||||
this._mergeNameMap(this._sheetNameMap, this._dirtyNameMap);
|
||||
}
|
||||
|
||||
loadDataLite(formulaData: IFormulaData, arrayFormulaCellData: IArrayFormulaUnitCellType, arrayFormulaRange: IArrayFormulaRangeType, rowData?: IUnitRowData) {
|
||||
loadDataLite(rowData?: IUnitRowData) {
|
||||
const { allUnitData, unitSheetNameMap, unitStylesData } = this._loadSheetData();
|
||||
|
||||
this._unitData = allUnitData;
|
||||
@@ -357,11 +356,9 @@ export class FormulaCurrentConfigService extends Disposable implements IFormulaC
|
||||
|
||||
this._sheetNameMap = unitSheetNameMap;
|
||||
|
||||
this._formulaData = formulaData;
|
||||
|
||||
this._arrayFormulaCellData = convertUnitDataToRuntime(arrayFormulaCellData);
|
||||
|
||||
this._arrayFormulaRange = arrayFormulaRange;
|
||||
this._formulaData = this._formulaDataModel.getFormulaData();
|
||||
this._arrayFormulaCellData = convertUnitDataToRuntime(this._formulaDataModel.getArrayFormulaCellData());
|
||||
this._arrayFormulaRange = this._formulaDataModel.getArrayFormulaRange();
|
||||
|
||||
// apply row data, including rows hidden by filters
|
||||
rowData && this._applyUnitRowData(rowData);
|
||||
|
||||
Reference in New Issue
Block a user