feat: add version repo (#4)

Reviewed-on: twhelp/corev3#4
This commit is contained in:
Dawid Wysokiński 2023-12-20 07:03:03 +00:00
parent f6d0dae6b6
commit 4f0e5ff8d5
42 changed files with 1418 additions and 47 deletions

View File

@ -53,6 +53,7 @@ linters:
- inamedparam
- sloglint
- revive
- gomnd
linters-settings:
gocyclo:
@ -105,6 +106,10 @@ linters-settings:
enable-all: true
sloglint:
attr-only: true
gomnd:
ignored-functions:
- strconv.FormatInt
- strconv.ParseInt
revive:
rules:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#add-constant

View File

@ -20,7 +20,6 @@ steps:
image: *go_image
pull: true
commands:
- go mod download
- make generate
test:

View File

@ -22,30 +22,30 @@ var (
}
dbFlagMaxIdleConns = &cli.IntFlag{
Name: "db.maxIdleConns",
Value: 2,
Value: 2, //nolint:gomnd
EnvVars: []string{"DB_MAX_IDLE_CONNS"},
Usage: "https://pkg.go.dev/database/sql#DB.SetMaxIdleConns",
}
dbFlagMaxOpenConns = &cli.IntFlag{
Name: "db.maxOpenConns",
Value: runtime.NumCPU() * 4,
Value: runtime.NumCPU() * 4, //nolint:gomnd
EnvVars: []string{"DB_MAX_OPEN_CONNS"},
Usage: "https://pkg.go.dev/database/sql#DB.SetMaxOpenConns",
}
dbFlagConnMaxLifetime = &cli.DurationFlag{
Name: "db.connMaxLifetime",
Value: 30 * time.Minute,
Value: 30 * time.Minute, //nolint:gomnd
EnvVars: []string{"DB_CONN_MAX_LIFETIME"},
Usage: "https://pkg.go.dev/database/sql#DB.SetConnMaxLifetime",
}
dbFlagReadTimeout = &cli.DurationFlag{
Name: "db.readTimeout",
Value: 10 * time.Second,
Value: 10 * time.Second, //nolint:gomnd
EnvVars: []string{"DB_READ_TIMEOUT"},
}
dbFlagWriteTimeout = &cli.DurationFlag{
Name: "db.writeTimeout",
Value: 5 * time.Second,
Value: 5 * time.Second, //nolint:gomnd
EnvVars: []string{"DB_WRITE_TIMEOUT"},
}
dbFlags = []cli.Flag{

46
go.mod
View File

@ -5,36 +5,80 @@ go 1.21
require (
github.com/ThreeDotsLabs/watermill v1.3.5
github.com/ThreeDotsLabs/watermill-amqp/v2 v2.1.1
github.com/cenkalti/backoff/v4 v4.2.1
github.com/elliotchance/phpserialize v1.3.3
github.com/go-chi/chi/v5 v5.0.10
github.com/google/go-cmp v0.6.0
github.com/google/uuid v1.3.1
github.com/gosimple/slug v1.13.1
github.com/ory/dockertest/v3 v3.10.0
github.com/stretchr/testify v1.8.4
github.com/uptrace/bun v1.1.16
github.com/uptrace/bun/dialect/pgdialect v1.1.16
github.com/uptrace/bun/dialect/sqlitedialect v1.1.16
github.com/uptrace/bun/driver/pgdriver v1.1.16
github.com/uptrace/bun/driver/sqliteshim v1.1.16
github.com/urfave/cli/v2 v2.26.0
)
require (
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 // indirect
github.com/Microsoft/go-winio v0.6.0 // indirect
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 // indirect
github.com/cenkalti/backoff/v3 v3.2.2 // indirect
github.com/containerd/continuity v0.3.0 // indirect
github.com/cpuguy83/go-md2man/v2 v2.0.2 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/google/uuid v1.3.1 // indirect
github.com/docker/cli v20.10.17+incompatible // indirect
github.com/docker/docker v20.10.7+incompatible // indirect
github.com/docker/go-connections v0.4.0 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/gosimple/unidecode v1.0.1 // indirect
github.com/hashicorp/errwrap v1.1.0 // indirect
github.com/hashicorp/go-multierror v1.1.1 // indirect
github.com/imdario/mergo v0.3.12 // indirect
github.com/jinzhu/inflection v1.0.0 // indirect
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
github.com/lithammer/shortuuid/v3 v3.0.7 // indirect
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/mattn/go-sqlite3 v1.14.17 // indirect
github.com/mitchellh/mapstructure v1.4.1 // indirect
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 // indirect
github.com/oklog/ulid v1.3.1 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.2 // indirect
github.com/opencontainers/runc v1.1.5 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rabbitmq/amqp091-go v1.9.0 // indirect
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc // indirect
github.com/vmihailenco/msgpack/v5 v5.3.5 // indirect
github.com/vmihailenco/tagparser/v2 v2.0.0 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
golang.org/x/crypto v0.13.0 // indirect
golang.org/x/mod v0.12.0 // indirect
golang.org/x/sys v0.12.0 // indirect
golang.org/x/tools v0.13.0 // indirect
gopkg.in/yaml.v2 v2.3.0 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
lukechampine.com/uint128 v1.3.0 // indirect
mellium.im/sasl v0.3.1 // indirect
modernc.org/cc/v3 v3.41.0 // indirect
modernc.org/ccgo/v3 v3.16.15 // indirect
modernc.org/libc v1.24.1 // indirect
modernc.org/mathutil v1.6.0 // indirect
modernc.org/memory v1.7.1 // indirect
modernc.org/opt v0.1.3 // indirect
modernc.org/sqlite v1.25.0 // indirect
modernc.org/strutil v1.2.0 // indirect
modernc.org/token v1.1.0 // indirect
)

186
go.sum
View File

@ -1,84 +1,270 @@
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78 h1:w+iIsaOQNcT7OZ575w+acHgRric5iCyQh+xv+KJ4HB8=
github.com/Azure/go-ansiterm v0.0.0-20170929234023-d6e3b3328b78/go.mod h1:LmzpDX56iTiv29bbRTIsUNlaFfuhWRQBWjQdVyAevI8=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/Microsoft/go-winio v0.6.0 h1:slsWYD/zyx7lCXoZVlvQrj0hPTM1HI4+v1sIda2yDvg=
github.com/Microsoft/go-winio v0.6.0/go.mod h1:cTAf44im0RAYeL23bpB+fzCyDH2MJiz2BO69KH/soAE=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw=
github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk=
github.com/ThreeDotsLabs/watermill v1.3.5 h1:50JEPEhMGZQMh08ct0tfO1PsgMOAOhV3zxK2WofkbXg=
github.com/ThreeDotsLabs/watermill v1.3.5/go.mod h1:O/u/Ptyrk5MPTxSeWM5vzTtZcZfxXfO9PK9eXTYiFZY=
github.com/ThreeDotsLabs/watermill-amqp/v2 v2.1.1 h1:OxvMB2/3YtcQuC7quC+CGmFpGz9oaxP2ef5wkp+R2oM=
github.com/ThreeDotsLabs/watermill-amqp/v2 v2.1.1/go.mod h1:MCNoh0HUg4w0bY64on9BnhUodHeimz8+vMfXrzyuWN8=
github.com/cenkalti/backoff/v3 v3.2.2 h1:cfUAAO3yvKMYKPrvhDuHSwQnhZNk/RMHKdZqKTxfm6M=
github.com/cenkalti/backoff/v3 v3.2.2/go.mod h1:cIeZDE3IrqwwJl6VUwCN6trj1oXrTS4rc0ij+ULvLYs=
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
github.com/checkpoint-restore/go-criu/v5 v5.3.0/go.mod h1:E/eQpaFtUKGOOSEBZgmKAcn+zUUwWxqcaKZlF54wK8E=
github.com/cilium/ebpf v0.7.0/go.mod h1:/oI2+1shJiTGAMgl6/RgJr36Eo1jzrRcAWbcXO2usCA=
github.com/containerd/console v1.0.3/go.mod h1:7LqA/THxQ86k76b8c/EMSiaJ3h1eZkMkXar0TQ1gf3U=
github.com/containerd/continuity v0.3.0 h1:nisirsYROK15TAMVukJOUyGJjz4BNQJBVsNvAXZJ/eg=
github.com/containerd/continuity v0.3.0/go.mod h1:wJEAIwKOm/pBZuBd0JmeTvnLquTB1Ag8espWhkykbPM=
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
github.com/cpuguy83/go-md2man/v2 v2.0.2 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/docker/cli v20.10.17+incompatible h1:eO2KS7ZFeov5UJeaDmIs1NFEDRf32PaqRpvoEkKBy5M=
github.com/docker/cli v20.10.17+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8=
github.com/docker/docker v20.10.7+incompatible h1:Z6O9Nhsjv+ayUEeI1IojKbYcsGdgYSNqxe1s2MYzUhQ=
github.com/docker/docker v20.10.7+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk=
github.com/docker/go-connections v0.4.0 h1:El9xVISelRB7BuFusrZozjnkIM5YnzCViNKohAFqRJQ=
github.com/docker/go-connections v0.4.0/go.mod h1:Gbd7IOopHjR8Iph03tsViu4nIes5XhDvyHbTtUxmeec=
github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw=
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY=
github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto=
github.com/elliotchance/phpserialize v1.3.3 h1:hV4QVmGdCiYgoBbw+ADt6fNgyZ2mYX0OgpnON1adTCM=
github.com/elliotchance/phpserialize v1.3.3/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lcLUAeS/AnGZ2e49TZs=
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
github.com/go-chi/chi/v5 v5.0.10 h1:rLz5avzKpjqxrYwXNfmjkrYYXOyLJd37pz53UFHC6vk=
github.com/go-chi/chi/v5 v5.0.10/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/godbus/dbus/v5 v5.0.6/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26 h1:Xim43kblpZXfIBQsbuBVKCudVG457BR2GZFIz3uw3hQ=
github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S37WGHujM7tX//fmj1uioxKzKxz3lo4HJo=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ=
github.com/google/uuid v1.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4=
github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/gosimple/slug v1.13.1 h1:bQ+kpX9Qa6tHRaK+fZR0A0M2Kd7Pa5eHPPsb1JpHD+Q=
github.com/gosimple/slug v1.13.1/go.mod h1:UiRaFH+GEilHstLUmcBgWcI42viBN7mAb818JrYOeFQ=
github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6T/o=
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo=
github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM=
github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2 h1:hRGSmZu7j271trc9sneMrpOW7GN5ngLm8YUZIPzf394=
github.com/lib/pq v0.0.0-20180327071824-d34b9ff171c2/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lithammer/shortuuid/v3 v3.0.7 h1:trX0KTHy4Pbwo/6ia8fscyHoGA+mf1jWbPJVuvyJQQ8=
github.com/lithammer/shortuuid/v3 v3.0.7/go.mod h1:vMk8ke37EmiewwolSO1NLW8vP4ZaKlRuDIi8tWWmAts=
github.com/mattn/go-isatty v0.0.19 h1:JITubQf0MOLdlGRuRq+jtsDlekdYPia9ZFsB8h/APPA=
github.com/mattn/go-isatty v0.0.19/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag=
github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
github.com/moby/sys/mountinfo v0.5.0/go.mod h1:3bMD3Rg+zkqx8MRYPi7Pyb0Ie97QEBmdxbhnCLlSvSU=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635 h1:rzf0wL0CHVc8CEsgyygG0Mn9CNCCPZqOPaz8RiiHYQk=
github.com/moby/term v0.0.0-20201216013528-df9cb8a40635/go.mod h1:FBS0z0QWA44HXygs7VXDUOGoN/1TV3RuWkLO04am3wc=
github.com/mrunalp/fileutils v0.5.0/go.mod h1:M1WthSahJixYnrXQl/DFQuteStB1weuxD2QJNHXfbSQ=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs=
github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno=
github.com/oklog/ulid v1.3.1 h1:EGfNDEx6MqHz8B3uNV6QAib1UR2Lm97sHi3ocA6ESJ4=
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
github.com/opencontainers/image-spec v1.0.2 h1:9yCKha/T5XdGtO0q9Q9a6T5NUCsTn/DrBg0D7ufOcFM=
github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
github.com/opencontainers/runc v1.1.5 h1:L44KXEpKmfWDcS02aeGm8QNTFXTo2D+8MYGDIJ/GDEs=
github.com/opencontainers/runc v1.1.5/go.mod h1:1J5XiS+vdZ3wCyZybsuxXZWGrgSr8fFJHLXuG2PsnNg=
github.com/opencontainers/runtime-spec v1.0.3-0.20210326190908-1c3f411f0417/go.mod h1:jwyrGlmzljRJv/Fgzds9SsS/C5hL+LL3ko9hs6T5lQ0=
github.com/opencontainers/selinux v1.10.0/go.mod h1:2i0OySw99QjzBBQByd1Gr9gSjvuho1lHsJxIJ3gGbJI=
github.com/ory/dockertest/v3 v3.10.0 h1:4K3z2VMe8Woe++invjaTB7VRyQXQy5UY+loujO4aNE4=
github.com/ory/dockertest/v3 v3.10.0/go.mod h1:nr57ZbRWMqfsdGdFNLHz5jjNdDb7VVFnzAeW1n5N1Lg=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc3Aoo=
github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/seccomp/libseccomp-golang v0.9.2-0.20220502022130-f33da4d89646/go.mod h1:JA8cRccbGaA1s33RQf7Y1+q9gHmZX1yB/z9WDN1C6fg=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc h1:9lRDQMhESg+zvGYmW5DyG0UqvY96Bu5QYsTLvCHdrgo=
github.com/tmthrgd/go-hex v0.0.0-20190904060850-447a3041c3bc/go.mod h1:bciPuU6GHm1iF1pBvUfxfsH0Wmnc2VbpgvbI9ZWuIRs=
github.com/uptrace/bun v1.1.16 h1:cn9cgEMFwcyYRsQLfxCRMUxyK1WaHwOVrR3TvzEFZ/A=
github.com/uptrace/bun v1.1.16/go.mod h1:7HnsMRRvpLFUcquJxp22JO8PsWKpFQO/gNXqqsuGWg8=
github.com/uptrace/bun/dialect/pgdialect v1.1.16 h1:eUPZ+YCJ69BA+W1X1ZmpOJSkv1oYtinr0zCXf7zCo5g=
github.com/uptrace/bun/dialect/pgdialect v1.1.16/go.mod h1:KQjfx/r6JM0OXfbv0rFrxAbdkPD7idK8VitnjIV9fZI=
github.com/uptrace/bun/dialect/sqlitedialect v1.1.16 h1:gbc9BP/e4sNOB9VBj+Si46dpOz2oktmZPidkda92GYY=
github.com/uptrace/bun/dialect/sqlitedialect v1.1.16/go.mod h1:YNezpK7fIn5Wa2WGmTCZ/nEyiswcXmuT4iNWADeL1x4=
github.com/uptrace/bun/driver/pgdriver v1.1.16 h1:b/NiSXk6Ldw7KLfMLbOqIkm4odHd7QiNOCPLqPFJjK4=
github.com/uptrace/bun/driver/pgdriver v1.1.16/go.mod h1:Rmfbc+7lx1z/umjMyAxkOHK81LgnGj71XC5YpA6k1vU=
github.com/uptrace/bun/driver/sqliteshim v1.1.16 h1:dhXrdXQegGSM+Jk07s9p1Y575DMhCKl7wBkss8kgM+8=
github.com/uptrace/bun/driver/sqliteshim v1.1.16/go.mod h1:7fJaPqaiSvnWytQcMwVv1ZcjUJh7tGDonO/zq3O6RRI=
github.com/urfave/cli v1.22.1/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
github.com/urfave/cli/v2 v2.26.0 h1:3f3AMg3HpThFNT4I++TKOejZO8yU55t3JnnSr4S4QEI=
github.com/urfave/cli/v2 v2.26.0/go.mod h1:8qnjx1vcq5s2/wpsqoZFndg2CE5tNFyrTvS6SinrnYQ=
github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE=
github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU=
github.com/vmihailenco/msgpack/v5 v5.3.5 h1:5gO0H1iULLWGhs2H5tbAHIZTV8/cYafcFOr9znI5mJU=
github.com/vmihailenco/msgpack/v5 v5.3.5/go.mod h1:7xyJ9e+0+9SaZT0Wt1RGleJXzli6Q/V5KbhBonMG9jc=
github.com/vmihailenco/tagparser/v2 v2.0.0 h1:y09buUbR+b5aycVFQs/g70pqKVZNBmxwAhO7/IwNM9g=
github.com/vmihailenco/tagparser/v2 v2.0.0/go.mod h1:Wri+At7QHww0WTrCBeu4J6bNtoV6mEfg5OIWRZA9qds=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ=
github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74=
github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 h1:bAn7/zixMGCfxrRTfdpNzjtPYqr8smhKouy9mxVdGPU=
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673/go.mod h1:N3UwUGtsrSj3ccvlPHLoLsHnpR27oXr4ZE984MbSER8=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.uber.org/goleak v1.2.1 h1:NBol2c7O1ZokfZ0LEU9K6Whx/KnwvepVetCUhtKja4A=
go.uber.org/goleak v1.2.1/go.mod h1:qlT2yGI9QafXHhZZLxlSuNsMw3FFLxBr+tBRlmO1xH4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.13.0 h1:mvySKfSWJ+UKUii46M40LOvyWfN0s2U+46/jDd0e6Ck=
golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.12.0 h1:rmsUpXtvNzj340zd98LZ4KntptpfRHwpFOHG188oHXc=
golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
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.3.0 h1:ftCYgMx6zT/asHUrPw8BLLscYtGznsLAnjq5RH9P66E=
golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
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-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191115151921-52ab43148777/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200831180312-196b9ba8737a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210906170528-6f6e22806c34/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211116061358-0a5406a5449c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc=
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.13.0 h1:Iey4qkscZuv0VvIt8E0neZjtPVQFSc870HQ448QgEmQ=
golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f h1:BLraFXnmrev5lT+xlilqcH8XK9/i0At2xKjWk4p6zsU=
gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.3.0 h1:clyUAQHOM3G0M3f5vQj7LuJrETvjVot3Z5el9nffUtU=
gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gotest.tools/v3 v3.0.2/go.mod h1:3SzNCllyD9/Y+b5r9JIKQ474KzkZyqLqEfYqMsX94Bk=
gotest.tools/v3 v3.3.0 h1:MfDY1b1/0xN1CyMlQDac0ziEy9zJQd9CXBRRDHw2jJo=
gotest.tools/v3 v3.3.0/go.mod h1:Mcr9QNxkg0uMvy/YElmo4SpXgJKWgQvYrT7Kw5RzJ1A=
lukechampine.com/uint128 v1.3.0 h1:cDdUVfRwDUDovz610ABgFD17nXD4/uDgVHl2sC3+sbo=
lukechampine.com/uint128 v1.3.0/go.mod h1:c4eWIwlEGaxC/+H1VguhU4PHXNWDCDMUlWdIWl2j1gk=
mellium.im/sasl v0.3.1 h1:wE0LW6g7U83vhvxjC1IY8DnXM+EU095yeo8XClvCdfo=
mellium.im/sasl v0.3.1/go.mod h1:xm59PUYpZHhgQ9ZqoJ5QaCqzWMi8IeS49dhp6plPCzw=
modernc.org/cc/v3 v3.41.0 h1:QoR1Sn3YWlmA1T4vLaKZfawdVtSiGx8H+cEojbC7v1Q=
modernc.org/cc/v3 v3.41.0/go.mod h1:Ni4zjJYJ04CDOhG7dn640WGfwBzfE0ecX8TyMB0Fv0Y=
modernc.org/ccgo/v3 v3.16.15 h1:KbDR3ZAVU+wiLyMESPtbtE/Add4elztFyfsWoNTgxS0=
modernc.org/ccgo/v3 v3.16.15/go.mod h1:yT7B+/E2m43tmMOT51GMoM98/MtHIcQQSleGnddkUNI=
modernc.org/ccorpus v1.11.6 h1:J16RXiiqiCgua6+ZvQot4yUuUy8zxgqbqEEUuGPlISk=
modernc.org/ccorpus v1.11.6/go.mod h1:2gEUTrWqdpH2pXsmTM1ZkjeSrUWDpjMu2T6m29L/ErQ=
modernc.org/httpfs v1.0.6 h1:AAgIpFZRXuYnkjftxTAZwMIiwEqAfk8aVB2/oA6nAeM=
modernc.org/httpfs v1.0.6/go.mod h1:7dosgurJGp0sPaRanU53W4xZYKh14wfzX420oZADeHM=
modernc.org/libc v1.24.1 h1:uvJSeCKL/AgzBo2yYIPPTy82v21KgGnizcGYfBHaNuM=
modernc.org/libc v1.24.1/go.mod h1:FmfO1RLrU3MHJfyi9eYYmZBfi/R+tqZ6+hQ3yQQUkak=
modernc.org/mathutil v1.6.0 h1:fRe9+AmYlaej+64JsEEhoWuAYBkOtQiMEU7n/XgfYi4=
modernc.org/mathutil v1.6.0/go.mod h1:Ui5Q9q1TR2gFm0AQRqQUaBWFLAhQpCwNcuhBOSedWPo=
modernc.org/memory v1.7.1 h1:9J+2/GKTlV503mk3yv8QJ6oEpRCUrRy0ad8TXEPoV8M=
modernc.org/memory v1.7.1/go.mod h1:NO4NVCQy0N7ln+T9ngWqOQfi7ley4vpwvARR+Hjw95E=
modernc.org/opt v0.1.3 h1:3XOZf2yznlhC+ibLltsDGzABUGVx8J6pnFMS3E4dcq4=
modernc.org/opt v0.1.3/go.mod h1:WdSiB5evDcignE70guQKxYUl14mgWtbClRi5wmkkTX0=
modernc.org/sqlite v1.25.0 h1:AFweiwPNd/b3BoKnBOfFm+Y260guGMF+0UFk0savqeA=
modernc.org/sqlite v1.25.0/go.mod h1:FL3pVXie73rg3Rii6V/u5BoHlSoyeZeIgKZEgHARyCU=
modernc.org/strutil v1.2.0 h1:agBi9dp1I+eOnxXeiZawM8F4LawKv4NzGWSaLfyeNZA=
modernc.org/strutil v1.2.0/go.mod h1:/mdcBmfOibveCTBxUl5B5l6W+TTH1FXPLHZE6bTosX0=
modernc.org/tcl v1.15.2 h1:C4ybAYCGJw968e+Me18oW55kD/FexcHbqH2xak1ROSY=
modernc.org/tcl v1.15.2/go.mod h1:3+k/ZaEbKrC8ePv8zJWPtBSW0V7Gg9g8rkmhI1Kfs3c=
modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y=
modernc.org/token v1.1.0/go.mod h1:UGzOrNV1mAFSEB63lOFHIpNRUVMvYTc6yu1SMY/XTDM=
modernc.org/z v1.7.3 h1:zDJf6iHjrnB+WRD88stbXokugjyc0/pB91ri1gO6LZY=
modernc.org/z v1.7.3/go.mod h1:Ipv4tsdxZRbQyLq9Q1M6gdbkxYzdlrciF2Hi/lS7nWE=

View File

@ -0,0 +1,43 @@
package adapter_test
import (
"flag"
"log"
"os"
"testing"
"gitea.dwysokinski.me/twhelp/corev3/internal/adapter/adaptertest"
"github.com/ory/dockertest/v3"
)
var postgres *adaptertest.Postgres
func TestMain(m *testing.M) {
os.Exit(testMainWrapper(m))
}
func testMainWrapper(m *testing.M) int {
// https://github.com/golang/go/blob/7cfa7d69259590319524c3715df4a39b39924bc3/src/testing/testing.go#L224
flag.Parse()
if testing.Short() {
return m.Run()
}
pool, err := dockertest.NewPool("")
if err != nil {
log.Println("couldn't construct dockertest.Pool:", err)
return 1
}
postgres, err = adaptertest.NewPostgres(pool)
if err != nil {
log.Println("couldn't construct adaptertest.Postgres:", err)
return 1
}
defer func() {
_ = postgres.Close()
}()
return m.Run()
}

View File

@ -0,0 +1,183 @@
package adaptertest
import (
"database/sql"
"fmt"
"net/url"
"os"
"strings"
"time"
"unicode"
"github.com/cenkalti/backoff/v4"
"github.com/google/uuid"
"github.com/ory/dockertest/v3"
"github.com/ory/dockertest/v3/docker"
"github.com/stretchr/testify/require"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/pgdialect"
"github.com/uptrace/bun/driver/pgdriver"
)
type Postgres struct {
connectionString *url.URL
resource *dockertest.Resource
}
type postgresConfig struct {
repo string
tag string
ttl uint
}
type PostgresOption func(cfg *postgresConfig)
const postgresDefaultTTL = 60
func newPostgresConfig(opts ...PostgresOption) *postgresConfig {
cfg := &postgresConfig{
repo: "postgres",
tag: "14",
ttl: postgresDefaultTTL,
}
for _, opt := range opts {
opt(cfg)
}
return cfg
}
func WithTTL(ttlSeconds uint) PostgresOption {
return func(cfg *postgresConfig) {
cfg.ttl = ttlSeconds
}
}
func WithImage(image string) PostgresOption {
return func(cfg *postgresConfig) {
cfg.repo, cfg.tag = docker.ParseRepositoryTag(image)
}
}
// NewPostgres constructs a new Postgres resource. If the env variable 'TESTS_POSTGRES_CONNECTION_STRING' is set,
// this function doesn't run a new Docker container and uses the value of this variable as a connection string,
// otherwise this function runs a new PostgresSQL database in a Docker container.
// This function is intended for use in TestMain.
func NewPostgres(pool *dockertest.Pool, opts ...PostgresOption) (*Postgres, error) {
cfg := newPostgresConfig(opts...)
if connString := os.Getenv("TESTS_POSTGRES_CONNECTION_STRING"); connString != "" {
u, err := url.ParseRequestURI(connString)
if err != nil {
return nil, err
}
return &Postgres{
connectionString: u,
}, nil
}
u := &url.URL{
Scheme: "postgres",
User: url.UserPassword("postgres", "postgres"),
Path: "twhelpdb",
RawQuery: url.Values{
"sslmode": []string{"disable"},
}.Encode(),
}
pw, _ := u.User.Password()
resource, err := pool.RunWithOptions(&dockertest.RunOptions{
Repository: cfg.repo,
Tag: cfg.tag,
Env: []string{
fmt.Sprintf("POSTGRES_USER=%s", u.User.Username()),
fmt.Sprintf("POSTGRES_PASSWORD=%s", pw),
fmt.Sprintf("POSTGRES_DB=%s", u.Path),
},
}, func(config *docker.HostConfig) {
config.AutoRemove = true
config.RestartPolicy = docker.RestartPolicy{
Name: "no",
}
})
if err != nil {
return nil, fmt.Errorf("couldn't run postgres: %w", err)
}
if err = resource.Expire(cfg.ttl); err != nil {
return nil, err
}
u.Host, err = getHostPort(resource, "5432/tcp")
if err != nil {
return nil, err
}
return &Postgres{
connectionString: u,
resource: resource,
}, nil
}
const (
postgresPingBackOffMaxInterval = 5 * time.Second
postgresPingBackOffMaxElapsedTime = 30 * time.Second
)
// NewBunDB initializes a new instance of *bun.DB, which is ready for use (all required migrations are applied).
// This method guarantees data separation through PostgresSQL schemas
// (https://www.postgresql.org/docs/current/ddl-schemas.html)
// and it is safe to call Postgres.NewBunDB multiple times.
//
// It fails if Postgres hasn't been properly initialized (via NewPostgres).
func (p *Postgres) NewBunDB(tb TestingTB) *bun.DB {
tb.Helper()
require.NotNil(tb, p, "postgres resource not property initialized")
require.NotNil(tb, p.connectionString, "postgres resource not properly initialized")
schema := generatePostgresSchema()
sqldb := sql.OpenDB(
pgdriver.NewConnector(
pgdriver.WithDSN(p.connectionString.String()),
pgdriver.WithConnParams(map[string]any{
"search_path": schema,
}),
),
)
bunDB := bun.NewDB(sqldb, pgdialect.New())
tb.Cleanup(func() {
_ = bunDB.Close()
})
bo := backoff.NewExponentialBackOff()
bo.MaxInterval = postgresPingBackOffMaxInterval
bo.MaxElapsedTime = postgresPingBackOffMaxElapsedTime
require.NoError(tb, retry(bo, bunDB.Ping), "couldn't ping DB")
_, err := bunDB.Exec("CREATE SCHEMA ?", bun.Safe(schema))
require.NoError(tb, err, "couldn't create postgres schema")
runMigrations(tb, bunDB)
return bunDB
}
func (p *Postgres) Close() error {
if p.resource != nil {
if err := p.resource.Close(); err != nil {
return err
}
}
return nil
}
func generatePostgresSchema() string {
return strings.TrimFunc(strings.ReplaceAll(uuid.NewString(), "-", "_"), unicode.IsNumber)
}

View File

@ -0,0 +1,27 @@
package adaptertest
import (
"database/sql"
"github.com/stretchr/testify/require"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect/sqlitedialect"
"github.com/uptrace/bun/driver/sqliteshim"
)
const sqliteMaxIdleConns = 1000
// NewBunDBSQLite initializes a new instance of *bun.DB, which is ready for use (all required migrations are applied).
// Data is stored in memory (https://www.sqlite.org/inmemorydb.html).
func NewBunDBSQLite(tb TestingTB) *bun.DB {
sqldb, err := sql.Open(sqliteshim.ShimName, "file::memory:?cache=shared")
require.NoError(tb, err)
sqldb.SetMaxIdleConns(sqliteMaxIdleConns)
sqldb.SetConnMaxLifetime(0)
db := bun.NewDB(sqldb, sqlitedialect.New())
runMigrations(tb, db)
return db
}

View File

@ -0,0 +1,9 @@
package adaptertest
// TestingTB is a subset of the API provided by both *testing.T and *testing.B.
type TestingTB interface {
Helper()
Errorf(format string, args ...interface{})
FailNow()
Cleanup(f func())
}

View File

@ -0,0 +1,58 @@
package adaptertest
import (
"context"
"errors"
"fmt"
"net"
"net/url"
"os"
"time"
"gitea.dwysokinski.me/twhelp/corev3/internal/migrations"
"github.com/cenkalti/backoff/v4"
"github.com/ory/dockertest/v3"
"github.com/stretchr/testify/require"
"github.com/uptrace/bun"
)
const migrationTimeout = 10 * time.Second
func runMigrations(tb TestingTB, db *bun.DB) {
tb.Helper()
migrator := migrations.NewMigrator(db)
ctx, cancel := context.WithTimeout(context.Background(), migrationTimeout)
defer cancel()
require.NoError(tb, migrator.Init(ctx), "couldn't init migrator")
_, err := migrator.Migrate(ctx)
fmt.Println(err)
require.NoError(tb, err, "couldn't apply migrations")
}
func getHostPort(resource *dockertest.Resource, id string) (string, error) {
dockerURL := os.Getenv("DOCKER_HOST")
if dockerURL == "" {
return resource.GetHostPort(id), nil
}
u, err := url.Parse(dockerURL)
if err != nil {
return "", err
}
return net.JoinHostPort(u.Hostname(), resource.GetPort(id)), nil
}
func retry(bo backoff.BackOff, op backoff.Operation) error {
if err := backoff.Retry(op, bo); err != nil {
if bo.NextBackOff() == backoff.Stop {
return errors.New("reached retry deadline")
}
return err
}
return nil
}

View File

@ -0,0 +1,43 @@
package bunmodel
import (
"fmt"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
"github.com/uptrace/bun"
)
type Version struct {
bun.BaseModel `bun:"table:versions,alias:version"`
Code string `bun:"code,pk"`
Name string `bun:"name"`
Host string `bun:"host"`
Timezone string `bun:"timezone"`
}
func (v Version) ToDomain() (domain.Version, error) {
return domain.UnmarshalVersionFromDatabase(
v.Code,
v.Name,
v.Host,
v.Timezone,
)
}
type Versions []Version
func (vs Versions) ToDomain() (domain.Versions, error) {
res := make(domain.Versions, 0, len(vs))
for _, v := range vs {
converted, err := v.ToDomain()
if err != nil {
return nil, fmt.Errorf("couldn't construct domain.Version (version=%s): %w", v.Code, err)
}
res = append(res, converted)
}
return res, nil
}

View File

@ -0,0 +1,64 @@
package adapter
import (
"context"
"database/sql"
"errors"
"fmt"
"gitea.dwysokinski.me/twhelp/corev3/internal/adapter/internal/bunmodel"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
"github.com/uptrace/bun"
)
type VersionBunRepository struct {
db bun.IDB
}
func NewVersionBunRepository(db bun.IDB) *VersionBunRepository {
return &VersionBunRepository{db: db}
}
func (repo *VersionBunRepository) List(ctx context.Context, params domain.ListVersionsParams) (domain.Versions, error) {
var versions bunmodel.Versions
if err := repo.db.NewSelect().
Model(&versions).
Apply(listVersionsParamsApplier{params: params}.apply).
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
return nil, fmt.Errorf("couldn't select versions from the database: %w", err)
}
return versions.ToDomain()
}
func (repo *VersionBunRepository) ListCount(
ctx context.Context,
params domain.ListVersionsParams,
) (domain.Versions, int, error) {
versions, err := repo.List(ctx, params)
if err != nil {
return nil, 0, err
}
return versions, len(versions), nil
}
type listVersionsParamsApplier struct {
params domain.ListVersionsParams
}
func (a listVersionsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
for _, s := range a.params.Sort() {
switch s {
case domain.VersionSortCodeASC:
q = q.Order("version.code ASC")
case domain.VersionSortCodeDESC:
q = q.Order("version.code DESC")
default:
return q.Err(errors.New("unsupported sort value"))
}
}
return q
}

View File

@ -0,0 +1,30 @@
package adapter_test
import (
"testing"
"gitea.dwysokinski.me/twhelp/corev3/internal/adapter"
"gitea.dwysokinski.me/twhelp/corev3/internal/adapter/adaptertest"
)
func TestVersionBunRepo_Postgres(t *testing.T) {
t.Parallel()
if testing.Short() {
t.Skip("skipping long-running test")
}
testVersionRepo(t, func(t *testing.T) versionRepository {
t.Helper()
return adapter.NewVersionBunRepository(postgres.NewBunDB(t))
})
}
func TestVersionBunRepo_SQLite(t *testing.T) {
t.Parallel()
testVersionRepo(t, func(t *testing.T) versionRepository {
t.Helper()
return adapter.NewVersionBunRepository(adaptertest.NewBunDBSQLite(t))
})
}

View File

@ -0,0 +1,105 @@
package adapter_test
import (
"cmp"
"context"
"slices"
"testing"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
type versionRepository interface {
List(ctx context.Context, params domain.ListVersionsParams) (domain.Versions, error)
ListCount(
ctx context.Context,
params domain.ListVersionsParams,
) (domain.Versions, int, error)
}
func testVersionRepo(t *testing.T, newRepo func(t *testing.T) versionRepository) {
t.Helper()
t.Run("List & ListCount", func(t *testing.T) {
t.Parallel()
repo := newRepo(t)
tests := []struct {
name string
params func(t *testing.T) domain.ListVersionsParams
assertVersions func(t *testing.T, versions domain.Versions)
assertError func(t *testing.T, err error)
assertTotal func(t *testing.T, total int)
}{
{
name: "OK: default params",
params: func(t *testing.T) domain.ListVersionsParams {
t.Helper()
return domain.NewListVersionsParams()
},
assertVersions: func(t *testing.T, versions domain.Versions) {
t.Helper()
assert.NotEmpty(t, len(versions))
assert.True(t, slices.IsSortedFunc(versions, func(a, b domain.Version) int {
return cmp.Compare(a.Code(), b.Code())
}))
},
assertError: func(t *testing.T, err error) {
t.Helper()
require.NoError(t, err)
},
assertTotal: func(t *testing.T, total int) {
t.Helper()
assert.NotEmpty(t, total, 0)
},
},
{
name: "OK: Sort=[Code DESC]",
params: func(t *testing.T) domain.ListVersionsParams {
t.Helper()
params := domain.NewListVersionsParams()
require.NoError(t, params.SetSort([]domain.VersionSort{domain.VersionSortCodeDESC}))
return params
},
assertVersions: func(t *testing.T, versions domain.Versions) {
t.Helper()
assert.NotEmpty(t, len(versions))
assert.True(t, slices.IsSortedFunc(versions, func(a, b domain.Version) int {
return cmp.Compare(a.Code(), b.Code()) * -1
}))
},
assertError: func(t *testing.T, err error) {
t.Helper()
require.NoError(t, err)
},
assertTotal: func(t *testing.T, total int) {
t.Helper()
assert.NotEmpty(t, total)
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
ctx := context.Background()
params := tt.params(t)
res, err := repo.List(ctx, params)
tt.assertError(t, err)
tt.assertVersions(t, res)
res, count, err := repo.ListCount(ctx, params)
tt.assertError(t, err)
tt.assertVersions(t, res)
tt.assertTotal(t, count)
})
}
})
}

View File

@ -0,0 +1,23 @@
package app
import (
"context"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
)
type VersionRepository interface {
List(ctx context.Context, params domain.ListVersionsParams) (domain.Versions, error)
}
type VersionService struct {
repo VersionRepository
}
func NewVersionService(repo VersionRepository) *VersionService {
return &VersionService{repo: repo}
}
func (svc *VersionService) List(ctx context.Context, params domain.ListVersionsParams) (domain.Versions, error) {
return svc.repo.List(ctx, params)
}

View File

@ -47,6 +47,7 @@ func Logger(logger Slogger, opts ...Option) func(next http.Handler) http.Handler
slog.String("httpRequest.ip", cfg.ipExtractor(r)),
slog.Int("httpResponse.status", status),
slog.Int("httpResponse.bytes", ww.BytesWritten()),
//nolint:gomnd
slog.Float64("httpResponse.duration", float64(end.Sub(start).Nanoseconds())/1000000.0), // in milliseconds
)
})

77
internal/domain/error.go Normal file
View File

@ -0,0 +1,77 @@
package domain
import (
"errors"
"fmt"
"github.com/gosimple/slug"
)
type ErrorCode uint8
const (
ErrorCodeUnknown ErrorCode = iota
ErrorCodeEntityNotFound
ErrorCodeIncorrectInput
)
func (e ErrorCode) String() string {
switch e {
case ErrorCodeEntityNotFound:
return "entity-not-found"
case ErrorCodeIncorrectInput:
return "incorrect-input"
case ErrorCodeUnknown:
fallthrough
default:
return "unknown-error"
}
}
type Error interface {
error
Code() ErrorCode
Slug() string
}
type ErrorWithParams interface {
Error
Params() map[string]any
}
type ValidationError struct {
Field string
Err error
}
var _ ErrorWithParams = ValidationError{}
func (e ValidationError) Error() string {
return fmt.Sprintf("%s: %s", e.Field, e.Err)
}
func (e ValidationError) Code() ErrorCode {
var domainErr Error
if errors.As(e.Err, &domainErr) {
return domainErr.Code()
}
return ErrorCodeIncorrectInput
}
func (e ValidationError) Slug() string {
s := "validation"
var domainErr Error
if errors.As(e.Err, &domainErr) {
s = domainErr.Slug()
}
return fmt.Sprintf("%s-%s", slug.Make(e.Field), s)
}
func (e ValidationError) Params() map[string]any {
var withParams ErrorWithParams
ok := errors.As(e.Err, &withParams)
if !ok {
return nil
}
return withParams.Params()
}

View File

@ -0,0 +1,45 @@
package domain
import (
"fmt"
)
type LenError struct {
Min int
Max int
Current int
}
var _ ErrorWithParams = LenError{}
func (e LenError) Error() string {
return fmt.Sprintf("sort length must be between %d and %d (current length: %d)", e.Min, e.Max, e.Current)
}
func (e LenError) Code() ErrorCode {
return ErrorCodeIncorrectInput
}
func (e LenError) Slug() string {
return "length"
}
func (e LenError) Params() map[string]any {
return map[string]any{
"Min": e.Min,
"Max": e.Max,
"Current": e.Current,
}
}
func validateSliceLen[S ~[]E, E any](s S, min, max int) error {
if l := len(s); l > max || l < min {
return LenError{
Min: min,
Max: max,
Current: l,
}
}
return nil
}

109
internal/domain/version.go Normal file
View File

@ -0,0 +1,109 @@
package domain
import (
"errors"
"net/url"
)
type Version struct {
code string
name string
host string
timezone string
}
// UnmarshalVersionFromDatabase unmarshals Version from the database.
//
// It should be used only for unmarshalling from the database!
// You can't use UnmarshalVersionFromDatabase as constructor - It may put domain into the invalid state!
func UnmarshalVersionFromDatabase(
code string,
name string,
host string,
timezone string,
) (Version, error) {
if code == "" {
return Version{}, errors.New("code can't be blank")
}
if name == "" {
return Version{}, errors.New("name can't be blank")
}
if host == "" {
return Version{}, errors.New("host can't be blank")
}
if timezone == "" {
return Version{}, errors.New("timezone can't be blank")
}
return Version{
code: code,
name: name,
host: host,
timezone: timezone,
}, nil
}
func (v Version) Code() string {
return v.code
}
func (v Version) Name() string {
return v.name
}
func (v Version) Host() string {
return v.host
}
func (v Version) Timezone() string {
return v.timezone
}
func (v Version) URL() *url.URL {
return &url.URL{
Scheme: "https",
Host: v.host,
}
}
type Versions []Version
type VersionSort uint8
const (
VersionSortCodeASC VersionSort = iota + 1
VersionSortCodeDESC
)
type ListVersionsParams struct {
sort []VersionSort
}
func NewListVersionsParams() ListVersionsParams {
return ListVersionsParams{sort: []VersionSort{VersionSortCodeASC}}
}
const (
versionSortMinLength = 1
versionSortMaxLength = 1
)
func (params *ListVersionsParams) SetSort(sort []VersionSort) error {
if err := validateSliceLen(sort, versionSortMinLength, versionSortMaxLength); err != nil {
return ValidationError{
Field: "sort",
Err: err,
}
}
params.sort = sort
return nil
}
func (params *ListVersionsParams) Sort() []VersionSort {
return params.sort
}

View File

@ -0,0 +1,79 @@
package domain_test
import (
"testing"
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestListVersionsParams_SetSort(t *testing.T) {
t.Parallel()
type args struct {
sort []domain.VersionSort
}
tests := []struct {
name string
args args
expectedErr error
}{
{
name: "OK",
args: args{
sort: []domain.VersionSort{
domain.VersionSortCodeASC,
},
},
},
{
name: "ERR: len(sort) < 1",
args: args{
sort: nil,
},
expectedErr: domain.ValidationError{
Field: "sort",
Err: domain.LenError{
Min: 1,
Max: 1,
Current: 0,
},
},
},
{
name: "ERR: len(sort) > 1",
args: args{
sort: []domain.VersionSort{
domain.VersionSortCodeASC,
domain.VersionSortCodeDESC,
},
},
expectedErr: domain.ValidationError{
Field: "sort",
Err: domain.LenError{
Min: 1,
Max: 1,
Current: 2,
},
},
},
}
for _, tt := range tests {
tt := tt
t.Run(tt.name, func(t *testing.T) {
t.Parallel()
params := domain.NewListVersionsParams()
require.ErrorIs(t, params.SetSort(tt.args.sort), tt.expectedErr)
if tt.expectedErr != nil {
return
}
assert.Equal(t, tt.args.sort, params.Sort())
})
}
}

View File

@ -52,7 +52,7 @@ func (h *Health) CheckReady(ctx context.Context) Result {
}
type singleCheckResultWithName struct {
Name string
name string
SingleCheckResult
}
@ -83,7 +83,7 @@ func (h *Health) check(ctx context.Context, checks []Checker) Result {
}
checkCh <- singleCheckResultWithName{
Name: ch.Name(),
name: ch.Name(),
SingleCheckResult: check,
}
}(ch)
@ -105,7 +105,7 @@ func (h *Health) check(ctx context.Context, checks []Checker) Result {
res.Status = StatusFail
}
res.Checks[check.Name] = append(res.Checks[check.Name], check.SingleCheckResult)
res.Checks[check.name] = append(res.Checks[check.name], check.SingleCheckResult)
}
return res

View File

@ -1 +0,0 @@
drop table if exists versions CASCADE;

View File

@ -1 +0,0 @@
drop table if exists servers cascade;

View File

@ -1 +0,0 @@
drop table if exists tribes cascade;

View File

@ -1 +0,0 @@
drop table if exists players cascade;

View File

@ -1 +0,0 @@
drop table if exists ennoblements cascade;

View File

@ -1 +0,0 @@
drop table if exists player_snapshots cascade;

View File

@ -1 +0,0 @@
drop table if exists tribe_snapshots cascade;

View File

@ -1 +0,0 @@
drop table if exists tribe_changes cascade;

View File

@ -1,3 +1,14 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
)
func init() {
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, `
create table if not exists versions
(
code varchar(6) not null
@ -28,4 +39,11 @@ values ('pl', 'Poland', 'www.plemiona.pl', 'Europe/Warsaw'),
('de', 'Germany', 'www.die-staemme.de', 'Europe/Berlin'),
('sk', 'Slovakia', 'www.divoke-kmene.sk', 'Europe/Bratislava'),
('ru', 'Russia', 'www.voynaplemyon.com', 'Europe/Moscow')
ON CONFLICT DO NOTHING;
ON CONFLICT DO NOTHING;`)
return err
}, func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, "drop table if exists versions CASCADE;")
return err
})
}

View File

@ -1,3 +1,14 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
)
func init() {
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, `
create table if not exists tribes
(
id bigint not null,
@ -33,3 +44,11 @@ create table if not exists tribes
create index if not exists tribes_server_key_idx
on tribes (server_key);
`)
return err
}, func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, "drop table if exists tribes cascade;")
return err
})
}

View File

@ -1,3 +1,14 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
)
func init() {
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, `
create table if not exists players
(
id bigint not null,
@ -31,3 +42,10 @@ create table if not exists players
create index if not exists players_server_key_idx
on players (server_key);
`)
return err
}, func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, "drop table if exists players cascade;")
return err
})
}

View File

@ -0,0 +1,42 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
)
func init() {
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, `
create table if not exists villages
(
id bigint not null,
server_key varchar(100) not null
references servers,
name varchar(150) not null,
points bigint default 0,
x bigint default 0,
y bigint default 0,
continent varchar(5),
bonus bigint default 0,
player_id bigint,
created_at timestamp with time zone default CURRENT_TIMESTAMP not null,
profile_url varchar(150),
primary key (id, server_key)
);
create index if not exists villages_server_key_idx
on villages (server_key);
create index if not exists villages_server_key_x_y_idx
on villages (server_key, x, y);
create index if not exists villages_server_key_player_id_idx
on villages (server_key, player_id);`)
return err
}, func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, "drop table if exists villages cascade;")
return err
})
}

View File

@ -1,6 +1,17 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
)
func init() {
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, `
create table if not exists ennoblements
(
id bigint generated by default as identity
id bigint ?
primary key,
server_key varchar(100) not null
references servers,
@ -13,11 +24,6 @@ create table if not exists ennoblements
created_at timestamp with time zone default CURRENT_TIMESTAMP not null
);
create unique index if not exists ennoblements_hash_key
on ennoblements (hash_record_extended(
ROW (server_key, village_id, new_owner_id, new_tribe_id, old_owner_id, old_tribe_id, points, created_at),
0::bigint));
create index if not exists ennoblements_server_key_created_at_idx
on ennoblements (server_key, created_at);
@ -35,3 +41,10 @@ create index if not exists ennoblements_server_key_new_tribe_id_idx
create index if not exists ennoblements_server_key_old_tribe_id_idx
on ennoblements (server_key, old_tribe_id);
`, bun.Safe(autoIncrement(db)))
return err
}, func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, "drop table if exists ennoblements cascade;")
return err
})
}

View File

@ -1,6 +1,17 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
)
func init() {
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, `
create table if not exists player_snapshots
(
id bigint generated by default as identity
id bigint ?
primary key,
player_id bigint not null,
num_villages bigint default 0,
@ -22,3 +33,10 @@ create table if not exists player_snapshots
unique (player_id, server_key, date),
foreign key (player_id, server_key) references players
);
`, bun.Safe(autoIncrement(db)))
return err
}, func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, "drop table if exists player_snapshots cascade;")
return err
})
}

View File

@ -1,7 +1,17 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
)
func init() {
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, `
create table if not exists tribe_snapshots
(
id bigint generated by default as identity
primary key,
id bigint ? primary key,
tribe_id bigint not null,
server_key varchar(100) not null
references servers,
@ -24,3 +34,10 @@ create table if not exists tribe_snapshots
unique (tribe_id, server_key, date),
foreign key (tribe_id, server_key) references tribes
);
`, bun.Safe(autoIncrement(db)))
return err
}, func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, "drop table if exists tribe_snapshots cascade;")
return err
})
}

View File

@ -1,7 +1,17 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
)
func init() {
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, `
create table if not exists tribe_changes
(
id bigint generated by default as identity
primary key,
id bigint ? primary key,
player_id bigint not null,
new_tribe_id bigint,
old_tribe_id bigint,
@ -14,13 +24,15 @@ create table if not exists tribe_changes
create index if not exists tribe_changes_server_key_player_id_idx
on tribe_changes (server_key, player_id);
create unique index if not exists tribe_changes_hash_key
on tribe_changes (hash_record_extended(
ROW (player_id, new_tribe_id, old_tribe_id, server_key, date_trunc('hours'::text, (created_at AT TIME ZONE 'UTC'::text))),
0::bigint));
create index if not exists tribe_changes_server_key_new_tribe_id_idx
on tribe_changes (server_key, new_tribe_id);
create index if not exists tribe_changes_server_key_old_tribe_id_idx
on tribe_changes (server_key, old_tribe_id);
`, bun.Safe(autoIncrement(db)))
return err
}, func(ctx context.Context, db *bun.DB) error {
_, err := db.ExecContext(ctx, "drop table if exists tribe_changes cascade;")
return err
})
}

View File

@ -0,0 +1,34 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect"
)
//nolint:lll
func init() {
// this index is for Postgres only
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
if db.Dialect().Name() != dialect.PG {
return nil
}
_, err := db.ExecContext(
ctx,
`create unique index concurrently if not exists ennoblements_hash_key
on ennoblements (hash_record_extended(
ROW (server_key, village_id, new_owner_id, new_tribe_id, old_owner_id, old_tribe_id, points, created_at),
0::bigint));`,
)
return err
}, func(ctx context.Context, db *bun.DB) error {
if db.Dialect().Name() != dialect.PG {
return nil
}
_, err := db.ExecContext(ctx, "DROP INDEX CONCURRENTLY ennoblements_hash_key")
return err
})
}

View File

@ -0,0 +1,34 @@
package migrations
import (
"context"
"github.com/uptrace/bun"
"github.com/uptrace/bun/dialect"
)
//nolint:lll
func init() {
// this index is for Postgres only
migrations.MustRegister(func(ctx context.Context, db *bun.DB) error {
if db.Dialect().Name() != dialect.PG {
return nil
}
_, err := db.ExecContext(
ctx,
`create unique index concurrently if not exists tribe_changes_hash_key
on tribe_changes (hash_record_extended(
ROW (player_id, new_tribe_id, old_tribe_id, server_key, date_trunc('hours'::text, (created_at AT TIME ZONE 'UTC'::text))),
0::bigint));`,
)
return err
}, func(ctx context.Context, db *bun.DB) error {
if db.Dialect().Name() != dialect.PG {
return nil
}
_, err := db.ExecContext(ctx, "DROP INDEX CONCURRENTLY tribe_changes_hash_key")
return err
})
}

View File

@ -1,23 +1,12 @@
package migrations
import (
"embed"
"github.com/uptrace/bun"
"github.com/uptrace/bun/migrate"
)
var migrations = migrate.NewMigrations()
//go:embed *.sql
var sqlMigrations embed.FS
func init() {
if err := migrations.Discover(sqlMigrations); err != nil {
panic(err)
}
}
func NewMigrator(db *bun.DB, opts ...migrate.MigratorOption) *migrate.Migrator {
return migrate.NewMigrator(db, migrations, opts...)
}

View File

@ -0,0 +1,17 @@
package migrations
import "github.com/uptrace/bun/dialect/feature"
type hasFeaturer interface {
HasFeature(feat feature.Feature) bool
}
func autoIncrement(f hasFeaturer) string {
if f.HasFeature(feature.GeneratedIdentity) {
return "GENERATED BY DEFAULT AS IDENTITY"
}
if f.HasFeature(feature.AutoIncrement) {
return "AUTO_INCREMENT"
}
return ""
}