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

Feature/num 255 error handling on ledger #123

Merged
merged 2 commits into from
Jan 10, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,14 @@ go 1.16

require (
github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/davecgh/go-spew v1.1.1
github.com/gin-contrib/cors v1.3.1
github.com/gin-contrib/logger v0.2.0
github.com/gin-gonic/gin v1.7.7
github.com/go-openapi/spec v0.20.4 // indirect
github.com/google/go-cmp v0.5.6
github.com/huandu/go-sqlbuilder v1.13.0
github.com/jackc/pgconn v1.10.1
github.com/jackc/pgx/v4 v4.14.1
github.com/mailru/easyjson v0.7.7 // indirect
github.com/mattn/go-sqlite3 v1.14.9
Expand Down
9 changes: 9 additions & 0 deletions pkg/api/controllers/transaction_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package controllers

import (
"errors"
"github.com/numary/ledger/pkg/storage"
"net/http"

"github.com/gin-gonic/gin"
Expand Down Expand Up @@ -74,6 +75,14 @@ func (ctl *TransactionController) PostTransaction(c *gin.Context) {

ts, err := l.(*ledger.Ledger).Commit(c, []core.Transaction{t})
if err != nil {
switch eerr := err.(type) {
case *storage.Error:
switch eerr.Code {
case storage.ConstraintFailed:
ctl.responseError(c, http.StatusConflict, err)
return
}
}
ctl.responseError(
c,
http.StatusInternalServerError,
Expand Down
2 changes: 1 addition & 1 deletion pkg/storage/sqlstorage/accounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (s *Store) FindAccounts(ctx context.Context, q query.Query) (query.Cursor,
)

if err != nil {
return c, err
return c, s.error(err)
}

for rows.Next() {
Expand Down
12 changes: 6 additions & 6 deletions pkg/storage/sqlstorage/aggregations.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ func (s *Store) CountTransactions(ctx context.Context) (int64, error) {

err := s.db.QueryRowContext(ctx, sqlq, args...).Scan(&count)

return count, err
return count, s.error(err)
}

func (s *Store) CountAccounts(ctx context.Context) (int64, error) {
Expand All @@ -34,7 +34,7 @@ func (s *Store) CountAccounts(ctx context.Context) (int64, error) {

err := s.db.QueryRowContext(ctx, sqlq, args...).Scan(&count)

return count, err
return count, s.error(err)
}

func (s *Store) CountMeta(ctx context.Context) (int64, error) {
Expand All @@ -52,7 +52,7 @@ func (s *Store) CountMeta(ctx context.Context) (int64, error) {
q := s.db.QueryRowContext(ctx, sqlq, args...)
err := q.Scan(&count)

return count, err
return count, s.error(err)
}

func (s *Store) AggregateBalances(ctx context.Context, address string) (map[string]int64, error) {
Expand All @@ -61,7 +61,7 @@ func (s *Store) AggregateBalances(ctx context.Context, address string) (map[stri
volumes, err := s.AggregateVolumes(ctx, address)

if err != nil {
return balances, err
return balances, s.error(err)
}

for asset := range volumes {
Expand Down Expand Up @@ -97,7 +97,7 @@ func (s *Store) AggregateVolumes(ctx context.Context, address string) (map[strin
rows, err := s.db.QueryContext(ctx, sqlq, args...)

if err != nil {
return volumes, err
return volumes, s.error(err)
}

for rows.Next() {
Expand All @@ -110,7 +110,7 @@ func (s *Store) AggregateVolumes(ctx context.Context, address string) (map[strin
err := rows.Scan(&row.asset, &row.t, &row.amount)

if err != nil {
return volumes, err
return volumes, s.error(err)
}

if _, ok := volumes[row.asset]; !ok {
Expand Down
8 changes: 0 additions & 8 deletions pkg/storage/sqlstorage/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,9 @@ import (
"database/sql"
"errors"
"fmt"
"github.com/huandu/go-sqlbuilder"
"github.com/numary/ledger/pkg/storage"
)

type Flavor = sqlbuilder.Flavor

var (
SQLite = sqlbuilder.SQLite
PostgreSQL = sqlbuilder.PostgreSQL
)

var sqlDrivers = map[Flavor]struct {
driverName string
}{
Expand Down
41 changes: 41 additions & 0 deletions pkg/storage/sqlstorage/flavor.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package sqlstorage

import (
"github.com/huandu/go-sqlbuilder"
"github.com/jackc/pgconn"
"github.com/mattn/go-sqlite3"
"github.com/numary/ledger/pkg/storage"
)

type Flavor = sqlbuilder.Flavor

var (
SQLite = sqlbuilder.SQLite
PostgreSQL = sqlbuilder.PostgreSQL
)

func errorFromFlavor(f Flavor, err error) error {
if err == nil {
return nil
}
switch f {
case SQLite:
eerr, ok := err.(sqlite3.Error)
if !ok {
return err
}
if eerr.Code == sqlite3.ErrConstraint {
return storage.NewError(storage.ConstraintFailed, err)
}
case PostgreSQL:
eerr, ok := err.(*pgconn.PgError)
if !ok {
return err
}
switch eerr.Code {
case "23505":
return storage.NewError(storage.ConstraintFailed, err)
}
}
return err
}
12 changes: 6 additions & 6 deletions pkg/storage/sqlstorage/metadata.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
func (s *Store) LastMetaID(ctx context.Context) (int64, error) {
count, err := s.CountMeta(ctx)
if err != nil {
return 0, err
return 0, s.error(err)
}
return count - 1, nil
}
Expand All @@ -36,7 +36,7 @@ func (s *Store) GetMeta(ctx context.Context, ty string, id string) (core.Metadat
rows, err := s.db.QueryContext(ctx, sqlq, args...)

if err != nil {
return nil, err
return nil, s.error(err)
}

meta := core.Metadata{}
Expand All @@ -51,15 +51,15 @@ func (s *Store) GetMeta(ctx context.Context, ty string, id string) (core.Metadat
)

if err != nil {
return nil, err
return nil, s.error(err)
}

var value json.RawMessage

err = json.Unmarshal([]byte(metaValue), &value)

if err != nil {
return nil, err
return nil, s.error(err)
}

meta[metaKey] = value
Expand All @@ -71,7 +71,7 @@ func (s *Store) GetMeta(ctx context.Context, ty string, id string) (core.Metadat
func (s *Store) SaveMeta(ctx context.Context, id int64, timestamp, targetType, targetID, key, value string) error {
tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return err
return s.error(err)
}

ib := sqlbuilder.NewInsertBuilder()
Expand Down Expand Up @@ -101,7 +101,7 @@ func (s *Store) SaveMeta(ctx context.Context, id int64, timestamp, targetType, t
logrus.Debugln("failed to save metadata", err)
tx.Rollback()

return err
return s.error(err)
}

err = tx.Commit()
Expand Down
10 changes: 7 additions & 3 deletions pkg/storage/sqlstorage/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,13 +26,17 @@ type Store struct {

func (s *Store) table(name string) string {
switch s.flavor {
case sqlbuilder.PostgreSQL:
case PostgreSQL:
return fmt.Sprintf(`"%s"."%s"`, s.ledger, name)
default:
return name
}
}

func (s *Store) error(err error) error {
return errorFromFlavor(s.flavor, err)
}

func NewStore(name string, flavor sqlbuilder.Flavor, db *sql.DB, onClose func(ctx context.Context) error) (*Store, error) {
return &Store{
ledger: name,
Expand All @@ -56,7 +60,7 @@ func (s *Store) Initialize(ctx context.Context) error {
entries, err := migrations.ReadDir(migrationsDir)

if err != nil {
return err
return s.error(err)
}

for _, m := range entries {
Expand All @@ -82,7 +86,7 @@ func (s *Store) Initialize(ctx context.Context) error {
if err != nil {
err = fmt.Errorf("failed to run statement %d: %w", i, err)
logrus.Errorln(err)
return err
return s.error(err)
}
}

Expand Down
22 changes: 22 additions & 0 deletions pkg/storage/sqlstorage/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,10 @@ func TestStore(t *testing.T) {
name: "SaveTransactions",
fn: testSaveTransaction,
},
{
name: "DuplicatedTransaction",
fn: testDuplicatedTransaction,
},
{
name: "SaveMeta",
fn: testSaveMeta,
Expand Down Expand Up @@ -167,6 +171,24 @@ func testSaveTransaction(t *testing.T, store storage.Store) {
assert.NoError(t, err)
}

func testDuplicatedTransaction(t *testing.T, store storage.Store) {
txs := []core.Transaction{
{
Postings: []core.Posting{
{},
},
Reference: "foo",
},
}
err := store.SaveTransactions(context.Background(), txs)
assert.NoError(t, err)

err = store.SaveTransactions(context.Background(), txs)
assert.Error(t, err)
assert.IsType(t, &storage.Error{}, err)
assert.Equal(t, storage.ConstraintFailed, err.(*storage.Error).Code)
}

func testSaveMeta(t *testing.T, store storage.Store) {
err := store.SaveMeta(context.Background(), 1, time.Now().Format(time.RFC3339),
"transaction", "1", "firstname", "\"YYY\"")
Expand Down
20 changes: 10 additions & 10 deletions pkg/storage/sqlstorage/transactions.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ func (s *Store) FindTransactions(ctx context.Context, q query.Query) (query.Curs
)

if err != nil {
return c, err
return c, s.error(err)
}

transactions := map[int64]core.Transaction{}
Expand Down Expand Up @@ -114,7 +114,7 @@ func (s *Store) FindTransactions(ctx context.Context, q query.Query) (query.Curs
for _, t := range transactions {
meta, err := s.GetMeta(ctx, "transaction", fmt.Sprintf("%d", t.ID))
if err != nil {
return c, err
return c, s.error(err)
}
t.Metadata = meta

Expand Down Expand Up @@ -143,7 +143,7 @@ func (s *Store) SaveTransactions(ctx context.Context, ts []core.Transaction) err

tx, err := s.db.BeginTx(ctx, nil)
if err != nil {
return err
return s.error(err)
}

for _, t := range ts {
Expand All @@ -163,7 +163,7 @@ func (s *Store) SaveTransactions(ctx context.Context, ts []core.Transaction) err
if err != nil {
tx.Rollback()

return err
return s.error(err)
}

for i, p := range t.Postings {
Expand All @@ -179,15 +179,15 @@ func (s *Store) SaveTransactions(ctx context.Context, ts []core.Transaction) err
if err != nil {
tx.Rollback()

return err
return s.error(err)
}
}

nextID, err := s.CountMeta(ctx)
if err != nil {
tx.Rollback()

return err
return s.error(err)
}

for key, value := range t.Metadata {
Expand Down Expand Up @@ -217,7 +217,7 @@ func (s *Store) SaveTransactions(ctx context.Context, ts []core.Transaction) err
if err != nil {
tx.Rollback()

return err
return s.error(err)
}

nextID++
Expand Down Expand Up @@ -254,7 +254,7 @@ func (s *Store) GetTransaction(ctx context.Context, txid string) (tx core.Transa
)

if err != nil {
return tx, err
return tx, s.error(err)
}

for rows.Next() {
Expand Down Expand Up @@ -290,7 +290,7 @@ func (s *Store) GetTransaction(ctx context.Context, txid string) (tx core.Transa

meta, err := s.GetMeta(ctx, "transaction", fmt.Sprintf("%d", tx.ID))
if err != nil {
return tx, err
return tx, s.error(err)
}
tx.Metadata = meta

Expand All @@ -305,7 +305,7 @@ func (s *Store) LastTransaction(ctx context.Context) (*core.Transaction, error)

c, err := s.FindTransactions(ctx, q)
if err != nil {
return nil, err
return nil, s.error(err)
}

txs := (c.Data).([]core.Transaction)
Expand Down
Loading