Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(formula): remove non-existent formula ids #2531

Merged
merged 5 commits into from
Jun 21, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fix(formula): address returns array value
  • Loading branch information
Dushusir committed Jun 19, 2024
commit c4c63c39c97ef86bbcf5d27d7da19ebafff23561
Original file line number Diff line number Diff line change
Expand Up @@ -25,17 +25,19 @@ import {
} from '../../../../engine/value-object/primitive-object';
import { FUNCTION_NAMES_LOOKUP } from '../../function-names';
import { Address } from '../index';
import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object';
import { getObjectValue } from '../../../__tests__/create-function-test-bed';

describe('Test address', () => {
const textFunction = new Address(FUNCTION_NAMES_LOOKUP.ADDRESS);
const testFunction = new Address(FUNCTION_NAMES_LOOKUP.ADDRESS);
const calculate = (row: number, column: number, abs?: number, a1?: boolean, sheet?: string) => {
const rowNumber = NumberValueObject.create(row);
const columnNumber = NumberValueObject.create(column);
const absNumber = abs ? NumberValueObject.create(abs) : undefined;
const absNumber = abs !== undefined ? NumberValueObject.create(abs) : undefined;
const a1Value = a1 !== undefined ? BooleanValueObject.create(a1) : undefined;
const sheetText = sheet ? StringValueObject.create(sheet) : undefined;
const result = textFunction.calculate(rowNumber, columnNumber, absNumber, a1Value, sheetText);
return result.getValue();
const sheetText = sheet !== undefined ? StringValueObject.create(sheet) : undefined;
const result = testFunction.calculate(rowNumber, columnNumber, absNumber, a1Value, sheetText);
return (getObjectValue(result) as string[][])[0][0];
};

describe('Correct situations', () => {
Expand Down Expand Up @@ -66,12 +68,82 @@ describe('Test address', () => {
it('Absolute reference to another worksheet', async () => {
expect(calculate(2, 3, 1, false, 'EXCEL SHEET')).toBe("'EXCEL SHEET'!R2C3");
});
it('Abs less than 1', async () => {
expect(calculate(2, 3, 0, false, 'EXCEL SHEET')).toBe(ErrorType.VALUE);
});
it('Abs greater than 4', async () => {
expect(calculate(2, 3, 5, false, 'EXCEL SHEET')).toBe(ErrorType.VALUE);
});

it('Array parameter', async () => {
const rowNumber = ArrayValueObject.create({
calculateValueList: transformToValueObject([
[1],
[2],
[3],
]),
rowCount: 3,
columnCount: 1,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const columnNumber = ArrayValueObject.create({
calculateValueList: transformToValueObject([
[4, 5, 6],
]),
rowCount: 1,
columnCount: 3,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const absNumber = ArrayValueObject.create({
calculateValueList: transformToValueObject([
[2],
[3],
]),
rowCount: 2,
columnCount: 1,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const a1Value = ArrayValueObject.create({
calculateValueList: transformToValueObject([
[true, false],
]),
rowCount: 1,
columnCount: 2,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const sheetText = ArrayValueObject.create({
calculateValueList: transformToValueObject([
['Sheet1'],
['Sheet4'],
]),
rowCount: 2,
columnCount: 1,
unitId: '',
sheetId: '',
row: 0,
column: 0,
});
const result = testFunction.calculate(rowNumber, columnNumber, absNumber, a1Value, sheetText);
expect(transformToValue(result.getArrayValue())).toStrictEqual([['Sheet1!D$1', 'Sheet1!R1C[5]', '#N/A'], ['Sheet4!$D2', 'Sheet4!R[2]C5', '#N/A'], ['#N/A', '#N/A', '#N/A']]);
});
});

describe('Fault situations', () => {
it('Value error', async () => {
const error = ErrorValueObject.create(ErrorType.VALUE);
const errorValue = textFunction.calculate(error, error);
const errorValue = testFunction.calculate(error, error);
expect(errorValue.isError()).toBeTruthy();
});
});
Expand Down
81 changes: 73 additions & 8 deletions packages/engine-formula/src/functions/lookup/address/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,17 @@ import { ErrorType } from '../../../basics/error-type';
import { serializeRangeToR1C1 } from '../../../engine/utils/r1c1-reference';
import { needsQuoting, serializeRange } from '../../../engine/utils/reference';
import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object';
import { StringValueObject } from '../../../engine/value-object/primitive-object';
import { BooleanValueObject, NumberValueObject, StringValueObject } from '../../../engine/value-object/primitive-object';
import { BaseFunction } from '../../base-function';
import type { ArrayValueObject } from '../../../engine/value-object/array-value-object';
import { expandArrayValueObject } from '../../../engine/utils/array-object';

export class Address extends BaseFunction {
override minParams = 2;

override maxParams = 5;

// eslint-disable-next-line max-lines-per-function
override calculate(
rowNumber: BaseValueObject,
columnNumber: BaseValueObject,
Expand Down Expand Up @@ -55,18 +58,80 @@ export class Address extends BaseFunction {
return sheetText;
}

const row = Number(rowNumber.getValue()) - 1;
const column = Number(columnNumber.getValue()) - 1;
absNumber = absNumber ?? NumberValueObject.create(1);
a1 = a1 ?? BooleanValueObject.create(true);
sheetText = sheetText ?? StringValueObject.create('');

// get max row length
const maxRowLength = Math.max(
rowNumber.isArray() ? (rowNumber as ArrayValueObject).getRowCount() : 1,
columnNumber.isArray() ? (columnNumber as ArrayValueObject).getRowCount() : 1,
absNumber.isArray() ? (absNumber as ArrayValueObject).getRowCount() : 1,
a1.isArray() ? (a1 as ArrayValueObject).getRowCount() : 1,
sheetText.isArray() ? (sheetText as ArrayValueObject).getRowCount() : 1
);

// get max column length
const maxColumnLength = Math.max(
rowNumber.isArray() ? (rowNumber as ArrayValueObject).getColumnCount() : 1,
columnNumber.isArray() ? (columnNumber as ArrayValueObject).getColumnCount() : 1,
absNumber.isArray() ? (absNumber as ArrayValueObject).getColumnCount() : 1,
a1.isArray() ? (a1 as ArrayValueObject).getColumnCount() : 1,
sheetText.isArray() ? (sheetText as ArrayValueObject).getColumnCount() : 1
);

const rowNumArray = expandArrayValueObject(maxRowLength, maxColumnLength, rowNumber, ErrorValueObject.create(ErrorType.NA));
const columnNumArray = expandArrayValueObject(maxRowLength, maxColumnLength, columnNumber, ErrorValueObject.create(ErrorType.NA));
const absNumArray = expandArrayValueObject(maxRowLength, maxColumnLength, absNumber, ErrorValueObject.create(ErrorType.NA));
const a1Array = expandArrayValueObject(maxRowLength, maxColumnLength, a1, ErrorValueObject.create(ErrorType.NA));
const sheetTextArray = expandArrayValueObject(maxRowLength, maxColumnLength, sheetText, ErrorValueObject.create(ErrorType.NA));

return rowNumArray.map((rowNumValue, rowIndex, columnIndex) => {
const columnNumValue = columnNumArray.get(rowIndex, columnIndex) || ErrorValueObject.create(ErrorType.NA);
const absNumValue = absNumArray.get(rowIndex, columnIndex) || ErrorValueObject.create(ErrorType.NA);
const a1Value = a1Array.get(rowIndex, columnIndex) || ErrorValueObject.create(ErrorType.NA);
const sheetTextValue = sheetTextArray.get(rowIndex, columnIndex) || ErrorValueObject.create(ErrorType.NA);

if (rowNumValue.isError()) {
return rowNumValue;
}

if (columnNumValue.isError()) {
return columnNumValue;
}

if (absNumValue.isError()) {
return absNumValue;
}

if (a1Value.isError()) {
return a1Value;
}

if (sheetTextValue.isError()) {
return sheetTextValue;
}

return this._calculateSingleCell(rowNumValue, columnNumValue, absNumValue, a1Value, sheetTextValue);
});
}

if (Number.isNaN(row) || Number.isNaN(column)) {
private _calculateSingleCell(rowNumber: BaseValueObject,
columnNumber: BaseValueObject,
absNumber: BaseValueObject,
a1: BaseValueObject,
sheetText: BaseValueObject) {
const row = Number.parseInt(`${Number(rowNumber.getValue()) - 1}`);
const column = Number.parseInt(`${Number(columnNumber.getValue()) - 1}`);
const absNumberValue = Number.parseInt(`${Number(absNumber.getValue())}`);

if (Number.isNaN(row) || Number.isNaN(column) || Number.isNaN(absNumberValue) || absNumberValue < 1 || absNumberValue > 4) {
return ErrorValueObject.create(ErrorType.VALUE);
}

const absType = absNumber ? transformAbsoluteRefType(absNumber.getValue()) : AbsoluteRefType.ALL;

const absType = transformAbsoluteRefType(absNumberValue);
const a1Value = this.getZeroOrOneByOneDefault(a1);

const sheetTextValue = sheetText ? `${sheetText.getValue()}` : '';
const sheetTextValue = `${sheetText.getValue()}`;
const sheetName = needsQuoting(sheetTextValue) ? `'${sheetTextValue}'` : sheetTextValue;

const range: IRange = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ export class Index extends BaseFunction {

override needsReferenceObject = true;

// eslint-disable-next-line max-lines-per-function, complexity
override calculate(reference: FunctionVariantType, rowNum?: FunctionVariantType, columnNum?: FunctionVariantType, areaNum?: FunctionVariantType) {
if (reference.isError()) {
return reference;
Expand Down