forked from dream-num/univer
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(formula): add LEFT function implementation dream-num#2572
- Loading branch information
sneha khaitan
authored and
sneha khaitan
committed
Jun 21, 2024
1 parent
b3393ef
commit 69d5f65
Showing
8 changed files
with
281 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
170 changes: 170 additions & 0 deletions
170
packages/engine-formula/src/functions/text/left/__test__/index.spec.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
/** | ||
* 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_TEXT } from '../../function-names'; | ||
import { Left } from '../index'; | ||
import { NumberValueObject, StringValueObject } from '../../../../engine/value-object/primitive-object'; | ||
import { ArrayValueObject, transformToValue, transformToValueObject } from '../../../../engine/value-object/array-value-object'; | ||
import { ErrorType } from '../../../../basics/error-type'; | ||
|
||
describe('Test LEFT function', () => { | ||
const leftFunction = new Left(FUNCTION_NAMES_TEXT.LEFT); | ||
|
||
describe('Left', () => { | ||
it('Extracts single character from single cell', () => { | ||
const text = StringValueObject.create('Hello'); | ||
const numChars = NumberValueObject.create(1); | ||
const result = leftFunction.calculate(text, numChars); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([['H']]); | ||
}); | ||
|
||
it('Extracts multiple characters from single cell', () => { | ||
const text = StringValueObject.create('Hello World'); | ||
const numChars = NumberValueObject.create(5); | ||
const result = leftFunction.calculate(text, numChars); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([['Hello']]); | ||
}); | ||
|
||
it('Handles no numChars passed, defaults to 1', () => { | ||
const text = StringValueObject.create('Hello'); | ||
const result = leftFunction.calculate(text); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([['H']]); | ||
}); | ||
|
||
it('Handles numChars larger than text length', () => { | ||
const text = StringValueObject.create('Hi'); | ||
const numChars = NumberValueObject.create(10); | ||
const result = leftFunction.calculate(text, numChars); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([['Hi']]); | ||
}); | ||
|
||
it('Handles empty text', () => { | ||
const text = StringValueObject.create(''); | ||
const numChars = NumberValueObject.create(1); | ||
const result = leftFunction.calculate(text, numChars); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([['']]); | ||
}); | ||
|
||
it('Handles negative numChars', () => { | ||
const text = StringValueObject.create('Hello'); | ||
const numChars = NumberValueObject.create(-1); | ||
const result = leftFunction.calculate(text, numChars); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([[ErrorType.VALUE]]); | ||
}); | ||
|
||
it('Extracts characters from array by specifying single numChar', () => { | ||
const textArray = new ArrayValueObject({ | ||
calculateValueList: transformToValueObject([ | ||
['Hello'], | ||
['World'], | ||
['New World'], | ||
['Example'], | ||
]), | ||
rowCount: 4, | ||
columnCount: 1, | ||
unitId: '', | ||
sheetId: '', | ||
row: 0, | ||
column: 0, | ||
}); | ||
const numChars = NumberValueObject.create(3); | ||
const result = leftFunction.calculate(textArray, numChars); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([ | ||
['Hel'], // First character of 'Hello' | ||
['Wor'], // First two characters of 'World' | ||
['New'], // First three characters of 'Test' | ||
['Exa'], // First four characters of 'Example' | ||
]); | ||
}); | ||
it('Extracts characters from array', () => { | ||
const textArray = new ArrayValueObject({ | ||
calculateValueList: transformToValueObject([ | ||
['Hello'], | ||
['World'], | ||
['Test'], | ||
['Example'], | ||
]), | ||
rowCount: 4, | ||
columnCount: 1, | ||
unitId: '', | ||
sheetId: '', | ||
row: 0, | ||
column: 0, | ||
}); | ||
const numCharsArray = new ArrayValueObject({ | ||
calculateValueList: transformToValueObject([ | ||
[1], | ||
[2], | ||
[3], | ||
[4], | ||
]), | ||
rowCount: 4, | ||
columnCount: 1, | ||
unitId: '', | ||
sheetId: '', | ||
row: 0, | ||
column: 0, | ||
}); | ||
const result = leftFunction.calculate(textArray, numCharsArray); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([ | ||
['H'], // First character of 'Hello' | ||
['Wo'], // First two characters of 'World' | ||
['Tes'], // First three characters of 'Test' | ||
['Exam'], // First four characters of 'Example' | ||
]); | ||
}); | ||
|
||
it('Handles numChars not provided for array', () => { | ||
const textArray = new ArrayValueObject({ | ||
calculateValueList: transformToValueObject([ | ||
['Hello'], | ||
['World'], | ||
['Test'], | ||
['Example'], | ||
]), | ||
rowCount: 4, | ||
columnCount: 1, | ||
unitId: '', | ||
sheetId: '', | ||
row: 0, | ||
column: 0, | ||
}); | ||
const result = leftFunction.calculate(textArray); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([ | ||
['H'], // Default to first character of 'Hello' | ||
['W'], // Default to first character of 'World' | ||
['T'], // Default to first character of 'Test' | ||
['E'], // Default to first character of 'Example' | ||
]); | ||
}); | ||
|
||
it('Handles extracting from text with emojis', () => { | ||
const text = StringValueObject.create('Hello 😊 World'); | ||
const numChars = NumberValueObject.create(7); | ||
const result = leftFunction.calculate(text, numChars); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([['Hello 😊']]); | ||
}); | ||
|
||
it('Handles extracting with numChars as zero', () => { | ||
const text = StringValueObject.create('Hello'); | ||
const numChars = NumberValueObject.create(0); | ||
const result = leftFunction.calculate(text, numChars); | ||
expect(transformToValue(result.getArrayValue())).toStrictEqual([['']]); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** | ||
* 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 { expandArrayValueObject } from '../../../engine/utils/array-object'; | ||
import { ArrayValueObject } from '../../../engine/value-object/array-value-object'; | ||
import { type BaseValueObject, ErrorValueObject } from '../../../engine/value-object/base-value-object'; | ||
import { NumberValueObject, StringValueObject } from '../../../engine/value-object/primitive-object'; | ||
import { BaseFunction } from '../../base-function'; | ||
|
||
export class Left extends BaseFunction { | ||
override minParams = 1; | ||
|
||
override maxParams = 2; | ||
|
||
override calculate(text: BaseValueObject, numChars?: BaseValueObject) { | ||
if (text.isError()) { | ||
return text; | ||
} | ||
|
||
if (numChars && numChars.isError()) { | ||
return numChars; | ||
} | ||
|
||
if (text.isArray()) { | ||
const maxRowLength = Math.max( | ||
text.isArray() ? (text as ArrayValueObject).getRowCount() : 1, | ||
numChars && numChars.isArray() ? (numChars as ArrayValueObject).getRowCount() : 1 | ||
); | ||
|
||
const maxColumnLength = Math.max( | ||
text.isArray() ? (text as ArrayValueObject).getColumnCount() : 1, | ||
numChars && numChars.isArray() ? (numChars as ArrayValueObject).getColumnCount() : 1 | ||
); | ||
|
||
const textArray = expandArrayValueObject(maxRowLength, maxColumnLength, text); | ||
const numCharsArray = numChars ? expandArrayValueObject(maxRowLength, maxColumnLength, numChars) : null; | ||
|
||
return textArray.map((textValue, rowIndex, columnIndex) => { | ||
if (textValue.isError()) { | ||
return textValue; | ||
} | ||
|
||
const numCharsValue = numCharsArray ? numCharsArray.get(rowIndex, columnIndex) : NumberValueObject.create(1); | ||
if (numCharsValue?.isError()) { | ||
return numCharsValue; | ||
} | ||
|
||
const numCharsValueNumber = numCharsValue?.getValue() as number; | ||
|
||
if (typeof numCharsValueNumber !== 'number' || numCharsValueNumber < 0) { | ||
return ErrorValueObject.create(ErrorType.VALUE); | ||
} | ||
|
||
const textValueString = `${textValue.getValue()}`; | ||
return StringValueObject.create(Array.from(textValueString).slice(0, numCharsValueNumber).join('')); | ||
}); | ||
} | ||
|
||
return this._handleSingleText(text, numChars); | ||
} | ||
|
||
private _handleSingleText(text: BaseValueObject, numChars?: BaseValueObject) { | ||
if (text.isError()) { | ||
return text; | ||
} | ||
|
||
if (numChars && numChars.isError()) { | ||
return numChars; | ||
} | ||
|
||
const textValueString = `${text.getValue()}`; | ||
const numCharsValueNumber = numChars ? (numChars.getValue() as number) : 1; | ||
|
||
if (typeof numCharsValueNumber !== 'number' || numCharsValueNumber < 0) { | ||
return ArrayValueObject.createByArray([[ErrorType.VALUE]]); | ||
} | ||
|
||
return ArrayValueObject.createByArray([[Array.from(textValueString).slice(0, numCharsValueNumber).join('')]]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters