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

[IMP] evaluation: functions can handle errors #2932

Closed
wants to merge 8 commits into from

Conversation

laa-odoo
Copy link
Collaborator

@laa-odoo laa-odoo commented Sep 25, 2023

With those commits, functions can handle errors more easily. See individual commits for details.

The purpose of this commit is to allow the formulas
to return errors as results.

Functionally we want formulas like TRANSPOSE to be
able to transpose an error without invalidating the
entire evaluation process.

We also want formulas like LOOKUP not to be interrupted
when the search range has one or more errors.

Task: 2969401

@robodoo
Copy link
Collaborator

robodoo commented Sep 25, 2023

@laa-odoo laa-odoo force-pushed the master-formulas-handle-error2-laa branch 4 times, most recently from 350c0b7 to 818db7c Compare September 28, 2023 09:00
src/functions/index.ts Outdated Show resolved Hide resolved
src/functions/index.ts Outdated Show resolved Hide resolved
src/functions/module_info.ts Outdated Show resolved Hide resolved
src/helpers/cells/cell_evaluation.ts Outdated Show resolved Hide resolved
src/plugins/core/cell.ts Outdated Show resolved Hide resolved
src/plugins/ui_stateful/selection.ts Outdated Show resolved Hide resolved
src/plugins/ui_stateful/selection.ts Outdated Show resolved Hide resolved
tests/test_helpers/getters_helpers.ts Outdated Show resolved Hide resolved
tests/test_helpers/helpers.ts Outdated Show resolved Hide resolved
tests/test_helpers/helpers.ts Outdated Show resolved Hide resolved
@laa-odoo laa-odoo force-pushed the master-formulas-handle-error2-laa branch from 818db7c to 0a65786 Compare September 28, 2023 14:21
@laa-odoo laa-odoo force-pushed the master-formulas-handle-error2-laa branch 4 times, most recently from a0b0713 to 8b2b53f Compare November 20, 2023 15:09
@laa-odoo laa-odoo force-pushed the master-formulas-handle-error2-laa branch from 8b2b53f to c49698f Compare November 21, 2023 19:35
Copy link
Contributor

@hokolomopo hokolomopo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some small problems and nitpicking.

Really nice work testing every function that may or may not accept error, I certenly wouldn't have bothered testing everything 😛

src/formulas/code_builder.ts Show resolved Hide resolved
src/functions/helpers.ts Outdated Show resolved Hide resolved
@@ -74,7 +75,7 @@ class FunctionRegistry extends Registry<FunctionDescription> {
}
const descr = addMetaInfoFromArg(addDescr);
validateArguments(descr.args);
this.mapping[name] = createComputeFunctionFromDescription(descr);
this.mapping[name] = addErrorHandling(createComputeFunctionFromDescription(descr), name);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

might as well fo the try/catch directly in createComputeFunctionFromDescription to avoid creating a second function wrapping the first

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Indeed, to avoid that, we can put the tryCatch directly in buildComputeFunctionFromDescription. @LucasLefevre are you agree with that ?

src/functions/helpers.ts Outdated Show resolved Hide resolved
src/functions/module_array.ts Show resolved Hide resolved
src/functions/module_statistical.ts Outdated Show resolved Hide resolved
return evaluateCell;
}
function _createEvaluatedCell(value: CellValue, localeFormat: LocaleFormat): EvaluatedCell {
if (value instanceof EvaluationError) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm didn't really liked the builders so I don't really care, but what's the rationale to remove them and to use simple if ? Because that's more readable, or is there a practical reason ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I find it easier to read, less code to have in mind.
Actually, if it really bothers you, I'll go back.

tests/evaluation/evaluation.test.ts Outdated Show resolved Hide resolved
@laa-odoo laa-odoo force-pushed the master-formulas-handle-error2-laa branch 4 times, most recently from 61a747d to c42f2f6 Compare December 14, 2023 14:53
Copy link
Collaborator

@LucasLefevre LucasLefevre left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice !
I think we finally found a good way ! Good job :)

Some general comment (more detailed in individual comments)

  • if we find a more meaningful name for UnitData, it would be nice
  • throwing objects (and not Errors) makes me feel 🤨 but 🤷
  • I think there's some useless changes that could be reverted.
  • Now that the functional side is working with this PR, a next step is to improve performance by using returns as much as possible (especially for ODOO.* functions)

src/functions/module_array.ts Outdated Show resolved Hide resolved
src/functions/helpers.ts Outdated Show resolved Hide resolved
src/types/errors.ts Outdated Show resolved Hide resolved
src/types/errors.ts Outdated Show resolved Hide resolved
@@ -181,13 +179,11 @@ export interface RangeCompiledFormula extends Omit<CompiledFormula, "dependencie
}

export type Matrix<T = unknown> = T[][];
export type ValueAndFormat = { value: CellValue; format?: Format };
export type UnitData = { value: CellValue; format?: Format; message?: string };
Copy link
Collaborator

@LucasLefevre LucasLefevre Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UnitData doesn't really makes sense to me. But I don't have any brilliant better idea
CellEvaluation ? CellEvaluationResult ? CellFunctionResult ? EvaluationResult ? FunctionResult ? FormulaResult ? FormulaValue ? FormulaPayload (FP for short) ? FormulaData ? FData ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FunctionResult

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FPayload

@@ -210,17 +216,21 @@ export class Evaluator {
}

const cellId = cell.id;

const localeFormat = { format: cell.format, locale: this.getters.getLocale() };
try {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A next step would be to change every throw in this file to returns.

src/plugins/ui_core_views/cell_evaluation/evaluator.ts Outdated Show resolved Hide resolved
@@ -228,9 +226,11 @@ export class EvaluationDataValidationPlugin extends UIPlugin {
);

const evaluated = this.getters.evaluateFormula(sheetId, translatedFormula);
return evaluated && !isMatrix(evaluated) ? evaluated.toString() : "";
return evaluated?.toString() || "";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what if it's a matrix? Is it safe to remove the check?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't know what we want exactly:

Here I removed the check because the try catch below takes care of this case.
The evaluateFormula getter has been modified to throw when an array is received.
Perhaps we should first ask ourselves what exactly we want to do with this getters when it returns an array ?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok understood. After live discussion: this.getters.evaluateFormula shouldn't throw

src/types/cells.ts Outdated Show resolved Hide resolved
@laa-odoo laa-odoo force-pushed the master-formulas-handle-error2-laa branch 7 times, most recently from 80bce50 to 6cb8d40 Compare December 21, 2023 11:26
@laa-odoo laa-odoo force-pushed the master-formulas-handle-error2-laa branch 2 times, most recently from bbae191 to 416e207 Compare January 8, 2024 13:31
@laa-odoo laa-odoo force-pushed the master-formulas-handle-error2-laa branch 2 times, most recently from 5de6280 to b9c4ec4 Compare January 9, 2024 12:09
@@ -64,10 +64,10 @@ export function compileTokens(tokens: Token[]): CompiledFormula {
const scope = new Scope();

if (ast.type === "BIN_OPERATION" && ast.value === ":") {
throw new BadExpressionError(_t("Invalid formula"));
throw { value: CellErrorType.BadExpression, message: _t("Invalid formula") };
Copy link
Contributor

@anhe-odoo anhe-odoo Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Personnally I prefere the old way to throw/return error. Why did you change this ?. Maybe we can keep something like a function BadExpressionError(message: string) so that we can have return BadExpressionError(_t("Invalid formula"));. Same for the other type of error ?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the goal would be that the formulas end up returning errors in the form of the normal payload rather than throwing errors, (performance reason)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I must admit I agree with Anthony. It feels very here where we are not in the context of a function implementation that would return a value (or an error).

Copy link
Collaborator Author

@laa-odoo laa-odoo Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BadExpressionError(message) and other errors could indeed be functions that result in {value: "#SomeError", message}

Copy link
Collaborator

@LucasLefevre LucasLefevre Jan 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or keep BadExpressionError as a class extending Error but with an additional property value.
That way it would:

  • still be an error (and it feels natural to throw it)
  • respect the same interface { value, message }

Basically the same as now, but errorType becomes value

@LucasLefevre LucasLefevre changed the title Master formulas handle error2 laa [IMP] evaluation: functions can handle errors Jan 16, 2024
@LucasLefevre
Copy link
Collaborator

robodoo rebase-merge r+

@robodoo
Copy link
Collaborator

robodoo commented Jan 16, 2024

Branch saas-17.1 is not within my remit, imma just ignore it.

@LucasLefevre LucasLefevre force-pushed the master-formulas-handle-error2-laa branch from f2eaf85 to 4b3e29c Compare January 16, 2024 12:53
@LucasLefevre
Copy link
Collaborator

et maintenant ?
robodoo rebase-merge r+

@robodoo
Copy link
Collaborator

robodoo commented Jan 16, 2024

@robodoo
Copy link
Collaborator

robodoo commented Jan 16, 2024

Merge method set to rebase and merge, using the PR as merge commit message.

1 similar comment
@robodoo
Copy link
Collaborator

robodoo commented Jan 16, 2024

Merge method set to rebase and merge, using the PR as merge commit message.

@robodoo
Copy link
Collaborator

robodoo commented Jan 16, 2024

I'm sorry, @LucasLefevre: this PR is already reviewed, reviewing it again is useless.

@robodoo
Copy link
Collaborator

robodoo commented Jan 16, 2024

@laa-odoo @LucasLefevre I didn't know about this PR and had to retrieve its information, you may have to re-approve it as I didn't see previous commands.

laa-odoo and others added 3 commits January 16, 2024 14:04
we would like in a future commit change spreadsheet
error object by string errors and keep the error
message at the level of the formula payload,

if we want to do this, we will encounter a problem
with the 'compute' functions of the formulas because
the compute functions only manage the value (and not
the entire payload), so we will not be able to
transcribe the errors with their message.

To resolve this, this commit unifies all the computes
('compute', 'computeFormat', computeValueAndFormat')
into a same 'compute' which manages the entire payload.

To avoid too many changes, it is now the casting helpers
(toNumber, toString...) which take the payload and extract
the value.

Task: 2969401
This commit changes the form of user errors
in the formula evaluation process.

With the previous commits, having a user error is no
longer an event that destroys the process of
evaluating a formula: A cell with a user error is a
cell that can functionally have an interest in
changing the result of a formula in one direction
rather than another.

Thus, it is possible for each sub-formula of the same
formula to return a payload corresponding to an error.

Before this commit, an error payload corresponds to an
error object stored on the "value" attribute of the
formula payload

{value: errorObject, format?: string}

Now, the important error information is stored at the
payload level.

{value: string, format?: string, message?: string}

There are two advantages to doing this:
- In terms of performance, it can be expensive to create
an error object and throw it. This commit gives the
possibility for future commits to no longer throw an error
object but to simply return an error payload.
- the form of the formula payload is close to evaluatedCelle
--> code simplification

Task: 2969401
Jest doesn't fail if a console.error or console.warn
is triggered.
With this commit, any such message will make the
test to fail

Task: 2969401
@LucasLefevre LucasLefevre force-pushed the master-formulas-handle-error2-laa branch from 4b3e29c to da02f26 Compare January 16, 2024 13:05
@LucasLefevre
Copy link
Collaborator

robodoo r+

robodoo pushed a commit that referenced this pull request Jan 16, 2024
- refactor the code used to create the evaluated cells
- removes certain parameters not used when handling errors during evaluation

Task: 2969401
Part-of: #2932
robodoo pushed a commit that referenced this pull request Jan 16, 2024
The purpose of this commit is to allow the formulas
to return errors as results.

Functionally we want formulas like TRANSPOSE to be
able to transpose an error without invalidating the
entire evaluation process.

We also want formulas like LOOKUP not to be interrupted
when the search range has one or more errors.

To make this change we accepted errors in input and
output on the formulas,

It nevertheless remains possible to throw errors in the
formulas:
it is no longer the evaluation process at the cell level
which is stopped but the evaluation process at the formula
level.

Technically there is no longer a "try catch" at the
evaluator level,
here each formula is encapsulated in a “try catch”
when it enters the formula register

Other point, the _lastFnCalled present in the evaluation
context and allowing to know which is the last formula to
have been called before the raise  of an error is no longer
used. The information is available during the encapsulation
of the formula in the "try catch".
So, _lastFnCalled has therefore been removed from the
evaluation context.

Task: 2969401
Part-of: #2932
Co-authored-by: Lucas Lefèvre (lul) <lul@odoo.com>
robodoo pushed a commit that referenced this pull request Jan 16, 2024
Before the previous commit, the lazy type arguments made
it possible to not stop the entire evaluation process
when an error was provided as an argument.

Here, with the previous commit, the evaluation process is
no longer stopped when an error is passed as formula input,

So we no longer need lazy type arguments,
This commit remove it.

Task: 2969401
Part-of: #2932
robodoo pushed a commit that referenced this pull request Jan 16, 2024
Allow specific function to accept/throw errors
when they are present in arguments

Task: 2969401
Part-of: #2932
robodoo pushed a commit that referenced this pull request Jan 16, 2024
with the idea of ​​extending ValueAndFormat to something
more complex that can handle errors and their messages,
we are renaming it to FPayload

Task: 2969401
Part-of: #2932
robodoo pushed a commit that referenced this pull request Jan 16, 2024
we would like in a future commit change spreadsheet
error object by string errors and keep the error
message at the level of the formula payload,

if we want to do this, we will encounter a problem
with the 'compute' functions of the formulas because
the compute functions only manage the value (and not
the entire payload), so we will not be able to
transcribe the errors with their message.

To resolve this, this commit unifies all the computes
('compute', 'computeFormat', computeValueAndFormat')
into a same 'compute' which manages the entire payload.

To avoid too many changes, it is now the casting helpers
(toNumber, toString...) which take the payload and extract
the value.

Task: 2969401
Part-of: #2932
robodoo pushed a commit that referenced this pull request Jan 16, 2024
This commit changes the form of user errors
in the formula evaluation process.

With the previous commits, having a user error is no
longer an event that destroys the process of
evaluating a formula: A cell with a user error is a
cell that can functionally have an interest in
changing the result of a formula in one direction
rather than another.

Thus, it is possible for each sub-formula of the same
formula to return a payload corresponding to an error.

Before this commit, an error payload corresponds to an
error object stored on the "value" attribute of the
formula payload

{value: errorObject, format?: string}

Now, the important error information is stored at the
payload level.

{value: string, format?: string, message?: string}

There are two advantages to doing this:
- In terms of performance, it can be expensive to create
an error object and throw it. This commit gives the
possibility for future commits to no longer throw an error
object but to simply return an error payload.
- the form of the formula payload is close to evaluatedCelle
--> code simplification

Task: 2969401
Part-of: #2932
robodoo pushed a commit that referenced this pull request Jan 16, 2024
Jest doesn't fail if a console.error or console.warn
is triggered.
With this commit, any such message will make the
test to fail

Task: 2969401
Part-of: #2932
robodoo added a commit that referenced this pull request Jan 16, 2024
With those commits, functions can handle errors more easily. See individual commits for details.

The purpose of this commit is to allow the formulas
to return errors as results.

Functionally we want formulas like TRANSPOSE to be
able to transpose an error without invalidating the
entire evaluation process.

We also want formulas like LOOKUP not to be interrupted
when the search range has one or more errors.

closes #2932

Task: 2969401
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
@robodoo robodoo closed this Jan 16, 2024
robodoo added a commit that referenced this pull request Jan 16, 2024
With those commits, functions can handle errors more easily. See individual commits for details.

The purpose of this commit is to allow the formulas
to return errors as results.

Functionally we want formulas like TRANSPOSE to be
able to transpose an error without invalidating the
entire evaluation process.

We also want formulas like LOOKUP not to be interrupted
when the search range has one or more errors.

closes #3454

Task: 2969401
Forward-port-of: #2932
Signed-off-by: Lucas Lefèvre (lul) <lul@odoo.com>
@fw-bot fw-bot deleted the master-formulas-handle-error2-laa branch January 30, 2024 13:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants