diff --git a/cmd/buckets_upgrade.go b/cmd/buckets_upgrade.go index e481648823..e7a763429c 100644 --- a/cmd/buckets_upgrade.go +++ b/cmd/buckets_upgrade.go @@ -7,7 +7,6 @@ import ( "github.com/formancehq/ledger/internal/storage/bucket" "github.com/formancehq/ledger/internal/storage/driver" "github.com/formancehq/ledger/internal/storage/ledger" - systemstore "github.com/formancehq/ledger/internal/storage/system" "github.com/spf13/cobra" "github.com/uptrace/bun" ) @@ -56,9 +55,9 @@ func getDriver(cmd *cobra.Command) (*driver.Driver, *bun.DB, error) { } driver := driver.New( + db, ledger.NewFactory(db), - systemstore.New(db), - bucket.NewDefaultFactory(db), + bucket.NewDefaultFactory(), ) if err := driver.Initialize(cmd.Context()); err != nil { return nil, nil, err diff --git a/cmd/root.go b/cmd/root.go index ac9eed7f74..fbb1440d85 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -7,7 +7,6 @@ import ( "github.com/formancehq/ledger/internal/storage/bucket" "github.com/formancehq/ledger/internal/storage/driver" "github.com/formancehq/ledger/internal/storage/ledger" - systemstore "github.com/formancehq/ledger/internal/storage/system" "github.com/uptrace/bun" "github.com/spf13/cobra" @@ -43,11 +42,7 @@ func NewRootCommand() *cobra.Command { logger := logging.NewDefaultLogger(cmd.OutOrStdout(), service.IsDebug(cmd), false, false) cmd.SetContext(logging.ContextWithLogger(cmd.Context(), logger)) - driver := driver.New( - ledger.NewFactory(db), - systemstore.New(db), - bucket.NewDefaultFactory(db), - ) + driver := driver.New(db, ledger.NewFactory(db), bucket.NewDefaultFactory()) if err := driver.Initialize(cmd.Context()); err != nil { return err } diff --git a/go.mod b/go.mod index fa04cc6c29..9e1fbbf5b6 100644 --- a/go.mod +++ b/go.mod @@ -14,7 +14,7 @@ require ( github.com/antlr/antlr4/runtime/Go/antlr v1.4.10 github.com/bluele/gcache v0.0.2 github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3 - github.com/formancehq/go-libs/v2 v2.0.1-0.20250217160145-75857677eef9 + github.com/formancehq/go-libs/v2 v2.0.1-0.20250225100718-5e1dfe022817 github.com/formancehq/ledger/pkg/client v0.0.0-00010101000000-000000000000 github.com/go-chi/chi/v5 v5.2.1 github.com/go-chi/cors v1.2.1 @@ -24,14 +24,14 @@ require ( github.com/jackc/pgx/v5 v5.7.2 github.com/jamiealquiza/tachymeter v2.0.0+incompatible github.com/logrusorgru/aurora v2.0.3+incompatible - github.com/nats-io/nats.go v1.38.0 + github.com/nats-io/nats.go v1.39.1 github.com/onsi/ginkgo/v2 v2.22.1 github.com/onsi/gomega v1.36.2 github.com/ory/dockertest/v3 v3.11.0 github.com/pborman/uuid v1.2.1 github.com/pkg/errors v0.9.1 github.com/shomali11/xsql v0.0.0-20190608141458-bf76292144df - github.com/spf13/cobra v1.8.1 + github.com/spf13/cobra v1.9.1 github.com/spf13/pflag v1.0.6 github.com/stoewer/go-strcase v1.3.0 github.com/stretchr/testify v1.10.0 @@ -47,7 +47,7 @@ require ( go.uber.org/fx v1.23.0 go.uber.org/mock v0.5.0 golang.org/x/oauth2 v0.24.0 - golang.org/x/sync v0.10.0 + golang.org/x/sync v0.11.0 ) require gopkg.in/yaml.v3 v3.0.1 // indirect @@ -71,19 +71,19 @@ require ( github.com/ajg/form v1.5.1 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 // indirect - github.com/aws/aws-sdk-go-v2 v1.36.1 // indirect - github.com/aws/aws-sdk-go-v2/config v1.29.6 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.59 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 // indirect - github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.9 // indirect - github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 // indirect - github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 // indirect - github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 // indirect - github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 // indirect - github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 // indirect - github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 // indirect + github.com/aws/aws-sdk-go-v2 v1.36.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.29.7 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.60 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29 // indirect + github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.10 // indirect + github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 // indirect + github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 // indirect + github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 // indirect + github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 // indirect + github.com/aws/aws-sdk-go-v2/service/sso v1.24.16 // indirect + github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15 // indirect + github.com/aws/aws-sdk-go-v2/service/sts v1.33.15 // indirect github.com/aws/smithy-go v1.22.2 // indirect github.com/bahlo/generic-list-go v0.2.0 // indirect github.com/buger/jsonparser v1.1.1 // indirect @@ -93,7 +93,7 @@ require ( github.com/dlclark/regexp2 v1.11.4 // indirect github.com/dnwe/otelsarama v0.0.0-20240308230250-9388d9d40bc0 // indirect github.com/docker/cli v27.3.1+incompatible // indirect - github.com/docker/docker v27.4.1+incompatible // indirect + github.com/docker/docker v27.5.1+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/eapache/go-resiliency v1.7.0 // indirect @@ -103,14 +103,14 @@ require ( github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect github.com/fatih/color v1.18.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect - github.com/formancehq/numscript v0.0.10 + github.com/formancehq/numscript v0.0.11 github.com/go-chi/chi v4.1.2+incompatible // indirect github.com/go-chi/render v1.0.3 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/go-sourcemap/sourcemap v2.1.3+incompatible // indirect - github.com/go-sql-driver/mysql v1.8.1 // indirect + github.com/go-sql-driver/mysql v1.9.0 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/go-viper/mapstructure/v2 v2.2.1 // indirect github.com/gogo/protobuf v1.3.2 // indirect @@ -199,11 +199,11 @@ require ( go.uber.org/dig v1.18.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.32.0 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect - golang.org/x/net v0.34.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/net v0.35.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect golang.org/x/time v0.9.0 // indirect golang.org/x/tools v0.28.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f // indirect diff --git a/go.sum b/go.sum index 6641118a9f..de3ca1a605 100644 --- a/go.sum +++ b/go.sum @@ -30,32 +30,32 @@ github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYW github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JIgManMX79Q6quV6E= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI= -github.com/aws/aws-sdk-go-v2 v1.36.1 h1:iTDl5U6oAhkNPba0e1t1hrwAo02ZMqbrGq4k5JBWM5E= -github.com/aws/aws-sdk-go-v2 v1.36.1/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= -github.com/aws/aws-sdk-go-v2/config v1.29.6 h1:fqgqEKK5HaZVWLQoLiC9Q+xDlSp+1LYidp6ybGE2OGg= -github.com/aws/aws-sdk-go-v2/config v1.29.6/go.mod h1:Ft+WLODzDQmCTHDvqAH1JfC2xxbZ0MxpZAcJqmE1LTQ= -github.com/aws/aws-sdk-go-v2/credentials v1.17.59 h1:9btwmrt//Q6JcSdgJOLI98sdr5p7tssS9yAsGe8aKP4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.59/go.mod h1:NM8fM6ovI3zak23UISdWidyZuI1ghNe2xjzUZAyT+08= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 h1:KwsodFKVQTlI5EyhRSugALzsV6mG/SGrdjlMXSZSdso= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28/go.mod h1:EY3APf9MzygVhKuPXAc5H+MkGb8k/DOSQjWS0LgkKqI= -github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.9 h1:bgT3nh3B42Glpr1lT8TiVT0XEvJIqieoRFaW+AMTW8s= -github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.9/go.mod h1:FmhyqqiI3BYgCrkdl4Xit5DyGZw1dtOaRb6aLqJLQ8w= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 h1:BjUcr3X3K0wZPGFg2bxOWW3VPN8rkE3/61zhP+IHviA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32/go.mod h1:80+OGC/bgzzFFTUmcuwD0lb4YutwQeKLFpmt6hoWapU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 h1:m1GeXHVMJsRsUAqG6HjZWx9dj7F5TR+cF1bjyfYyBd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32/go.mod h1:IitoQxGfaKdVLNg0hD8/DXmAqNy0H4K2H2Sf91ti8sI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 h1:SYVGSFQHlchIcy6e7x12bsrxClCXSP5et8cqVhL8cuw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13/go.mod h1:kizuDaLX37bG5WZaoxGPQR/LNFXpxp0vsUnqfkWXfNE= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 h1:/eE3DogBjYlvlbhd2ssWyeuovWunHLxfgw3s/OJa4GQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.15/go.mod h1:2PCJYpi7EKeA5SkStAmZlF6fi0uUABuhtF8ILHjGc3Y= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 h1:M/zwXiL2iXUrHputuXgmO94TVNmcenPHxgLXLutodKE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14/go.mod h1:RVwIw3y/IqxC2YEXSIkAzRDdEU1iRabDPaYjpGCbCGQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 h1:TzeR06UCMUq+KA3bDkujxK1GVGy+G8qQN/QVYzGLkQE= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.14/go.mod h1:dspXf/oYWGWo6DEvj98wpaTeqt5+DMidZD0A9BYTizc= +github.com/aws/aws-sdk-go-v2 v1.36.2 h1:Ub6I4lq/71+tPb/atswvToaLGVMxKZvjYDVOWEExOcU= +github.com/aws/aws-sdk-go-v2 v1.36.2/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= +github.com/aws/aws-sdk-go-v2/config v1.29.7 h1:71nqi6gUbAUiEQkypHQcNVSFJVUFANpSeUNShiwWX2M= +github.com/aws/aws-sdk-go-v2/config v1.29.7/go.mod h1:yqJQ3nh2HWw/uxd56bicyvmDW4KSc+4wN6lL8pYjynU= +github.com/aws/aws-sdk-go-v2/credentials v1.17.60 h1:1dq+ELaT5ogfmqtV1eocq8SpOK1NRsuUfmhQtD/XAh4= +github.com/aws/aws-sdk-go-v2/credentials v1.17.60/go.mod h1:HDes+fn/xo9VeszXqjBVkxOo/aUy8Mc6QqKvZk32GlE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29 h1:JO8pydejFKmGcUNiiwt75dzLHRWthkwApIvPoyUtXEg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29/go.mod h1:adxZ9i9DRmB8zAT0pO0yGnsmu0geomp5a3uq5XpgOJ8= +github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.10 h1:dWT0CmI2v2mA0tdcBY+xH/FJl25Koirl76MREqw/dSM= +github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.10/go.mod h1:xkd3fB3k0zkzUkCplj8Cz+f7b4mJj8KoNTKogu8X8do= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 h1:knLyPMw3r3JsU8MFHWctE4/e2qWbPaxDYLlohPvnY8c= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33/go.mod h1:EBp2HQ3f+XCB+5J+IoEbGhoV7CpJbnrsd4asNXmTL0A= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 h1:K0+Ne08zqti8J9jwENxZ5NoUyBnaFDTu3apwQJWrwwA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33/go.mod h1:K97stwwzaWzmqxO8yLGHhClbVW1tC6VT1pDLk1pGrq4= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 h1:2scbY6//jy/s8+5vGrk7l1+UtHl0h9A4MjOO2k/TM2E= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14/go.mod h1:bRpZPHZpSe5YRHmPfK3h1M7UBFCn2szHzyx0rw04zro= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.16 h1:YV6xIKDJp6U7YB2bxfud9IENO1LRpGhe2Tv/OKtPrOQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.16/go.mod h1:DvbmMKgtpA6OihFJK13gHMZOZrCHttz8wPHGKXqU+3o= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15 h1:kMyK3aKotq1aTBsj1eS8ERJLjqYRRRcsmP33ozlCvlk= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15/go.mod h1:5uPZU7vSNzb8Y0dm75xTikinegPYK3uJmIHQZFq5Aqo= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.15 h1:ht1jVmeeo2anR7zDiYJLSnRYnO/9NILXXu42FP3rJg0= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.15/go.mod h1:xWZ5cOiFe3czngChE4LhCBqUxNwgfwndEF7XlYP/yD8= github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= @@ -68,7 +68,7 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -81,8 +81,8 @@ github.com/dnwe/otelsarama v0.0.0-20240308230250-9388d9d40bc0 h1:R2zQhFwSCyyd7L4 github.com/dnwe/otelsarama v0.0.0-20240308230250-9388d9d40bc0/go.mod h1:2MqLKYJfjs3UriXXF9Fd0Qmh/lhxi/6tHXkqtXxyIHc= github.com/docker/cli v27.3.1+incompatible h1:qEGdFBF3Xu6SCvCYhc7CzaQTlBmqDuzxPDpigSyeKQQ= github.com/docker/cli v27.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v27.4.1+incompatible h1:ZJvcY7gfwHn1JF48PfbyXg7Jyt9ZCWDW+GGXOIxEwp4= -github.com/docker/docker v27.4.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8= +github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -104,10 +104,10 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/formancehq/go-libs/v2 v2.0.1-0.20250217160145-75857677eef9 h1:68gyI+zMcWowRrUz8SYUJGCFUb64LD8P0w5dRyHWIz8= -github.com/formancehq/go-libs/v2 v2.0.1-0.20250217160145-75857677eef9/go.mod h1:U9+fV6R34gG24TfNuOCUMQmfdP3g54nsFlLNlManZ5s= -github.com/formancehq/numscript v0.0.10 h1:ElvYpoayUX5tHtCCR18ihJTjNlHzdkE4M0IqSm9aufg= -github.com/formancehq/numscript v0.0.10/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= +github.com/formancehq/go-libs/v2 v2.0.1-0.20250225100718-5e1dfe022817 h1:cqsYamzWEvqvQfPrWJBDqLUMtaoLJB2f1CMQKR0MfpQ= +github.com/formancehq/go-libs/v2 v2.0.1-0.20250225100718-5e1dfe022817/go.mod h1:XxvR+WrPGq7UjYA/Uk0Ch0bgPs+pDoVCVOo//aYbIRI= +github.com/formancehq/numscript v0.0.11 h1:vZDfRfrhOkuInv5fLIXvWZU3ylK+fVgmR4la01dO5to= +github.com/formancehq/numscript v0.0.11/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/gkampitakis/ciinfo v0.3.0 h1:gWZlOC2+RYYttL0hBqcoQhM7h1qNkVqvRCV1fOvpAv8= @@ -134,8 +134,8 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= +github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= @@ -258,8 +258,8 @@ github.com/nats-io/jwt/v2 v2.7.3 h1:6bNPK+FXgBeAqdj4cYQ0F8ViHRbi7woQLq4W29nUAzE= github.com/nats-io/jwt/v2 v2.7.3/go.mod h1:GvkcbHhKquj3pkioy5put1wvPxs78UlZ7D/pY+BgZk4= github.com/nats-io/nats-server/v2 v2.10.25 h1:J0GWLDDXo5HId7ti/lTmBfs+lzhmu8RPkoKl0eSCqwc= github.com/nats-io/nats-server/v2 v2.10.25/go.mod h1:/YYYQO7cuoOBt+A7/8cVjuhWTaTUEAlZbJT+3sMAfFU= -github.com/nats-io/nats.go v1.38.0 h1:A7P+g7Wjp4/NWqDOOP/K6hfhr54DvdDQUznt5JFg9XA= -github.com/nats-io/nats.go v1.38.0/go.mod h1:IGUM++TwokGnXPs82/wCuiHS02/aKrdYUQkU8If6yjw= +github.com/nats-io/nats.go v1.39.1 h1:oTkfKBmz7W047vRxV762M67ZdXeOtUgvbBaNoQ+3PPk= +github.com/nats-io/nats.go v1.39.1/go.mod h1:MgRb8oOdigA6cYpEPhXJuRVH6UE/V4jblJ2jQ27IXYM= github.com/nats-io/nkeys v0.4.9 h1:qe9Faq2Gxwi6RZnZMXfmGMZkg3afLLOtrU+gDZJ35b0= github.com/nats-io/nkeys v0.4.9/go.mod h1:jcMqs+FLG+W5YO36OX6wFIFcmpdAns+w1Wm6D3I/evE= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= @@ -310,9 +310,8 @@ github.com/shomali11/xsql v0.0.0-20190608141458-bf76292144df h1:SVCDTuzM3KEk8WBw github.com/shomali11/xsql v0.0.0-20190608141458-bf76292144df/go.mod h1:K8jR5lDI2MGs9Ky+X2jIF4MwIslI0L8o8ijIlEq7/Vw= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= @@ -441,8 +440,8 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= @@ -457,16 +456,16 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -487,8 +486,8 @@ golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= @@ -497,8 +496,8 @@ golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= diff --git a/internal/controller/ledger/store.go b/internal/controller/ledger/store.go index 3b1375b924..8aabac11cb 100644 --- a/internal/controller/ledger/store.go +++ b/internal/controller/ledger/store.go @@ -138,7 +138,17 @@ func newVmStoreAdapter(tx Store) *vmStoreAdapter { } } -type ListLedgersQuery bunpaginate.OffsetPaginatedQuery[PaginatedQueryOptions[struct{}]] +type ListLedgersQueryPayload struct { + Bucket string +} + +type ListLedgersQuery bunpaginate.OffsetPaginatedQuery[PaginatedQueryOptions[ListLedgersQueryPayload]] + +func (q ListLedgersQuery) WithBucket(bucket string) ListLedgersQuery { + q.Options.Options.Bucket = bucket + + return q +} func NewListLedgersQuery(pageSize uint64) ListLedgersQuery { return ListLedgersQuery{ diff --git a/internal/storage/bucket/bucket.go b/internal/storage/bucket/bucket.go index 48a6b9316d..4b8802f071 100644 --- a/internal/storage/bucket/bucket.go +++ b/internal/storage/bucket/bucket.go @@ -19,27 +19,24 @@ type Bucket interface { } type Factory interface { - Create(name string) Bucket - GetMigrator(b string) *migrations.Migrator + Create(name string, db bun.IDB) Bucket + GetMigrator(b string, db bun.IDB) *migrations.Migrator } type DefaultFactory struct { tracer trace.Tracer - db *bun.DB } -func (f *DefaultFactory) Create(name string) Bucket { - return NewDefault(f.db, f.tracer, name) +func (f *DefaultFactory) Create(name string, db bun.IDB) Bucket { + return NewDefault(db, f.tracer, name) } -func (f *DefaultFactory) GetMigrator(b string) *migrations.Migrator { - return GetMigrator(f.db, b) +func (f *DefaultFactory) GetMigrator(b string, db bun.IDB) *migrations.Migrator { + return GetMigrator(db, b) } -func NewDefaultFactory(db *bun.DB, options ...DefaultFactoryOption) *DefaultFactory { - ret := &DefaultFactory{ - db: db, - } +func NewDefaultFactory(options ...DefaultFactoryOption) *DefaultFactory { + ret := &DefaultFactory{} for _, option := range append(defaultOptions, options...) { option(ret) } diff --git a/internal/storage/bucket/default_bucket.go b/internal/storage/bucket/default_bucket.go index 13e3ca8afa..dd5648838b 100644 --- a/internal/storage/bucket/default_bucket.go +++ b/internal/storage/bucket/default_bucket.go @@ -19,7 +19,7 @@ const MinimalSchemaVersion = 12 type DefaultBucket struct { name string - db *bun.DB + db bun.IDB tracer trace.Tracer } @@ -79,7 +79,7 @@ func (b *DefaultBucket) AddLedger(ctx context.Context, l ledger.Ledger) error { return nil } -func NewDefault(db *bun.DB, tracer trace.Tracer, name string) *DefaultBucket { +func NewDefault(db bun.IDB, tracer trace.Tracer, name string) *DefaultBucket { return &DefaultBucket{ db: db, name: name, @@ -92,6 +92,9 @@ type ledgerSetup struct { script string } +// notes: Be careful if changing the order of the migration. +// The actions on tables are organized following the same order used when committing a new transaction. +// It prevents deadlocks. var ledgerSetups = []ledgerSetup{ { script: ` @@ -100,66 +103,70 @@ var ledgerSetups = []ledgerSetup{ create sequence "{{.Bucket}}"."transaction_id_{{.ID}}" owned by "{{.Bucket}}".transactions.id; select setval('"{{.Bucket}}"."transaction_id_{{.ID}}"', coalesce(( select max(id) + 1 - from "{{.Bucket}}".transactions + from "{{.Bucket}}"."transactions" where ledger = '{{ .Name }}' ), 1)::bigint, false); `, }, { + requireFeatures: features.FeatureSet{ + features.FeatureTransactionMetadataHistory: "SYNC", + }, script: ` - -- create a sequence for logs by ledger instead of a sequence of the table as we want to have contiguous ids - -- notes: we can still have "holes" on id since a sql transaction can be reverted after a usage of the sequence - create sequence "{{.Bucket}}"."log_id_{{.ID}}" owned by "{{.Bucket}}".logs.id; - select setval('"{{.Bucket}}"."log_id_{{.ID}}"', coalesce(( - select max(id) + 1 - from "{{.Bucket}}".logs - where ledger = '{{ .Name }}' - ), 1)::bigint, false); + create trigger "update_transaction_metadata_history_{{.ID}}" + after update + on "{{.Bucket}}"."transactions" + for each row + when ( + new.ledger = '{{.Name}}' + ) + execute procedure "{{.Bucket}}".update_transaction_metadata_history(); `, }, { requireFeatures: features.FeatureSet{ - features.FeatureMovesHistoryPostCommitEffectiveVolumes: "SYNC", + features.FeatureTransactionMetadataHistory: "SYNC", }, script: ` - create trigger "set_effective_volumes_{{.ID}}" - before insert - on "{{.Bucket}}"."moves" + create trigger "insert_transaction_metadata_history_{{.ID}}" + after insert + on "{{.Bucket}}"."transactions" for each row when ( new.ledger = '{{.Name}}' ) - execute procedure "{{.Bucket}}".set_effective_volumes(); + execute procedure "{{.Bucket}}".insert_transaction_metadata_history(); `, }, { requireFeatures: features.FeatureSet{ - features.FeatureMovesHistoryPostCommitEffectiveVolumes: "SYNC", + features.FeatureIndexTransactionAccounts: "ON", }, script: ` - create trigger "update_effective_volumes_{{.ID}}" - after insert - on "{{.Bucket}}"."moves" + create trigger "transaction_set_addresses_{{.ID}}" + before insert + on "{{.Bucket}}"."transactions" for each row when ( new.ledger = '{{.Name}}' ) - execute procedure "{{.Bucket}}".update_effective_volumes(); + execute procedure "{{.Bucket}}".set_transaction_addresses(); `, }, { requireFeatures: features.FeatureSet{ - features.FeatureHashLogs: "SYNC", + features.FeatureIndexAddressSegments: "ON", + features.FeatureIndexTransactionAccounts: "ON", }, script: ` - create trigger "set_log_hash_{{.ID}}" + create trigger "transaction_set_addresses_segments_{{.ID}}" before insert - on "{{.Bucket}}"."logs" + on "{{.Bucket}}"."transactions" for each row when ( new.ledger = '{{.Name}}' ) - execute procedure "{{.Bucket}}".set_log_hash(); + execute procedure "{{.Bucket}}".set_transaction_addresses_segments(); `, }, { @@ -194,78 +201,74 @@ var ledgerSetups = []ledgerSetup{ }, { requireFeatures: features.FeatureSet{ - features.FeatureTransactionMetadataHistory: "SYNC", + features.FeatureIndexAddressSegments: "ON", }, script: ` - create trigger "update_transaction_metadata_history_{{.ID}}" - after update - on "{{.Bucket}}"."transactions" + create trigger "accounts_set_address_array_{{.ID}}" + before insert + on "{{.Bucket}}"."accounts" for each row when ( new.ledger = '{{.Name}}' ) - execute procedure "{{.Bucket}}".update_transaction_metadata_history(); + execute procedure "{{.Bucket}}".set_address_array_for_account(); `, }, { requireFeatures: features.FeatureSet{ - features.FeatureTransactionMetadataHistory: "SYNC", + features.FeatureMovesHistoryPostCommitEffectiveVolumes: "SYNC", }, script: ` - create trigger "insert_transaction_metadata_history_{{.ID}}" - after insert - on "{{.Bucket}}"."transactions" + create trigger "set_effective_volumes_{{.ID}}" + before insert + on "{{.Bucket}}"."moves" for each row when ( new.ledger = '{{.Name}}' ) - execute procedure "{{.Bucket}}".insert_transaction_metadata_history(); + execute procedure "{{.Bucket}}".set_effective_volumes(); `, }, { requireFeatures: features.FeatureSet{ - features.FeatureIndexTransactionAccounts: "ON", + features.FeatureMovesHistoryPostCommitEffectiveVolumes: "SYNC", }, script: ` - create trigger "transaction_set_addresses_{{.ID}}" - before insert - on "{{.Bucket}}"."transactions" + create trigger "update_effective_volumes_{{.ID}}" + after insert + on "{{.Bucket}}"."moves" for each row when ( new.ledger = '{{.Name}}' ) - execute procedure "{{.Bucket}}".set_transaction_addresses(); + execute procedure "{{.Bucket}}".update_effective_volumes(); `, }, { - requireFeatures: features.FeatureSet{ - features.FeatureIndexAddressSegments: "ON", - }, script: ` - create trigger "accounts_set_address_array_{{.ID}}" - before insert - on "{{.Bucket}}"."accounts" - for each row - when ( - new.ledger = '{{.Name}}' - ) - execute procedure "{{.Bucket}}".set_address_array_for_account(); + -- create a sequence for logs by ledger instead of a sequence of the table as we want to have contiguous ids + -- notes: we can still have "holes" on id since a sql transaction can be reverted after a usage of the sequence + create sequence "{{.Bucket}}"."log_id_{{.ID}}" owned by "{{.Bucket}}".logs.id; + select setval('"{{.Bucket}}"."log_id_{{.ID}}"', coalesce(( + select max(id) + 1 + from "{{.Bucket}}".logs + where ledger = '{{ .Name }}' + ), 1)::bigint, false); `, }, { requireFeatures: features.FeatureSet{ - features.FeatureIndexAddressSegments: "ON", - features.FeatureIndexTransactionAccounts: "ON", + features.FeatureHashLogs: "SYNC", }, script: ` - create trigger "transaction_set_addresses_segments_{{.ID}}" + create trigger "set_log_hash_{{.ID}}" before insert - on "{{.Bucket}}"."transactions" + on "{{.Bucket}}"."logs" for each row when ( new.ledger = '{{.Name}}' ) - execute procedure "{{.Bucket}}".set_transaction_addresses_segments(); + execute procedure "{{.Bucket}}".set_log_hash(); `, }, } diff --git a/internal/storage/bucket/migrations.go b/internal/storage/bucket/migrations.go index d44e702a38..56ec6eb43a 100644 --- a/internal/storage/bucket/migrations.go +++ b/internal/storage/bucket/migrations.go @@ -12,19 +12,29 @@ import ( //go:embed migrations var MigrationsFS embed.FS -func GetMigrator(db *bun.DB, name string, options ...migrations.Option) *migrations.Migrator { +func GetMigrator(db bun.IDB, name string, options ...migrations.Option) *migrations.Migrator { options = append(options, migrations.WithSchema(name)) migrator := migrations.NewMigrator(db, options...) - migrations, err := migrations.CollectMigrations(MigrationsFS, name) + + _, transactional := db.(bun.Tx) + + collectOptions := make([]migrations.CollectOption, 0) + if transactional { + collectOptions = append(collectOptions, migrations.WithTemplateVars(map[string]any{ + "Transactional": true, + })) + } + + allMigrations, err := migrations.CollectMigrations(MigrationsFS, name, collectOptions...) if err != nil { panic(err) } - migrator.RegisterMigrations(migrations...) + migrator.RegisterMigrations(allMigrations...) return migrator } -func migrate(ctx context.Context, tracer trace.Tracer, db *bun.DB, name string, options ...migrations.Option) error { +func migrate(ctx context.Context, tracer trace.Tracer, db bun.IDB, name string, options ...migrations.Option) error { ctx, span := tracer.Start(ctx, "Migrate bucket") defer span.End() diff --git a/internal/storage/bucket/migrations/12-transaction-sequence-index/up.sql b/internal/storage/bucket/migrations/12-transaction-sequence-index/up.sql index 53ecd3c687..c79820b963 100644 --- a/internal/storage/bucket/migrations/12-transaction-sequence-index/up.sql +++ b/internal/storage/bucket/migrations/12-transaction-sequence-index/up.sql @@ -1 +1 @@ -create index concurrently transactions_sequences on "{{.Schema}}".transactions (id, seq); \ No newline at end of file +create index {{ if not .Transactional }}concurrently{{end}} transactions_sequences on "{{.Schema}}".transactions (id, seq); \ No newline at end of file diff --git a/internal/storage/bucket/migrations/13-accounts-sequence-index/up.sql b/internal/storage/bucket/migrations/13-accounts-sequence-index/up.sql index b496462049..b0b6e0a64a 100644 --- a/internal/storage/bucket/migrations/13-accounts-sequence-index/up.sql +++ b/internal/storage/bucket/migrations/13-accounts-sequence-index/up.sql @@ -1 +1 @@ -create index concurrently accounts_sequences on "{{.Schema}}".accounts (address, seq); \ No newline at end of file +create index {{ if not .Transactional }}concurrently{{end}} accounts_sequences on "{{.Schema}}".accounts (address, seq); \ No newline at end of file diff --git a/internal/storage/bucket/migrations/14-transaction-reference-index/up.sql b/internal/storage/bucket/migrations/14-transaction-reference-index/up.sql index ab3e875862..0d2a1fad31 100644 --- a/internal/storage/bucket/migrations/14-transaction-reference-index/up.sql +++ b/internal/storage/bucket/migrations/14-transaction-reference-index/up.sql @@ -1,2 +1 @@ --- todo: clean empty reference in subsequent migration -create unique index concurrently transactions_reference2 on "{{.Schema}}".transactions (ledger, reference) where reference <> ''; \ No newline at end of file +create unique index {{ if not .Transactional }}concurrently{{end}} transactions_reference2 on "{{.Schema}}".transactions (ledger, reference) where reference <> ''; \ No newline at end of file diff --git a/internal/storage/bucket/migrations/16-create-transaction-id-index-on-moves/up.sql b/internal/storage/bucket/migrations/16-create-transaction-id-index-on-moves/up.sql index de13279d0b..4e3e2202f0 100644 --- a/internal/storage/bucket/migrations/16-create-transaction-id-index-on-moves/up.sql +++ b/internal/storage/bucket/migrations/16-create-transaction-id-index-on-moves/up.sql @@ -1 +1 @@ -create index concurrently moves_transactions_id on "{{ .Schema }}".moves(transactions_id); \ No newline at end of file +create index {{ if not .Transactional }}concurrently{{end}} moves_transactions_id on "{{ .Schema }}".moves(transactions_id); \ No newline at end of file diff --git a/internal/storage/bucket/migrations/24-accounts-metadata-index/up.sql b/internal/storage/bucket/migrations/24-accounts-metadata-index/up.sql index a8fa79bb18..363a3d30d3 100644 --- a/internal/storage/bucket/migrations/24-accounts-metadata-index/up.sql +++ b/internal/storage/bucket/migrations/24-accounts-metadata-index/up.sql @@ -1 +1 @@ -create index concurrently accounts_metadata_idx on "{{.Schema}}".accounts using gin(metadata JSONB_PATH_OPS); \ No newline at end of file +create index {{ if not .Transactional }}concurrently{{end}} accounts_metadata_idx on "{{.Schema}}".accounts using gin(metadata JSONB_PATH_OPS); \ No newline at end of file diff --git a/internal/storage/bucket/migrations/25-accounts-volumes-index/up.sql b/internal/storage/bucket/migrations/25-accounts-volumes-index/up.sql index 321c2b86bb..aed1a9f3ba 100644 --- a/internal/storage/bucket/migrations/25-accounts-volumes-index/up.sql +++ b/internal/storage/bucket/migrations/25-accounts-volumes-index/up.sql @@ -1 +1 @@ -create index concurrently accounts_volumes_idx on "{{.Schema}}".accounts_volumes (ledger, accounts_address, asset) include (input, output); +create index {{ if not .Transactional }}concurrently{{end}} accounts_volumes_idx on "{{.Schema}}".accounts_volumes (ledger, accounts_address, asset) include (input, output); diff --git a/internal/storage/driver/buckets_generated_test.go b/internal/storage/driver/buckets_generated_test.go index b717808137..737885ed5a 100644 --- a/internal/storage/driver/buckets_generated_test.go +++ b/internal/storage/driver/buckets_generated_test.go @@ -12,6 +12,7 @@ import ( migrations "github.com/formancehq/go-libs/v2/migrations" ledger "github.com/formancehq/ledger/internal" bucket "github.com/formancehq/ledger/internal/storage/bucket" + bun "github.com/uptrace/bun" gomock "go.uber.org/mock/gomock" ) @@ -155,29 +156,29 @@ func (m *BucketFactory) EXPECT() *BucketFactoryMockRecorder { } // Create mocks base method. -func (m *BucketFactory) Create(name string) bucket.Bucket { +func (m *BucketFactory) Create(name string, db bun.IDB) bucket.Bucket { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "Create", name) + ret := m.ctrl.Call(m, "Create", name, db) ret0, _ := ret[0].(bucket.Bucket) return ret0 } // Create indicates an expected call of Create. -func (mr *BucketFactoryMockRecorder) Create(name any) *gomock.Call { +func (mr *BucketFactoryMockRecorder) Create(name, db any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*BucketFactory)(nil).Create), name) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Create", reflect.TypeOf((*BucketFactory)(nil).Create), name, db) } // GetMigrator mocks base method. -func (m *BucketFactory) GetMigrator(b string) *migrations.Migrator { +func (m *BucketFactory) GetMigrator(b string, db bun.IDB) *migrations.Migrator { m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "GetMigrator", b) + ret := m.ctrl.Call(m, "GetMigrator", b, db) ret0, _ := ret[0].(*migrations.Migrator) return ret0 } // GetMigrator indicates an expected call of GetMigrator. -func (mr *BucketFactoryMockRecorder) GetMigrator(b any) *gomock.Call { +func (mr *BucketFactoryMockRecorder) GetMigrator(b, db any) *gomock.Call { mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMigrator", reflect.TypeOf((*BucketFactory)(nil).GetMigrator), b) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetMigrator", reflect.TypeOf((*BucketFactory)(nil).GetMigrator), b, db) } diff --git a/internal/storage/driver/driver.go b/internal/storage/driver/driver.go index a10a2b0367..8451726e39 100644 --- a/internal/storage/driver/driver.go +++ b/internal/storage/driver/driver.go @@ -6,10 +6,10 @@ import ( "fmt" "github.com/alitto/pond" "github.com/formancehq/go-libs/v2/metadata" - "github.com/formancehq/go-libs/v2/migrations" "github.com/formancehq/go-libs/v2/platform/postgres" systemcontroller "github.com/formancehq/ledger/internal/controller/system" systemstore "github.com/formancehq/ledger/internal/storage/system" + "github.com/uptrace/bun" "go.opentelemetry.io/otel/metric" noopmetrics "go.opentelemetry.io/otel/metric/noop" "go.opentelemetry.io/otel/trace" @@ -27,14 +27,13 @@ import ( type Driver struct { ledgerStoreFactory ledgerstore.Factory - systemStore systemstore.Store + db *bun.DB bucketFactory bucket.Factory tracer trace.Tracer meter metric.Meter - migrationRetryPeriod time.Duration - migratorLockRetryInterval time.Duration - parallelBucketMigrations int + migrationRetryPeriod time.Duration + parallelBucketMigrations int } func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgerstore.Store, error) { @@ -43,51 +42,60 @@ func (d *Driver) CreateLedger(ctx context.Context, l *ledger.Ledger) (*ledgersto l.Metadata = metadata.Metadata{} } - if err := d.systemStore.CreateLedger(ctx, l); err != nil { - if errors.Is(postgres.ResolveError(err), postgres.ErrConstraintsFailed{}) { - return nil, systemcontroller.ErrLedgerAlreadyExists + var ret *ledgerstore.Store + err := d.db.RunInTx(ctx, nil, func(ctx context.Context, tx bun.Tx) error { + systemStore := systemstore.New(tx) + + if err := systemStore.CreateLedger(ctx, l); err != nil { + if errors.Is(postgres.ResolveError(err), postgres.ErrConstraintsFailed{}) { + return systemcontroller.ErrLedgerAlreadyExists + } + return err } - return nil, postgres.ResolveError(err) - } - b := d.bucketFactory.Create(l.Bucket) - isInitialized, err := b.IsInitialized(ctx) - if err != nil { - return nil, fmt.Errorf("checking if bucket is initialized: %w", err) - } - if isInitialized { - upToDate, err := b.IsUpToDate(ctx) + b := d.bucketFactory.Create(l.Bucket, tx) + isInitialized, err := b.IsInitialized(ctx) if err != nil { - return nil, fmt.Errorf("checking if bucket is up to date: %w", err) + return fmt.Errorf("checking if bucket is initialized: %w", err) } + if isInitialized { + upToDate, err := b.IsUpToDate(ctx) + if err != nil { + return fmt.Errorf("checking if bucket is up to date: %w", err) + } - if !upToDate { - return nil, systemcontroller.ErrBucketOutdated - } + if !upToDate { + return systemcontroller.ErrBucketOutdated + } - if err := b.AddLedger(ctx, *l); err != nil { - return nil, fmt.Errorf("adding ledger to bucket: %w", err) - } - } else { - if err := b.Migrate( - ctx, - migrations.WithLockRetryInterval(d.migratorLockRetryInterval), - ); err != nil { - return nil, fmt.Errorf("migrating bucket: %w", err) + if err := b.AddLedger(ctx, *l); err != nil { + return fmt.Errorf("adding ledger to bucket: %w", err) + } + } else { + if err := b.Migrate(ctx); err != nil { + return fmt.Errorf("migrating bucket: %w", err) + } } + + ret = d.ledgerStoreFactory.Create(b, *l) + + return nil + }) + if err != nil { + return nil, postgres.ResolveError(err) } - return d.ledgerStoreFactory.Create(b, *l), nil + return ret, nil } func (d *Driver) OpenLedger(ctx context.Context, name string) (*ledgerstore.Store, *ledger.Ledger, error) { // todo: keep the ledger in cache somewhere to avoid read the ledger at each request, maybe in the factory - ret, err := d.systemStore.GetLedger(ctx, name) + ret, err := systemstore.New(d.db).GetLedger(ctx, name) if err != nil { return nil, nil, err } - store := d.ledgerStoreFactory.Create(d.bucketFactory.Create(ret.Bucket), *ret) + store := d.ledgerStoreFactory.Create(d.bucketFactory.Create(ret.Bucket, d.db), *ret) return store, ret, err } @@ -99,16 +107,8 @@ func (d *Driver) Initialize(ctx context.Context) error { return fmt.Errorf("detecting rollbacks: %w", err) } - err = d.systemStore.Migrate(ctx, migrations.WithLockRetryInterval(d.migratorLockRetryInterval)) + err = systemstore.New(d.db).Migrate(ctx) if err != nil { - constraintsFailed := postgres.ErrConstraintsFailed{} - if errors.As(err, &constraintsFailed) && - constraintsFailed.GetConstraint() == "pg_namespace_nspname_index" { - // notes(gfyrag): Creating schema concurrently can result in a constraint violation of pg_namespace_nspname_index table. - // If we have this error, it's because a concurrent instance of the service is actually creating the schema - // I guess we can ignore the error. - return nil - } return fmt.Errorf("migrating system store: %w", err) } @@ -117,12 +117,13 @@ func (d *Driver) Initialize(ctx context.Context) error { func (d *Driver) detectRollbacks(ctx context.Context) error { + systemStore := systemstore.New(d.db) logging.FromContext(ctx).Debugf("Checking for downgrades on system schema") - if err := detectDowngrades(d.systemStore.GetMigrator(), ctx); err != nil { + if err := detectDowngrades(systemStore.GetMigrator(), ctx); err != nil { return fmt.Errorf("detecting rollbacks of system schema: %w", err) } - buckets, err := d.systemStore.GetDistinctBuckets(ctx) + buckets, err := systemStore.GetDistinctBuckets(ctx) if err != nil { if !errors.Is(err, postgres.ErrMissingTable) { return fmt.Errorf("getting distinct buckets: %w", err) @@ -132,7 +133,7 @@ func (d *Driver) detectRollbacks(ctx context.Context) error { for _, b := range buckets { logging.FromContext(ctx).Debugf("Checking for downgrades on bucket '%s'", b) - if err := detectDowngrades(d.bucketFactory.GetMigrator(b), ctx); err != nil { + if err := detectDowngrades(d.bucketFactory.GetMigrator(b, d.db), ctx); err != nil { return fmt.Errorf("detecting rollbacks on bucket '%s': %w", b, err) } } @@ -141,31 +142,28 @@ func (d *Driver) detectRollbacks(ctx context.Context) error { } func (d *Driver) UpdateLedgerMetadata(ctx context.Context, name string, m metadata.Metadata) error { - return d.systemStore.UpdateLedgerMetadata(ctx, name, m) + return systemstore.New(d.db).UpdateLedgerMetadata(ctx, name, m) } func (d *Driver) DeleteLedgerMetadata(ctx context.Context, name string, key string) error { - return d.systemStore.DeleteLedgerMetadata(ctx, name, key) + return systemstore.New(d.db).DeleteLedgerMetadata(ctx, name, key) } func (d *Driver) ListLedgers(ctx context.Context, q ledgercontroller.ListLedgersQuery) (*bunpaginate.Cursor[ledger.Ledger], error) { - return d.systemStore.ListLedgers(ctx, q) + return systemstore.New(d.db).ListLedgers(ctx, q) } func (d *Driver) GetLedger(ctx context.Context, name string) (*ledger.Ledger, error) { - return d.systemStore.GetLedger(ctx, name) + return systemstore.New(d.db).GetLedger(ctx, name) } func (d *Driver) UpgradeBucket(ctx context.Context, name string) error { - return d.bucketFactory.Create(name).Migrate( - ctx, - migrations.WithLockRetryInterval(d.migratorLockRetryInterval), - ) + return d.bucketFactory.Create(name, d.db).Migrate(ctx) } func (d *Driver) UpgradeAllBuckets(ctx context.Context) error { - buckets, err := d.systemStore.GetDistinctBuckets(ctx) + buckets, err := systemstore.New(d.db).GetDistinctBuckets(ctx) if err != nil { return fmt.Errorf("getting distinct buckets: %w", err) } @@ -177,17 +175,14 @@ func (d *Driver) UpgradeAllBuckets(ctx context.Context) error { logger := logging.FromContext(ctx).WithFields(map[string]any{ "bucket": bucketName, }) - b := d.bucketFactory.Create(bucketName) + b := d.bucketFactory.Create(bucketName, d.db) l: for { errChan := make(chan error, 1) go func() { logger.Infof("Upgrading...") - errChan <- b.Migrate( - logging.ContextWithLogger(ctx, logger), - migrations.WithLockRetryInterval(d.migratorLockRetryInterval), - ) + errChan <- b.Migrate(logging.ContextWithLogger(ctx, logger)) }() for { @@ -220,7 +215,9 @@ func (d *Driver) UpgradeAllBuckets(ctx context.Context) error { } func (d *Driver) HasReachMinimalVersion(ctx context.Context) (bool, error) { - isUpToDate, err := d.systemStore.IsUpToDate(ctx) + systemStore := systemstore.New(d.db) + + isUpToDate, err := systemStore.IsUpToDate(ctx) if err != nil { return false, fmt.Errorf("checking if system store is up to date: %w", err) } @@ -228,13 +225,13 @@ func (d *Driver) HasReachMinimalVersion(ctx context.Context) (bool, error) { return false, nil } - buckets, err := d.systemStore.GetDistinctBuckets(ctx) + buckets, err := systemStore.GetDistinctBuckets(ctx) if err != nil { return false, fmt.Errorf("getting distinct buckets: %w", err) } for _, b := range buckets { - hasMinimalVersion, err := d.bucketFactory.Create(b).HasMinimalVersion(ctx) + hasMinimalVersion, err := d.bucketFactory.Create(b, d.db).HasMinimalVersion(ctx) if err != nil { return false, fmt.Errorf("checking if bucket '%s' is up to date: %w", b, err) } @@ -247,15 +244,15 @@ func (d *Driver) HasReachMinimalVersion(ctx context.Context) (bool, error) { } func New( + db *bun.DB, ledgerStoreFactory ledgerstore.Factory, - systemStore systemstore.Store, bucketFactory bucket.Factory, opts ...Option, ) *Driver { ret := &Driver{ + db: db, ledgerStoreFactory: ledgerStoreFactory, bucketFactory: bucketFactory, - systemStore: systemStore, } for _, opt := range append(defaultOptions, opts...) { opt(ret) @@ -277,12 +274,6 @@ func WithTracer(tracer trace.Tracer) Option { } } -func WithMigratorLockRetryInterval(interval time.Duration) Option { - return func(d *Driver) { - d.migratorLockRetryInterval = interval - } -} - func WithParallelBucketMigration(p int) Option { return func(d *Driver) { d.parallelBucketMigrations = p diff --git a/internal/storage/driver/driver_test.go b/internal/storage/driver/driver_test.go index b78b9e91a3..34328a2a1e 100644 --- a/internal/storage/driver/driver_test.go +++ b/internal/storage/driver/driver_test.go @@ -1,13 +1,12 @@ +//go:build it + package driver_test import ( - "context" - "errors" - "github.com/formancehq/go-libs/v2/bun/bunpaginate" + "fmt" + "github.com/formancehq/go-libs/v2/collectionutils" "github.com/formancehq/go-libs/v2/logging" "github.com/formancehq/go-libs/v2/metadata" - "github.com/formancehq/go-libs/v2/migrations" - "github.com/formancehq/go-libs/v2/pointer" ledger "github.com/formancehq/ledger/internal" ledgercontroller "github.com/formancehq/ledger/internal/controller/ledger" "github.com/formancehq/ledger/internal/storage/bucket" @@ -15,240 +14,93 @@ import ( ledgerstore "github.com/formancehq/ledger/internal/storage/ledger" "github.com/google/uuid" "github.com/stretchr/testify/require" - "go.uber.org/mock/gomock" + "math/rand" + "sync" "testing" - "time" ) -func TestUpgradeAllLedgers(t *testing.T) { +func TestLedgersCreate(t *testing.T) { t.Parallel() - ctx := logging.TestingContext() - t.Run("single bucket with no error", func(t *testing.T) { - t.Parallel() - - ctrl := gomock.NewController(t) - ledgerStoreFactory := driver.NewLedgerStoreFactory(ctrl) - bucketFactory := driver.NewBucketFactory(ctrl) - systemStore := driver.NewSystemStore(ctrl) - - d := driver.New( - ledgerStoreFactory, - systemStore, - bucketFactory, - ) - - bucket := driver.NewMockBucket(ctrl) + d := driver.New(db, ledgerstore.NewFactory(db), bucket.NewDefaultFactory()) - systemStore.EXPECT(). - GetDistinctBuckets(gomock.Any()). - Return([]string{ledger.DefaultBucket}, nil) + buckets := []string{"bucket1", "bucket2"} + const countLedgers = 80 - bucketFactory.EXPECT(). - Create(ledger.DefaultBucket). - AnyTimes(). - Return(bucket) + wg := sync.WaitGroup{} + wg.Add(countLedgers) + errors := make(chan error, countLedgers) + for i := range countLedgers { + go func() { + defer wg.Done() - bucket.EXPECT(). - Migrate(gomock.Any(), gomock.Any()). - DoAndReturn(func(ctx context.Context, opts ...migrations.Option) error { - return nil + l, err := ledger.New(fmt.Sprintf("ledger%d", i), ledger.Configuration{ + Bucket: buckets[rand.Int31n(int32(len(buckets)))], }) + if err != nil { + errors <- err + return + } - ctx, cancel := context.WithTimeout(ctx, 2*time.Second) - t.Cleanup(cancel) - - require.NoError(t, d.UpgradeAllBuckets(ctx)) - }) - - t.Run("with concurrent buckets", func(t *testing.T) { - t.Parallel() - - t.Run("and no error", func(t *testing.T) { - t.Parallel() - - ctrl := gomock.NewController(t) - ledgerStoreFactory := driver.NewLedgerStoreFactory(ctrl) - bucketFactory := driver.NewBucketFactory(ctrl) - systemStore := driver.NewSystemStore(ctrl) - - d := driver.New( - ledgerStoreFactory, - systemStore, - bucketFactory, - ) - - bucketList := []string{"bucket1", "bucket2", "bucket3"} - buckets := make(map[string]bucket.Bucket) + _, err = d.CreateLedger(ctx, l) + if err != nil { + errors <- err + return + } + }() + } + wg.Wait() - for _, name := range bucketList { - bucket := driver.NewMockBucket(ctrl) - buckets[name] = bucket + close(errors) - bucketFactory.EXPECT(). - Create(name). - Return(bucket) + for err := range errors { + require.NoError(t, err) + } - bucket.EXPECT(). - Migrate(gomock.Any(), gomock.Any()). - DoAndReturn(func(ctx context.Context, opts ...migrations.Option) error { - return nil - }) - } + hasReachMinimalVersion, err := d.HasReachMinimalVersion(ctx) + require.NoError(t, err) + require.True(t, hasReachMinimalVersion) - systemStore.EXPECT(). - GetDistinctBuckets(gomock.Any()). - Return(bucketList, nil) - - ctx, cancel := context.WithTimeout(ctx, 2*time.Second) - t.Cleanup(cancel) - - require.NoError(t, d.UpgradeAllBuckets(ctx)) - }) - - t.Run("and error", func(t *testing.T) { - t.Parallel() - - ctrl := gomock.NewController(t) - ledgerStoreFactory := driver.NewLedgerStoreFactory(ctrl) - bucketFactory := driver.NewBucketFactory(ctrl) - systemStore := driver.NewSystemStore(ctrl) - - d := driver.New(ledgerStoreFactory, systemStore, bucketFactory, - driver.WithMigrationRetryPeriod(10*time.Millisecond), - ) - - bucket1 := driver.NewMockBucket(ctrl) - bucket2 := driver.NewMockBucket(ctrl) - bucketList := []string{"bucket1", "bucket2"} - - bucketFactory.EXPECT(). - Create(gomock.AnyOf( - gomock.Eq("bucket1"), - gomock.Eq("bucket2"), - )). - AnyTimes(). - DoAndReturn(func(name string) bucket.Bucket { - if name == "bucket1" { - return bucket1 - } - return bucket2 - }) - - bucket1MigrationStarted := make(chan struct{}) - bucket1.EXPECT(). - Migrate(gomock.Any(), gomock.Any()). - AnyTimes(). - DoAndReturn(func(ctx context.Context, opts ...migrations.Option) error { - close(bucket1MigrationStarted) - - return nil - }) - - firstCall := true - bucket2.EXPECT(). - Migrate(gomock.Any(), gomock.Any()). - AnyTimes(). - DoAndReturn(func(ctx context.Context, opts ...migrations.Option) error { - select { - case <-ctx.Done(): - return ctx.Err() - case <-bucket1MigrationStarted: - if firstCall { - firstCall = false - return errors.New("unknown error") - } - return nil - } - }) - - systemStore.EXPECT(). - GetDistinctBuckets(gomock.Any()). - AnyTimes(). - Return(bucketList, nil) - - ctx, cancel := context.WithTimeout(ctx, 2*time.Second) - t.Cleanup(cancel) - - bucket1MigrationStarted = make(chan struct{}) - err := d.UpgradeAllBuckets(ctx) - require.NoError(t, err) - }) - }) + err = d.UpgradeAllBuckets(ctx) + require.NoError(t, err) } -func TestLedgersCreate(t *testing.T) { +func TestLedgersList(t *testing.T) { t.Parallel() ctx := logging.TestingContext() - ctrl := gomock.NewController(t) - ledgerStoreFactory := driver.NewLedgerStoreFactory(ctrl) - bucketFactory := driver.NewBucketFactory(ctrl) - systemStore := driver.NewSystemStore(ctrl) - - d := driver.New( - ledgerStoreFactory, - systemStore, - bucketFactory, - ) + d := driver.New(db, ledgerstore.NewFactory(db), bucket.NewDefaultFactory()) - l := pointer.For(ledger.MustNewWithDefault("test")) + bucket := uuid.NewString()[:8] - bucket := driver.NewMockBucket(ctrl) - bucketFactory.EXPECT(). - Create(ledger.DefaultBucket). - Return(bucket) - - systemStore.EXPECT(). - CreateLedger(gomock.Any(), l) - - bucket.EXPECT(). - IsInitialized(gomock.Any()). - Return(false, nil) - - bucket.EXPECT(). - Migrate(gomock.Any(), gomock.Any()). - Return(nil) - - ledgerStoreFactory.EXPECT(). - Create(gomock.Any(), *l). - Return(&ledgerstore.Store{}) - - _, err := d.CreateLedger(ctx, l) + l1, err := ledger.New(uuid.NewString(), ledger.Configuration{ + Bucket: bucket, + }) require.NoError(t, err) -} -func TestLedgersList(t *testing.T) { - t.Parallel() + _, err = d.CreateLedger(ctx, l1) + require.NoError(t, err) - ctx := logging.TestingContext() + l2, err := ledger.New(uuid.NewString(), ledger.Configuration{ + Bucket: bucket, + }) + require.NoError(t, err) - ctrl := gomock.NewController(t) - ledgerStoreFactory := driver.NewLedgerStoreFactory(ctrl) - bucketFactory := driver.NewBucketFactory(ctrl) - systemStore := driver.NewSystemStore(ctrl) + _, err = d.CreateLedger(ctx, l2) + require.NoError(t, err) - driver := driver.New( - ledgerStoreFactory, - systemStore, - bucketFactory, - ) + query := ledgercontroller.NewListLedgersQuery(15).WithBucket(bucket) - query := ledgercontroller.NewListLedgersQuery(15) + cursor, err := d.ListLedgers(ctx, query) + require.NoError(t, err) - systemStore.EXPECT(). - ListLedgers(gomock.Any(), query). - Return(&bunpaginate.Cursor[ledger.Ledger]{ - Data: []ledger.Ledger{ - ledger.MustNewWithDefault("testing"), - }, - }, nil) + ledgers := collectionutils.Filter(cursor.Data, func(l ledger.Ledger) bool { + return l.Bucket == bucket + }) - cursor, err := driver.ListLedgers(ctx, query) - require.NoError(t, err) - require.Len(t, cursor.Data, 1) + require.Len(t, ledgers, 2) } func TestLedgerUpdateMetadata(t *testing.T) { @@ -256,27 +108,16 @@ func TestLedgerUpdateMetadata(t *testing.T) { ctx := logging.TestingContext() - ctrl := gomock.NewController(t) - ledgerStoreFactory := driver.NewLedgerStoreFactory(ctrl) - bucketFactory := driver.NewBucketFactory(ctrl) - systemStore := driver.NewSystemStore(ctrl) - - d := driver.New( - ledgerStoreFactory, - systemStore, - bucketFactory, - ) + d := driver.New(db, ledgerstore.NewFactory(db), bucket.NewDefaultFactory()) l := ledger.MustNewWithDefault(uuid.NewString()) + _, err := d.CreateLedger(ctx, &l) + require.NoError(t, err) addedMetadata := metadata.Metadata{ "foo": "bar", } - systemStore.EXPECT(). - UpdateLedgerMetadata(gomock.Any(), l.Name, addedMetadata). - Return(nil) - - err := d.UpdateLedgerMetadata(ctx, l.Name, addedMetadata) + err = d.UpdateLedgerMetadata(ctx, l.Name, addedMetadata) require.NoError(t, err) } @@ -284,25 +125,14 @@ func TestLedgerDeleteMetadata(t *testing.T) { t.Parallel() ctx := logging.TestingContext() - ctrl := gomock.NewController(t) - ledgerStoreFactory := driver.NewLedgerStoreFactory(ctrl) - bucketFactory := driver.NewBucketFactory(ctrl) - systemStore := driver.NewSystemStore(ctrl) - - d := driver.New( - ledgerStoreFactory, - systemStore, - bucketFactory, - ) + d := driver.New(db, ledgerstore.NewFactory(db), bucket.NewDefaultFactory()) l := ledger.MustNewWithDefault(uuid.NewString()).WithMetadata(metadata.Metadata{ "foo": "bar", }) + _, err := d.CreateLedger(ctx, &l) + require.NoError(t, err) - systemStore.EXPECT(). - DeleteLedgerMetadata(gomock.Any(), l.Name, "foo"). - Return(nil) - - err := d.DeleteLedgerMetadata(ctx, l.Name, "foo") + err = d.DeleteLedgerMetadata(ctx, l.Name, "foo") require.NoError(t, err) } diff --git a/internal/storage/driver/main_test.go b/internal/storage/driver/main_test.go new file mode 100644 index 0000000000..9d5b41bd0f --- /dev/null +++ b/internal/storage/driver/main_test.go @@ -0,0 +1,44 @@ +//go:build it + +package driver_test + +import ( + "database/sql" + . "github.com/formancehq/go-libs/v2/testing/utils" + systemstore "github.com/formancehq/ledger/internal/storage/system" + "os" + "testing" + + "github.com/formancehq/go-libs/v2/bun/bundebug" + "github.com/formancehq/go-libs/v2/testing/docker" + "github.com/uptrace/bun/dialect/pgdialect" + + "github.com/uptrace/bun" + + "github.com/formancehq/go-libs/v2/logging" + "github.com/formancehq/go-libs/v2/testing/platform/pgtesting" + "github.com/stretchr/testify/require" +) + +var ( + srv *pgtesting.PostgresServer + db *bun.DB +) + +func TestMain(m *testing.M) { + WithTestMain(func(t *TestingTForMain) int { + srv = pgtesting.CreatePostgresServer(t, docker.NewPool(t, logging.Testing()), pgtesting.WithExtension("pgcrypto")) + sqlDB, err := sql.Open("pgx", srv.GetDSN()) + require.NoError(t, err) + + db = bun.NewDB(sqlDB, pgdialect.New(), bun.WithDiscardUnknownColumns()) + if os.Getenv("DEBUG") == "true" { + queryHook := bundebug.NewQueryHook() + queryHook.Debug = true + db.AddQueryHook(queryHook) + } + require.NoError(t, systemstore.Migrate(logging.TestingContext(), db)) + + return m.Run() + }) +} diff --git a/internal/storage/driver/module.go b/internal/storage/driver/module.go index 1c0ff88c0d..4f89d44056 100644 --- a/internal/storage/driver/module.go +++ b/internal/storage/driver/module.go @@ -25,8 +25,8 @@ type ModuleConfiguration struct { func NewFXModule() fx.Option { return fx.Options( - fx.Provide(fx.Annotate(func(db *bun.DB, tracerProvider trace.TracerProvider) bucket.Factory { - return bucket.NewDefaultFactory(db, bucket.WithTracer(tracerProvider.Tracer("store"))) + fx.Provide(fx.Annotate(func(tracerProvider trace.TracerProvider) bucket.Factory { + return bucket.NewDefaultFactory(bucket.WithTracer(tracerProvider.Tracer("store"))) })), fx.Provide(func(db *bun.DB) systemstore.Store { return systemstore.New(db) @@ -42,15 +42,15 @@ func NewFXModule() fx.Option { ) }), fx.Provide(func( + db *bun.DB, bucketFactory bucket.Factory, ledgerStoreFactory ledgerstore.Factory, - systemStore systemstore.Store, tracerProvider trace.TracerProvider, meterProvider metric.MeterProvider, ) (*Driver, error) { return New( + db, ledgerStoreFactory, - systemStore, bucketFactory, WithMeter(meterProvider.Meter("store")), WithTracer(tracerProvider.Tracer("store")), diff --git a/internal/storage/ledger/main_test.go b/internal/storage/ledger/main_test.go index 668451e64e..1b66eba5da 100644 --- a/internal/storage/ledger/main_test.go +++ b/internal/storage/ledger/main_test.go @@ -50,10 +50,14 @@ func TestMain(m *testing.M) { bunDB.SetMaxOpenConns(100) require.NoError(t, systemstore.Migrate(logging.TestingContext(), bunDB)) + + err = bucket.GetMigrator(bunDB, "_default").Up(logging.TestingContext()) + require.NoError(t, err) + defaultDriver.SetValue(driver.New( + bunDB, ledgerstore.NewFactory(bunDB), - systemstore.New(bunDB), - bucket.NewDefaultFactory(bunDB), + bucket.NewDefaultFactory(), )) return bunDB @@ -81,8 +85,6 @@ func newLedgerStore(t T) *ledgerstore.Store { ctx := logging.TestingContext() l := ledger.MustNewWithDefault(ledgerName) - err := bucket.GetMigrator(defaultBunDB.GetValue(), "_default").Up(ctx) - require.NoError(t, err) store, err := defaultDriver.GetValue().CreateLedger(ctx, &l) require.NoError(t, err) diff --git a/internal/storage/system/migrations.go b/internal/storage/system/migrations.go index 0de3250561..6763c5a19f 100644 --- a/internal/storage/system/migrations.go +++ b/internal/storage/system/migrations.go @@ -11,7 +11,7 @@ import ( "github.com/uptrace/bun" ) -func GetMigrator(db *bun.DB, options ...migrations.Option) *migrations.Migrator { +func GetMigrator(db bun.IDB, options ...migrations.Option) *migrations.Migrator { // configuration table has been removed, we keep the model to keep migrations consistent but the table is not used anymore. type configuration struct { diff --git a/internal/storage/system/store.go b/internal/storage/system/store.go index 4ebec7f79d..f0aedb048c 100644 --- a/internal/storage/system/store.go +++ b/internal/storage/system/store.go @@ -32,7 +32,7 @@ const ( ) type DefaultStore struct { - db *bun.DB + db bun.IDB } func (d *DefaultStore) IsUpToDate(ctx context.Context) (bool, error) { @@ -97,10 +97,14 @@ func (d *DefaultStore) ListLedgers(ctx context.Context, q ledgercontroller.ListL Column("*"). Order("added_at asc") - return bunpaginate.UsingOffset[ledgercontroller.PaginatedQueryOptions[struct{}], ledger.Ledger]( + if q.Options.Options.Bucket != "" { + query = query.Where("bucket = ?", q.Options.Options.Bucket) + } + + return bunpaginate.UsingOffset[ledgercontroller.PaginatedQueryOptions[ledgercontroller.ListLedgersQueryPayload], ledger.Ledger]( ctx, query, - bunpaginate.OffsetPaginatedQuery[ledgercontroller.PaginatedQueryOptions[struct{}]](q), + bunpaginate.OffsetPaginatedQuery[ledgercontroller.PaginatedQueryOptions[ledgercontroller.ListLedgersQueryPayload]](q), ) } @@ -125,11 +129,7 @@ func (d *DefaultStore) GetMigrator(options ...migrations.Option) *migrations.Mig return GetMigrator(d.db, options...) } -func (d *DefaultStore) GetDB() *bun.DB { - return d.db -} - -func New(db *bun.DB) *DefaultStore { +func New(db bun.IDB) *DefaultStore { return &DefaultStore{ db: db, } diff --git a/test/e2e/app_lifecycle_test.go b/test/e2e/app_lifecycle_test.go index 7940525c32..a590231acf 100644 --- a/test/e2e/app_lifecycle_test.go +++ b/test/e2e/app_lifecycle_test.go @@ -63,7 +63,7 @@ var _ = Context("Ledger application lifecycle tests", func() { When("having some in flight transactions on a ledger", func() { var ( sqlTx bun.Tx - countTransactions = 80 + countTransactions = 60 serverRestartTimeout = 10 * time.Second ) BeforeEach(func() { @@ -123,7 +123,7 @@ var _ = Context("Ledger application lifecycle tests", func() { }) When("restarting the service", func() { BeforeEach(func() { - // We will restart the server in a separate gorouting + // We will restart the server in a separate goroutine // the server should not restart until all pending transactions creation requests are fully completed restarted := make(chan struct{}) go func() { diff --git a/test/migrations/upgrade_test.go b/test/migrations/upgrade_test.go index 3884c9debd..be4c55c9ec 100644 --- a/test/migrations/upgrade_test.go +++ b/test/migrations/upgrade_test.go @@ -10,7 +10,6 @@ import ( "github.com/formancehq/ledger/internal/storage/bucket" "github.com/formancehq/ledger/internal/storage/driver" "github.com/formancehq/ledger/internal/storage/ledger" - systemstore "github.com/formancehq/ledger/internal/storage/system" "github.com/ory/dockertest/v3" dockerlib "github.com/ory/dockertest/v3/docker" "github.com/stretchr/testify/require" @@ -67,9 +66,9 @@ func TestMigrations(t *testing.T) { // Migrate database driver := driver.New( + db, ledger.NewFactory(db), - systemstore.New(db), - bucket.NewDefaultFactory(db), + bucket.NewDefaultFactory(), driver.WithParallelBucketMigration(1), ) require.NoError(t, driver.Initialize(ctx)) diff --git a/tools/generator/go.mod b/tools/generator/go.mod index ca77093055..b96f5c5e77 100644 --- a/tools/generator/go.mod +++ b/tools/generator/go.mod @@ -9,10 +9,10 @@ replace github.com/formancehq/ledger => ../.. replace github.com/formancehq/ledger/pkg/client => ../../pkg/client require ( - github.com/formancehq/go-libs/v2 v2.0.1-0.20250217160145-75857677eef9 + github.com/formancehq/go-libs/v2 v2.0.1-0.20250225100718-5e1dfe022817 github.com/formancehq/ledger v0.0.0-00010101000000-000000000000 github.com/formancehq/ledger/pkg/client v0.0.0-00010101000000-000000000000 - github.com/spf13/cobra v1.8.1 + github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 golang.org/x/oauth2 v0.24.0 ) @@ -32,7 +32,7 @@ require ( github.com/dop251/goja v0.0.0-20241009100908-5f46f2705ca3 // indirect github.com/ericlagergren/decimal v0.0.0-20240411145413-00de7ca16731 // indirect github.com/fatih/color v1.18.0 // indirect - github.com/formancehq/numscript v0.0.10 // indirect + github.com/formancehq/numscript v0.0.11 // indirect github.com/go-chi/chi/v5 v5.2.1 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect @@ -76,10 +76,10 @@ require ( go.uber.org/mock v0.5.0 // indirect go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect - golang.org/x/crypto v0.32.0 // indirect + golang.org/x/crypto v0.33.0 // indirect golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 // indirect - golang.org/x/sync v0.10.0 // indirect - golang.org/x/sys v0.29.0 // indirect - golang.org/x/text v0.21.0 // indirect + golang.org/x/sync v0.11.0 // indirect + golang.org/x/sys v0.30.0 // indirect + golang.org/x/text v0.22.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/tools/generator/go.sum b/tools/generator/go.sum index a6359d309f..71167bae80 100644 --- a/tools/generator/go.sum +++ b/tools/generator/go.sum @@ -30,32 +30,32 @@ github.com/antlr4-go/antlr/v4 v4.13.1 h1:SqQKkuVZ+zWkMMNkjy5FZe5mr5WURWnlpmOuzYW github.com/antlr4-go/antlr/v4 v4.13.1/go.mod h1:GKmUxMtwp6ZgGwZSva4eWPC5mS6vUAmOABFgjdkM7Nw= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1 h1:nMp7diZObd4XEVUR0pEvn7/E13JIgManMX79Q6quV6E= github.com/aws/aws-msk-iam-sasl-signer-go v1.0.1/go.mod h1:MVYeeOhILFFemC/XlYTClvBjYZrg/EPd3ts885KrNTI= -github.com/aws/aws-sdk-go-v2 v1.36.1 h1:iTDl5U6oAhkNPba0e1t1hrwAo02ZMqbrGq4k5JBWM5E= -github.com/aws/aws-sdk-go-v2 v1.36.1/go.mod h1:5PMILGVKiW32oDzjj6RU52yrNrDPUHcbZQYr1sM7qmM= -github.com/aws/aws-sdk-go-v2/config v1.29.6 h1:fqgqEKK5HaZVWLQoLiC9Q+xDlSp+1LYidp6ybGE2OGg= -github.com/aws/aws-sdk-go-v2/config v1.29.6/go.mod h1:Ft+WLODzDQmCTHDvqAH1JfC2xxbZ0MxpZAcJqmE1LTQ= -github.com/aws/aws-sdk-go-v2/credentials v1.17.59 h1:9btwmrt//Q6JcSdgJOLI98sdr5p7tssS9yAsGe8aKP4= -github.com/aws/aws-sdk-go-v2/credentials v1.17.59/go.mod h1:NM8fM6ovI3zak23UISdWidyZuI1ghNe2xjzUZAyT+08= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28 h1:KwsodFKVQTlI5EyhRSugALzsV6mG/SGrdjlMXSZSdso= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.28/go.mod h1:EY3APf9MzygVhKuPXAc5H+MkGb8k/DOSQjWS0LgkKqI= -github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.9 h1:bgT3nh3B42Glpr1lT8TiVT0XEvJIqieoRFaW+AMTW8s= -github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.9/go.mod h1:FmhyqqiI3BYgCrkdl4Xit5DyGZw1dtOaRb6aLqJLQ8w= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32 h1:BjUcr3X3K0wZPGFg2bxOWW3VPN8rkE3/61zhP+IHviA= -github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.32/go.mod h1:80+OGC/bgzzFFTUmcuwD0lb4YutwQeKLFpmt6hoWapU= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32 h1:m1GeXHVMJsRsUAqG6HjZWx9dj7F5TR+cF1bjyfYyBd4= -github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.32/go.mod h1:IitoQxGfaKdVLNg0hD8/DXmAqNy0H4K2H2Sf91ti8sI= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2 h1:Pg9URiobXy85kgFev3og2CuOZ8JZUBENF+dcgWBaYNk= -github.com/aws/aws-sdk-go-v2/internal/ini v1.8.2/go.mod h1:FbtygfRFze9usAadmnGJNc8KsP346kEe+y2/oyhGAGc= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2 h1:D4oz8/CzT9bAEYtVhSBmFj2dNOtaHOtMKc2vHBwYizA= -github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.2/go.mod h1:Za3IHqTQ+yNcRHxu1OFucBh0ACZT4j4VQFF0BqpZcLY= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13 h1:SYVGSFQHlchIcy6e7x12bsrxClCXSP5et8cqVhL8cuw= -github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.13/go.mod h1:kizuDaLX37bG5WZaoxGPQR/LNFXpxp0vsUnqfkWXfNE= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.15 h1:/eE3DogBjYlvlbhd2ssWyeuovWunHLxfgw3s/OJa4GQ= -github.com/aws/aws-sdk-go-v2/service/sso v1.24.15/go.mod h1:2PCJYpi7EKeA5SkStAmZlF6fi0uUABuhtF8ILHjGc3Y= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14 h1:M/zwXiL2iXUrHputuXgmO94TVNmcenPHxgLXLutodKE= -github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.14/go.mod h1:RVwIw3y/IqxC2YEXSIkAzRDdEU1iRabDPaYjpGCbCGQ= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.14 h1:TzeR06UCMUq+KA3bDkujxK1GVGy+G8qQN/QVYzGLkQE= -github.com/aws/aws-sdk-go-v2/service/sts v1.33.14/go.mod h1:dspXf/oYWGWo6DEvj98wpaTeqt5+DMidZD0A9BYTizc= +github.com/aws/aws-sdk-go-v2 v1.36.2 h1:Ub6I4lq/71+tPb/atswvToaLGVMxKZvjYDVOWEExOcU= +github.com/aws/aws-sdk-go-v2 v1.36.2/go.mod h1:LLXuLpgzEbD766Z5ECcRmi8AzSwfZItDtmABVkRLGzg= +github.com/aws/aws-sdk-go-v2/config v1.29.7 h1:71nqi6gUbAUiEQkypHQcNVSFJVUFANpSeUNShiwWX2M= +github.com/aws/aws-sdk-go-v2/config v1.29.7/go.mod h1:yqJQ3nh2HWw/uxd56bicyvmDW4KSc+4wN6lL8pYjynU= +github.com/aws/aws-sdk-go-v2/credentials v1.17.60 h1:1dq+ELaT5ogfmqtV1eocq8SpOK1NRsuUfmhQtD/XAh4= +github.com/aws/aws-sdk-go-v2/credentials v1.17.60/go.mod h1:HDes+fn/xo9VeszXqjBVkxOo/aUy8Mc6QqKvZk32GlE= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29 h1:JO8pydejFKmGcUNiiwt75dzLHRWthkwApIvPoyUtXEg= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.29/go.mod h1:adxZ9i9DRmB8zAT0pO0yGnsmu0geomp5a3uq5XpgOJ8= +github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.10 h1:dWT0CmI2v2mA0tdcBY+xH/FJl25Koirl76MREqw/dSM= +github.com/aws/aws-sdk-go-v2/feature/rds/auth v1.5.10/go.mod h1:xkd3fB3k0zkzUkCplj8Cz+f7b4mJj8KoNTKogu8X8do= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33 h1:knLyPMw3r3JsU8MFHWctE4/e2qWbPaxDYLlohPvnY8c= +github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.33/go.mod h1:EBp2HQ3f+XCB+5J+IoEbGhoV7CpJbnrsd4asNXmTL0A= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33 h1:K0+Ne08zqti8J9jwENxZ5NoUyBnaFDTu3apwQJWrwwA= +github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.33/go.mod h1:K97stwwzaWzmqxO8yLGHhClbVW1tC6VT1pDLk1pGrq4= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3 h1:bIqFDwgGXXN1Kpp99pDOdKMTTb5d2KyU5X/BZxjOkRo= +github.com/aws/aws-sdk-go-v2/internal/ini v1.8.3/go.mod h1:H5O/EsxDWyU+LP/V8i5sm8cxoZgc2fdNR9bxlOFrQTo= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3 h1:eAh2A4b5IzM/lum78bZ590jy36+d/aFLgKF/4Vd1xPE= +github.com/aws/aws-sdk-go-v2/service/internal/accept-encoding v1.12.3/go.mod h1:0yKJC/kb8sAnmlYa6Zs3QVYqaC8ug2AbnNChv5Ox3uA= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14 h1:2scbY6//jy/s8+5vGrk7l1+UtHl0h9A4MjOO2k/TM2E= +github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.14/go.mod h1:bRpZPHZpSe5YRHmPfK3h1M7UBFCn2szHzyx0rw04zro= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.16 h1:YV6xIKDJp6U7YB2bxfud9IENO1LRpGhe2Tv/OKtPrOQ= +github.com/aws/aws-sdk-go-v2/service/sso v1.24.16/go.mod h1:DvbmMKgtpA6OihFJK13gHMZOZrCHttz8wPHGKXqU+3o= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15 h1:kMyK3aKotq1aTBsj1eS8ERJLjqYRRRcsmP33ozlCvlk= +github.com/aws/aws-sdk-go-v2/service/ssooidc v1.28.15/go.mod h1:5uPZU7vSNzb8Y0dm75xTikinegPYK3uJmIHQZFq5Aqo= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.15 h1:ht1jVmeeo2anR7zDiYJLSnRYnO/9NILXXu42FP3rJg0= +github.com/aws/aws-sdk-go-v2/service/sts v1.33.15/go.mod h1:xWZ5cOiFe3czngChE4LhCBqUxNwgfwndEF7XlYP/yD8= github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk= @@ -68,7 +68,7 @@ github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK3 github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/containerd/continuity v0.4.3 h1:6HVkalIp+2u1ZLH1J/pYX2oBVXlJZvh1X1A7bEZ9Su8= github.com/containerd/continuity v0.4.3/go.mod h1:F6PTNCKepoxEaXLQp3wDAjygEnImnZ/7o4JzpodfroQ= -github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.6/go.mod h1:oOW0eioCTA6cOiMLiUPZOpcVxMig6NIQQ7OS05n1F4g= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= @@ -79,8 +79,8 @@ github.com/dnwe/otelsarama v0.0.0-20240308230250-9388d9d40bc0 h1:R2zQhFwSCyyd7L4 github.com/dnwe/otelsarama v0.0.0-20240308230250-9388d9d40bc0/go.mod h1:2MqLKYJfjs3UriXXF9Fd0Qmh/lhxi/6tHXkqtXxyIHc= github.com/docker/cli v27.3.1+incompatible h1:qEGdFBF3Xu6SCvCYhc7CzaQTlBmqDuzxPDpigSyeKQQ= github.com/docker/cli v27.3.1+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= -github.com/docker/docker v27.4.1+incompatible h1:ZJvcY7gfwHn1JF48PfbyXg7Jyt9ZCWDW+GGXOIxEwp4= -github.com/docker/docker v27.4.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.5.1+incompatible h1:4PYU5dnBYqRQi0294d1FBECqT9ECWeQAIfE8q4YnPY8= +github.com/docker/docker v27.5.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -102,10 +102,10 @@ github.com/fatih/color v1.18.0 h1:S8gINlzdQ840/4pfAwic/ZE0djQEH3wM94VfqLTZcOM= github.com/fatih/color v1.18.0/go.mod h1:4FelSpRwEGDpQ12mAdzqdOukCy4u8WUtOY6lkT/6HfU= github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= -github.com/formancehq/go-libs/v2 v2.0.1-0.20250217160145-75857677eef9 h1:68gyI+zMcWowRrUz8SYUJGCFUb64LD8P0w5dRyHWIz8= -github.com/formancehq/go-libs/v2 v2.0.1-0.20250217160145-75857677eef9/go.mod h1:U9+fV6R34gG24TfNuOCUMQmfdP3g54nsFlLNlManZ5s= -github.com/formancehq/numscript v0.0.10 h1:ElvYpoayUX5tHtCCR18ihJTjNlHzdkE4M0IqSm9aufg= -github.com/formancehq/numscript v0.0.10/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= +github.com/formancehq/go-libs/v2 v2.0.1-0.20250225100718-5e1dfe022817 h1:cqsYamzWEvqvQfPrWJBDqLUMtaoLJB2f1CMQKR0MfpQ= +github.com/formancehq/go-libs/v2 v2.0.1-0.20250225100718-5e1dfe022817/go.mod h1:XxvR+WrPGq7UjYA/Uk0Ch0bgPs+pDoVCVOo//aYbIRI= +github.com/formancehq/numscript v0.0.11 h1:vZDfRfrhOkuInv5fLIXvWZU3ylK+fVgmR4la01dO5to= +github.com/formancehq/numscript v0.0.11/go.mod h1:btuSv05cYwi9BvLRxVs5zrunU+O1vTgigG1T6UsawcY= github.com/gkampitakis/ciinfo v0.3.0 h1:gWZlOC2+RYYttL0hBqcoQhM7h1qNkVqvRCV1fOvpAv8= github.com/gkampitakis/ciinfo v0.3.0/go.mod h1:1NIwaOcFChN4fa/B0hEBdAb6npDlFL8Bwx4dfRLRqAo= github.com/gkampitakis/go-diff v1.3.2 h1:Qyn0J9XJSDTgnsgHRdz9Zp24RaJeKMUHg2+PDZZdC4M= @@ -129,8 +129,8 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-sourcemap/sourcemap v2.1.3+incompatible h1:W1iEw64niKVGogNgBN3ePyLFfuisuzeidWPMPWmECqU= github.com/go-sourcemap/sourcemap v2.1.3+incompatible/go.mod h1:F8jJfvm2KbVjc5NqelyYJmf/v5J0dwNLS2mL4sNA1Jg= -github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= -github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= +github.com/go-sql-driver/mysql v1.9.0 h1:Y0zIbQXhQKmQgTp44Y1dp3wTXcn804QoTptLZT1vtvo= +github.com/go-sql-driver/mysql v1.9.0/go.mod h1:pDetrLJeA3oMujJuvXc8RJoasr589B6A9fwzD3QMrqw= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIxtHqx8aGss= @@ -226,8 +226,8 @@ github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= github.com/muhlemmer/httpforwarded v0.1.0/go.mod h1:yo9czKedo2pdZhoXe+yDkGVbU0TJ0q9oQ90BVoDEtw0= -github.com/nats-io/nats.go v1.38.0 h1:A7P+g7Wjp4/NWqDOOP/K6hfhr54DvdDQUznt5JFg9XA= -github.com/nats-io/nats.go v1.38.0/go.mod h1:IGUM++TwokGnXPs82/wCuiHS02/aKrdYUQkU8If6yjw= +github.com/nats-io/nats.go v1.39.1 h1:oTkfKBmz7W047vRxV762M67ZdXeOtUgvbBaNoQ+3PPk= +github.com/nats-io/nats.go v1.39.1/go.mod h1:MgRb8oOdigA6cYpEPhXJuRVH6UE/V4jblJ2jQ27IXYM= github.com/nats-io/nkeys v0.4.9 h1:qe9Faq2Gxwi6RZnZMXfmGMZkg3afLLOtrU+gDZJ35b0= github.com/nats-io/nkeys v0.4.9/go.mod h1:jcMqs+FLG+W5YO36OX6wFIFcmpdAns+w1Wm6D3I/evE= github.com/nats-io/nuid v1.0.1 h1:5iA8DT8V7q8WK2EScv2padNa/rTESc1KdnPw4TC2paw= @@ -274,9 +274,8 @@ github.com/shomali11/xsql v0.0.0-20190608141458-bf76292144df h1:SVCDTuzM3KEk8WBw github.com/shomali11/xsql v0.0.0-20190608141458-bf76292144df/go.mod h1:K8jR5lDI2MGs9Ky+X2jIF4MwIslI0L8o8ijIlEq7/Vw= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= -github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= -github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/spf13/cobra v1.9.1 h1:CXSaggrXdbHK9CF+8ywj8Amf7PBRmPCOJugH954Nnlo= +github.com/spf13/cobra v1.9.1/go.mod h1:nDyEzZ8ogv936Cinf6g1RU9MRY64Ir93oCnqb9wxYW0= github.com/spf13/pflag v1.0.6 h1:jFzHGLGAlb3ruxLB8MhbI6A8+AQX/2eW4qeyNZXNp2o= github.com/spf13/pflag v1.0.6/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stoewer/go-strcase v1.3.0 h1:g0eASXYtp+yvN9fK8sH94oCIk0fau9uV1/ZdJ0AVEzs= @@ -389,16 +388,16 @@ go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0= go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y= go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8= go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E= -golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= -golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= +golang.org/x/crypto v0.33.0 h1:IOBPskki6Lysi0lo9qQvbxiQ+FvsCC/YWOecCHAixus= +golang.org/x/crypto v0.33.0/go.mod h1:bVdXmD7IV/4GdElGPozy6U7lWdRXA4qyRVGJV57uQ5M= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67 h1:1UoZQm6f0P/ZO0w1Ri+f+ifG/gXhegadRdwBIXEFWDo= golang.org/x/exp v0.0.0-20241217172543-b2144cdd0a67/go.mod h1:qj5a5QZpwLU2NLQudwIN5koi3beDhSAlJwa67PuM98c= -golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= -golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= +golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8= +golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk= golang.org/x/oauth2 v0.24.0 h1:KTBBxWqUa0ykRPLtV69rRto9TLXcqYkeswu48x/gvNE= golang.org/x/oauth2 v0.24.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.11.0 h1:GGz8+XQP4FvTTrjZPzNKTMFtSXH80RAzG+5ghFPgK9w= +golang.org/x/sync v0.11.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= @@ -406,10 +405,10 @@ golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU= -golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= +golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM= +golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY= golang.org/x/tools v0.28.0 h1:WuB6qZ4RPCQo5aP3WdKZS7i595EdWqWR8vqJTlwTVK8= golang.org/x/tools v0.28.0/go.mod h1:dcIOrVd3mfQKTgrDVQHqCPMWy6lnhfhtX3hLXYVLfRw= google.golang.org/genproto/googleapis/api v0.0.0-20250115164207-1a7da9e5054f h1:gap6+3Gk41EItBuyi4XX/bp4oqJ3UwuIMl25yGinuAA=