Skip to content

Commit

Permalink
feat(formula): supports numfmt
Browse files Browse the repository at this point in the history
  • Loading branch information
Dushusir committed Jan 30, 2024
1 parent 5353a03 commit 87c82d6
Show file tree
Hide file tree
Showing 22 changed files with 405 additions and 58 deletions.
3 changes: 1 addition & 2 deletions packages/engine-formula/src/basics/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ export interface IOtherFormulaData {
}

export interface INumfmtItemMap {
[unitId: string]: Nullable<{ [sheetId: string]: IObjectMatrixPrimitiveType<string> }>;
[unitId: string]: Nullable<{ [sheetId: string]: IObjectMatrixPrimitiveType<Nullable<string>> }>;
}

/**
Expand All @@ -113,7 +113,6 @@ export interface IFormulaDataItem {
x?: number; // Offset from x direction
y?: number; // Offset from y direction
si?: string; // formulaId,
p?: string; // number format
// row: number;
// column: number;
// sheetId: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* Copyright 2023-present DreamNum Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import type { IMutation } from '@univerjs/core';
import { CommandType } from '@univerjs/core';
import type { IAccessor } from '@wendellhu/redi';

import type { INumfmtItemMap } from '../../basics/common';
import { FormulaDataModel } from '../../models/formula-data.model';

export interface ISetNumfmtFormulaDataMutationParams {
numfmtItemMap: INumfmtItemMap;
}

export const SetNumfmtFormulaDataMutation: IMutation<ISetNumfmtFormulaDataMutationParams> = {
id: 'formula.mutation.set-numfmt-formula-data',
type: CommandType.MUTATION,
handler: (accessor: IAccessor, params: ISetNumfmtFormulaDataMutationParams) => {
const formulaDataModel = accessor.get(FormulaDataModel);
formulaDataModel.updateNumfmtItemMap(params.numfmtItemMap);
return true;
},
};
18 changes: 16 additions & 2 deletions packages/engine-formula/src/controller/calculate.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/

import type { ICommandInfo, IUnitRange } from '@univerjs/core';
import { Disposable, ICommandService, IUniverInstanceService, LifecycleStages, OnLifecycle } from '@univerjs/core';
import { Disposable, ICommandService, IUniverInstanceService, LifecycleStages, OnLifecycle, Tools } from '@univerjs/core';
import { Inject } from '@wendellhu/redi';

import type { IDirtyUnitFeatureMap, IDirtyUnitSheetNameMap, IFormulaData, INumfmtItemMap } from '../basics/common';
Expand All @@ -34,6 +34,7 @@ import { FormulaDataModel } from '../models/formula-data.model';
import { CalculateFormulaService } from '../services/calculate-formula.service';
import type { IAllRuntimeData } from '../services/runtime.service';
import { FormulaExecutedStateType } from '../services/runtime.service';
import { SetNumfmtFormulaDataMutation } from '../commands/mutations/set-numfmt-formula-data.mutation';

@OnLifecycle(LifecycleStages.Ready, CalculateController)
export class CalculateController extends Disposable {
Expand Down Expand Up @@ -188,7 +189,7 @@ export class CalculateController extends Disposable {
}

private async _applyFormula(data: IAllRuntimeData) {
const { unitData, unitOtherData, arrayFormulaRange, arrayFormulaCellData, clearArrayFormulaCellData } = data;
const { unitData, unitOtherData, arrayFormulaRange, arrayFormulaCellData, clearArrayFormulaCellData, numfmtItemMap } = data;

if (!unitData) {
console.error('No sheetData from Formula Engine!');
Expand Down Expand Up @@ -217,6 +218,19 @@ export class CalculateController extends Disposable {
);
}

// Synchronous to the main thread
if (!Tools.isEmptyObject(numfmtItemMap)) {
this._commandService.executeCommand(
SetNumfmtFormulaDataMutation.id,
{
numfmtItemMap,
},
{
onlyLocal: true,
}
);
}

this._commandService.executeCommand(
SetFormulaCalculationResultMutation.id,
{
Expand Down
2 changes: 2 additions & 0 deletions packages/engine-formula/src/controller/formula.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ import { functionText } from '../functions/text/function-map';
import { functionUniver } from '../functions/univer/function-map';
import { functionWeb } from '../functions/web/function-map';
import { IFunctionService } from '../services/function.service';
import { SetNumfmtFormulaDataMutation } from '../commands/mutations/set-numfmt-formula-data.mutation';

@OnLifecycle(LifecycleStages.Ready, FormulaController)
export class FormulaController extends Disposable {
Expand Down Expand Up @@ -85,6 +86,7 @@ export class FormulaController extends Disposable {
SetFormulaCalculationStopMutation,
SetFormulaCalculationNotificationMutation,
SetFormulaCalculationResultMutation,
SetNumfmtFormulaDataMutation,

SetDefinedNameMutation,
RemoveDefinedNameMutation,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ describe('Test indirect', () => {
formulaData: {},
arrayFormulaCellData: {},
forceCalculate: false,
numfmtItemMap: {},
dirtyRanges: [],
dirtyNameMap: {},
dirtyUnitFeatureMap: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ export class BaseReferenceObject extends ObjectClassType {
return callback(new ErrorValueObject(ErrorType.VALUE), startRow, startColumn);
}

const unitId = this._forcedUnitId || this._defaultUnitId;
const sheetId = this._forcedSheetId || this._defaultSheetId;

for (let r = startRow; r <= endRow; r++) {
for (let c = startColumn; c <= endColumn; c++) {
if (r < 0 || c < 0) {
Expand All @@ -160,6 +163,9 @@ export class BaseReferenceObject extends ObjectClassType {

const resultObjectValue = this.getCellValueObject(cell);

const pattern = this._numfmtItemData[unitId]?.[sheetId]?.[r]?.[c];
pattern && resultObjectValue.setPattern(pattern);

result = callback(resultObjectValue, r, c);

if (result === false) {
Expand All @@ -177,7 +183,15 @@ export class BaseReferenceObject extends ObjectClassType {
return new NumberValueObject(0, true);
}

return this.getCellValueObject(cell);
const cellValueObject = this.getCellValueObject(cell);

// Set numfmt pattern
const unitId = this._forcedUnitId || this._defaultUnitId;
const sheetId = this._forcedSheetId || this._defaultSheetId;
const numfmtItem = this._numfmtItemData[unitId]?.[sheetId]?.[startRow]?.[startColumn];
numfmtItem && cellValueObject.setPattern(numfmtItem);

return cellValueObject;
}

getRangeData() {
Expand Down Expand Up @@ -290,7 +304,7 @@ export class BaseReferenceObject extends ObjectClassType {
this._runtimeFeatureCellData = unitData;
}

getNmfmtItemData() {
getNumfmtItemData() {
return this._numfmtItemData;
}

Expand Down Expand Up @@ -471,10 +485,6 @@ export class BaseReferenceObject extends ObjectClassType {
}

arrayValueList[row][column] = valueObject;

if (rowIndex === startRow && columnIndex === startColumn) {
return false;
}
});

const arrayValueObjectData: IArrayValueObject = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@ export class CellReferenceObject extends BaseReferenceObject {

rangeReferenceObject.setRuntimeData(this.getRuntimeData());

rangeReferenceObject.setNumfmtItemData(this.getNumfmtItemData());

rangeReferenceObject.setArrayFormulaCellData(this.getArrayFormulaCellData());

rangeReferenceObject.setRuntimeArrayFormulaCellData(this.getRuntimeArrayFormulaCellData());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,9 @@ export class NumberValueObject extends BaseValueObject {
return this;
}

// Set number format
object.setPattern(this.getPattern() || valueObject.getPattern());

return object;
}

Expand All @@ -418,14 +421,22 @@ export class NumberValueObject extends BaseValueObject {
return this;
}

// Set number format
object.setPattern(this.getPattern() || valueObject.getPattern());

return object;
}

override multiply(valueObject: BaseValueObject): BaseValueObject {
if (valueObject.isArray()) {
return valueObject.multiply(this);
}
return this.multiplyBy(valueObject.getValue());
const object = this.multiplyBy(valueObject.getValue());

// Set number format
object.setPattern(this.getPattern() || valueObject.getPattern());

return object;
}

override divided(valueObject: BaseValueObject): BaseValueObject {
Expand All @@ -436,7 +447,12 @@ export class NumberValueObject extends BaseValueObject {
}
return (o as BaseValueObject).multiply(this);
}
return this.dividedBy(valueObject.getValue());
const object = this.dividedBy(valueObject.getValue());

// Set number format
object.setPattern(this.getPattern() || valueObject.getPattern());

return object;
}

override concatenateFront(valueObject: BaseValueObject): BaseValueObject {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ describe('Test indirect', () => {
formulaData: {},
arrayFormulaCellData: {},
forceCalculate: false,
numfmtItemMap: {},
dirtyRanges: [],
dirtyNameMap: {},
dirtyUnitFeatureMap: {},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ describe('Test offset', () => {
formulaData: {},
arrayFormulaCellData: {},
forceCalculate: false,
numfmtItemMap: {},
dirtyRanges: [],
dirtyNameMap: {},
dirtyUnitFeatureMap: {},
Expand Down
2 changes: 2 additions & 0 deletions packages/engine-formula/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,3 +135,5 @@ export { IFunctionService } from './services/function.service';
export { type IOtherFormulaManagerService, OtherFormulaManagerService } from './services/other-formula-manager.service';
export { FormulaExecuteStageType, type IExecutionInProgressParams } from './services/runtime.service';
export { FormulaExecutedStateType, type IAllRuntimeData } from './services/runtime.service';
export { SetNumfmtFormulaDataMutation } from './commands/mutations/set-numfmt-formula-data.mutation';
export type { ISetNumfmtFormulaDataMutationParams } from './commands/mutations/set-numfmt-formula-data.mutation';
87 changes: 83 additions & 4 deletions packages/engine-formula/src/models/formula-data.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import type {
IArrayFormulaUnitCellType,
IFormulaData,
IFormulaDataItem,
INumfmtItemMap,
IRuntimeUnitDataType,
ISheetData,
IUnitData,
Expand All @@ -43,6 +44,9 @@ export class FormulaDataModel extends Disposable {

private _arrayFormulaCellData: IArrayFormulaUnitCellType = {};

// TODO@Dushusir: Determine the node.js environment and synchronize to the resource plugin when SSC is used
private _numfmtItemMap: INumfmtItemMap = {};

constructor(
@IUniverInstanceService private readonly _currentUniverService: IUniverInstanceService,
@Inject(LexerTreeBuilder) private readonly _lexerTreeBuilder: LexerTreeBuilder
Expand Down Expand Up @@ -161,20 +165,55 @@ export class FormulaDataModel extends Disposable {
this._formulaData = value;
}

getArrayFormulaRange(): IArrayFormulaRangeType {
return this._arrayFormulaRange;
}

setArrayFormulaRange(value: IArrayFormulaRangeType) {
this._arrayFormulaRange = value;
}

getArrayFormulaRange(): IArrayFormulaRangeType {
return this._arrayFormulaRange;
getArrayFormulaCellData() {
return this._arrayFormulaCellData;
}

setArrayFormulaCellData(value: IArrayFormulaUnitCellType) {
this._arrayFormulaCellData = value;
}

getArrayFormulaCellData() {
return this._arrayFormulaCellData;
getNumfmtItemMap() {
return this._numfmtItemMap;
}

updateNumfmtItemMap(value: INumfmtItemMap) {
Object.keys(value).forEach((unitId) => {
const sheetData = value[unitId];

if (sheetData == null) {
return true;
}

if (this._numfmtItemMap[unitId] == null) {
this._numfmtItemMap[unitId] = {};
}

Object.keys(sheetData).forEach((sheetId) => {
const numfmtItemMap = sheetData[sheetId];
const numfmtItemMatrix = new ObjectMatrix(numfmtItemMap);

if (this._numfmtItemMap[unitId]![sheetId] == null) {
this._numfmtItemMap[unitId]![sheetId] = {};
}

numfmtItemMatrix.forValue((r, c, numfmtItem) => {
if (this._numfmtItemMap[unitId]![sheetId][r] == null) {
this._numfmtItemMap[unitId]![sheetId][r] = {};
}

this._numfmtItemMap[unitId]![sheetId][r][c] = numfmtItem;
});
});
});
}

mergeArrayFormulaRange(formulaData: IArrayFormulaRangeType) {
Expand Down Expand Up @@ -450,6 +489,46 @@ export class FormulaDataModel extends Disposable {
});
}

updateNumfmtData(
unitId: string,
sheetId: string,
cellValue: IObjectMatrixPrimitiveType<Nullable<ICellData>>
) {
// remove the array formula range when cell value is null

const arrayFormulaRange = this._arrayFormulaRange[unitId]?.[sheetId];
const arrayFormulaRangeMatrix = new ObjectMatrix(arrayFormulaRange);

const numfmtData = this._numfmtItemMap[unitId]?.[sheetId];

if (!numfmtData) return;

const numfmtDataMatrix = new ObjectMatrix(numfmtData);

const cellMatrix = new ObjectMatrix(cellValue);
cellMatrix.forValue((r, c, cell) => {
const formulaString = cell?.f || '';
const formulaId = cell?.si || '';

const checkFormulaString = isFormulaString(formulaString);
const checkFormulaId = isFormulaId(formulaId);

if (!checkFormulaString && !checkFormulaId) {
numfmtDataMatrix.setValue(r, c, null);

const arrayFormulaRangeValue = arrayFormulaRangeMatrix.getValue(r, c);
if (arrayFormulaRangeValue) {
const { startRow, startColumn, endRow, endColumn } = arrayFormulaRangeValue;
for (let row = startRow; row <= endRow; row++) {
for (let column = startColumn; column <= endColumn; column++) {
numfmtDataMatrix.setValue(row, column, null);
}
}
}
}
});
}

getFormulaItemBySId(sId: string, sheetId: string, unitId: string): Nullable<IFormulaDataItem> {
const formulaData = this._formulaData;
if (formulaData[unitId] == null) {
Expand Down
Loading

0 comments on commit 87c82d6

Please sign in to comment.