Skip to content

Commit

Permalink
fix(formula): get hidden rows by filter
Browse files Browse the repository at this point in the history
  • Loading branch information
Dushusir committed Dec 6, 2024
1 parent fdb0f37 commit 9a12f92
Show file tree
Hide file tree
Showing 9 changed files with 114 additions and 84 deletions.
5 changes: 5 additions & 0 deletions packages/engine-formula/src/basics/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,10 @@ export interface IUnitExcludedCell {
[unitId: string]: Nullable<{ [sheetId: string]: ObjectMatrix<boolean> }>;
}

export interface IUnitRowData {
[unitId: string]: Nullable<{ [sheetId: string]: IObjectArrayPrimitiveType<Partial<IRowData>> }>;
}

export interface IFormulaDatasetConfig {
formulaData: IFormulaData;
arrayFormulaCellData: IArrayFormulaUnitCellType;
Expand All @@ -190,6 +194,7 @@ export interface IFormulaDatasetConfig {
allUnitData?: IUnitData;
unitStylesData?: IUnitStylesData;
unitSheetNameMap?: IUnitSheetNameMap;
rowData?: IUnitRowData; // Include rows hidden by filters
}

export enum ConcatenateType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export class CalculateController extends Disposable {
private async _calculate(
formulaDirtyData: Partial<IFormulaDirtyData>
) {
const { forceCalculation: forceCalculate = false, dirtyRanges = [], dirtyNameMap = {}, dirtyDefinedNameMap = {}, dirtyUnitFeatureMap = {}, dirtyUnitOtherFormulaMap = {}, clearDependencyTreeCache = {} } = formulaDirtyData;
const { forceCalculation: forceCalculate = false, dirtyRanges = [], dirtyNameMap = {}, dirtyDefinedNameMap = {}, dirtyUnitFeatureMap = {}, dirtyUnitOtherFormulaMap = {}, clearDependencyTreeCache = {}, rowData } = formulaDirtyData;

const formulaData = this._formulaDataModel.getFormulaData();

Expand All @@ -96,6 +96,7 @@ export class CalculateController extends Disposable {
dirtyUnitFeatureMap,
dirtyUnitOtherFormulaMap,
clearDependencyTreeCache,
rowData,
});
}

Expand Down
1 change: 1 addition & 0 deletions packages/engine-formula/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,3 +168,4 @@ export { ENGINE_FORMULA_PLUGIN_CONFIG_KEY, type IUniverEngineFormulaConfig } fro

export { generateRandomDependencyTreeId } from './engine/dependency/formula-dependency';
export { DependencyManagerBaseService } from './services/dependency-manager.service';
export { type IUnitRowData } from './basics/common';
48 changes: 46 additions & 2 deletions packages/engine-formula/src/models/formula-data.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import type { ICellData, IObjectMatrixPrimitiveType, IRange, IUnitRange, Nullable, Workbook } from '@univerjs/core';
import type { ICellData, IObjectArrayPrimitiveType, IObjectMatrixPrimitiveType, IRange, IRowData, IUnitRange, Nullable, Workbook } from '@univerjs/core';
import type {
IArrayFormulaRangeType,
IArrayFormulaUnitCellType,
Expand All @@ -24,10 +24,12 @@ import type {
IRuntimeUnitDataType,
ISheetData,
IUnitData,
IUnitRowData,
IUnitSheetNameMap,
IUnitStylesData,
} from '../basics/common';

import { Disposable, Inject, isFormulaId, isFormulaString, IUniverInstanceService, ObjectMatrix, RANGE_TYPE, UniverInstanceType } from '@univerjs/core';
import { BooleanNumber, Disposable, Inject, isFormulaId, isFormulaString, IUniverInstanceService, ObjectMatrix, RANGE_TYPE, UniverInstanceType } from '@univerjs/core';
import { LexerTreeBuilder } from '../engine/analysis/lexer-tree-builder';
import { clearArrayFormulaCellDataByCell, updateFormulaDataByCellValue } from './utils/formula-data-util';

Expand Down Expand Up @@ -258,6 +260,8 @@ export class FormulaDataModel extends Disposable {

const allUnitData: IUnitData = {};

const unitStylesData: IUnitStylesData = {};

const unitSheetNameMap: IUnitSheetNameMap = {};

for (const workbook of unitAllSheet) {
Expand Down Expand Up @@ -287,15 +291,55 @@ export class FormulaDataModel extends Disposable {

allUnitData[unitId] = sheetData;

unitStylesData[unitId] = workbook.getStyles();

unitSheetNameMap[unitId] = sheetNameMap;
}

return {
allUnitData,
unitStylesData,
unitSheetNameMap,
};
}

/**
* Get the hidden rows that are filtered or manually hidden.
*
* For formulas that are sensitive to hidden rows.
*/
getHiddenRowsFiltered() {
const unitAllSheet = this._univerInstanceService.getAllUnitsForType<Workbook>(UniverInstanceType.UNIVER_SHEET);
const rowData: IUnitRowData = {};

for (const workbook of unitAllSheet) {
const unitId = workbook.getUnitId();
const sheets = workbook.getSheets();
rowData[unitId] = {};

for (const sheet of sheets) {
const sheetId = sheet.getSheetId();
rowData[unitId][sheetId] = {};

const startRow = 0;
const endRow = sheet.getRowCount() - 1;
const sheetRowData: IObjectArrayPrimitiveType<Partial<IRowData>> = {};

for (let i = startRow; i <= endRow; i++) {
if (!sheet.getRowVisible(i)) {
sheetRowData[i] = {
hd: BooleanNumber.TRUE,
};
}
}

rowData[unitId][sheetId] = sheetRowData;
}
}

return rowData;
}

updateFormulaData(unitId: string, sheetId: string, cellValue: IObjectMatrixPrimitiveType<Nullable<ICellData>>) {
const cellMatrix = new ObjectMatrix(cellValue);

Expand Down
103 changes: 40 additions & 63 deletions packages/engine-formula/src/services/current-data.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
* limitations under the License.
*/

import type { IObjectArrayPrimitiveType, IRowData, IUnitRange, LocaleType, Nullable, Workbook, Worksheet } from '@univerjs/core';
import type { IUnitRange, LocaleType, Nullable, Workbook } from '@univerjs/core';
import type {
IArrayFormulaRangeType,
IDirtyUnitFeatureMap,
Expand All @@ -24,16 +24,17 @@ import type {
IFormulaData,
IFormulaDatasetConfig,
IRuntimeUnitDataType,
ISheetData,
IUnitData,
IUnitExcludedCell,
IUnitRowData,
IUnitSheetIdToNameMap,
IUnitSheetNameMap,
IUnitStylesData,
} from '../basics/common';

import { BooleanNumber, createIdentifier, Disposable, Inject, IUniverInstanceService, LocaleService, ObjectMatrix, UniverInstanceType } from '@univerjs/core';
import { createIdentifier, Disposable, Inject, IUniverInstanceService, LocaleService, ObjectMatrix, UniverInstanceType } from '@univerjs/core';
import { convertUnitDataToRuntime } from '../basics/runtime';
import { FormulaDataModel } from '../models/formula-data.model';

export interface IFormulaDirtyData {
forceCalculation: boolean;
Expand All @@ -43,6 +44,7 @@ export interface IFormulaDirtyData {
dirtyUnitFeatureMap: IDirtyUnitFeatureMap;
dirtyUnitOtherFormulaMap: IDirtyUnitOtherFormulaMap;
clearDependencyTreeCache: IDirtyUnitSheetNameMap; // unitId -> sheetId
rowData?: IUnitRowData; // Include rows hidden by filters
}

export interface IFormulaCurrentConfigService {
Expand Down Expand Up @@ -143,7 +145,8 @@ export class FormulaCurrentConfigService extends Disposable implements IFormulaC

constructor(
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService,
@Inject(LocaleService) private readonly _localeService: LocaleService
@Inject(LocaleService) private readonly _localeService: LocaleService,
@Inject(FormulaDataModel) private readonly _formulaDataModel: FormulaDataModel
) {
super();
}
Expand Down Expand Up @@ -287,6 +290,11 @@ export class FormulaCurrentConfigService extends Disposable implements IFormulaC
this._sheetNameMap = unitSheetNameMap;
}

// apply row data, including rows hidden by filters
if (config.rowData) {
this._applyUnitRowData(config.rowData);
}

this._formulaData = config.formulaData;

this._arrayFormulaCellData = convertUnitDataToRuntime(config.arrayFormulaCellData);
Expand Down Expand Up @@ -449,81 +457,50 @@ export class FormulaCurrentConfigService extends Disposable implements IFormulaC
}

private _loadSheetData() {
const unitAllSheet = this._univerInstanceService.getAllUnitsForType<Workbook>(UniverInstanceType.UNIVER_SHEET);

const workbook = this._univerInstanceService.getCurrentUnitForType<Workbook>(UniverInstanceType.UNIVER_SHEET)!;
const worksheet = workbook?.getActiveSheet();

this._executeUnitId = workbook?.getUnitId();
this._executeSubUnitId = worksheet?.getSheetId();

const allUnitData: IUnitData = {};

const unitStylesData: IUnitStylesData = {};

const unitSheetNameMap: IUnitSheetNameMap = {};

for (const workbook of unitAllSheet) {
const unitId = workbook.getUnitId();
return this._formulaDataModel.getCalculateData();
}

const sheets = workbook.getSheets();
/**
* There is no filter information in the worker, it must be passed in from the main thread after it is ready
* @param rowData
*/
private _applyUnitRowData(rowData: IUnitRowData) {
for (const unitId in rowData) {
if (rowData[unitId] == null) {
continue;
}

const sheetData: ISheetData = {};
for (const sheetId in rowData[unitId]) {
if (rowData[unitId][sheetId] == null) {
continue;
}

const sheetNameMap: { [sheetName: string]: string } = {};
if (this._unitData[unitId] == null) {
this._unitData[unitId] = {};
}

for (const sheet of sheets) {
const sheetId = sheet.getSheetId();
if (this._unitData[unitId][sheetId] == null) {
this._unitData[unitId][sheetId] = {
cellData: new ObjectMatrix({}),
rowCount: 0,
columnCount: 0,
rowData: {},
columnData: {},
};
}

const sheetConfig = sheet.getConfig();
sheetData[sheetId] = {
cellData: new ObjectMatrix(sheetConfig.cellData),
rowCount: sheetConfig.rowCount,
columnCount: sheetConfig.columnCount,
rowData: getHiddenRowsFiltered(sheet),
columnData: sheetConfig.columnData,
defaultRowHeight: sheetConfig.defaultRowHeight,
defaultColumnWidth: sheetConfig.defaultColumnWidth,
};
sheetNameMap[sheet.getName()] = sheet.getSheetId();
this._unitData[unitId][sheetId].rowData = rowData[unitId][sheetId];
}

allUnitData[unitId] = sheetData;

unitStylesData[unitId] = workbook.getStyles();

unitSheetNameMap[unitId] = sheetNameMap;
}

return {
allUnitData,
unitStylesData,
unitSheetNameMap,
};
}
}

export const IFormulaCurrentConfigService = createIdentifier<FormulaCurrentConfigService>(
'univer.formula.current-data.service'
);

/**
* Get the hidden rows that are filtered or manually hidden.
*
* For formulas that are sensitive to hidden rows.
*/
function getHiddenRowsFiltered(sheet: Worksheet): IObjectArrayPrimitiveType<Partial<IRowData>> {
const startRow = 0;
const endRow = sheet.getRowCount() - 1;
const rowData: IObjectArrayPrimitiveType<Partial<IRowData>> = {};

for (let i = startRow; i <= endRow; i++) {
if (!sheet.getRowVisible(i)) {
rowData[i] = {
hd: BooleanNumber.TRUE,
};
}
}

return rowData;
}
14 changes: 3 additions & 11 deletions packages/sheets-filter/src/controllers/sheets-filter.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ import type { EffectRefRangeParams, IAddWorksheetMergeMutationParams, ICopySheet
import type { ISetSheetsFilterCriteriaMutationParams, ISetSheetsFilterRangeMutationParams } from '../commands/mutations/sheets-filter.mutation';
import type { FilterColumn } from '../models/filter-model';

import { Disposable, DisposableCollection, ICommandService, Inject, IUniverInstanceService, moveMatrixArray, Optional, Rectangle } from '@univerjs/core';
import { DataSyncPrimaryController } from '@univerjs/rpc';
import { Disposable, DisposableCollection, ICommandService, Inject, IUniverInstanceService, moveMatrixArray, Rectangle } from '@univerjs/core';
import { CopySheetCommand, EffectRefRangId, expandToContinuousRange, getSheetCommandTarget, InsertColCommand, InsertRowCommand, InsertRowMutation, INTERCEPTOR_POINT, MoveRangeCommand, MoveRowsCommand, RefRangeService, RemoveColCommand, RemoveRowCommand, RemoveRowMutation, RemoveSheetCommand, SetRangeValuesMutation, SetWorksheetActiveOperation, SheetInterceptorService } from '@univerjs/sheets';
import { ReCalcSheetsFilterMutation, RemoveSheetsFilterMutation, SetSheetsFilterCriteriaMutation, SetSheetsFilterRangeMutation } from '../commands/mutations/sheets-filter.mutation';
import { SheetsFilterService } from '../services/sheet-filter.service';
Expand All @@ -33,9 +32,7 @@ export class SheetsFilterController extends Disposable {
@Inject(SheetInterceptorService) private readonly _sheetInterceptorService: SheetInterceptorService,
@Inject(SheetsFilterService) private readonly _sheetsFilterService: SheetsFilterService,
@IUniverInstanceService private readonly _univerInstanceService: IUniverInstanceService,
@Inject(RefRangeService) private readonly _refRangeService: RefRangeService,
@Optional(DataSyncPrimaryController) private readonly _dataSyncPrimaryController?: DataSyncPrimaryController
) {
@Inject(RefRangeService) private readonly _refRangeService: RefRangeService) {
super();

this._initCommands();
Expand All @@ -51,12 +48,7 @@ export class SheetsFilterController extends Disposable {
SetSheetsFilterRangeMutation,
ReCalcSheetsFilterMutation,
RemoveSheetsFilterMutation,
].forEach((command) => {
this.disposeWithMe(this._commandService.registerCommand(command));

// Hidden rows after filtering affect formula calculation
this._dataSyncPrimaryController?.registerSyncingMutations(command);
});
].forEach((command) => this.disposeWithMe(this._commandService.registerCommand(command)));
}

private _initInterceptors(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export class SheetsFilterFormulaService extends Disposable {

const { startRow, endRow } = range;

// covert range to dirtyRanges
// covert hidden rows to dirtyRanges
const dirtyRanges = [{
unitId,
sheetId: subUnitId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import type {
IExecutionInProgressParams,
IFormulaDirtyData,
ISetFormulaCalculationNotificationMutation,
ISetFormulaCalculationStartMutation,
} from '@univerjs/engine-formula';
ISetFormulaCalculationStartMutation } from '@univerjs/engine-formula';
import type { ISetRangeValuesMutationParams } from '@univerjs/sheets';
import type { IUniverSheetsFormulaBaseConfig } from './config.schema';
import { Disposable, ICommandService, IConfigService, ILogService, Inject, LocaleService } from '@univerjs/core';
Expand Down Expand Up @@ -164,6 +163,17 @@ export class TriggerCalculationController extends Disposable {
}

private _commandExecutedListener() {
// The filtering information is not synchronized to the worker and must be passed in from the main thread each time
this.disposeWithMe(
this._commandService.beforeCommandExecuted((command: ICommandInfo) => {
if (command.id === SetFormulaCalculationStartMutation.id) {
const params = command.params as ISetFormulaCalculationStartMutation;

params.rowData = this._formulaDataModel.getHiddenRowsFiltered();
}
})
);

this.disposeWithMe(
this._commandService.onCommandExecuted((command: ICommandInfo, options) => {
if (!this._activeDirtyManagerService.get(command.id)) {
Expand Down Expand Up @@ -512,13 +522,13 @@ export class TriggerCalculationController extends Disposable {
}

private _initialExecuteFormula() {
const params = this._getDiryDataByCalculationMode(this._calculationMode);
const params = this._getDirtyDataByCalculationMode(this._calculationMode);
this._commandService.executeCommand(SetFormulaCalculationStartMutation.id, params, lo);

this._registerOtherFormulaService.calculateStarted$.next(true);
}

private _getDiryDataByCalculationMode(calculationMode: CalculationMode): IFormulaDirtyData {
private _getDirtyDataByCalculationMode(calculationMode: CalculationMode): IFormulaDirtyData {
const forceCalculation = calculationMode === CalculationMode.FORCED;

// loop all sheets cell data, and get the dirty data
Expand Down
Loading

0 comments on commit 9a12f92

Please sign in to comment.