parent
f6d0dae6b6
commit
4f0e5ff8d5
|
@ -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
|
||||
|
|
|
@ -20,7 +20,6 @@ steps:
|
|||
image: *go_image
|
||||
pull: true
|
||||
commands:
|
||||
- go mod download
|
||||
- make generate
|
||||
|
||||
test:
|
||||
|
|
|
@ -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
46
go.mod
|
@ -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
186
go.sum
|
@ -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=
|
||||
|
|
43
internal/adapter/adapter_test.go
Normal file
43
internal/adapter/adapter_test.go
Normal 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()
|
||||
}
|
183
internal/adapter/adaptertest/postgres.go
Normal file
183
internal/adapter/adaptertest/postgres.go
Normal 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)
|
||||
}
|
27
internal/adapter/adaptertest/sqlite.go
Normal file
27
internal/adapter/adaptertest/sqlite.go
Normal 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
|
||||
}
|
9
internal/adapter/adaptertest/testing_t.go
Normal file
9
internal/adapter/adaptertest/testing_t.go
Normal 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())
|
||||
}
|
58
internal/adapter/adaptertest/utils.go
Normal file
58
internal/adapter/adaptertest/utils.go
Normal 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
|
||||
}
|
43
internal/adapter/internal/bunmodel/version.go
Normal file
43
internal/adapter/internal/bunmodel/version.go
Normal 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
|
||||
}
|
64
internal/adapter/repository_bun_version.go
Normal file
64
internal/adapter/repository_bun_version.go
Normal 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
|
||||
}
|
30
internal/adapter/repository_bun_version_test.go
Normal file
30
internal/adapter/repository_bun_version_test.go
Normal 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))
|
||||
})
|
||||
}
|
105
internal/adapter/repository_version_test.go
Normal file
105
internal/adapter/repository_version_test.go
Normal 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)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
23
internal/app/service_version.go
Normal file
23
internal/app/service_version.go
Normal 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)
|
||||
}
|
|
@ -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
77
internal/domain/error.go
Normal 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()
|
||||
}
|
45
internal/domain/validators.go
Normal file
45
internal/domain/validators.go
Normal 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
109
internal/domain/version.go
Normal 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
|
||||
}
|
79
internal/domain/version_test.go
Normal file
79
internal/domain/version_test.go
Normal 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())
|
||||
})
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
drop table if exists versions CASCADE;
|
|
@ -1 +0,0 @@
|
|||
drop table if exists servers cascade;
|
|
@ -1 +0,0 @@
|
|||
drop table if exists tribes cascade;
|
|
@ -1 +0,0 @@
|
|||
drop table if exists players cascade;
|
|
@ -1 +0,0 @@
|
|||
drop table if exists ennoblements cascade;
|
|
@ -1 +0,0 @@
|
|||
drop table if exists player_snapshots cascade;
|
|
@ -1 +0,0 @@
|
|||
drop table if exists tribe_snapshots cascade;
|
|
@ -1 +0,0 @@
|
|||
drop table if exists tribe_changes cascade;
|
|
@ -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
|
||||
})
|
||||
}
|
File diff suppressed because one or more lines are too long
|
@ -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
|
||||
})
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
42
internal/migrations/20231220051221_create_villages_table.go
Normal file
42
internal/migrations/20231220051221_create_villages_table.go
Normal 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
|
||||
})
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
|
@ -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
|
||||
})
|
||||
}
|
|
@ -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...)
|
||||
}
|
||||
|
|
17
internal/migrations/sql_utils.go
Normal file
17
internal/migrations/sql_utils.go
Normal 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 ""
|
||||
}
|
Loading…
Reference in New Issue
Block a user