From afa6f4d63a8ba2fd658566523bece328ac08ee9a Mon Sep 17 00:00:00 2001 From: ascandone Date: Wed, 9 Oct 2024 16:47:31 +0200 Subject: [PATCH] more error handling --- go.mod | 2 +- go.sum | 4 +++ .../api/v2/controllers_transactions_create.go | 5 +++ internal/api/v2/errors.go | 3 ++ internal/controller/ledger/errors.go | 31 +++++++++++++++++++ internal/controller/ledger/machine.go | 5 ++- internal/controller/ledger/machine_factory.go | 6 ++-- 7 files changed, 52 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index ee689b76b..47929e61a 100644 --- a/go.mod +++ b/go.mod @@ -88,7 +88,7 @@ require ( github.com/eapache/queue v1.1.0 // indirect github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/formancehq/numscript v0.0.9-0.20241007165056-153e7139a0d6 // indirect + github.com/formancehq/numscript v0.0.9-0.20241009144012-1150c14a1417 // indirect github.com/getsentry/sentry-go v0.28.1 // indirect github.com/go-chi/chi v4.1.2+incompatible // indirect github.com/go-chi/render v1.0.3 // indirect diff --git a/go.sum b/go.sum index bae06774f..66c8b5072 100644 --- a/go.sum +++ b/go.sum @@ -109,6 +109,10 @@ github.com/formancehq/numscript v0.0.9-0.20241007145104-93591532fb96 h1:Y+B10r16 github.com/formancehq/numscript v0.0.9-0.20241007145104-93591532fb96/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= github.com/formancehq/numscript v0.0.9-0.20241007165056-153e7139a0d6 h1:VtiK2H3svTfUe1UlsaajynICc9t+XwXCBbHgEwv416Q= github.com/formancehq/numscript v0.0.9-0.20241007165056-153e7139a0d6/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= +github.com/formancehq/numscript v0.0.9-0.20241009142721-febe5da15eb9 h1:ZvVrISOuEaXqpRdTyaSbHGjzObWtk454EQbdMrDUS/Y= +github.com/formancehq/numscript v0.0.9-0.20241009142721-febe5da15eb9/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= +github.com/formancehq/numscript v0.0.9-0.20241009144012-1150c14a1417 h1:LOd5hxnXDIBcehFrpW1OnXk+VSs0yJXeu1iAOO+Hji4= +github.com/formancehq/numscript v0.0.9-0.20241009144012-1150c14a1417/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= github.com/fortytw2/leaktest v1.3.0 h1:u8491cBMTQ8ft8aeV+adlcytMZylmA5nnwwkRZjI8vw= github.com/fortytw2/leaktest v1.3.0/go.mod h1:jDsjWgpAGjm2CA7WthBh/CdZYEPF31XHquHwclZch5g= github.com/getsentry/sentry-go v0.28.1 h1:zzaSm/vHmGllRM6Tpx1492r0YDzauArdBfkJRtY6P5k= diff --git a/internal/api/v2/controllers_transactions_create.go b/internal/api/v2/controllers_transactions_create.go index 20cbc1d5e..f9fade310 100644 --- a/internal/api/v2/controllers_transactions_create.go +++ b/internal/api/v2/controllers_transactions_create.go @@ -7,6 +7,7 @@ import ( ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" "errors" + "github.com/formancehq/go-libs/api" "github.com/formancehq/ledger/internal/api/common" ) @@ -45,6 +46,10 @@ func createTransaction(w http.ResponseWriter, r *http.Request) { api.WriteErrorResponse(w, http.StatusConflict, ErrConflict, err) case errors.Is(err, ledgercontroller.ErrInvalidIdempotencyInput{}): api.BadRequest(w, ErrValidation, err) + case errors.Is(err, ledgercontroller.ErrParsing{}): + api.BadRequest(w, ErrInterpreterParse, err) + case errors.Is(err, ledgercontroller.ErrRuntime{}): + api.BadRequest(w, ErrInterpreterRuntime, err) default: api.InternalServerError(w, r, err) } diff --git a/internal/api/v2/errors.go b/internal/api/v2/errors.go index b511a422b..df986123f 100644 --- a/internal/api/v2/errors.go +++ b/internal/api/v2/errors.go @@ -8,4 +8,7 @@ const ( ErrNoPostings = "NO_POSTINGS" ErrCompilationFailed = "COMPILATION_FAILED" ErrMetadataOverride = "METADATA_OVERRIDE" + + ErrInterpreterParse = "INTERPRETER_PARSE" + ErrInterpreterRuntime = "INTERPRETER_RUNTIME" ) diff --git a/internal/controller/ledger/errors.go b/internal/controller/ledger/errors.go index 682b2f299..1893e43bd 100644 --- a/internal/controller/ledger/errors.go +++ b/internal/controller/ledger/errors.go @@ -5,6 +5,7 @@ import ( "fmt" "github.com/formancehq/go-libs/platform/postgres" + "github.com/formancehq/numscript" "github.com/formancehq/ledger/internal/machine" @@ -186,6 +187,36 @@ func newErrCompilationFailed(err error) ErrCompilationFailed { } } +type ErrRuntime struct { + Source string + Inner numscript.InterpreterError +} + +func (e ErrRuntime) Error() string { + return e.Inner.Error() +} + +func (e ErrRuntime) Is(err error) bool { + _, ok := err.(ErrRuntime) + return ok +} + +type ErrParsing struct { + Source string + // Precondition: Errors is not empty + Errors []numscript.ParserError +} + +func (e ErrParsing) Error() string { + // TODO write a decent description + return "Got parsing errors" +} + +func (e ErrParsing) Is(err error) bool { + _, ok := err.(ErrParsing) + return ok +} + // ErrMetadataOverride is used when a metadata is defined at numscript level AND at the input level type ErrMetadataOverride struct { key string diff --git a/internal/controller/ledger/machine.go b/internal/controller/ledger/machine.go index 07f58ca45..a5e3a3e5e 100644 --- a/internal/controller/ledger/machine.go +++ b/internal/controller/ledger/machine.go @@ -101,7 +101,10 @@ func NewDefaultInterpreterMachineAdapter(parseResult numscript.ParseResult) *Def func (d *DefaultInterpreterMachineAdapter) Execute(ctx context.Context, tx TX, vars map[string]string) (*MachineResult, error) { execResult, err := d.parseResult.Run(ctx, vars, newNumscriptRewriteAdapter(tx)) if err != nil { - return nil, err + return nil, ErrRuntime{ + Source: d.parseResult.GetSource(), + Inner: err, + } } return &MachineResult{ diff --git a/internal/controller/ledger/machine_factory.go b/internal/controller/ledger/machine_factory.go index 7753158e7..967cbe19e 100644 --- a/internal/controller/ledger/machine_factory.go +++ b/internal/controller/ledger/machine_factory.go @@ -36,8 +36,10 @@ var _ MachineFactory = (*DefaultInterpreterMachineFactory)(nil) func (*DefaultInterpreterMachineFactory) Make(script string) (Machine, error) { parseResult := numscript.Parse(script) - if len(parseResult.GetParsingErrors()) != 0 { - return nil, nil + errs := parseResult.GetParsingErrors() + + if len(errs) != 0 { + return nil, ErrParsing{Source: script, Errors: errs} } return NewDefaultInterpreterMachineAdapter(parseResult), nil