Pascal/refactor error signatures #869
Open
+249
−320
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Goal
This PR should be entirely ISO in terms of business logic.
The starting point for me was to remove the
GetBoolReturnValue
andGetStringReturnValue
helper methods on the NodeEvaluation type. The reason for this is that they provided no real simplification over repeated code, because they replaced "null check and type assert" logic by "catch sentinel errors everywhere" logic. Namely, the codebase was a mess ofif errors.Is(err, ast. ErrNullFieldRead) {...} else if err != nil {...}
.Continuing on this path, I completely removed the following sentinel errors from the models/ast package:
ErrNullFieldRead
ErrNoRowsRead
ErrPayloadFieldNotFound
Only
ErrDivisionByZero
remains as a specific error at runtime, because that should be the only error we really encounter.Note that old rule dtos
ast.ExecutionError
can still return theNoRowsRead
,PayloadFieldNotFound
values and that rules can still have theNullFieldRead
status (if they return a nil not a bool).In the same logic, the
models.ErrScenarioTriggerConditionAndTriggerObjectMismatch
error, that was possibly returned by EvalScenario and caught higher up the stack for a side effect of "don't create a decision" or "return a 400 error", is dropped in favor of explicitly returning a boolean (for "trigger condition [not] passed")implementation details
A nasty piece of code that recreated go error types from (integer) ExecutionError DTOs is replaced, decision rule models now hold a proper ExecutionError rather than an error that can be mapped to it.
Bug fixes
Design reflexions
In the end, what this PR attemps to fix is a design that seemed ok at the start but became a horrible mess to memorize, never mind understand.
My take away from it is: using generic sentinel errors to trigger specific side effects at some level of the caller stack is ok in the following cases:
errors.Is(err, models.NotFoundErr)
but the pattern where a very specific sentinel error is returned by a method down the stack to be hopefully caught several layers above and through module boundaries is a big "no".