Skip to content

Commit

Permalink
feat(formula): add some Text/Math/Lookup formulas (#2842)
Browse files Browse the repository at this point in the history
Co-authored-by: wpxp123456 <Wpxp1223456>
  • Loading branch information
wpxp123456 authored Jul 27, 2024
1 parent 43220a1 commit 778e371
Show file tree
Hide file tree
Showing 48 changed files with 4,830 additions and 216 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* 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 { describe, expect, it } from 'vitest';

import { FUNCTION_NAMES_LOOKUP } from '../../function-names';
import { Areas } from '../index';
import { StringValueObject } from '../../../../engine/value-object/primitive-object';
import { ErrorType } from '../../../../basics/error-type';
import { CellReferenceObject } from '../../../../engine/reference-object/cell-reference-object';

describe('Test areas function', () => {
const testFunction = new Areas(FUNCTION_NAMES_LOOKUP.AREAS);

describe('Areas', () => {
it('Value is reference', async () => {
const reference = new CellReferenceObject('A1');
const result = testFunction.calculate(reference);
expect(result.getValue()).toBe(1);
});

it('Value is not reference', async () => {
const reference = StringValueObject.create('A1');
const result = testFunction.calculate(reference);
expect(result.getValue()).toBe(ErrorType.VALUE);
});
});
});
37 changes: 37 additions & 0 deletions packages/engine-formula/src/functions/lookup/areas/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* 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 { ErrorType } from '../../../basics/error-type';
import type { FunctionVariantType } from '../../../engine/reference-object/base-reference-object';
import { ErrorValueObject } from '../../../engine/value-object/base-value-object';
import { NumberValueObject } from '../../../engine/value-object/primitive-object';
import { BaseFunction } from '../../base-function';

export class Areas extends BaseFunction {
override minParams = 1;

override maxParams = 1;

override needsReferenceObject = true;

override calculate(reference: FunctionVariantType) {
if (reference.isReferenceObject()) {
return NumberValueObject.create(1);
}

return ErrorValueObject.create(ErrorType.VALUE);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
/**
* 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 { describe, expect, it } from 'vitest';

import { ArrayValueObject } from '../../../../engine/value-object/array-value-object';
import { FUNCTION_NAMES_LOOKUP } from '../../function-names';
import { Choosecols } from '../index';
import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object';
import { ErrorType } from '../../../../basics/error-type';
import { getObjectValue } from '../../../__tests__/create-function-test-bed';
import { ErrorValueObject } from '../../../../engine/value-object/base-value-object';

describe('Test choosecols function', () => {
const testFunction = new Choosecols(FUNCTION_NAMES_LOOKUP.CHOOSECOLS);

describe('Choosecols', () => {
it('Value is normal', async () => {
const array = ArrayValueObject.create('{1,2,3;2,3,4}');
const colNum1 = NumberValueObject.create(1);
const colNum2 = NumberValueObject.create(2);
const resultObject = testFunction.calculate(array, colNum1, colNum2);
expect(getObjectValue(resultObject)).toStrictEqual([
[1, 2],
[2, 3],
]);
});

it('ColNum value is zero or exceeds the number of columns in the array', async () => {
const array = ArrayValueObject.create('{1,2,3;2,3,4}');
const colNum1 = NumberValueObject.create(0);
const resultObject = testFunction.calculate(array, colNum1);
expect(getObjectValue(resultObject)).toStrictEqual(ErrorType.VALUE);

const colNum2 = NumberValueObject.create(4);
const resultObject2 = testFunction.calculate(array, colNum2);
expect(getObjectValue(resultObject2)).toStrictEqual(ErrorType.VALUE);
});

it('Array value is error', async () => {
const array = ErrorValueObject.create(ErrorType.NAME);
const colNum1 = NumberValueObject.create(11);
const resultObject = testFunction.calculate(array, colNum1);
expect(getObjectValue(resultObject)).toStrictEqual(ErrorType.NAME);
});

it('ColNum value is error or string or boolean or blank cell or multi-column array', async () => {
const array = ArrayValueObject.create('{1,2,3;2,3,4}');
const colNum1 = ErrorValueObject.create(ErrorType.NAME);
const resultObject = testFunction.calculate(array, colNum1);
expect(getObjectValue(resultObject)).toStrictEqual(ErrorType.NAME);

const colNum2 = StringValueObject.create('test');
const resultObject2 = testFunction.calculate(array, colNum2);
expect(getObjectValue(resultObject2)).toStrictEqual(ErrorType.VALUE);

const colNum3 = BooleanValueObject.create(true);
const resultObject3 = testFunction.calculate(array, colNum3);
expect(getObjectValue(resultObject3)).toStrictEqual([
[1],
[2],
]);

const colNum4 = BooleanValueObject.create(false);
const resultObject4 = testFunction.calculate(array, colNum4);
expect(getObjectValue(resultObject4)).toStrictEqual(ErrorType.VALUE);

const colNum5 = NullValueObject.create();
const resultObject5 = testFunction.calculate(array, colNum5);
expect(getObjectValue(resultObject5)).toStrictEqual(ErrorType.VALUE);

const colNum6 = ArrayValueObject.create('{1,2}');
const resultObject6 = testFunction.calculate(array, colNum6);
expect(getObjectValue(resultObject6)).toStrictEqual(ErrorType.VALUE);
});
});
});
100 changes: 100 additions & 0 deletions packages/engine-formula/src/functions/lookup/choosecols/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* 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 { ErrorType } from '../../../basics/error-type';
import { ArrayValueObject } from '../../../engine/value-object/array-value-object';
import type { BaseValueObject } from '../../../engine/value-object/base-value-object';
import { ErrorValueObject } from '../../../engine/value-object/base-value-object';

import { BaseFunction } from '../../base-function';

export class Choosecols extends BaseFunction {
override minParams = 2;

override maxParams = 255;

override calculate(array: BaseValueObject, ...variants: BaseValueObject[]) {
if (array.isError()) {
return array;
}

const arrayRowCount = array.isArray() ? (array as ArrayValueObject).getRowCount() : 1;
const arrayColumnCount = array.isArray() ? (array as ArrayValueObject).getColumnCount() : 1;

const result: BaseValueObject[][] = [];

for (let i = 0; i < variants.length; i++) {
let variantObject = variants[i];

if (variantObject.isArray()) {
const variantRowCount = (variantObject as ArrayValueObject).getRowCount();
const variantColumnCount = (variantObject as ArrayValueObject).getColumnCount();

if (variantRowCount > 1 || variantColumnCount > 1) {
return ErrorValueObject.create(ErrorType.VALUE);
}

variantObject = (variantObject as ArrayValueObject).get(0, 0) as BaseValueObject;
}

if (variantObject.isString()) {
variantObject = variantObject.convertToNumberObjectValue();
}

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

const variantValue = Math.trunc(+variantObject.getValue());

if (variantValue === 0 || Math.abs(variantValue) > arrayColumnCount) {
return ErrorValueObject.create(ErrorType.VALUE);
}

let searchColArray = array;

if (arrayColumnCount > 1) {
if (variantValue < 0) {
searchColArray = (array as ArrayValueObject).slice(undefined, [variantValue + arrayColumnCount, variantValue + 1 + arrayColumnCount]) as BaseValueObject;
} else {
searchColArray = (array as ArrayValueObject).slice(undefined, [variantValue - 1, variantValue]) as BaseValueObject;
}
}

for (let r = 0; r < arrayRowCount; r++) {
if (!result[r]) {
result[r] = [];
}

if (array.isArray()) {
result[r].push((searchColArray as ArrayValueObject).get(r, 0) as BaseValueObject);
} else {
result[r].push(array);
}
}
}

return ArrayValueObject.create({
calculateValueList: result,
rowCount: result.length,
columnCount: result[0].length || 0,
unitId: this.unitId as string,
sheetId: this.subUnitId as string,
row: this.row,
column: this.column,
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/**
* 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 { describe, expect, it } from 'vitest';

import { ArrayValueObject } from '../../../../engine/value-object/array-value-object';
import { FUNCTION_NAMES_LOOKUP } from '../../function-names';
import { Chooserows } from '../index';
import { BooleanValueObject, NullValueObject, NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object';
import { ErrorType } from '../../../../basics/error-type';
import { getObjectValue } from '../../../__tests__/create-function-test-bed';
import { ErrorValueObject } from '../../../../engine/value-object/base-value-object';

describe('Test chooserows function', () => {
const testFunction = new Chooserows(FUNCTION_NAMES_LOOKUP.CHOOSEROWS);

describe('Chooserows', () => {
it('Value is normal', async () => {
const array = ArrayValueObject.create('{1,2,3;2,3,4}');
const rowNum1 = NumberValueObject.create(1);
const rowNum2 = NumberValueObject.create(2);
const resultObject = testFunction.calculate(array, rowNum1, rowNum2);
expect(getObjectValue(resultObject)).toStrictEqual([
[1, 2, 3],
[2, 3, 4],
]);
});

it('RowNum value is zero or exceeds the number of rows in the array', async () => {
const array = ArrayValueObject.create('{1,2,3;2,3,4}');
const rowNum1 = NumberValueObject.create(0);
const resultObject = testFunction.calculate(array, rowNum1);
expect(getObjectValue(resultObject)).toStrictEqual(ErrorType.VALUE);

const rowNum2 = NumberValueObject.create(4);
const resultObject2 = testFunction.calculate(array, rowNum2);
expect(getObjectValue(resultObject2)).toStrictEqual(ErrorType.VALUE);
});

it('Array value is error', async () => {
const array = ErrorValueObject.create(ErrorType.NAME);
const rowNum1 = NumberValueObject.create(11);
const resultObject = testFunction.calculate(array, rowNum1);
expect(getObjectValue(resultObject)).toStrictEqual(ErrorType.NAME);
});

it('RowNum value is error or string or boolean or blank cell or multi-row array', async () => {
const array = ArrayValueObject.create('{1,2,3;2,3,4}');
const rowNum1 = ErrorValueObject.create(ErrorType.NAME);
const resultObject = testFunction.calculate(array, rowNum1);
expect(getObjectValue(resultObject)).toStrictEqual(ErrorType.NAME);

const rowNum2 = StringValueObject.create('test');
const resultObject2 = testFunction.calculate(array, rowNum2);
expect(getObjectValue(resultObject2)).toStrictEqual(ErrorType.VALUE);

const rowNum3 = BooleanValueObject.create(true);
const resultObject3 = testFunction.calculate(array, rowNum3);
expect(getObjectValue(resultObject3)).toStrictEqual([
[1, 2, 3],
]);

const rowNum4 = BooleanValueObject.create(false);
const resultObject4 = testFunction.calculate(array, rowNum4);
expect(getObjectValue(resultObject4)).toStrictEqual(ErrorType.VALUE);

const rowNum5 = NullValueObject.create();
const resultObject5 = testFunction.calculate(array, rowNum5);
expect(getObjectValue(resultObject5)).toStrictEqual(ErrorType.VALUE);

const rowNum6 = ArrayValueObject.create('{1;2}');
const resultObject6 = testFunction.calculate(array, rowNum6);
expect(getObjectValue(resultObject6)).toStrictEqual(ErrorType.VALUE);
});
});
});
Loading

0 comments on commit 778e371

Please sign in to comment.