feat: add a new endpoint - GET /api/v2/versions (#53)
Reviewed-on: twhelp/corev3#53
This commit is contained in:
parent
aff2b077c0
commit
1409e0a1be
|
@ -20,7 +20,7 @@ servers:
|
||||||
- http
|
- http
|
||||||
- https
|
- https
|
||||||
hostname:
|
hostname:
|
||||||
default: localhost:9913
|
default: localhost:9234
|
||||||
paths:
|
paths:
|
||||||
/v2/versions:
|
/v2/versions:
|
||||||
get:
|
get:
|
||||||
|
@ -77,29 +77,24 @@ components:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
self:
|
self:
|
||||||
description: Pagination link pointing to the current page.
|
description: Cursor pointing to the current page.
|
||||||
type: string
|
type: string
|
||||||
format: uri
|
|
||||||
x-go-type-skip-optional-pointer: true
|
x-go-type-skip-optional-pointer: true
|
||||||
first:
|
first:
|
||||||
description: Pagination link pointing to the first page.
|
description: Cursor pointing to the first page.
|
||||||
type: string
|
type: string
|
||||||
format: uri
|
|
||||||
x-go-type-skip-optional-pointer: true
|
x-go-type-skip-optional-pointer: true
|
||||||
prev:
|
prev:
|
||||||
description: Pagination link pointing to the previous page.
|
description: Cursor pointing to the previous page.
|
||||||
type: string
|
type: string
|
||||||
format: uri
|
|
||||||
x-go-type-skip-optional-pointer: true
|
x-go-type-skip-optional-pointer: true
|
||||||
next:
|
next:
|
||||||
description: Pagination link pointing to the next page.
|
description: Cursor pointing to the next page.
|
||||||
type: string
|
type: string
|
||||||
format: uri
|
|
||||||
x-go-type-skip-optional-pointer: true
|
x-go-type-skip-optional-pointer: true
|
||||||
last:
|
last:
|
||||||
description: Pagination link pointing to the last page.
|
description: Cursor pointing to the last page.
|
||||||
type: string
|
type: string
|
||||||
format: uri
|
|
||||||
x-go-type-skip-optional-pointer: true
|
x-go-type-skip-optional-pointer: true
|
||||||
parameters:
|
parameters:
|
||||||
CursorQueryParam:
|
CursorQueryParam:
|
||||||
|
|
|
@ -10,6 +10,8 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/adapter"
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/app"
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/chislog"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/chislog"
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/health"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/health"
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/port"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/port"
|
||||||
|
@ -87,6 +89,7 @@ var cmdServe = &cli.Command{
|
||||||
Action: func(c *cli.Context) error {
|
Action: func(c *cli.Context) error {
|
||||||
logger := loggerFromCtx(c.Context)
|
logger := loggerFromCtx(c.Context)
|
||||||
|
|
||||||
|
// deps
|
||||||
bunDB, err := newBunDBFromFlags(c)
|
bunDB, err := newBunDBFromFlags(c)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -100,6 +103,13 @@ var cmdServe = &cli.Command{
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
// adapters
|
||||||
|
versionRepo := adapter.NewVersionBunRepository(bunDB)
|
||||||
|
|
||||||
|
// services
|
||||||
|
versionSvc := app.NewVersionService(versionRepo)
|
||||||
|
|
||||||
|
// health
|
||||||
h := health.New()
|
h := health.New()
|
||||||
|
|
||||||
server, err := newHTTPServer(
|
server, err := newHTTPServer(
|
||||||
|
@ -120,7 +130,10 @@ var cmdServe = &cli.Command{
|
||||||
|
|
||||||
r.Mount(metaBasePath, port.NewMetaHTTPHandler(h))
|
r.Mount(metaBasePath, port.NewMetaHTTPHandler(h))
|
||||||
|
|
||||||
r.Mount(apiBasePath, port.NewAPIHTTPHandler(port.WithOpenAPIConfig(oapiCfg)))
|
r.Mount(apiBasePath, port.NewAPIHTTPHandler(
|
||||||
|
versionSvc,
|
||||||
|
port.WithOpenAPIConfig(oapiCfg),
|
||||||
|
))
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
},
|
},
|
||||||
|
|
8
go.mod
8
go.mod
|
@ -8,11 +8,11 @@ require (
|
||||||
github.com/brianvoe/gofakeit/v6 v6.28.0
|
github.com/brianvoe/gofakeit/v6 v6.28.0
|
||||||
github.com/cenkalti/backoff/v4 v4.2.1
|
github.com/cenkalti/backoff/v4 v4.2.1
|
||||||
github.com/elliotchance/phpserialize v1.3.3
|
github.com/elliotchance/phpserialize v1.3.3
|
||||||
github.com/getkin/kin-openapi v0.122.0
|
github.com/getkin/kin-openapi v0.123.0
|
||||||
github.com/go-chi/chi/v5 v5.0.11
|
github.com/go-chi/chi/v5 v5.0.11
|
||||||
github.com/go-chi/render v1.0.3
|
github.com/go-chi/render v1.0.3
|
||||||
github.com/google/go-cmp v0.6.0
|
github.com/google/go-cmp v0.6.0
|
||||||
github.com/google/uuid v1.5.0
|
github.com/google/uuid v1.6.0
|
||||||
github.com/oapi-codegen/runtime v1.1.1
|
github.com/oapi-codegen/runtime v1.1.1
|
||||||
github.com/ory/dockertest/v3 v3.10.0
|
github.com/ory/dockertest/v3 v3.10.0
|
||||||
github.com/stretchr/testify v1.8.4
|
github.com/stretchr/testify v1.8.4
|
||||||
|
@ -42,8 +42,8 @@ require (
|
||||||
github.com/docker/go-units v0.4.0 // indirect
|
github.com/docker/go-units v0.4.0 // indirect
|
||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/fatih/color v1.16.0 // indirect
|
github.com/fatih/color v1.16.0 // indirect
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 // indirect
|
github.com/go-openapi/jsonpointer v0.20.2 // indirect
|
||||||
github.com/go-openapi/swag v0.22.4 // indirect
|
github.com/go-openapi/swag v0.22.8 // indirect
|
||||||
github.com/gogo/protobuf v1.3.2 // indirect
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
|
||||||
github.com/hashicorp/errwrap v1.1.0 // indirect
|
github.com/hashicorp/errwrap v1.1.0 // indirect
|
||||||
|
|
24
go.sum
24
go.sum
|
@ -30,7 +30,6 @@ github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSV
|
||||||
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.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 h1:p1EgwI/C7NhT0JmVkwCD2ZBK8j4aeHQX2pMHHBfMQ6w=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
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/cyphar/filepath-securejoin v0.2.3/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4=
|
||||||
|
@ -52,17 +51,16 @@ github.com/elliotchance/phpserialize v1.3.3/go.mod h1:gt7XX9+ETUcLXbtTKEuyrqW3lc
|
||||||
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM=
|
||||||
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE=
|
||||||
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
github.com/frankban/quicktest v1.11.3/go.mod h1:wRf/ReqHper53s+kmmSZizM8NamnL3IM0I9ntUbOk+k=
|
||||||
github.com/getkin/kin-openapi v0.122.0 h1:WB9Jbl0Hp/T79/JF9xlSW5Kl9uYdk/AWD0yAd9HOM10=
|
github.com/getkin/kin-openapi v0.123.0 h1:zIik0mRwFNLyvtXK274Q6ut+dPh6nlxBp0x7mNrPhs8=
|
||||||
github.com/getkin/kin-openapi v0.122.0/go.mod h1:PCWw/lfBrJY4HcdqE3jj+QFkaFK8ABoqo7PvqVhXXqw=
|
github.com/getkin/kin-openapi v0.123.0/go.mod h1:wb1aSZA/iWmorQP9KTAS/phLj/t17B5jT7+fS8ed9NM=
|
||||||
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
|
github.com/go-chi/chi/v5 v5.0.11 h1:BnpYbFZ3T3S1WMpD79r7R5ThWX40TaFB7L31Y8xqSwA=
|
||||||
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
github.com/go-chi/chi/v5 v5.0.11/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8=
|
||||||
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
github.com/go-chi/render v1.0.3 h1:AsXqd2a1/INaIfUSKq3G5uA8weYx20FOsM7uSoCyyt4=
|
||||||
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
github.com/go-chi/render v1.0.3/go.mod h1:/gr3hVkmYR0YlEy3LxCuVRFzEu9Ruok+gFqbIofjao0=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6 h1:eCs3fxoIi3Wh6vtgmLTOjdhSpiqphQ+DaPn38N2ZdrE=
|
github.com/go-openapi/jsonpointer v0.20.2 h1:mQc3nmndL8ZBzStEo3JYF8wzmeWffDH4VbXz58sAx6Q=
|
||||||
github.com/go-openapi/jsonpointer v0.19.6/go.mod h1:osyAmYz/mB/C3I+WsTTSgw1ONzaLJoLCyoi6/zppojs=
|
github.com/go-openapi/jsonpointer v0.20.2/go.mod h1:bHen+N0u1KEO3YlmqOjTT9Adn1RfD91Ar825/PuiRVs=
|
||||||
github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
github.com/go-openapi/swag v0.22.8 h1:/9RjDSQ0vbFR+NyjGMkFTsA1IA0fmhKSThmfGZjicbw=
|
||||||
github.com/go-openapi/swag v0.22.4 h1:QLMzNJnMGPRNDCbySlcj1x01tzU8/9LTTL9hZZZogBU=
|
github.com/go-openapi/swag v0.22.8/go.mod h1:6QT22icPLEqAM/z/TChgb4WAveCHF92+2gF0CNjHpPI=
|
||||||
github.com/go-openapi/swag v0.22.4/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14=
|
|
||||||
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
|
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/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
|
||||||
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
github.com/go-test/deep v1.0.8 h1:TDsG77qcSprGbC6vTN8OuXp5g+J+b5Pcguhf7Zt61VM=
|
||||||
|
@ -83,8 +81,8 @@ github.com/google/pprof v0.0.0-20221118152302-e6195bd50e26/go.mod h1:dDKJzRmX4S3
|
||||||
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4=
|
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/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.2.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
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 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I=
|
||||||
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4=
|
||||||
|
@ -157,8 +155,8 @@ github.com/rabbitmq/amqp091-go v1.9.0 h1:qrQtyzB4H8BQgEuJwhmVQqVHB9O4+MNDJCCAcpc
|
||||||
github.com/rabbitmq/amqp091-go v1.9.0/go.mod h1:+jPrT9iY2eLjRaMSRHUhc3z14E/l85kv/f+6luSD3pc=
|
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 h1:W09IVJc94icq4NjY3clb7Lk8O1qJ8BdBEF8z0ibU0rE=
|
||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec/go.mod h1:qqbHyh8v60DhA7CoWK5oRCqLrMHRGoxYCSS9EjAz6Eo=
|
||||||
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
|
github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8=
|
||||||
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
|
github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
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 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
@ -172,12 +170,10 @@ github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnIn
|
||||||
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
github.com/spkg/bom v0.0.0-20160624110644-59b7046e48ad/go.mod h1:qLr4V1qq6nMqFKkMo8ZTx3f+BZEkzsRUY10Xsm2mwU0=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
|
||||||
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
|
|
||||||
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.7.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.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
|
||||||
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
|
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/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/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww=
|
||||||
|
|
|
@ -12,3 +12,14 @@ func appendODSetClauses(q *bun.InsertQuery) *bun.InsertQuery {
|
||||||
Set("rank_total = EXCLUDED.rank_total").
|
Set("rank_total = EXCLUDED.rank_total").
|
||||||
Set("score_total = EXCLUDED.score_total")
|
Set("score_total = EXCLUDED.score_total")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func separateListResultAndNext[T any](res []T, limit int) ([]T, T) {
|
||||||
|
var next T
|
||||||
|
|
||||||
|
if len(res) > limit {
|
||||||
|
next = res[limit]
|
||||||
|
res = res[:limit]
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, next
|
||||||
|
}
|
||||||
|
|
|
@ -19,29 +19,25 @@ func NewVersionBunRepository(db bun.IDB) *VersionBunRepository {
|
||||||
return &VersionBunRepository{db: db}
|
return &VersionBunRepository{db: db}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (repo *VersionBunRepository) List(ctx context.Context, params domain.ListVersionsParams) (domain.Versions, error) {
|
func (repo *VersionBunRepository) List(
|
||||||
|
ctx context.Context,
|
||||||
|
params domain.ListVersionsParams,
|
||||||
|
) (domain.ListVersionsResult, error) {
|
||||||
var versions bunmodel.Versions
|
var versions bunmodel.Versions
|
||||||
|
|
||||||
if err := repo.db.NewSelect().
|
if err := repo.db.NewSelect().
|
||||||
Model(&versions).
|
Model(&versions).
|
||||||
Apply(listVersionsParamsApplier{params: params}.apply).
|
Apply(listVersionsParamsApplier{params: params}.apply).
|
||||||
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
Scan(ctx); err != nil && !errors.Is(err, sql.ErrNoRows) {
|
||||||
return nil, fmt.Errorf("couldn't select versions from the database: %w", err)
|
return domain.ListVersionsResult{}, fmt.Errorf("couldn't select versions from the database: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return versions.ToDomain()
|
converted, err := 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 {
|
if err != nil {
|
||||||
return nil, 0, err
|
return domain.ListVersionsResult{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return versions, len(versions), nil
|
return domain.NewListVersionsResult(separateListResultAndNext(converted, params.Limit()))
|
||||||
}
|
}
|
||||||
|
|
||||||
type listVersionsParamsApplier struct {
|
type listVersionsParamsApplier struct {
|
||||||
|
@ -50,15 +46,25 @@ type listVersionsParamsApplier struct {
|
||||||
|
|
||||||
func (a listVersionsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
func (a listVersionsParamsApplier) apply(q *bun.SelectQuery) *bun.SelectQuery {
|
||||||
for _, s := range a.params.Sort() {
|
for _, s := range a.params.Sort() {
|
||||||
|
codeCursor := a.params.Cursor().Code()
|
||||||
|
|
||||||
switch s {
|
switch s {
|
||||||
case domain.VersionSortCodeASC:
|
case domain.VersionSortCodeASC:
|
||||||
|
if codeCursor.Valid {
|
||||||
|
q = q.Where("version.code >= ?", codeCursor.Value)
|
||||||
|
}
|
||||||
|
|
||||||
q = q.Order("version.code ASC")
|
q = q.Order("version.code ASC")
|
||||||
case domain.VersionSortCodeDESC:
|
case domain.VersionSortCodeDESC:
|
||||||
|
if codeCursor.Valid {
|
||||||
|
q = q.Where("version.code <= ?", codeCursor.Value)
|
||||||
|
}
|
||||||
|
|
||||||
q = q.Order("version.code DESC")
|
q = q.Order("version.code DESC")
|
||||||
default:
|
default:
|
||||||
return q.Err(errors.New("unsupported sort value"))
|
return q.Err(errors.New("unsupported sort value"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return q
|
return q.Limit(a.params.Limit() + 1)
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,10 +57,10 @@ func testServerRepository(t *testing.T, newRepos func(t *testing.T) repositories
|
||||||
t.Run("OK", func(t *testing.T) {
|
t.Run("OK", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
versions, err := repos.version.List(ctx, domain.NewListVersionsParams())
|
listVersionsRes, err := repos.version.List(ctx, domain.NewListVersionsParams())
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.NotEmpty(t, versions)
|
require.NotEmpty(t, listVersionsRes)
|
||||||
version := versions[0]
|
version := listVersionsRes.Versions()[0]
|
||||||
|
|
||||||
serversToCreate := domain.BaseServers{
|
serversToCreate := domain.BaseServers{
|
||||||
domaintest.NewBaseServer(t),
|
domaintest.NewBaseServer(t),
|
||||||
|
|
|
@ -12,11 +12,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type versionRepository interface {
|
type versionRepository interface {
|
||||||
List(ctx context.Context, params domain.ListVersionsParams) (domain.Versions, error)
|
List(ctx context.Context, params domain.ListVersionsParams) (domain.ListVersionsResult, error)
|
||||||
ListCount(
|
|
||||||
ctx context.Context,
|
|
||||||
params domain.ListVersionsParams,
|
|
||||||
) (domain.Versions, int, error)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type serverRepository interface {
|
type serverRepository interface {
|
||||||
|
|
|
@ -7,6 +7,7 @@ import (
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/domain/domaintest"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
@ -16,17 +17,16 @@ func testVersionRepository(t *testing.T, newRepos func(t *testing.T) repositorie
|
||||||
|
|
||||||
ctx := context.Background()
|
ctx := context.Background()
|
||||||
|
|
||||||
t.Run("List & ListCount", func(t *testing.T) {
|
t.Run("List", func(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
repos := newRepos(t)
|
repos := newRepos(t)
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
params func(t *testing.T) domain.ListVersionsParams
|
params func(t *testing.T) domain.ListVersionsParams
|
||||||
assertVersions func(t *testing.T, versions domain.Versions)
|
assertResult func(t *testing.T, params domain.ListVersionsParams, res domain.ListVersionsResult)
|
||||||
assertError func(t *testing.T, err error)
|
assertError func(t *testing.T, err error)
|
||||||
assertTotal func(t *testing.T, total int)
|
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
name: "OK: default params",
|
name: "OK: default params",
|
||||||
|
@ -34,21 +34,18 @@ func testVersionRepository(t *testing.T, newRepos func(t *testing.T) repositorie
|
||||||
t.Helper()
|
t.Helper()
|
||||||
return domain.NewListVersionsParams()
|
return domain.NewListVersionsParams()
|
||||||
},
|
},
|
||||||
assertVersions: func(t *testing.T, versions domain.Versions) {
|
assertResult: func(t *testing.T, params domain.ListVersionsParams, res domain.ListVersionsResult) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
assert.NotEmpty(t, len(versions))
|
assert.NotEmpty(t, res.Versions())
|
||||||
assert.True(t, slices.IsSortedFunc(versions, func(a, b domain.Version) int {
|
assert.True(t, slices.IsSortedFunc(res.Versions(), func(a, b domain.Version) int {
|
||||||
return cmp.Compare(a.Code(), b.Code())
|
return cmp.Compare(a.Code(), b.Code())
|
||||||
}))
|
}))
|
||||||
|
assert.True(t, res.Next().IsZero())
|
||||||
},
|
},
|
||||||
assertError: func(t *testing.T, err error) {
|
assertError: func(t *testing.T, err error) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
},
|
},
|
||||||
assertTotal: func(t *testing.T, total int) {
|
|
||||||
t.Helper()
|
|
||||||
assert.NotEmpty(t, total)
|
|
||||||
},
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "OK: sort=[code DESC]",
|
name: "OK: sort=[code DESC]",
|
||||||
|
@ -58,10 +55,10 @@ func testVersionRepository(t *testing.T, newRepos func(t *testing.T) repositorie
|
||||||
require.NoError(t, params.SetSort([]domain.VersionSort{domain.VersionSortCodeDESC}))
|
require.NoError(t, params.SetSort([]domain.VersionSort{domain.VersionSortCodeDESC}))
|
||||||
return params
|
return params
|
||||||
},
|
},
|
||||||
assertVersions: func(t *testing.T, versions domain.Versions) {
|
assertResult: func(t *testing.T, params domain.ListVersionsParams, res domain.ListVersionsResult) {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
assert.NotEmpty(t, len(versions))
|
assert.NotEmpty(t, res.Versions())
|
||||||
assert.True(t, slices.IsSortedFunc(versions, func(a, b domain.Version) int {
|
assert.True(t, slices.IsSortedFunc(res.Versions(), func(a, b domain.Version) int {
|
||||||
return cmp.Compare(a.Code(), b.Code()) * -1
|
return cmp.Compare(a.Code(), b.Code()) * -1
|
||||||
}))
|
}))
|
||||||
},
|
},
|
||||||
|
@ -69,9 +66,95 @@ func testVersionRepository(t *testing.T, newRepos func(t *testing.T) repositorie
|
||||||
t.Helper()
|
t.Helper()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
},
|
},
|
||||||
assertTotal: func(t *testing.T, total int) {
|
},
|
||||||
|
{
|
||||||
|
name: "OK: cursor sort=[code ASC]",
|
||||||
|
params: func(t *testing.T) domain.ListVersionsParams {
|
||||||
t.Helper()
|
t.Helper()
|
||||||
assert.NotEmpty(t, total)
|
|
||||||
|
params := domain.NewListVersionsParams()
|
||||||
|
require.NoError(t, params.SetSort([]domain.VersionSort{domain.VersionSortCodeASC}))
|
||||||
|
|
||||||
|
res, err := repos.version.List(ctx, params)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Greater(t, len(res.Versions()), 2)
|
||||||
|
|
||||||
|
require.NoError(t, params.SetCursor(domaintest.NewVersionCursor(t, func(cfg *domaintest.VersionCursorConfig) {
|
||||||
|
cfg.Code = domain.NullString{
|
||||||
|
Value: res.Versions()[1].Code(),
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
assertResult: func(t *testing.T, params domain.ListVersionsParams, res domain.ListVersionsResult) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, res.Versions())
|
||||||
|
assert.True(t, slices.IsSortedFunc(res.Versions(), func(a, b domain.Version) int {
|
||||||
|
return cmp.Compare(a.Code(), b.Code())
|
||||||
|
}))
|
||||||
|
for _, v := range res.Versions() {
|
||||||
|
assert.GreaterOrEqual(t, v.Code(), params.Cursor().Code().Value, v.Code())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
assertError: func(t *testing.T, err error) {
|
||||||
|
t.Helper()
|
||||||
|
require.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: cursor sort=[code DESC]",
|
||||||
|
params: func(t *testing.T) domain.ListVersionsParams {
|
||||||
|
t.Helper()
|
||||||
|
|
||||||
|
params := domain.NewListVersionsParams()
|
||||||
|
require.NoError(t, params.SetSort([]domain.VersionSort{domain.VersionSortCodeDESC}))
|
||||||
|
|
||||||
|
res, err := repos.version.List(ctx, params)
|
||||||
|
require.NoError(t, err)
|
||||||
|
require.Greater(t, len(res.Versions()), 2)
|
||||||
|
|
||||||
|
require.NoError(t, params.SetCursor(domaintest.NewVersionCursor(t, func(cfg *domaintest.VersionCursorConfig) {
|
||||||
|
cfg.Code = domain.NullString{
|
||||||
|
Value: res.Versions()[1].Code(),
|
||||||
|
Valid: true,
|
||||||
|
}
|
||||||
|
})))
|
||||||
|
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
assertResult: func(t *testing.T, params domain.ListVersionsParams, res domain.ListVersionsResult) {
|
||||||
|
t.Helper()
|
||||||
|
assert.NotEmpty(t, res.Versions())
|
||||||
|
assert.True(t, slices.IsSortedFunc(res.Versions(), func(a, b domain.Version) int {
|
||||||
|
return cmp.Compare(a.Code(), b.Code()) * -1
|
||||||
|
}))
|
||||||
|
for _, v := range res.Versions() {
|
||||||
|
assert.LessOrEqual(t, v.Code(), params.Cursor().Code().Value, v.Code())
|
||||||
|
}
|
||||||
|
},
|
||||||
|
assertError: func(t *testing.T, err error) {
|
||||||
|
t.Helper()
|
||||||
|
require.NoError(t, err)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: limit=5",
|
||||||
|
params: func(t *testing.T) domain.ListVersionsParams {
|
||||||
|
t.Helper()
|
||||||
|
params := domain.NewListVersionsParams()
|
||||||
|
require.NoError(t, params.SetLimit(5))
|
||||||
|
return params
|
||||||
|
},
|
||||||
|
assertResult: func(t *testing.T, params domain.ListVersionsParams, res domain.ListVersionsResult) {
|
||||||
|
t.Helper()
|
||||||
|
assert.Len(t, res.Versions(), params.Limit())
|
||||||
|
assert.False(t, res.Next().IsZero())
|
||||||
|
},
|
||||||
|
assertError: func(t *testing.T, err error) {
|
||||||
|
t.Helper()
|
||||||
|
require.NoError(t, err)
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
@ -86,12 +169,7 @@ func testVersionRepository(t *testing.T, newRepos func(t *testing.T) repositorie
|
||||||
|
|
||||||
res, err := repos.version.List(ctx, params)
|
res, err := repos.version.List(ctx, params)
|
||||||
tt.assertError(t, err)
|
tt.assertError(t, err)
|
||||||
tt.assertVersions(t, res)
|
tt.assertResult(t, params, res)
|
||||||
|
|
||||||
res, count, err := repos.version.ListCount(ctx, params)
|
|
||||||
tt.assertError(t, err)
|
|
||||||
tt.assertVersions(t, res)
|
|
||||||
tt.assertTotal(t, count)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
|
@ -29,10 +29,11 @@ func NewDataSyncService(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *DataSyncService) Sync(ctx context.Context) error {
|
func (svc *DataSyncService) Sync(ctx context.Context) error {
|
||||||
versions, err := svc.versionSvc.List(ctx, domain.NewListVersionsParams())
|
listVersionsRes, err := svc.versionSvc.List(ctx, domain.NewListVersionsParams())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
versions := listVersionsRes.Versions()
|
||||||
|
|
||||||
payloads := make([]domain.SyncServersCmdPayload, 0, len(versions))
|
payloads := make([]domain.SyncServersCmdPayload, 0, len(versions))
|
||||||
|
|
||||||
|
@ -49,10 +50,11 @@ func (svc *DataSyncService) Sync(ctx context.Context) error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *DataSyncService) SyncEnnoblements(ctx context.Context) error {
|
func (svc *DataSyncService) SyncEnnoblements(ctx context.Context) error {
|
||||||
versions, err := svc.versionSvc.List(ctx, domain.NewListVersionsParams())
|
listVersionsRes, err := svc.versionSvc.List(ctx, domain.NewListVersionsParams())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
versions := listVersionsRes.Versions()
|
||||||
|
|
||||||
for _, v := range versions {
|
for _, v := range versions {
|
||||||
if err = svc.syncEnnoblementsForVersion(ctx, v); err != nil {
|
if err = svc.syncEnnoblementsForVersion(ctx, v); err != nil {
|
||||||
|
|
|
@ -31,10 +31,11 @@ func NewSnapshotService(
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *SnapshotService) Create(ctx context.Context) error {
|
func (svc *SnapshotService) Create(ctx context.Context) error {
|
||||||
versions, err := svc.versionSvc.List(ctx, domain.NewListVersionsParams())
|
listVersionsRes, err := svc.versionSvc.List(ctx, domain.NewListVersionsParams())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
versions := listVersionsRes.Versions()
|
||||||
|
|
||||||
for _, v := range versions {
|
for _, v := range versions {
|
||||||
loc, loopErr := time.LoadLocation(v.Timezone())
|
loc, loopErr := time.LoadLocation(v.Timezone())
|
||||||
|
|
|
@ -7,7 +7,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type VersionRepository interface {
|
type VersionRepository interface {
|
||||||
List(ctx context.Context, params domain.ListVersionsParams) (domain.Versions, error)
|
List(ctx context.Context, params domain.ListVersionsParams) (domain.ListVersionsResult, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type VersionService struct {
|
type VersionService struct {
|
||||||
|
@ -18,6 +18,9 @@ func NewVersionService(repo VersionRepository) *VersionService {
|
||||||
return &VersionService{repo: repo}
|
return &VersionService{repo: repo}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (svc *VersionService) List(ctx context.Context, params domain.ListVersionsParams) (domain.Versions, error) {
|
func (svc *VersionService) List(
|
||||||
|
ctx context.Context,
|
||||||
|
params domain.ListVersionsParams,
|
||||||
|
) (domain.ListVersionsResult, error) {
|
||||||
return svc.repo.List(ctx, params)
|
return svc.repo.List(ctx, params)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,30 @@ import (
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type VersionCursorConfig struct {
|
||||||
|
Code domain.NullString
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewVersionCursor(tb TestingTB, opts ...func(cfg *VersionCursorConfig)) domain.VersionCursor {
|
||||||
|
tb.Helper()
|
||||||
|
|
||||||
|
cfg := &VersionCursorConfig{
|
||||||
|
Code: domain.NullString{
|
||||||
|
Value: RandVersionCode(),
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, opt := range opts {
|
||||||
|
opt(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
vc, err := domain.NewVersionCursor(cfg.Code)
|
||||||
|
require.NoError(tb, err)
|
||||||
|
|
||||||
|
return vc
|
||||||
|
}
|
||||||
|
|
||||||
type VersionConfig struct {
|
type VersionConfig struct {
|
||||||
Code string
|
Code string
|
||||||
}
|
}
|
||||||
|
@ -21,7 +45,7 @@ func NewVersion(tb TestingTB, opts ...func(cfg *VersionConfig)) domain.Version {
|
||||||
opt(cfg)
|
opt(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
s, err := domain.UnmarshalVersionFromDatabase(
|
v, err := domain.UnmarshalVersionFromDatabase(
|
||||||
cfg.Code,
|
cfg.Code,
|
||||||
gofakeit.LetterN(10),
|
gofakeit.LetterN(10),
|
||||||
gofakeit.DomainName(),
|
gofakeit.DomainName(),
|
||||||
|
@ -29,7 +53,7 @@ func NewVersion(tb TestingTB, opts ...func(cfg *VersionConfig)) domain.Version {
|
||||||
)
|
)
|
||||||
require.NoError(tb, err)
|
require.NoError(tb, err)
|
||||||
|
|
||||||
return s
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
func RandVersionCode() string {
|
func RandVersionCode() string {
|
||||||
|
|
|
@ -165,8 +165,6 @@ const (
|
||||||
EnnoblementSortServerKeyDESC
|
EnnoblementSortServerKeyDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
const EnnoblementListMaxLimit = 200
|
|
||||||
|
|
||||||
type ListEnnoblementsParams struct {
|
type ListEnnoblementsParams struct {
|
||||||
serverKeys []string
|
serverKeys []string
|
||||||
sort []EnnoblementSort
|
sort []EnnoblementSort
|
||||||
|
@ -174,7 +172,10 @@ type ListEnnoblementsParams struct {
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
const listEnnoblementsParamsModelName = "ListEnnoblementsParams"
|
const (
|
||||||
|
EnnoblementListMaxLimit = 200
|
||||||
|
listEnnoblementsParamsModelName = "ListEnnoblementsParams"
|
||||||
|
)
|
||||||
|
|
||||||
func NewListEnnoblementsParams() ListEnnoblementsParams {
|
func NewListEnnoblementsParams() ListEnnoblementsParams {
|
||||||
return ListEnnoblementsParams{
|
return ListEnnoblementsParams{
|
||||||
|
|
|
@ -373,8 +373,6 @@ const (
|
||||||
PlayerSortServerKeyDESC
|
PlayerSortServerKeyDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
const PlayerListMaxLimit = 200
|
|
||||||
|
|
||||||
type ListPlayersParams struct {
|
type ListPlayersParams struct {
|
||||||
ids []int
|
ids []int
|
||||||
idGT NullInt
|
idGT NullInt
|
||||||
|
@ -385,7 +383,10 @@ type ListPlayersParams struct {
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
const listPlayersParamsModelName = "ListPlayersParams"
|
const (
|
||||||
|
PlayerListMaxLimit = 200
|
||||||
|
listPlayersParamsModelName = "ListPlayersParams"
|
||||||
|
)
|
||||||
|
|
||||||
func NewListPlayersParams() ListPlayersParams {
|
func NewListPlayersParams() ListPlayersParams {
|
||||||
return ListPlayersParams{
|
return ListPlayersParams{
|
||||||
|
|
|
@ -464,8 +464,6 @@ const (
|
||||||
ServerSortOpenDESC
|
ServerSortOpenDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
const ServerListMaxLimit = 500
|
|
||||||
|
|
||||||
type ListServersParams struct {
|
type ListServersParams struct {
|
||||||
keys []string
|
keys []string
|
||||||
keyGT NullString
|
keyGT NullString
|
||||||
|
@ -479,7 +477,10 @@ type ListServersParams struct {
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
const listServersParamsModelName = "ListServersParams"
|
const (
|
||||||
|
ServerListMaxLimit = 500
|
||||||
|
listServersParamsModelName = "ListServersParams"
|
||||||
|
)
|
||||||
|
|
||||||
func NewListServersParams() ListServersParams {
|
func NewListServersParams() ListServersParams {
|
||||||
return ListServersParams{
|
return ListServersParams{
|
||||||
|
|
|
@ -368,8 +368,6 @@ const (
|
||||||
TribeSortServerKeyDESC
|
TribeSortServerKeyDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
const TribeListMaxLimit = 200
|
|
||||||
|
|
||||||
type ListTribesParams struct {
|
type ListTribesParams struct {
|
||||||
ids []int
|
ids []int
|
||||||
idGT NullInt
|
idGT NullInt
|
||||||
|
@ -380,7 +378,10 @@ type ListTribesParams struct {
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
const listTribesParamsModelName = "ListTribesParams"
|
const (
|
||||||
|
TribeListMaxLimit = 200
|
||||||
|
listTribesParamsModelName = "ListTribesParams"
|
||||||
|
)
|
||||||
|
|
||||||
func NewListTribesParams() ListTribesParams {
|
func NewListTribesParams() ListTribesParams {
|
||||||
return ListTribesParams{
|
return ListTribesParams{
|
||||||
|
|
|
@ -213,8 +213,6 @@ const (
|
||||||
TribeChangeSortServerKeyDESC
|
TribeChangeSortServerKeyDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
const TribeChangeListMaxLimit = 200
|
|
||||||
|
|
||||||
type ListTribeChangesParams struct {
|
type ListTribeChangesParams struct {
|
||||||
serverKeys []string
|
serverKeys []string
|
||||||
sort []TribeChangeSort
|
sort []TribeChangeSort
|
||||||
|
@ -222,7 +220,10 @@ type ListTribeChangesParams struct {
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
const listTribeChangesParamsModelName = "ListTribeChangesParams"
|
const (
|
||||||
|
TribeChangeListMaxLimit = 200
|
||||||
|
listTribeChangesParamsModelName = "ListTribeChangesParams"
|
||||||
|
)
|
||||||
|
|
||||||
func NewListTribeChangesParams() ListTribeChangesParams {
|
func NewListTribeChangesParams() ListTribeChangesParams {
|
||||||
return ListTribeChangesParams{
|
return ListTribeChangesParams{
|
||||||
|
|
|
@ -224,8 +224,6 @@ const (
|
||||||
TribeSnapshotSortServerKeyDESC
|
TribeSnapshotSortServerKeyDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
const TribeSnapshotListMaxLimit = 200
|
|
||||||
|
|
||||||
type ListTribeSnapshotsParams struct {
|
type ListTribeSnapshotsParams struct {
|
||||||
serverKeys []string
|
serverKeys []string
|
||||||
sort []TribeSnapshotSort
|
sort []TribeSnapshotSort
|
||||||
|
@ -233,7 +231,10 @@ type ListTribeSnapshotsParams struct {
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
const listTribeSnapshotsParamsModelName = "ListTribeSnapshotsParams"
|
const (
|
||||||
|
TribeSnapshotListMaxLimit = 200
|
||||||
|
listTribeSnapshotsParamsModelName = "ListTribeSnapshotsParams"
|
||||||
|
)
|
||||||
|
|
||||||
func NewListTribeSnapshotsParams() ListTribeSnapshotsParams {
|
func NewListTribeSnapshotsParams() ListTribeSnapshotsParams {
|
||||||
return ListTribeSnapshotsParams{
|
return ListTribeSnapshotsParams{
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package domain
|
package domain
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
"net/url"
|
"net/url"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -91,6 +92,10 @@ func (v Version) URL() *url.URL {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (v Version) IsZero() bool {
|
||||||
|
return v == Version{}
|
||||||
|
}
|
||||||
|
|
||||||
type Versions []Version
|
type Versions []Version
|
||||||
|
|
||||||
type VersionSort uint8
|
type VersionSort uint8
|
||||||
|
@ -100,14 +105,77 @@ const (
|
||||||
VersionSortCodeDESC
|
VersionSortCodeDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
type ListVersionsParams struct {
|
type VersionCursor struct {
|
||||||
sort []VersionSort
|
code NullString
|
||||||
}
|
}
|
||||||
|
|
||||||
const listVersionsParamsModelName = "ListVersionsParams"
|
func NewVersionCursor(code NullString) (VersionCursor, error) {
|
||||||
|
if !code.Valid {
|
||||||
|
return VersionCursor{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := validateVersionCode(code.Value); err != nil {
|
||||||
|
return VersionCursor{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return VersionCursor{
|
||||||
|
code: code,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
encodedVersionCursorMinLength = 1
|
||||||
|
encodedVersionCursorMaxLength = 5000
|
||||||
|
)
|
||||||
|
|
||||||
|
func decodeVersionCursor(encoded string) (VersionCursor, error) {
|
||||||
|
if err := validateStringLen(encoded, encodedVersionCursorMinLength, encodedVersionCursorMaxLength); err != nil {
|
||||||
|
return VersionCursor{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
decoded, err := base64.StdEncoding.DecodeString(encoded)
|
||||||
|
if err != nil {
|
||||||
|
return VersionCursor{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return NewVersionCursor(NullString{
|
||||||
|
Value: string(decoded),
|
||||||
|
Valid: true,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vc VersionCursor) Code() NullString {
|
||||||
|
return vc.code
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vc VersionCursor) IsZero() bool {
|
||||||
|
return !vc.code.Valid
|
||||||
|
}
|
||||||
|
|
||||||
|
func (vc VersionCursor) Encode() string {
|
||||||
|
if vc.IsZero() {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64.StdEncoding.EncodeToString([]byte(vc.code.Value))
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListVersionsParams struct {
|
||||||
|
sort []VersionSort
|
||||||
|
cursor VersionCursor
|
||||||
|
limit int
|
||||||
|
}
|
||||||
|
|
||||||
|
const (
|
||||||
|
VersionListMaxLimit = 200
|
||||||
|
listVersionsParamsModelName = "ListVersionsParams"
|
||||||
|
)
|
||||||
|
|
||||||
func NewListVersionsParams() ListVersionsParams {
|
func NewListVersionsParams() ListVersionsParams {
|
||||||
return ListVersionsParams{sort: []VersionSort{VersionSortCodeASC}}
|
return ListVersionsParams{
|
||||||
|
sort: []VersionSort{VersionSortCodeASC},
|
||||||
|
limit: VersionListMaxLimit,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -132,3 +200,100 @@ func (params *ListVersionsParams) SetSort(sort []VersionSort) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (params *ListVersionsParams) Cursor() VersionCursor {
|
||||||
|
return params.cursor
|
||||||
|
}
|
||||||
|
|
||||||
|
func (params *ListVersionsParams) SetCursor(vc VersionCursor) error {
|
||||||
|
params.cursor = vc
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (params *ListVersionsParams) SetEncodedCursor(encoded string) error {
|
||||||
|
decoded, err := decodeVersionCursor(encoded)
|
||||||
|
if err != nil {
|
||||||
|
return ValidationError{
|
||||||
|
Model: listVersionsParamsModelName,
|
||||||
|
Field: "cursor",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params.cursor = decoded
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (params *ListVersionsParams) Limit() int {
|
||||||
|
return params.limit
|
||||||
|
}
|
||||||
|
|
||||||
|
func (params *ListVersionsParams) SetLimit(limit int) error {
|
||||||
|
if err := validateIntInRange(limit, 1, VersionListMaxLimit); err != nil {
|
||||||
|
return ValidationError{
|
||||||
|
Model: listVersionsParamsModelName,
|
||||||
|
Field: "limit",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
params.limit = limit
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListVersionsResult struct {
|
||||||
|
versions Versions
|
||||||
|
self VersionCursor
|
||||||
|
next VersionCursor
|
||||||
|
}
|
||||||
|
|
||||||
|
const listVersionsResultModelName = "ListVersionsResult"
|
||||||
|
|
||||||
|
func NewListVersionsResult(versions Versions, next Version) (ListVersionsResult, error) {
|
||||||
|
var err error
|
||||||
|
res := ListVersionsResult{
|
||||||
|
versions: versions,
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(versions) > 0 {
|
||||||
|
res.self, err = NewVersionCursor(NullString{
|
||||||
|
Value: versions[0].Code(),
|
||||||
|
Valid: true,
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return ListVersionsResult{}, ValidationError{
|
||||||
|
Model: listVersionsResultModelName,
|
||||||
|
Field: "self",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.next, err = NewVersionCursor(NullString{
|
||||||
|
Value: next.Code(),
|
||||||
|
Valid: !next.IsZero(),
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
return ListVersionsResult{}, ValidationError{
|
||||||
|
Model: listVersionsResultModelName,
|
||||||
|
Field: "next",
|
||||||
|
Err: err,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return res, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (res ListVersionsResult) Versions() Versions {
|
||||||
|
return res.versions
|
||||||
|
}
|
||||||
|
|
||||||
|
func (res ListVersionsResult) Self() VersionCursor {
|
||||||
|
return res.self
|
||||||
|
}
|
||||||
|
|
||||||
|
func (res ListVersionsResult) Next() VersionCursor {
|
||||||
|
return res.next
|
||||||
|
}
|
||||||
|
|
|
@ -1,13 +1,83 @@
|
||||||
package domain_test
|
package domain_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/base64"
|
||||||
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/domain/domaintest"
|
||||||
|
"github.com/brianvoe/gofakeit/v6"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestNewVersionCursor(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
validVersionCursor := domaintest.NewVersionCursor(t)
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
code domain.NullString
|
||||||
|
}
|
||||||
|
|
||||||
|
type test struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
expectedErr error
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []test{
|
||||||
|
{
|
||||||
|
name: "OK",
|
||||||
|
args: args{
|
||||||
|
code: validVersionCursor.Code(),
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "OK: nil code",
|
||||||
|
args: args{
|
||||||
|
code: domain.NullString{},
|
||||||
|
},
|
||||||
|
expectedErr: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, versionCodeTest := range newVersionCodeValidationTests() {
|
||||||
|
tests = append(tests, test{
|
||||||
|
name: versionCodeTest.name,
|
||||||
|
args: args{
|
||||||
|
code: domain.NullString{
|
||||||
|
Value: versionCodeTest.code,
|
||||||
|
Valid: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
expectedErr: versionCodeTest.expectedErr,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
vc, err := domain.NewVersionCursor(tt.args.code)
|
||||||
|
require.ErrorIs(t, err, tt.expectedErr)
|
||||||
|
if tt.expectedErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.Equal(t, tt.args.code, vc.Code())
|
||||||
|
if tt.args.code.Valid {
|
||||||
|
assert.NotEmpty(t, vc.Encode())
|
||||||
|
} else {
|
||||||
|
assert.Empty(t, vc.Encode())
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestListVersionsParams_SetSort(t *testing.T) {
|
func TestListVersionsParams_SetSort(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
|
@ -80,6 +150,200 @@ func TestListVersionsParams_SetSort(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestListVersionsParams_SetEncodedCursor(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
validCursor := domaintest.NewVersionCursor(t)
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
cursor string
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
expectedCursor domain.VersionCursor
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "OK",
|
||||||
|
args: args{
|
||||||
|
cursor: validCursor.Encode(),
|
||||||
|
},
|
||||||
|
expectedCursor: validCursor,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: len(cursor) < 1",
|
||||||
|
args: args{
|
||||||
|
cursor: "",
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ListVersionsParams",
|
||||||
|
Field: "cursor",
|
||||||
|
Err: domain.LenOutOfRangeError{
|
||||||
|
Min: 1,
|
||||||
|
Max: 5000,
|
||||||
|
Current: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: len(cursor) > 5000",
|
||||||
|
args: args{
|
||||||
|
cursor: gofakeit.LetterN(5001),
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ListVersionsParams",
|
||||||
|
Field: "cursor",
|
||||||
|
Err: domain.LenOutOfRangeError{
|
||||||
|
Min: 1,
|
||||||
|
Max: 5000,
|
||||||
|
Current: 5001,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: malformed base64",
|
||||||
|
args: args{
|
||||||
|
cursor: "112345",
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ListVersionsParams",
|
||||||
|
Field: "cursor",
|
||||||
|
Err: base64.CorruptInputError(4),
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
params := domain.NewListVersionsParams()
|
||||||
|
|
||||||
|
require.ErrorIs(t, params.SetEncodedCursor(tt.args.cursor), tt.expectedErr)
|
||||||
|
if tt.expectedErr != nil {
|
||||||
|
fmt.Println(tt.expectedErr.Error())
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.True(t, params.Cursor().Code().Valid)
|
||||||
|
assert.Equal(t, tt.expectedCursor.Code(), params.Cursor().Code())
|
||||||
|
assert.Equal(t, tt.args.cursor, params.Cursor().Encode())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestListVersionsParams_SetLimit(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
type args struct {
|
||||||
|
limit int
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
args args
|
||||||
|
expectedErr error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "OK",
|
||||||
|
args: args{
|
||||||
|
limit: domain.VersionListMaxLimit,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "ERR: limit < 1",
|
||||||
|
args: args{
|
||||||
|
limit: 0,
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ListVersionsParams",
|
||||||
|
Field: "limit",
|
||||||
|
Err: domain.MinGreaterEqualError{
|
||||||
|
Min: 1,
|
||||||
|
Current: 0,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: fmt.Sprintf("ERR: limit > %d", domain.VersionListMaxLimit),
|
||||||
|
args: args{
|
||||||
|
limit: domain.VersionListMaxLimit + 1,
|
||||||
|
},
|
||||||
|
expectedErr: domain.ValidationError{
|
||||||
|
Model: "ListVersionsParams",
|
||||||
|
Field: "limit",
|
||||||
|
Err: domain.MaxLessEqualError{
|
||||||
|
Max: domain.VersionListMaxLimit,
|
||||||
|
Current: domain.VersionListMaxLimit + 1,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
tt := tt
|
||||||
|
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
params := domain.NewListVersionsParams()
|
||||||
|
|
||||||
|
require.ErrorIs(t, params.SetLimit(tt.args.limit), tt.expectedErr)
|
||||||
|
if tt.expectedErr != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.Equal(t, tt.args.limit, params.Limit())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNewListVersionsResult(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
versions := domain.Versions{
|
||||||
|
domaintest.NewVersion(t),
|
||||||
|
domaintest.NewVersion(t),
|
||||||
|
domaintest.NewVersion(t),
|
||||||
|
}
|
||||||
|
next := domaintest.NewVersion(t)
|
||||||
|
|
||||||
|
t.Run("OK: with next", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
res, err := domain.NewListVersionsResult(versions, next)
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, versions, res.Versions())
|
||||||
|
assert.True(t, res.Self().Code().Valid)
|
||||||
|
assert.Equal(t, versions[0].Code(), res.Self().Code().Value)
|
||||||
|
assert.True(t, res.Next().Code().Valid)
|
||||||
|
assert.Equal(t, next.Code(), res.Next().Code().Value)
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("OK: without next", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
res, err := domain.NewListVersionsResult(versions, domain.Version{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Equal(t, versions, res.Versions())
|
||||||
|
assert.True(t, res.Self().Code().Valid)
|
||||||
|
assert.Equal(t, versions[0].Code(), res.Self().Code().Value)
|
||||||
|
assert.True(t, res.Next().IsZero())
|
||||||
|
})
|
||||||
|
|
||||||
|
t.Run("OK: 0 versions", func(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
res, err := domain.NewListVersionsResult(nil, domain.Version{})
|
||||||
|
require.NoError(t, err)
|
||||||
|
assert.Zero(t, res.Versions())
|
||||||
|
assert.True(t, res.Self().IsZero())
|
||||||
|
assert.True(t, res.Next().IsZero())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
type versionCodeValidationTest struct {
|
type versionCodeValidationTest struct {
|
||||||
name string
|
name string
|
||||||
code string
|
code string
|
||||||
|
|
|
@ -224,8 +224,6 @@ const (
|
||||||
VillageSortServerKeyDESC
|
VillageSortServerKeyDESC
|
||||||
)
|
)
|
||||||
|
|
||||||
const VillageListMaxLimit = 500
|
|
||||||
|
|
||||||
type ListVillagesParams struct {
|
type ListVillagesParams struct {
|
||||||
ids []int
|
ids []int
|
||||||
idGT NullInt
|
idGT NullInt
|
||||||
|
@ -235,7 +233,10 @@ type ListVillagesParams struct {
|
||||||
offset int
|
offset int
|
||||||
}
|
}
|
||||||
|
|
||||||
const listVillagesParamsModelName = "ListVillagesParams"
|
const (
|
||||||
|
VillageListMaxLimit = 500
|
||||||
|
listVillagesParamsModelName = "ListVillagesParams"
|
||||||
|
)
|
||||||
|
|
||||||
func NewListVillagesParams() ListVillagesParams {
|
func NewListVillagesParams() ListVillagesParams {
|
||||||
return ListVillagesParams{
|
return ListVillagesParams{
|
||||||
|
|
|
@ -4,6 +4,7 @@ import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"sync"
|
"sync"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/app"
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/swgui"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/swgui"
|
||||||
"github.com/getkin/kin-openapi/openapi3"
|
"github.com/getkin/kin-openapi/openapi3"
|
||||||
|
@ -12,7 +13,7 @@ import (
|
||||||
)
|
)
|
||||||
|
|
||||||
type apiHTTPHandler struct {
|
type apiHTTPHandler struct {
|
||||||
apimodel.Unimplemented
|
versionSvc *app.VersionService
|
||||||
getOpenAPISchema func() (*openapi3.T, error)
|
getOpenAPISchema func() (*openapi3.T, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,10 +23,11 @@ func WithOpenAPIConfig(oapiCfg OpenAPIConfig) APIHTTPHandlerOption {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewAPIHTTPHandler(opts ...APIHTTPHandlerOption) http.Handler {
|
func NewAPIHTTPHandler(versionSvc *app.VersionService, opts ...APIHTTPHandlerOption) http.Handler {
|
||||||
cfg := newAPIHTTPHandlerConfig(opts...)
|
cfg := newAPIHTTPHandlerConfig(opts...)
|
||||||
|
|
||||||
h := &apiHTTPHandler{
|
h := &apiHTTPHandler{
|
||||||
|
versionSvc: versionSvc,
|
||||||
getOpenAPISchema: sync.OnceValues(func() (*openapi3.T, error) {
|
getOpenAPISchema: sync.OnceValues(func() (*openapi3.T, error) {
|
||||||
return getOpenAPISchema(cfg.openAPI)
|
return getOpenAPISchema(cfg.openAPI)
|
||||||
}),
|
}),
|
||||||
|
|
|
@ -35,8 +35,10 @@ func getOpenAPISchema(cfg OpenAPIConfig) (*openapi3.T, error) {
|
||||||
schema.Servers = make(openapi3.Servers, 0, len(cfg.Servers))
|
schema.Servers = make(openapi3.Servers, 0, len(cfg.Servers))
|
||||||
|
|
||||||
for _, s := range cfg.Servers {
|
for _, s := range cfg.Servers {
|
||||||
|
u := *s.URL
|
||||||
|
u.Path = cfg.BasePath
|
||||||
schema.Servers = append(schema.Servers, &openapi3.Server{
|
schema.Servers = append(schema.Servers, &openapi3.Server{
|
||||||
URL: s.URL.String(),
|
URL: u.String(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,11 @@ func TestOpenAPI(t *testing.T) {
|
||||||
t.Parallel()
|
t.Parallel()
|
||||||
|
|
||||||
u1, err := url.Parse(gofakeit.URL())
|
u1, err := url.Parse(gofakeit.URL())
|
||||||
|
u1.Path = ""
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
u2, err := url.Parse(gofakeit.URL())
|
u2, err := url.Parse(gofakeit.URL())
|
||||||
|
u2.Path = ""
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
servers := []port.OpenAPIConfigServer{
|
servers := []port.OpenAPIConfigServer{
|
||||||
|
@ -35,10 +37,13 @@ func TestOpenAPI(t *testing.T) {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
basePath := "/api"
|
||||||
|
|
||||||
handler := newAPIHTTPHandler(t, func(cfg *apiHTTPHandlerConfig) {
|
handler := newAPIHTTPHandler(t, func(cfg *apiHTTPHandlerConfig) {
|
||||||
cfg.options = append(cfg.options, port.WithOpenAPIConfig(port.OpenAPIConfig{
|
cfg.options = append(cfg.options, port.WithOpenAPIConfig(port.OpenAPIConfig{
|
||||||
Enabled: true,
|
Enabled: true,
|
||||||
Servers: servers,
|
BasePath: basePath,
|
||||||
|
Servers: servers,
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -52,7 +57,7 @@ func TestOpenAPI(t *testing.T) {
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
for i, expected := range servers {
|
for i, expected := range servers {
|
||||||
idx := slices.IndexFunc(body.Servers, func(s *openapi3.Server) bool {
|
idx := slices.IndexFunc(body.Servers, func(s *openapi3.Server) bool {
|
||||||
return s.URL == expected.URL.String()
|
return s.URL == expected.URL.String()+basePath
|
||||||
})
|
})
|
||||||
assert.GreaterOrEqualf(t, idx, 0, "expected[%d] not found", i)
|
assert.GreaterOrEqualf(t, idx, 0, "expected[%d] not found", i)
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@ import (
|
||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/adapter"
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/app"
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/bun/buntest"
|
||||||
"gitea.dwysokinski.me/twhelp/corev3/internal/port"
|
"gitea.dwysokinski.me/twhelp/corev3/internal/port"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -22,7 +25,12 @@ func newAPIHTTPHandler(tb testing.TB, opts ...func(cfg *apiHTTPHandlerConfig)) h
|
||||||
opt(cfg)
|
opt(cfg)
|
||||||
}
|
}
|
||||||
|
|
||||||
return port.NewAPIHTTPHandler(cfg.options...)
|
versionRepo := adapter.NewVersionBunRepository(buntest.NewSQLiteDB(tb))
|
||||||
|
|
||||||
|
return port.NewAPIHTTPHandler(
|
||||||
|
app.NewVersionService(versionRepo),
|
||||||
|
cfg.options...,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func doRequest(h http.Handler, method, target string, body io.Reader) *http.Response {
|
func doRequest(h http.Handler, method, target string, body io.Reader) *http.Response {
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
package port
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
||||||
|
"gitea.dwysokinski.me/twhelp/corev3/internal/port/internal/apimodel"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (h *apiHTTPHandler) ListVersions(w http.ResponseWriter, r *http.Request, params apimodel.ListVersionsParams) {
|
||||||
|
domainParams := domain.NewListVersionsParams()
|
||||||
|
|
||||||
|
if params.Limit != nil {
|
||||||
|
_ = domainParams.SetLimit(*params.Limit)
|
||||||
|
}
|
||||||
|
|
||||||
|
if params.Cursor != nil {
|
||||||
|
_ = domainParams.SetEncodedCursor(*params.Cursor)
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := h.versionSvc.List(r.Context(), domainParams)
|
||||||
|
if err != nil {
|
||||||
|
w.WriteHeader(http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.renderJSON(w, r, http.StatusOK, apimodel.NewListVersionsResponse(res))
|
||||||
|
}
|
|
@ -1,3 +1,30 @@
|
||||||
package apimodel
|
package apimodel
|
||||||
|
|
||||||
|
import "gitea.dwysokinski.me/twhelp/corev3/internal/domain"
|
||||||
|
|
||||||
//go:generate oapi-codegen --config=config.yml ../../../../api/openapi3.yml
|
//go:generate oapi-codegen --config=config.yml ../../../../api/openapi3.yml
|
||||||
|
|
||||||
|
func NewVersion(v domain.Version) Version {
|
||||||
|
return Version{
|
||||||
|
Code: v.Code(),
|
||||||
|
Host: v.Host(),
|
||||||
|
Name: v.Name(),
|
||||||
|
Timezone: v.Timezone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewListVersionsResponse(res domain.ListVersionsResult) ListVersionsResponse {
|
||||||
|
versions := res.Versions()
|
||||||
|
|
||||||
|
resp := ListVersionsResponse{
|
||||||
|
Items: make([]Version, 0, len(versions)),
|
||||||
|
Self: res.Self().Encode(),
|
||||||
|
Next: res.Next().Encode(),
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, v := range versions {
|
||||||
|
resp.Items = append(resp.Items, NewVersion(v))
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue