Skip to content

Commit

Permalink
fix(ledger): use a unique index on idempotency key and ledger
Browse files Browse the repository at this point in the history
  • Loading branch information
paul-nicolas committed Aug 6, 2024
1 parent 8436bef commit a34eec5
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 0 deletions.
10 changes: 10 additions & 0 deletions components/ledger/internal/storage/ledgerstore/bucket.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ var addIndexOnReference string
//go:embed migrations/7-add-ik-unique-index.sql
var addIKUniqueIndex string

//go:embed migrations/8-ik-ledger-unique-index.sql
var updateIKUniqueIndex string

type Bucket struct {
name string
db *bun.DB
Expand Down Expand Up @@ -200,6 +203,13 @@ func registerMigrations(migrator *migrations.Migrator, name string) {
return err
},
},
migrations.Migration{
Name: "Update unique index on IK",
UpWithContext: func(ctx context.Context, tx bun.Tx) error {
_, err := tx.ExecContext(ctx, updateIKUniqueIndex)
return err
},
},
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
drop index logs_idempotency_key;

create unique index logs_idempotency_key on logs (ledger, idempotency_key);
86 changes: 86 additions & 0 deletions tests/integration/suite/ledger-create-transaction-ik.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
package suite

import (
"math/big"
"net/http"
"time"

"github.com/formancehq/stack/tests/integration/internal/modules"

"github.com/formancehq/formance-sdk-go/v2/pkg/models/operations"
"github.com/formancehq/formance-sdk-go/v2/pkg/models/shared"
"github.com/formancehq/stack/libs/go-libs/pointer"
. "github.com/formancehq/stack/tests/integration/internal"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
)

var _ = WithModules([]*Module{modules.Search, modules.Ledger}, func() {
BeforeEach(func() {
createLedgerResponse, err := Client().Ledger.V2CreateLedger(TestContext(), operations.V2CreateLedgerRequest{
Ledger: "default",
})
Expect(err).To(BeNil())
Expect(createLedgerResponse.StatusCode).To(Equal(http.StatusNoContent))

createLedgerResponse, err = Client().Ledger.V2CreateLedger(TestContext(), operations.V2CreateLedgerRequest{
Ledger: "test",
})
Expect(err).To(BeNil())
Expect(createLedgerResponse.StatusCode).To(Equal(http.StatusNoContent))
})
When("creating a transaction on a ledger", func() {
var (
timestamp = time.Now().Add(-1 * time.Minute).Round(time.Second).UTC()
timestamp2 = time.Now().Round(time.Second).UTC()
)
It("should fail", func() {
// Create a transaction
response, err := Client().Ledger.V2CreateTransaction(
TestContext(),
operations.V2CreateTransactionRequest{
IdempotencyKey: pointer.For("foo"),
V2PostTransaction: shared.V2PostTransaction{
Metadata: map[string]string{},
Postings: []shared.V2Posting{
{
Amount: big.NewInt(100),
Asset: "USD",
Source: "world",
Destination: "alice",
},
},
Timestamp: &timestamp,
Reference: pointer.For("foo"),
},
Ledger: "default",
},
)
Expect(err).ToNot(HaveOccurred())
Expect(response.StatusCode).To(Equal(200))

response, err = Client().Ledger.V2CreateTransaction(
TestContext(),
operations.V2CreateTransactionRequest{
IdempotencyKey: pointer.For("foo"),
V2PostTransaction: shared.V2PostTransaction{
Metadata: map[string]string{},
Postings: []shared.V2Posting{
{
Amount: big.NewInt(100),
Asset: "USD",
Source: "world",
Destination: "alice",
},
},
Timestamp: &timestamp2,
Reference: pointer.For("foo2"),
},
Ledger: "test",
},
)
Expect(err).ToNot(HaveOccurred())
Expect(response.StatusCode).To(Equal(200))
})
})
})

0 comments on commit a34eec5

Please sign in to comment.