diff --git a/grade/internal/infrastructure/seedwork/batch/multi_query.go b/grade/internal/infrastructure/seedwork/batch/multi_query.go index 44b7d26c..d6ecf922 100644 --- a/grade/internal/infrastructure/seedwork/batch/multi_query.go +++ b/grade/internal/infrastructure/seedwork/batch/multi_query.go @@ -4,6 +4,8 @@ import ( "fmt" "regexp" + "github.com/hashicorp/go-multierror" + "github.com/emacsway/grade/grade/internal/infrastructure/seedwork/session" "github.com/emacsway/grade/grade/internal/infrastructure/seedwork/utils" ) @@ -76,6 +78,7 @@ type MultiQuery struct { } func (q MultiQuery) Evaluate(s session.DbSession) (session.Result, error) { + var errs error r, err := s.Exec(q.sql(), q.flatParams()...) if err != nil { return nil, err @@ -83,10 +86,10 @@ func (q MultiQuery) Evaluate(s session.DbSession) (session.Result, error) { for i := range q.results { err = q.results[i].Resolve(0, 0) if err != nil { - return nil, err + errs = multierror.Append(errs, err) } } - return r, nil + return r, errs } type AutoincrementMultiInsertQuery struct { @@ -95,6 +98,7 @@ type AutoincrementMultiInsertQuery struct { func (q AutoincrementMultiInsertQuery) Evaluate(s session.DbSession) (session.Result, error) { var id int64 + var errs error rows, err := s.Query(q.sql(), q.flatParams()...) if err != nil { return nil, err @@ -108,7 +112,7 @@ func (q AutoincrementMultiInsertQuery) Evaluate(s session.DbSession) (session.Re } err = q.results[i].Resolve(id, 0) if err != nil { - return nil, err + errs = multierror.Append(errs, err) } i++ } @@ -116,5 +120,5 @@ func (q AutoincrementMultiInsertQuery) Evaluate(s session.DbSession) (session.Re if err != nil { return nil, err } - return session.NewResult(0, int64(len(q.results))), nil + return session.NewResult(0, int64(len(q.results))), errs } diff --git a/grade/internal/infrastructure/seedwork/session/deferred.go b/grade/internal/infrastructure/seedwork/session/deferred.go new file mode 100644 index 00000000..6422b573 --- /dev/null +++ b/grade/internal/infrastructure/seedwork/session/deferred.go @@ -0,0 +1,45 @@ +package session + +type DeferredImp[T interface{}] struct { + value T + err error + onSuccess DeferredCallback[T] + onFailure DeferredCallback[error] + isResolved bool +} + +func (r *DeferredImp[T]) Resolve(value T) error { + r.value = value + r.isResolved = true + return r.doResolve() +} + +func (r *DeferredImp[T]) Then(callback DeferredCallback[T]) error { + r.onSuccess = callback + if r.isResolved { + return r.doResolve() + } + return nil +} + +func (r *DeferredImp[T]) Catch(callback DeferredCallback[error]) error { + r.onFailure = callback + if r.isResolved && r.err != nil { + return r.onFailure(r.err) + } + return nil +} + +func (r *DeferredImp[T]) doResolve() error { + if r.onSuccess != nil { + r.err = r.onSuccess(r.value) + } + if r.err != nil { + if r.onFailure != nil { + return r.onFailure(r.err) + } else { + return r.err + } + } + return nil +} diff --git a/grade/internal/infrastructure/seedwork/session/interfaces.go b/grade/internal/infrastructure/seedwork/session/interfaces.go index cec94ac2..671966f1 100644 --- a/grade/internal/infrastructure/seedwork/session/interfaces.go +++ b/grade/internal/infrastructure/seedwork/session/interfaces.go @@ -51,22 +51,23 @@ type EventSourcedQueryEvaluator interface { // Deferred -type DeferredResultCallback func(Result) error +type DeferredCallback[T interface{}] func(T) error -type DeferredResult interface { - AddCallback(DeferredResultCallback) error +type Deferred[T interface{}] interface { + Then(DeferredCallback[T]) error + Catch(DeferredCallback[error]) error } -type DeferredRowsCallback func(Rows) error +type DeferredResult interface { + Deferred[Result] +} type DeferredRows interface { - AddCallback(DeferredRowsCallback) error + Then(DeferredCallback[Rows]) error } -type DeferredRowCallback func(Rows) error - type DeferredRow interface { - AddCallback(DeferredRowsCallback) error + Then(DeferredCallback[Row]) error } type DeferredDbSessionExecutor interface { diff --git a/grade/internal/infrastructure/seedwork/session/deferred_result.go b/grade/internal/infrastructure/seedwork/session/result.go similarity index 57% rename from grade/internal/infrastructure/seedwork/session/deferred_result.go rename to grade/internal/infrastructure/seedwork/session/result.go index cce0ff54..50e3aeea 100644 --- a/grade/internal/infrastructure/seedwork/session/deferred_result.go +++ b/grade/internal/infrastructure/seedwork/session/result.go @@ -17,36 +17,12 @@ func NewDeferredResult() *DeferredResultImp { return &DeferredResultImp{} } -type DeferredResultImp struct { +type ResultImp struct { lastInsertId int64 rowsAffected int64 - callbacks []DeferredResultCallback - isResolved bool -} - -func (r *DeferredResultImp) Resolve(lastInsertId, rowsAffected int64) error { - r.lastInsertId = lastInsertId - r.rowsAffected = rowsAffected - r.isResolved = true - for i := range r.callbacks { - err := r.callbacks[i](r) - if err != nil { - return err - } - } - return nil } -func (r *DeferredResultImp) AddCallback(callback DeferredResultCallback) error { - if r.isResolved { - return callback(r) - } else { - r.callbacks = append(r.callbacks, callback) - } - return nil -} - -func (r DeferredResultImp) LastInsertId() (int64, error) { +func (r ResultImp) LastInsertId() (int64, error) { if r.rowsAffected == 0 { return r.lastInsertId, nil } else { @@ -54,10 +30,20 @@ func (r DeferredResultImp) LastInsertId() (int64, error) { } } -func (r DeferredResultImp) RowsAffected() (int64, error) { +func (r ResultImp) RowsAffected() (int64, error) { if r.lastInsertId == 0 { return r.rowsAffected, nil } else { return 0, errors.New("RowsAffected is not supported by INSERT command") } } + +type DeferredResultImp struct { + DeferredImp[Result] + ResultImp +} + +func (r *DeferredResultImp) Resolve(lastInsertId, rowsAffected int64) error { + r.ResultImp = ResultImp{lastInsertId, rowsAffected} + return r.DeferredImp.Resolve(r) +}