diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d20baa4d..30b59dfa 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -33,7 +33,7 @@ jobs: - name: Set up Golang uses: actions/setup-go@v3 with: - go-version: '1.18' + go-version: '1.19' - name: Test run: go test -v -p 1 -parallel 1 -failfast ./... @@ -80,7 +80,7 @@ jobs: - name: Set up Golang uses: actions/setup-go@v3 with: - go-version: '1.18' + go-version: '1.19' - name: Test run: go test -v -p 1 -parallel 1 -failfast ./... @@ -113,7 +113,7 @@ jobs: - name: Set up Golang uses: actions/setup-go@v3 with: - go-version: '1.18' + go-version: '1.19' - name: Get dependencies run: | diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 3ec899d0..67acd673 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -24,7 +24,7 @@ jobs: - name: Set up Golang uses: actions/setup-go@v3 with: - go-version: '1.18' + go-version: '1.19' # despite the fact docker will build binary internally # we want to stop workflow in case of any error before pushing to registry diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3e97b987..e15fd525 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -14,7 +14,7 @@ jobs: - name: Set up Golang uses: actions/setup-go@v3 with: - go-version: '1.18' + go-version: '1.19' - name: Check out code into the Go module directory uses: actions/checkout@v3 diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 0cda263a..5ff876ea 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -6,7 +6,7 @@ { "label": "Unit Test", "type": "shell", - "command": "gotest -failfast -timeout=300s -parallel=1 ./${relativeFileDirname}/... -coverprofile='coverage.out' && go tool cover -func='coverage.out'", + "command": "go test -failfast -timeout=300s -parallel=1 ./${relativeFileDirname}/... -coverprofile='coverage.out' -json | tparse -all", "problemMatcher": [ "$go" ], @@ -23,7 +23,7 @@ { "label": "Coverage Report", "type": "shell", - "command": "go tool cover -html='coverage.out'", + "command": "go tool cover -func='coverage.out' && go tool cover -html='coverage.out'", "problemMatcher": [ "$go" ], diff --git a/go.mod b/go.mod index 178016f6..4deb207d 100644 --- a/go.mod +++ b/go.mod @@ -1,16 +1,13 @@ module github.com/cybertec-postgresql/pg_timetable -go 1.18 +go 1.19 require ( github.com/cavaliercoder/grab v2.0.0+incompatible - github.com/georgysavva/scany v1.2.0 - github.com/jackc/pgconn v1.13.0 - github.com/jackc/pgtype v1.12.0 - github.com/jackc/pgx/v4 v4.17.2 + github.com/jackc/pgx/v5 v5.0.0 github.com/jessevdk/go-flags v1.5.0 github.com/ory/mail/v3 v3.0.1-0.20210418065910-7f033ddea8dc - github.com/pashagolub/pgxmock v1.8.0 + github.com/pashagolub/pgxmock/v2 v2.0.0 github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 github.com/sethvargo/go-retry v0.2.3 github.com/sirupsen/logrus v1.9.0 @@ -22,25 +19,22 @@ require ( github.com/davecgh/go-spew v1.1.1 // indirect github.com/fsnotify/fsnotify v1.5.4 // indirect github.com/hashicorp/hcl v1.0.0 // indirect - github.com/jackc/chunkreader/v2 v2.0.1 // indirect - github.com/jackc/pgio v1.0.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgproto3/v2 v2.3.1 // indirect github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b // indirect - github.com/jackc/puddle v1.3.0 // indirect + github.com/jackc/puddle/v2 v2.0.0 // indirect github.com/magiconair/properties v1.8.6 // indirect github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/pelletier/go-toml v1.9.5 // indirect github.com/pelletier/go-toml/v2 v2.0.5 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect - github.com/spf13/afero v1.8.2 // indirect + github.com/spf13/afero v1.9.2 // indirect github.com/spf13/cast v1.5.0 // indirect github.com/spf13/jwalterweatherman v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // indirect github.com/subosito/gotenv v1.4.1 // indirect - golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa // indirect - golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 // indirect + golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 // indirect + golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 // indirect golang.org/x/text v0.3.7 // indirect gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect gopkg.in/ini.v1 v1.67.0 // indirect diff --git a/go.sum b/go.sum index 1a6cc9b7..d129fc27 100644 --- a/go.sum +++ b/go.sum @@ -38,7 +38,6 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= -github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs= github.com/cavaliercoder/grab v2.0.0+incompatible h1:wZHbBQx56+Yxjx2TCGDcenhh3cJn7cCLMfkEPmySTSE= github.com/cavaliercoder/grab v2.0.0+incompatible/go.mod h1:tTBkfNqSBfuMmMBFaO2phgyhdYhiZQ/+iXCZDzcDsMI= github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= @@ -49,13 +48,6 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/cockroachdb/cockroach-go/v2 v2.2.0 h1:/5znzg5n373N/3ESjHF5SMLxiW4RKB05Ql//KWfeTFs= -github.com/cockroachdb/cockroach-go/v2 v2.2.0/go.mod h1:u3MiKYGupPPjkn3ozknpMUpxPaNLTFWAya419/zv6eI= -github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4= -github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY= 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= @@ -68,20 +60,9 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7 github.com/frankban/quicktest v1.14.3 h1:FJKSZTDHjyhriyC81FLQ0LY93eSai0ZyR/ZIkd3ZUKE= github.com/fsnotify/fsnotify v1.5.4 h1:jRbGcIw6P2Meqdwuo0H1p6JVLbL5DHKAKlYndzMwVZI= github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU= -github.com/georgysavva/scany v1.2.0 h1:/rO39YZ5HT3lzDp3lNkkE30Mu95ebEtQ7F1/GluLc8Y= -github.com/georgysavva/scany v1.2.0/go.mod h1:vGBpL5XRLOocMFFa55pj0P04DrL3I7qKVRL49K6Eu5o= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/gofrs/flock v0.8.1 h1:+gYjHKf32LDeiEEFhQaotPbLuUXjY5ZqxKgXy7n59aw= -github.com/gofrs/flock v0.8.1/go.mod h1:F1TvTiK9OcQqauNUHlbJvyl9Qa1QvF/gOUDKA14jxHU= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gofrs/uuid v4.0.0+incompatible h1:1SD/1F5pU8p29ybwgQSwpQk+mwdRrXCYuPhW6m+TnJw= -github.com/gofrs/uuid v4.0.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -143,115 +124,37 @@ github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= -github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo= -github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8= -github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk= -github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA= -github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE= -github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s= -github.com/jackc/pgconn v1.4.0/go.mod h1:Y2O3ZDF0q4mMacyWV3AstPJpeHXWGEetiFttmq5lahk= -github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.5.1-0.20200601181101-fa742c524853/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI= -github.com/jackc/pgconn v1.8.0/go.mod h1:1C2Pb36bGIP9QHGBYCjnyhqu7Rv3sGshaQUvmfGIB/o= -github.com/jackc/pgconn v1.9.0/go.mod h1:YctiPyvzfU11JFxoXokUOOKQXQmDMoJL9vJzHH8/2JY= -github.com/jackc/pgconn v1.9.1-0.20210724152538-d89c8390a530/go.mod h1:4z2w8XhRbP1hYxkpTuBjTS3ne3J48K83+u0zoyvg2pI= -github.com/jackc/pgconn v1.13.0 h1:3L1XMNV2Zvca/8BYhzcRFS70Lr0WlDg16Di6SFGAbys= -github.com/jackc/pgconn v1.13.0/go.mod h1:AnowpAqO4CMIIJNZl2VJp+KrkAZciAkhEl0W0JIobpI= -github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE= -github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8= -github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE= -github.com/jackc/pgmock v0.0.0-20201204152224-4fe30f7445fd/go.mod h1:hrBW0Enj2AZTNpt/7Y5rr2xe/9Mn757Wtb2xeBzPv2c= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65 h1:DadwsjnMwFjfWc9y5Wi/+Zz7xoE5ALHsRQlOctkOiHc= -github.com/jackc/pgmock v0.0.0-20210724152146-4ad1a8207f65/go.mod h1:5R2h2EEX+qri8jOWMbJCtaPWkrrNc7OHwsp2TCqp7ak= github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA= -github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg= -github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM= -github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.0.6/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.1.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgproto3/v2 v2.3.1 h1:nwj7qwf0S+Q7ISFfBndqeLwSwxs+4DPsbRFjECT1Y4Y= -github.com/jackc/pgproto3/v2 v2.3.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA= -github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg= github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg= -github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc= -github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw= -github.com/jackc/pgtype v1.2.0/go.mod h1:5m2OfMh1wTK7x+Fk952IDmI4nw3nPrvtQdM0ZT4WpC0= -github.com/jackc/pgtype v1.3.1-0.20200510190516-8cd94a14c75a/go.mod h1:vaogEUkALtxZMCH411K+tKzNpwzCKU+AnPzBKZ+I+Po= -github.com/jackc/pgtype v1.3.1-0.20200606141011-f6355165a91c/go.mod h1:cvk9Bgu/VzJ9/lxTO5R5sf80p0DiucVtN7ZxvaC4GmQ= -github.com/jackc/pgtype v1.6.2/go.mod h1:JCULISAZBFGrHaOXIIFiyfzW5VY0GRitRr8NeJsrdig= -github.com/jackc/pgtype v1.8.1-0.20210724151600-32e20a603178/go.mod h1:C516IlIV9NKqfsMCXTdChteoXmwgUceqaLfjg2e3NlM= -github.com/jackc/pgtype v1.12.0 h1:Dlq8Qvcch7kiehm8wPGIW0W3KsCCHJnRacKW0UM8n5w= -github.com/jackc/pgtype v1.12.0/go.mod h1:LUMuVrfsFfdKGLw+AFFVv6KtHOFMwRgDDzBt76IqCA4= -github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y= -github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM= -github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc= -github.com/jackc/pgx/v4 v4.5.0/go.mod h1:EpAKPLdnTorwmPUUsqrPxy5fphV18j9q3wrfRXgo+kA= -github.com/jackc/pgx/v4 v4.6.1-0.20200510190926-94ba730bb1e9/go.mod h1:t3/cdRQl6fOLDxqtlyhe9UWgfIi9R8+8v8GKV5TRA/o= -github.com/jackc/pgx/v4 v4.6.1-0.20200606145419-4e5062306904/go.mod h1:ZDaNWkt9sW1JMiNn0kdYBaLelIhw7Pg4qd+Vk6tw7Hg= -github.com/jackc/pgx/v4 v4.10.1/go.mod h1:QlrWebbs3kqEZPHCTGyxecvzG6tvIsYu+A5b1raylkA= -github.com/jackc/pgx/v4 v4.12.1-0.20210724153913-640aa07df17c/go.mod h1:1QD0+tgSXP7iUjYm9C1NxKhny7lq6ee99u/z+IHFcgs= -github.com/jackc/pgx/v4 v4.17.2 h1:0Ut0rpeKwvIVbMQ1KbMBU4h6wxehBI535LK6Flheh8E= -github.com/jackc/pgx/v4 v4.17.2/go.mod h1:lcxIZN44yMIrWI78a5CpucdD14hX0SBDbNRvjDBItsw= -github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.1/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= -github.com/jackc/puddle v1.3.0 h1:eHK/5clGOatcjX3oWGBO/MpxpbHzSwud5EWTSCI+MX0= -github.com/jackc/puddle v1.3.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk= +github.com/jackc/pgx/v5 v5.0.0 h1:3UdmB3yUeTnJtZ+nDv3Mxzd4GHHvHkl9XN3oboIbOrY= +github.com/jackc/pgx/v5 v5.0.0/go.mod h1:JBbvW3Hdw77jKl9uJrEDATUZIFM2VFPzRq4RWIhkF4o= +github.com/jackc/puddle/v2 v2.0.0 h1:Kwk/AlLigcnZsDssc3Zun1dk1tAtQNPaBBxBHWn0Mjc= +github.com/jackc/puddle/v2 v2.0.0/go.mod h1:itE7ZJY8xnoo0JqJEpSMprN0f+NQkMCuEV/N9j8h0oc= github.com/jessevdk/go-flags v1.5.0 h1:1jKYvbxEjfUl0fmqTCOfonvskHHXMjBySTLW4y9LFvc= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= -github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= -github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= -github.com/jmoiron/sqlx v1.3.1/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw= 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/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.3.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/lib/pq v1.10.0/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8= -github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/magiconair/properties v1.8.6 h1:5ibWZ6iY0NctNGWo87LalDlEZ6R41TqbbDamhfG/Qzo= github.com/magiconair/properties v1.8.6/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= -github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-colorable v0.1.6/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= -github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= -github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/ory/mail/v3 v3.0.1-0.20210418065910-7f033ddea8dc h1:BU12v9x5hvONtYU2R2LnlkxmWSsjzco046NzJLcWMHg= github.com/ory/mail/v3 v3.0.1-0.20210418065910-7f033ddea8dc/go.mod h1:vAPEMm1zIQKGmM9hcZTSlOU/CDVCXHGOw6SFxPlSoHw= -github.com/pashagolub/pgxmock v1.8.0 h1:05JB+jng7yPdeC6i04i8TC4H1Kr7TfcFeQyf4JP6534= -github.com/pashagolub/pgxmock v1.8.0/go.mod h1:kDkER7/KJdD3HQjNvFw5siwR7yREKmMvwf8VhAgTK5o= +github.com/pashagolub/pgxmock/v2 v2.0.0 h1:abmYLYEWdBuxlIa/RiDljdWXtXfZaXkDu+vnAuapxK0= +github.com/pashagolub/pgxmock/v2 v2.0.0/go.mod h1:CIfK2sDrMpIWlBJC55MJ0LroA1rBYmLetPICx28Q7Jo= github.com/pelletier/go-toml v1.9.5 h1:4yBQzkHv+7BHq2PQUZF3Mx0IYxG7LsP222s7Agd3ve8= github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= github.com/pelletier/go-toml/v2 v2.0.5 h1:ipoSadvV8oGUjnUbMub59IDPPwfxF694nG/jwbMiyQg= github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas= -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/pkg/sftp v1.13.1/go.mod h1:3HaPG6Dq1ILlpPZRO0HVMrsydcdLt6HRDccSgb87qRg= @@ -262,22 +165,12 @@ github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5 h1:mZHayPoR0lNmnH github.com/rifflock/lfshook v0.0.0-20180920164130-b9218ef580f5/go.mod h1:GEXHk5HgEKCvEIIrSpFI3ozzG5xOKA2DVlEX/gGnewM= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ= -github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU= -github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc= -github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= github.com/sethvargo/go-retry v0.2.3 h1:oYlgvIvsju3jNbottWABtbnoLC+GDtLdBHxKWxQm/iU= github.com/sethvargo/go-retry v0.2.3/go.mod h1:1afjQuvh7s4gflMObvjLPaWgluLLyhA1wmVZ6KLpICw= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/shopspring/decimal v0.0.0-20200227202807-02e2044944cc/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/shopspring/decimal v1.2.0 h1:abSATXmQEYyShuxI4/vyW3tV1MrKAJzCZ/0zLUXYbsQ= -github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o= -github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0= github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/spf13/afero v1.8.2 h1:xehSyVa0YnHWsJ49JFljMpg1HX19V6NDZ1fkm1Xznbo= -github.com/spf13/afero v1.8.2/go.mod h1:CtAatgMJh6bJEIs48Ay/FOnkljP3WeGUG0MC1RfAqwo= +github.com/spf13/afero v1.9.2 h1:j49Hj62F0n+DaZ1dDCvhABaPNSGNkt32oRFxI33IEMw= +github.com/spf13/afero v1.9.2/go.mod h1:iUV7ddyEEZPO5gA3zD4fJt6iStLlL+Lg4m2cihcDf8Y= github.com/spf13/cast v1.5.0 h1:rj3WzYc11XZaIZMPKmwP96zkFEnnAmV8s6XbB2aY32w= github.com/spf13/cast v1.5.0/go.mod h1:SpXXQ5YoyJw6s3/6cMTQuxvgRl3PCJiyaX9p6b155UU= github.com/spf13/jwalterweatherman v1.1.0 h1:ue6voC5bR5F8YxI5S67j9i582FU4Qvo2bmqnqMYADFk= @@ -287,9 +180,6 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An github.com/spf13/viper v1.13.0 h1:BWSJ/M+f+3nmdz9bxB+bWX28kkALN2ok11D0rSo8EJU= github.com/spf13/viper v1.13.0/go.mod h1:Icm2xNL3/8uyh/wFuB1jI7TiTNKp8632Nwegu+zgdYw= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE= -github.com/stretchr/objx v0.4.0 h1:M2gUjqZET1qApGOWNSnZ49BAIMX4F/1plDv3+l31EJ4= 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= @@ -305,41 +195,21 @@ github.com/yuin/goldmark v1.1.25/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q= go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.3/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.4/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= go.opencensus.io v0.22.5/go.mod h1:5pWMHQbX5EPX2/62yrJeAkowc+lfs/XD7Uxpq3pI6kk= -go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= -go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/atomic v1.6.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= -go.uber.org/multierr v1.3.0/go.mod h1:VgVr7evmIr6uPjLBxg28wmKNXyqE9akIJ5XnfpiKl+4= -go.uber.org/multierr v1.5.0/go.mod h1:FeouvMocqHpRaaGuG9EjoKcStLC43Zu/fmqdUMPcKYU= -go.uber.org/tools v0.0.0-20190618225709-2cfd321de3ee/go.mod h1:vJERXedbb3MVM5f9Ejo0C68/HhF8uaILCdgjnY+goOA= -go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= -go.uber.org/zap v1.13.0/go.mod h1:zwrFLgMcdUuIBviXEYEH1YKNaOBnKXsx2IPda5bBwHM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20190911031432-227b76d455e7/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.0.0-20201203163018-be400aefbc4c/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= -golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20211108221036-ceb1ce70b4fa/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa h1:zuSxTR4o9y82ebqCUJYNGJbGPo6sKVl54f/TVDObg1c= -golang.org/x/crypto v0.0.0-20220722155217-630584e8d5aa/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0 h1:a5Yg6ylndHHYJqIPrdq0AhvR6KTvDTAvgBtaidhEevY= +golang.org/x/crypto v0.0.0-20220919173607-35f4265a4bc0/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -385,7 +255,6 @@ golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190628185345-da137c7871d7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200202094626-16171245cfb2/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -405,7 +274,6 @@ golang.org/x/net v0.0.0-20201031054903-ff519b6c9102/go.mod h1:sp8m0HH+o8qH0wwXwY golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20201224014010-6772e930b67b/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -426,26 +294,18 @@ golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200113162924-86b910548bc1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -466,14 +326,12 @@ golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20210823070655-63515b42dcdf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8 h1:h+EGohizhe9XlX18rfpa8k8RAc5XyaeamM+0VHRd4lc= +golang.org/x/sys v0.0.0-20220919091848-fb04ddd9f9c8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -481,8 +339,6 @@ golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.4/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -495,18 +351,14 @@ golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3 golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029041327-9cc4af7d6b2c/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20191029190741-b9c20aec41a5/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -514,7 +366,6 @@ golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.0.0-20191130070609-6e064ea0cf2d/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= -golang.org/x/tools v0.0.0-20200103221440-774c71fcf114/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200117161641-43d50277825c/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200122220014-bf1340f18c4a/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= @@ -540,8 +391,6 @@ golang.org/x/tools v0.0.0-20201208233053-a543418bbed2/go.mod h1:emZCQorbCU4vsT4f golang.org/x/tools v0.0.0-20210105154028-b0ab187a4818/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.0.0-20210108195828-e2f9c7f1fc8e/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= -golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= 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= @@ -637,10 +486,9 @@ google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlba gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc h1:2gGKlE2+asNV9m7xrywl36YYNnBG5ZQ0r/BOOxqPpmk= gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc/go.mod h1:m7x9LTH6d71AHyAX77c9yqWCCa3UKHcVEj9y7hAtKDk= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s= gopkg.in/ini.v1 v1.67.0 h1:Dgnx+6+nfE+IfzjUEISNeydPJh9AXNNsWbGP9KzCsOA= gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= @@ -649,9 +497,6 @@ gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= 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= -gorm.io/driver/postgres v1.0.8/go.mod h1:4eOzrI1MUfm6ObJU/UcmbXyiHSs8jSwH95G5P5dxcAg= -gorm.io/gorm v1.20.12/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= -gorm.io/gorm v1.21.4/go.mod h1:0HFTzE/SqkGTzK6TlDPPQbAYCluiVvhzoA1+aVyzenw= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/internal/log/log.go b/internal/log/log.go index c3ba4597..1af30a86 100644 --- a/internal/log/log.go +++ b/internal/log/log.go @@ -5,7 +5,7 @@ import ( "os" "github.com/cybertec-postgresql/pg_timetable/internal/config" - "github.com/jackc/pgx/v4" + "github.com/jackc/pgx/v5/tracelog" "github.com/rifflock/lfshook" "github.com/sirupsen/logrus" ) @@ -60,7 +60,7 @@ func NewPgxLogger(l LoggerIface) *PgxLogger { } // Log transforms logging calls from pgx to logrus -func (pgxlogger *PgxLogger) Log(ctx context.Context, level pgx.LogLevel, msg string, data map[string]interface{}) { +func (pgxlogger *PgxLogger) Log(ctx context.Context, level tracelog.LogLevel, msg string, data map[string]any) { logger := GetLogger(ctx) if logger == FallbackLogger { //switch from standard to specified logger = pgxlogger.l @@ -69,13 +69,13 @@ func (pgxlogger *PgxLogger) Log(ctx context.Context, level pgx.LogLevel, msg str logger = logger.WithFields(data) } switch level { - case pgx.LogLevelTrace: + case tracelog.LogLevelTrace: logger.WithField("PGX_LOG_LEVEL", level).Debug(msg) - case pgx.LogLevelDebug, pgx.LogLevelInfo: //pgx is way too chatty on INFO level + case tracelog.LogLevelDebug, tracelog.LogLevelInfo: //pgx is way too chatty on INFO level logger.Debug(msg) - case pgx.LogLevelWarn: + case tracelog.LogLevelWarn: logger.Warn(msg) - case pgx.LogLevelError: + case tracelog.LogLevelError: logger.Error(msg) default: logger.WithField("INVALID_PGX_LOG_LEVEL", level).Error(msg) diff --git a/internal/log/log_test.go b/internal/log/log_test.go index 84dce428..6f3d0abb 100644 --- a/internal/log/log_test.go +++ b/internal/log/log_test.go @@ -7,7 +7,7 @@ import ( "github.com/cybertec-postgresql/pg_timetable/internal/config" "github.com/cybertec-postgresql/pg_timetable/internal/log" - "github.com/jackc/pgx/v4" + "github.com/jackc/pgx/v5/tracelog" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" ) @@ -33,8 +33,8 @@ func TestFileLogger(t *testing.T) { func TestPgxLog(t *testing.T) { pgxl := log.NewPgxLogger(log.Init(config.LoggingOpts{LogLevel: "trace"})) - var level pgx.LogLevel - for level = pgx.LogLevelNone; level <= pgx.LogLevelTrace; level++ { + var level tracelog.LogLevel + for level = tracelog.LogLevelNone; level <= tracelog.LogLevelTrace; level++ { pgxl.Log(context.Background(), level, "foo", map[string]interface{}{"func": "TestPgxLog"}) } } diff --git a/internal/migrator/migrator.go b/internal/migrator/migrator.go index 76d0584c..95bc2160 100644 --- a/internal/migrator/migrator.go +++ b/internal/migrator/migrator.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" - "github.com/jackc/pgconn" - pgx "github.com/jackc/pgx/v4" + pgx "github.com/jackc/pgx/v5" + pgconn "github.com/jackc/pgx/v5/pgconn" ) // PgxIface is interface for database connection or transaction diff --git a/internal/migrator/migrator_test.go b/internal/migrator/migrator_test.go index 38be2ade..87a8f01c 100644 --- a/internal/migrator/migrator_test.go +++ b/internal/migrator/migrator_test.go @@ -12,8 +12,8 @@ import ( "github.com/cybertec-postgresql/pg_timetable/internal/log" "github.com/cybertec-postgresql/pg_timetable/internal/migrator" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" - pgx "github.com/jackc/pgx/v4" - "github.com/pashagolub/pgxmock" + pgx "github.com/jackc/pgx/v5" + "github.com/pashagolub/pgxmock/v2" "github.com/stretchr/testify/assert" ) diff --git a/internal/pgengine/access.go b/internal/pgengine/access.go index 3141e45a..54ec5b30 100644 --- a/internal/pgengine/access.go +++ b/internal/pgengine/access.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/georgysavva/scany/pgxscan" + "github.com/jackc/pgx/v5" ) // InvalidOid specifies value for non-existent objects @@ -34,7 +34,7 @@ chain_id, task_id, command, kind, last_run, finished, returncode, pid, output, c VALUES ($1, $2, $3, $4, clock_timestamp() - $5 :: interval, clock_timestamp(), $6, $7, NULLIF($8, ''), $9, $10)`, task.ChainID, task.TaskID, task.Script, task.Kind, fmt.Sprintf("%f seconds", float64(task.Duration)/1000000), - retCode, pge.Getpid(), strings.TrimSpace(output), pge.ClientName, task.Txid) + retCode, pge.Getsid(), strings.TrimSpace(output), pge.ClientName, task.Txid) if err != nil { pge.l.WithError(err).Error("Failed to log chain element execution status") } @@ -65,30 +65,45 @@ func (pge *PgEngine) RemoveChainRunStatus(ctx context.Context, chainID int) { } // Select live chains with proper client_name value -const sqlSelectLiveChains = `SELECT chain_id, chain_name, self_destruct, exclusive_execution, COALESCE(timeout, 0) as timeout, COALESCE(max_instances, 16) as max_instances +const sqlSelectLiveChains = `SELECT chain_id, chain_name, self_destruct, exclusive_execution, +COALESCE(max_instances, 16) as max_instances, COALESCE(timeout, 0) as timeout FROM timetable.chain WHERE live AND (client_name = $1 or client_name IS NULL)` // SelectRebootChains returns a list of chains should be executed after reboot -func (pge *PgEngine) SelectRebootChains(ctx context.Context, dest interface{}) error { +func (pge *PgEngine) SelectRebootChains(ctx context.Context, dest *[]Chain) error { const sqlSelectRebootChains = sqlSelectLiveChains + ` AND run_at = '@reboot'` - return pgxscan.Select(ctx, pge.ConfigDb, dest, sqlSelectRebootChains, pge.ClientName) + rows, err := pge.ConfigDb.Query(ctx, sqlSelectRebootChains, pge.ClientName) + if err != nil { + return err + } + *dest, err = pgx.CollectRows(rows, pgx.RowToStructByPos[Chain]) + return err } // SelectChains returns a list of chains should be executed at the current moment -func (pge *PgEngine) SelectChains(ctx context.Context, dest interface{}) error { +func (pge *PgEngine) SelectChains(ctx context.Context, dest *[]Chain) error { const sqlSelectChains = sqlSelectLiveChains + ` AND NOT COALESCE(starts_with(run_at, '@'), FALSE) AND timetable.is_cron_in_time(run_at, now())` - return pgxscan.Select(ctx, pge.ConfigDb, dest, sqlSelectChains, pge.ClientName) + rows, err := pge.ConfigDb.Query(ctx, sqlSelectChains, pge.ClientName) + if err != nil { + return err + } + *dest, err = pgx.CollectRows(rows, pgx.RowToStructByPos[Chain]) + return err } // SelectIntervalChains returns list of interval chains to be executed -func (pge *PgEngine) SelectIntervalChains(ctx context.Context, dest interface{}) error { - const sqlSelectIntervalChains = `SELECT -chain_id, chain_name, self_destruct, exclusive_execution, -COALESCE(timeout, 0) as timeout, COALESCE(max_instances, 16) as max_instances, +func (pge *PgEngine) SelectIntervalChains(ctx context.Context, dest *[]IntervalChain) error { + const sqlSelectIntervalChains = `SELECT chain_id, chain_name, self_destruct, exclusive_execution, +COALESCE(max_instances, 16), COALESCE(timeout, 0), EXTRACT(EPOCH FROM (substr(run_at, 7) :: interval)) :: int4 as interval_seconds, starts_with(run_at, '@after') as repeat_after FROM timetable.chain WHERE live AND (client_name = $1 or client_name IS NULL) AND substr(run_at, 1, 6) IN ('@every', '@after')` - return pgxscan.Select(ctx, pge.ConfigDb, dest, sqlSelectIntervalChains, pge.ClientName) + rows, err := pge.ConfigDb.Query(ctx, sqlSelectIntervalChains, pge.ClientName) + if err != nil { + return err + } + *dest, err = pgx.CollectRows(rows, pgx.RowToStructByPos[IntervalChain]) + return err } // SelectChain returns the chain with the specified ID @@ -96,5 +111,5 @@ func (pge *PgEngine) SelectChain(ctx context.Context, dest interface{}, chainID // we accept not only live chains here because we want to run them in debug mode const sqlSelectSingleChain = `SELECT chain_id, chain_name, self_destruct, exclusive_execution, COALESCE(timeout, 0) as timeout, COALESCE(max_instances, 16) as max_instances FROM timetable.chain WHERE (client_name = $1 OR client_name IS NULL) AND chain_id = $2` - return pgxscan.Get(ctx, pge.ConfigDb, dest, sqlSelectSingleChain, pge.ClientName, chainID) + return pge.ConfigDb.QueryRow(ctx, sqlSelectSingleChain, pge.ClientName, chainID).Scan(dest) } diff --git a/internal/pgengine/access_test.go b/internal/pgengine/access_test.go index 2112699e..b341b629 100644 --- a/internal/pgengine/access_test.go +++ b/internal/pgengine/access_test.go @@ -6,7 +6,7 @@ import ( "testing" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" - "github.com/pashagolub/pgxmock" + "github.com/pashagolub/pgxmock/v2" "github.com/stretchr/testify/assert" ) @@ -61,18 +61,20 @@ func TestRemoveChainRunStatus(t *testing.T) { } func TestSelectChains(t *testing.T) { + var c *[]pgengine.Chain + var ic *[]pgengine.IntervalChain initmockdb(t) pge := pgengine.NewDB(mockPool, "pgengine_unit_test") defer mockPool.Close() mockPool.ExpectExec("SELECT.+chain_id").WillReturnError(errors.New("error")) - assert.Error(t, pge.SelectChains(context.Background(), struct{}{})) + assert.Error(t, pge.SelectChains(context.Background(), c)) mockPool.ExpectExec("SELECT.+chain_id").WillReturnError(errors.New("error")) - assert.Error(t, pge.SelectRebootChains(context.Background(), struct{}{})) + assert.Error(t, pge.SelectRebootChains(context.Background(), c)) mockPool.ExpectExec("SELECT.+chain_id").WillReturnError(errors.New("error")) - assert.Error(t, pge.SelectIntervalChains(context.Background(), struct{}{})) + assert.Error(t, pge.SelectIntervalChains(context.Background(), ic)) } func TestSelectChain(t *testing.T) { diff --git a/internal/pgengine/bootstrap.go b/internal/pgengine/bootstrap.go index 363c3964..45857258 100644 --- a/internal/pgengine/bootstrap.go +++ b/internal/pgengine/bootstrap.go @@ -4,16 +4,18 @@ import ( "context" "errors" "fmt" - "io/ioutil" "math/rand" + "os" "time" "github.com/cybertec-postgresql/pg_timetable/internal/config" "github.com/cybertec-postgresql/pg_timetable/internal/log" - pgconn "github.com/jackc/pgconn" - pgx "github.com/jackc/pgx/v4" - pgxpool "github.com/jackc/pgx/v4/pgxpool" + pgx "github.com/jackc/pgx/v5" + pgconn "github.com/jackc/pgx/v5/pgconn" + pgtype "github.com/jackc/pgx/v5/pgtype" + pgxpool "github.com/jackc/pgx/v5/pgxpool" + tracelog "github.com/jackc/pgx/v5/tracelog" retry "github.com/sethvargo/go-retry" ) @@ -56,18 +58,19 @@ type PgEngine struct { config.CmdOptions // NOTIFY messages passed verification are pushed to this channel chainSignalChan chan ChainSignal - pid int32 + sid int32 + logTypeOID uint32 } -// Getpid returns the pseudo-random process ID to use for the session identification. +// Getsid returns the pseudo-random session ID to use for the session identification. // Previously `os.Getpid()` used but this approach is not producing unique IDs for docker containers // where all IDs are the same across all running containers, e.g. 1 -func (pge *PgEngine) Getpid() int32 { - if pge.pid == 0 { +func (pge *PgEngine) Getsid() int32 { + if pge.sid == 0 { rand.Seed(time.Now().UnixNano()) - pge.pid = rand.Int31() + pge.sid = rand.Int31() } - return pge.pid + return pge.sid } var sqls = []string{sqlDDL, sqlJSONSchema, sqlCronFunctions, sqlJobFunctions} @@ -82,13 +85,17 @@ func New(ctx context.Context, cmdOpts config.CmdOptions, logger log.LoggerHooker CmdOptions: cmdOpts, chainSignalChan: make(chan ChainSignal, 64), } - pge.l.WithField("PID", pge.Getpid()).Info("Starting new session... ") + pge.l.WithField("sid", pge.Getsid()).Info("Starting new session... ") connctx, conncancel := context.WithTimeout(ctx, time.Duration(cmdOpts.Connection.Timeout)*time.Second) defer conncancel() config := pge.getPgxConnConfig() if err = retry.Do(connctx, backoff, func(ctx context.Context) error { - if pge.ConfigDb, err = pgxpool.ConnectConfig(connctx, config); err != nil { + if pge.ConfigDb, err = pgxpool.NewWithConfig(connctx, config); err == nil { + err = pge.ConfigDb.Ping(connctx) + } + if err != nil { + pge.l.WithError(err).Error("Connection failed") pge.l.Info("Sleeping before reconnecting...") return retry.RetryableError(err) } @@ -147,24 +154,27 @@ func (pge *PgEngine) getPgxConnConfig() *pgxpool.Config { pge.l.WithField("severity", n.Severity).WithField("notice", n.Message).Info("Notice received") } connConfig.AfterConnect = func(ctx context.Context, pgconn *pgx.Conn) (err error) { - pge.l.WithField("ConnPID", pgconn.PgConn().PID()). + pge.l.WithField("pid", pgconn.PgConn().PID()). WithField("client", pge.ClientName). Debug("Trying to get lock for the session") if err = pge.TryLockClientName(ctx, pgconn); err != nil { return err } _, err = pgconn.Exec(ctx, "LISTEN "+quoteIdent(pge.ClientName)) + if pge.logTypeOID == InvalidOid { + err = pgconn.QueryRow(ctx, "select coalesce(to_regtype('timetable.log_type')::oid, 0)").Scan(&pge.logTypeOID) + } + pgconn.TypeMap().RegisterType(&pgtype.Type{Name: "timetable.log_type", OID: pge.logTypeOID, Codec: &pgtype.EnumCodec{}}) return err } if !pge.Start.Debug { //will handle notification in HandleNotifications directly connConfig.ConnConfig.OnNotification = pge.NotificationHandler } - connConfig.ConnConfig.Logger = log.NewPgxLogger(pge.l) - if pge.Verbose() { - connConfig.ConnConfig.LogLevel = pgx.LogLevelDebug - } else { - connConfig.ConnConfig.LogLevel = pgx.LogLevelWarn + tracelogger := &tracelog.TraceLog{ + Logger: log.NewPgxLogger(pge.l), + LogLevel: map[bool]tracelog.LogLevel{false: tracelog.LogLevelWarn, true: tracelog.LogLevelDebug}[pge.Verbose()], } + connConfig.ConnConfig.Tracer = tracelogger return connConfig } @@ -192,7 +202,7 @@ func (pge *PgEngine) TryLockClientName(ctx context.Context, conn QueryRowIface) sql = "SELECT timetable.try_lock_client_name($1, $2)" return retry.Do(ctx, backoff, func(ctx context.Context) error { var locked bool - if e := conn.QueryRow(ctx, sql, pge.Getpid(), pge.ClientName).Scan(&locked); e != nil { + if e := conn.QueryRow(ctx, sql, pge.Getsid(), pge.ClientName).Scan(&locked); e != nil { return e } else if !locked { pge.l.Info("Cannot obtain lock for a session") @@ -205,7 +215,7 @@ func (pge *PgEngine) TryLockClientName(ctx context.Context, conn QueryRowIface) // ExecuteCustomScripts executes SQL scripts in files func (pge *PgEngine) ExecuteCustomScripts(ctx context.Context, filename ...string) error { for _, f := range filename { - sql, err := ioutil.ReadFile(f) + sql, err := os.ReadFile(f) if err != nil { pge.l.WithError(err).Error("Cannot read command file") return err diff --git a/internal/pgengine/bootstrap_test.go b/internal/pgengine/bootstrap_test.go index 60548ea6..facf27d6 100644 --- a/internal/pgengine/bootstrap_test.go +++ b/internal/pgengine/bootstrap_test.go @@ -9,8 +9,8 @@ import ( "time" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" - pgx "github.com/jackc/pgx/v4" - "github.com/pashagolub/pgxmock" + pgx "github.com/jackc/pgx/v5" + "github.com/pashagolub/pgxmock/v2" "github.com/stretchr/testify/assert" ) diff --git a/internal/pgengine/log_hook.go b/internal/pgengine/log_hook.go index 33b8ac10..78810102 100644 --- a/internal/pgengine/log_hook.go +++ b/internal/pgengine/log_hook.go @@ -5,7 +5,7 @@ import ( "encoding/json" "time" - pgx "github.com/jackc/pgx/v4" + pgx "github.com/jackc/pgx/v5" "github.com/sirupsen/logrus" ) @@ -34,7 +34,7 @@ func NewHook(ctx context.Context, pge *PgEngine, level string) *LogHook { input: make(chan logrus.Entry, cacheLimit), lastError: make(chan error), ctx: ctx, - pid: pge.Getpid(), + pid: pge.Getsid(), client: pge.ClientName, level: level, } diff --git a/internal/pgengine/log_hook_test.go b/internal/pgengine/log_hook_test.go index 59b52bf0..eac1581f 100644 --- a/internal/pgengine/log_hook_test.go +++ b/internal/pgengine/log_hook_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/pashagolub/pgxmock" + "github.com/pashagolub/pgxmock/v2" "github.com/sirupsen/logrus" "github.com/stretchr/testify/assert" ) diff --git a/internal/pgengine/migration.go b/internal/pgengine/migration.go index 8c3db8f2..c3080109 100644 --- a/internal/pgengine/migration.go +++ b/internal/pgengine/migration.go @@ -6,7 +6,7 @@ import ( "github.com/cybertec-postgresql/pg_timetable/internal/log" "github.com/cybertec-postgresql/pg_timetable/internal/migrator" - pgx "github.com/jackc/pgx/v4" + pgx "github.com/jackc/pgx/v5" ) //go:embed sql/migrations/*.sql diff --git a/internal/pgengine/notification.go b/internal/pgengine/notification.go index 556144a6..1047ca64 100644 --- a/internal/pgengine/notification.go +++ b/internal/pgengine/notification.go @@ -7,7 +7,7 @@ import ( "sync" "time" - pgconn "github.com/jackc/pgconn" + pgconn "github.com/jackc/pgx/v5/pgconn" ) // NotifyTTL specifies how long processed NOTIFY messages should be stored @@ -20,9 +20,9 @@ type ChainSignal struct { Ts int64 // timestamp NOTIFY sent } -// Since there are usually multiple opened connections to the database, all of them will receive NOTIFY messages. -// To process each NOTIFY message only once we store each message with TTL 1 minute because the max idle period for a -// a connection is the main loop period of 1 minute. +// Since there are usually multiple opened connections to the database, all of them will receive NOTIFY messages. +// To process each NOTIFY message only once we store each message with TTL 1 minute because the max idle period for a +// a connection is the main loop period of 1 minute. var mutex sync.Mutex var notifications map[ChainSignal]struct{} = func() (m map[ChainSignal]struct{}) { m = make(map[ChainSignal]struct{}) @@ -42,7 +42,7 @@ var notifications map[ChainSignal]struct{} = func() (m map[ChainSignal]struct{}) // NotificationHandler consumes notifications from the PostgreSQL server func (pge *PgEngine) NotificationHandler(c *pgconn.PgConn, n *pgconn.Notification) { - l := pge.l.WithField("ConnPID", c.PID()).WithField("notification", *n) + l := pge.l.WithField("pid", c.PID()).WithField("notification", *n) l.Debug("Notification received") var signal ChainSignal var err error diff --git a/internal/pgengine/pgengine_test.go b/internal/pgengine/pgengine_test.go index f90ffd83..4d58a483 100644 --- a/internal/pgengine/pgengine_test.go +++ b/internal/pgengine/pgengine_test.go @@ -3,12 +3,12 @@ package pgengine_test import ( "context" "fmt" - "io/ioutil" + "os" "testing" "time" - "github.com/jackc/pgtype" - pgx "github.com/jackc/pgx/v4" + pgx "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgtype" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" @@ -143,7 +143,7 @@ func TestSchedulerFunctions(t *testing.T) { tx, txid, err := pge.StartTransaction(ctx, 0) assert.NoError(t, err, "Should start transaction") assert.Greater(t, txid, 0, "Should return transaction id") - assert.True(t, pge.GetChainElements(ctx, tx, &chains, 0), "Should no error in clean database") + assert.NoError(t, pge.GetChainElements(ctx, tx, &chains, 0), "Should no error in clean database") assert.Empty(t, chains, "Should be empty in clean database") pge.CommitTransaction(ctx, tx) }) @@ -153,7 +153,7 @@ func TestSchedulerFunctions(t *testing.T) { tx, txid, err := pge.StartTransaction(ctx, 0) assert.NoError(t, err, "Should start transaction") assert.Greater(t, txid, 0, "Should return transaction id") - assert.True(t, pge.GetChainParamValues(ctx, tx, ¶mVals, &pgengine.ChainTask{ + assert.NoError(t, pge.GetChainParamValues(ctx, tx, ¶mVals, &pgengine.ChainTask{ TaskID: 0, ChainID: 0}), "Should no error in clean database") assert.Empty(t, paramVals, "Should be empty in clean database") @@ -205,7 +205,7 @@ func TestGetRemoteDBTransaction(t *testing.T) { }) t.Run("Check set role function", func(t *testing.T) { - var runUID pgtype.Varchar + var runUID pgtype.Text runUID.String = cmdOpts.Connection.User assert.NotPanics(t, func() { pge.SetRole(ctx, tx, runUID) }, "Set Role failed") }) @@ -221,7 +221,7 @@ func TestSamplesScripts(t *testing.T) { teardownTestCase := SetupTestCase(t) defer teardownTestCase(t) - files, err := ioutil.ReadDir("../../samples") + files, err := os.ReadDir("../../samples") assert.NoError(t, err, "Cannot read samples directory") l := log.Init(config.LoggingOpts{LogLevel: "error"}) for _, f := range files { diff --git a/internal/pgengine/rows.go b/internal/pgengine/rows.go new file mode 100644 index 00000000..6aa0761e --- /dev/null +++ b/internal/pgengine/rows.go @@ -0,0 +1,109 @@ +package pgengine + +import ( + "fmt" + "reflect" + "strings" + + pgx "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +// RowToStructByName returns a T scanned from row. T must be a struct. T must have the same number a named public fields as row +// has fields. The row and T fields will by matched by name. +func RowToStructByName[T any](row pgx.CollectableRow) (T, error) { + var value T + err := row.Scan(&namedStructRowScanner{ptrToStruct: &value}) + return value, err +} + +// RowToAddrOfStructByPos returns the address of a T scanned from row. T must be a struct. T must have the same number a +// named public fields as row has fields. The row and T fields will by matched by name. +func RowToAddrOfStructByName[T any](row pgx.CollectableRow) (*T, error) { + var value T + err := row.Scan(&namedStructRowScanner{ptrToStruct: &value}) + return &value, err +} + +type namedStructRowScanner struct { + ptrToStruct any +} + +func (rs *namedStructRowScanner) ScanRow(rows pgx.Rows) error { + dst := rs.ptrToStruct + dstValue := reflect.ValueOf(dst) + if dstValue.Kind() != reflect.Ptr { + return fmt.Errorf("dst not a pointer") + } + + dstElemValue := dstValue.Elem() + scanTargets, err := rs.appendScanTargets(dstElemValue, nil, rows.FieldDescriptions()) + + if err != nil { + return err + } + + for i, t := range scanTargets { + if t == nil { + return fmt.Errorf("struct doesn't have corresponding row field %s", rows.FieldDescriptions()[i].Name) + } + } + + return rows.Scan(scanTargets...) +} + +const structTagKey = "db" + +func fieldPosByName(fldDescs []pgconn.FieldDescription, field string) (i int) { + i = -1 + for i, desc := range fldDescs { + if strings.EqualFold(desc.Name, field) { + return i + } + } + return +} + +func (rs *namedStructRowScanner) appendScanTargets(dstElemValue reflect.Value, scanTargets []any, fldDescs []pgconn.FieldDescription) ([]any, error) { + var err error + dstElemType := dstElemValue.Type() + + if scanTargets == nil { + scanTargets = make([]any, len(fldDescs)) + } + + for i := 0; i < dstElemType.NumField(); i++ { + sf := dstElemType.Field(i) + if sf.PkgPath != "" && !sf.Anonymous { + // Field is unexported, skip it. + continue + } + // Handle anoymous struct embedding, but do not try to handle embedded pointers. + if sf.Anonymous && sf.Type.Kind() == reflect.Struct { + scanTargets, err = rs.appendScanTargets(dstElemValue.Field(i), scanTargets, fldDescs) + if err != nil { + return nil, err + } + } else { + dbTag, dbTagPresent := sf.Tag.Lookup(structTagKey) + if dbTagPresent { + dbTag = strings.Split(dbTag, ",")[0] + } + if dbTag == "-" { + // Field is ignored, skip it. + continue + } + colName := dbTag + if !dbTagPresent { + colName = sf.Name + } + fpos := fieldPosByName(fldDescs, colName) + if fpos == -1 || fpos >= len(scanTargets) { + return nil, fmt.Errorf("cannot find field %s in returned row", colName) + } + scanTargets[fpos] = dstElemValue.Field(i).Addr().Interface() + } + } + + return scanTargets, err +} diff --git a/internal/pgengine/rows_test.go b/internal/pgengine/rows_test.go new file mode 100644 index 00000000..db1771ea --- /dev/null +++ b/internal/pgengine/rows_test.go @@ -0,0 +1,48 @@ +package pgengine_test + +import ( + "context" + "testing" + + "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" + "github.com/jackc/pgx/v5" + "github.com/stretchr/testify/assert" +) + +func TestRowToStructByNameEmbeddedStruct(t *testing.T) { + type Name struct { + Last string `db:"last_name"` + First string `db:"first_name"` + } + + type person struct { + Ignore bool `db:"-"` + Name + Age int32 + } + + teardownTestCase := SetupTestCase(t) + defer teardownTestCase(t) + ctx := context.Background() + + rows, _ := pge.ConfigDb.Query(ctx, `select 'John' as first_name, 'Smith' as last_name, n as age from generate_series(0, 9) n`) + slice, err := pgx.CollectRows(rows, pgengine.RowToStructByName[person]) + assert.NoError(t, err) + + assert.Len(t, slice, 10) + for i := range slice { + assert.Equal(t, "Smith", slice[i].Name.Last) + assert.Equal(t, "John", slice[i].Name.First) + assert.EqualValues(t, i, slice[i].Age) + } + + // check missing fields in a returned row + rows, _ = pge.ConfigDb.Query(ctx, `select 'Smith' as last_name, n as age from generate_series(0, 9) n`) + _, err = pgx.CollectRows(rows, pgengine.RowToStructByName[person]) + assert.ErrorContains(t, err, "cannot find field first_name in returned row") + + // check missing field in a destination struct + rows, _ = pge.ConfigDb.Query(ctx, `select 'John' as first_name, 'Smith' as last_name, n as age, null as ignore from generate_series(0, 9) n`) + _, err = pgx.CollectRows(rows, pgengine.RowToAddrOfStructByName[person]) + assert.ErrorContains(t, err, "struct doesn't have corresponding row field ignore") +} diff --git a/internal/pgengine/transaction.go b/internal/pgengine/transaction.go index ebb24519..7ca6c2fe 100644 --- a/internal/pgengine/transaction.go +++ b/internal/pgengine/transaction.go @@ -10,26 +10,51 @@ import ( "time" "github.com/cybertec-postgresql/pg_timetable/internal/log" - "github.com/georgysavva/scany/pgxscan" - "github.com/jackc/pgconn" - "github.com/jackc/pgtype" - pgx "github.com/jackc/pgx/v4" + pgx "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" + "github.com/jackc/pgx/v5/pgtype" ) +// Chain structure used to represent tasks chains +type Chain struct { + ChainID int `db:"chain_id"` + ChainName string `db:"chain_name"` + SelfDestruct bool `db:"self_destruct"` + ExclusiveExecution bool `db:"exclusive_execution"` + MaxInstances int `db:"max_instances"` + Timeout int `db:"timeout"` +} + +// IntervalChain structure used to represent repeated chains. +type IntervalChain struct { + Chain + Interval int `db:"interval_seconds"` + RepeatAfter bool `db:"repeat_after"` +} + +func (ichain IntervalChain) IsListed(ichains []IntervalChain) bool { + for _, ic := range ichains { + if ichain.ChainID == ic.ChainID { + return true + } + } + return false +} + // ChainTask structure describes each chain task type ChainTask struct { - ChainID int - TaskID int `db:"task_id"` - Script string `db:"command"` - Kind string `db:"kind"` - RunAs pgtype.Varchar `db:"run_as"` - IgnoreError bool `db:"ignore_error"` - Autonomous bool `db:"autonomous"` - ConnectString pgtype.Varchar `db:"database_connection"` - Timeout int `db:"timeout"` // in milliseconds - StartedAt time.Time - Duration int64 // in microseconds - Txid int + ChainID int `db:"-"` + TaskID int `db:"task_id"` + Script string `db:"command"` + Kind string `db:"kind"` + RunAs pgtype.Text `db:"run_as"` + IgnoreError bool `db:"ignore_error"` + Autonomous bool `db:"autonomous"` + ConnectString pgtype.Text `db:"database_connection"` + Timeout int `db:"timeout"` // in milliseconds + StartedAt time.Time `db:"-"` + Duration int64 `db:"-"` // in microseconds + Txid int `db:"-"` } // StartTransaction returns transaction object, transaction id and error @@ -38,7 +63,7 @@ func (pge *PgEngine) StartTransaction(ctx context.Context, chainID int) (tx pgx. if err != nil { return } - err = pgxscan.Get(ctx, tx, &txid, "SELECT txid_current()") + err = tx.QueryRow(ctx, "SELECT txid_current()").Scan(&txid) if err != nil { return } @@ -83,26 +108,28 @@ func (pge *PgEngine) MustRollbackToSavepoint(ctx context.Context, tx pgx.Tx, sav } // GetChainElements returns all elements for a given chain -func (pge *PgEngine) GetChainElements(ctx context.Context, tx pgx.Tx, chainTasks interface{}, chainID int) bool { +func (pge *PgEngine) GetChainElements(ctx context.Context, tx pgx.Tx, chainTasks *[]ChainTask, chainID int) error { const sqlSelectChainTasks = `SELECT task_id, command, kind, run_as, ignore_error, autonomous, database_connection, timeout FROM timetable.task WHERE chain_id = $1 ORDER BY task_order ASC` - err := pgxscan.Select(ctx, tx, chainTasks, sqlSelectChainTasks, chainID) + // return Select(ctx, tx, chainTasks, sqlSelectChainTasks, chainID) + rows, err := pge.ConfigDb.Query(ctx, sqlSelectChainTasks, chainID) if err != nil { - log.GetLogger(ctx).WithError(err).Error("Failed to retrieve chain elements") - return false + return err } - return true + *chainTasks, err = pgx.CollectRows(rows, RowToStructByName[ChainTask]) + return err } // GetChainParamValues returns parameter values to pass for task being executed -func (pge *PgEngine) GetChainParamValues(ctx context.Context, tx pgx.Tx, paramValues interface{}, task *ChainTask) bool { +func (pge *PgEngine) GetChainParamValues(ctx context.Context, tx pgx.Tx, paramValues *[]string, task *ChainTask) error { const sqlGetParamValues = `SELECT value FROM timetable.parameter WHERE task_id = $1 AND value IS NOT NULL ORDER BY order_id ASC` - err := pgxscan.Select(ctx, tx, paramValues, sqlGetParamValues, task.TaskID) + // return Select(ctx, tx, paramValues, sqlGetParamValues, task.TaskID) + rows, err := pge.ConfigDb.Query(ctx, sqlGetParamValues, task.TaskID) if err != nil { - log.GetLogger(ctx).WithError(err).Error("cannot fetch parameters values for chain: ", err) - return false + return err } - return true + *paramValues, err = pgx.CollectRows(rows, pgx.RowTo[string]) + return err } type executor interface { @@ -123,7 +150,7 @@ func (pge *PgEngine) ExecuteSQLTask(ctx context.Context, tx pgx.Tx, task *ChainT } //Connect to Remote DB - if task.ConnectString.Status != pgtype.Null { + if task.ConnectString.Valid { remoteDb, execTx, err = pge.GetRemoteDBTransaction(ctx, task.ConnectString.String) if err != nil { return @@ -153,12 +180,12 @@ func (pge *PgEngine) ExecuteSQLTask(ctx context.Context, tx pgx.Tx, task *ChainT } //Reset The Role - if task.RunAs.Status != pgtype.Null && !task.Autonomous { + if task.RunAs.Valid && !task.Autonomous { pge.ResetRole(ctx, execTx) } // Commit changes on remote server - if task.ConnectString.Status != pgtype.Null && !task.Autonomous { + if task.ConnectString.Valid && !task.Autonomous { pge.CommitTransaction(ctx, execTx) } @@ -175,7 +202,7 @@ func (pge *PgEngine) ExecuteSQLCommand(ctx context.Context, executor executor, c } if len(paramValues) == 0 { //mimic empty param ct, err = executor.Exec(ctx, command) - out = string(ct) + out = ct.String() } else { for _, val := range paramValues { if val > "" { @@ -183,14 +210,14 @@ func (pge *PgEngine) ExecuteSQLCommand(ctx context.Context, executor executor, c return } ct, err = executor.Exec(ctx, command, params...) - out = out + string(ct) + "\n" + out = out + ct.String() + "\n" } } } return } -//GetRemoteDBTransaction create a remote db connection and returns transaction object +// GetRemoteDBTransaction create a remote db connection and returns transaction object func (pge *PgEngine) GetRemoteDBTransaction(ctx context.Context, connectionString string) (PgxConnIface, pgx.Tx, error) { if strings.TrimSpace(connectionString) == "" { return nil, nil, errors.New("Connection string is blank") @@ -199,12 +226,12 @@ func (pge *PgEngine) GetRemoteDBTransaction(ctx context.Context, connectionStrin if err != nil { return nil, nil, err } - connConfig.Logger = log.NewPgxLogger(pge.l) - if pge.Verbose() { - connConfig.LogLevel = pgx.LogLevelDebug - } else { - connConfig.LogLevel = pgx.LogLevelWarn - } + // connConfig.Logger = log.NewPgxLogger(pge.l) + // if pge.Verbose() { + // connConfig.LogLevel = pgx.LogLevelDebug + // } else { + // connConfig.LogLevel = pgx.LogLevelWarn + // } l := log.GetLogger(ctx) remoteDb, err := pgx.ConnectConfig(ctx, connConfig) if err != nil { @@ -231,8 +258,8 @@ func (pge *PgEngine) FinalizeRemoteDBConnection(ctx context.Context, remoteDb Pg } // SetRole - set the current user identifier of the current session -func (pge *PgEngine) SetRole(ctx context.Context, tx pgx.Tx, runUID pgtype.Varchar) { - if runUID.Status == pgtype.Null { +func (pge *PgEngine) SetRole(ctx context.Context, tx pgx.Tx, runUID pgtype.Text) { + if !runUID.Valid { return } l := log.GetLogger(ctx) @@ -243,7 +270,7 @@ func (pge *PgEngine) SetRole(ctx context.Context, tx pgx.Tx, runUID pgtype.Varch } } -//ResetRole - RESET forms reset the current user identifier to be the current session user identifier +// ResetRole - RESET forms reset the current user identifier to be the current session user identifier func (pge *PgEngine) ResetRole(ctx context.Context, tx pgx.Tx) { l := log.GetLogger(ctx) l.Info("Resetting Role") diff --git a/internal/pgengine/transaction_test.go b/internal/pgengine/transaction_test.go index 0212059e..ef3c5ce7 100644 --- a/internal/pgengine/transaction_test.go +++ b/internal/pgengine/transaction_test.go @@ -7,8 +7,8 @@ import ( "testing" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" - "github.com/jackc/pgtype" - "github.com/pashagolub/pgxmock" + "github.com/jackc/pgx/v5/pgtype" + "github.com/pashagolub/pgxmock/v2" "github.com/stretchr/testify/assert" ) @@ -66,29 +66,29 @@ func TestExecuteSQLTask(t *testing.T) { { Autonomous: true, IgnoreError: true, - ConnectString: pgtype.Varchar{ + ConnectString: pgtype.Text{ String: "foo", - Status: pgtype.Present}, + Valid: true}, }, { Autonomous: false, IgnoreError: true, - ConnectString: pgtype.Varchar{ + ConnectString: pgtype.Text{ String: "foo", - Status: pgtype.Present}, + Valid: true}, }, { Autonomous: false, IgnoreError: true, - ConnectString: pgtype.Varchar{ + ConnectString: pgtype.Text{ String: "error", - Status: pgtype.Present}, + Valid: true}, }, { - RunAs: pgtype.Varchar{String: "foo", Status: pgtype.Present}, - ConnectString: pgtype.Varchar{Status: pgtype.Null}, + RunAs: pgtype.Text{String: "foo", Valid: true}, + ConnectString: pgtype.Text{Valid: false}, }, - {Autonomous: false, IgnoreError: true, ConnectString: pgtype.Varchar{Status: pgtype.Null}}, + {Autonomous: false, IgnoreError: true, ConnectString: pgtype.Text{Valid: false}}, } for _, element := range elements { @@ -157,28 +157,31 @@ func TestGetChainElements(t *testing.T) { ctx := context.Background() mockPool.ExpectBegin() - mockPool.ExpectQuery("SELECT task_id").WillReturnError(errors.New("error")) + mockPool.ExpectQuery("SELECT").WillReturnError(errors.New("error")) tx, err := mockPool.Begin(ctx) assert.NoError(t, err) - assert.False(t, pge.GetChainElements(ctx, tx, &[]string{}, 0)) + assert.Error(t, pge.GetChainElements(ctx, tx, &[]pgengine.ChainTask{}, 0)) mockPool.ExpectBegin() - mockPool.ExpectQuery("SELECT task_id").WithArgs(0).WillReturnRows(pgxmock.NewRows([]string{"s"}).AddRow("foo")) + mockPool.ExpectQuery("SELECT").WithArgs(0).WillReturnRows( + pgxmock.NewRows([]string{"task_id", "command", "kind", "run_as", + "ignore_error", "autonomous", "database_connection", "timeout"}). + AddRow(24, "foo", "sql", "user", false, false, "postgres://foo@boo/bar", 0)) tx, err = mockPool.Begin(ctx) assert.NoError(t, err) - assert.True(t, pge.GetChainElements(ctx, tx, &[]string{}, 0)) + assert.NoError(t, pge.GetChainElements(ctx, tx, &[]pgengine.ChainTask{}, 0)) mockPool.ExpectBegin() mockPool.ExpectQuery("SELECT").WillReturnError(errors.New("error")) tx, err = mockPool.Begin(ctx) assert.NoError(t, err) - assert.False(t, pge.GetChainParamValues(ctx, tx, &[]string{}, &pgengine.ChainTask{})) + assert.Error(t, pge.GetChainParamValues(ctx, tx, &[]string{}, &pgengine.ChainTask{})) mockPool.ExpectBegin() mockPool.ExpectQuery("SELECT").WithArgs(0).WillReturnRows(pgxmock.NewRows([]string{"s"}).AddRow("foo")) tx, err = mockPool.Begin(ctx) assert.NoError(t, err) - assert.True(t, pge.GetChainParamValues(ctx, tx, &[]string{}, &pgengine.ChainTask{})) + assert.NoError(t, pge.GetChainParamValues(ctx, tx, &[]string{}, &pgengine.ChainTask{})) } func TestSetRole(t *testing.T) { @@ -190,7 +193,7 @@ func TestSetRole(t *testing.T) { mockPool.ExpectExec("SET ROLE").WillReturnError(errors.New("error")) tx, err := mockPool.Begin(ctx) assert.NoError(t, err) - pge.SetRole(ctx, tx, pgtype.Varchar{String: "foo"}) + pge.SetRole(ctx, tx, pgtype.Text{String: "foo", Valid: true}) mockPool.ExpectBegin() mockPool.ExpectExec("RESET ROLE").WillReturnError(errors.New("error")) diff --git a/internal/scheduler/chain.go b/internal/scheduler/chain.go index 9e662647..d5415925 100644 --- a/internal/scheduler/chain.go +++ b/internal/scheduler/chain.go @@ -7,18 +7,10 @@ import ( "github.com/cybertec-postgresql/pg_timetable/internal/log" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" - pgx "github.com/jackc/pgx/v4" + pgx "github.com/jackc/pgx/v5" ) -// Chain structure used to represent tasks chains -type Chain struct { - ChainID int `db:"chain_id"` - ChainName string `db:"chain_name"` - SelfDestruct bool `db:"self_destruct"` - ExclusiveExecution bool `db:"exclusive_execution"` - MaxInstances int `db:"max_instances"` - Timeout int `db:"timeout"` -} +type Chain = pgengine.Chain // SendChain sends chain to the channel for workers func (sch *Scheduler) SendChain(c Chain) { @@ -54,9 +46,9 @@ func (sch *Scheduler) retrieveAsyncChainsAndRun(ctx context.Context) { if chainSignal.ConfigID == 0 { return } + var c Chain switch chainSignal.Command { case "START": - var c Chain err := sch.pgengine.SelectChain(ctx, &c, chainSignal.ConfigID) if err != nil { sch.l.WithError(err).Error("Could not query pending tasks") @@ -73,11 +65,11 @@ func (sch *Scheduler) retrieveAsyncChainsAndRun(ctx context.Context) { func (sch *Scheduler) retrieveChainsAndRun(ctx context.Context, reboot bool) { var err error + var headChains []Chain msg := "Retrieve scheduled chains to run" if reboot { msg = msg + " @reboot" } - headChains := []Chain{} if reboot { err = sch.pgengine.SelectRebootChains(ctx, &headChains) } else { @@ -184,7 +176,9 @@ func (sch *Scheduler) executeChain(ctx context.Context, chain Chain) { } chainL = chainL.WithField("txid", txid) - if !sch.pgengine.GetChainElements(ctx, tx, &ChainTasks, chain.ChainID) { + err = sch.pgengine.GetChainElements(ctx, tx, &ChainTasks, chain.ChainID) + if err != nil { + chainL.WithError(err).Error("Failed to retrieve chain elements") sch.pgengine.RollbackTransaction(ctx, tx) return } @@ -229,7 +223,10 @@ func (sch *Scheduler) executeСhainElement(ctx context.Context, tx pgx.Tx, task ) l := log.GetLogger(ctx) - if !sch.pgengine.GetChainParamValues(ctx, tx, ¶mValues, task) { + + err = sch.pgengine.GetChainParamValues(ctx, tx, ¶mValues, task) + if err != nil { + l.WithError(err).Error("cannot fetch parameters values for chain: ", err) return -1 } diff --git a/internal/scheduler/chain_test.go b/internal/scheduler/chain_test.go index c9d2e85f..ef063c81 100644 --- a/internal/scheduler/chain_test.go +++ b/internal/scheduler/chain_test.go @@ -10,9 +10,9 @@ import ( "github.com/cybertec-postgresql/pg_timetable/internal/config" "github.com/cybertec-postgresql/pg_timetable/internal/log" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" - "github.com/jackc/pgconn" - "github.com/jackc/pgx/v4" - "github.com/pashagolub/pgxmock" + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" + "github.com/pashagolub/pgxmock/v2" "github.com/stretchr/testify/assert" ) diff --git a/internal/scheduler/interval_chain.go b/internal/scheduler/interval_chain.go index 9b4ec6bf..ef3084d6 100644 --- a/internal/scheduler/interval_chain.go +++ b/internal/scheduler/interval_chain.go @@ -5,23 +5,10 @@ import ( "time" "github.com/cybertec-postgresql/pg_timetable/internal/log" + "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" ) -// IntervalChain structure used to represent repeated chains. -type IntervalChain struct { - Chain - Interval int `db:"interval_seconds"` - RepeatAfter bool `db:"repeat_after"` -} - -func (ichain IntervalChain) isListed(ichains []IntervalChain) bool { - for _, ic := range ichains { - if ichain.ChainID == ic.ChainID { - return true - } - } - return false -} +type IntervalChain = pgengine.IntervalChain // SendIntervalChain sends interval chain to the channel for workers func (sch *Scheduler) SendIntervalChain(c IntervalChain) { @@ -56,7 +43,7 @@ func (sch *Scheduler) reschedule(ctx context.Context, ichain IntervalChain) { } func (sch *Scheduler) retrieveIntervalChainsAndRun(ctx context.Context) { - ichains := []IntervalChain{} + var ichains []IntervalChain err := sch.pgengine.SelectIntervalChains(ctx, &ichains) if err != nil { sch.l.WithError(err).Error("Could not query pending interval tasks") @@ -67,7 +54,7 @@ func (sch *Scheduler) retrieveIntervalChainsAndRun(ctx context.Context) { // delete chains that are not returned from the database sch.intervalChainMutex.Lock() for id, ichain := range sch.intervalChains { - if !ichain.isListed(ichains) { + if !ichain.IsListed(ichains) { delete(sch.intervalChains, id) } } diff --git a/internal/scheduler/interval_chain_test.go b/internal/scheduler/interval_chain_test.go index 95b80159..e61db929 100644 --- a/internal/scheduler/interval_chain_test.go +++ b/internal/scheduler/interval_chain_test.go @@ -7,7 +7,7 @@ import ( "github.com/cybertec-postgresql/pg_timetable/internal/config" "github.com/cybertec-postgresql/pg_timetable/internal/log" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" - "github.com/pashagolub/pgxmock" + "github.com/pashagolub/pgxmock/v2" "github.com/stretchr/testify/assert" ) @@ -18,8 +18,8 @@ func TestIntervalChain(t *testing.T) { sch := New(pge, log.Init(config.LoggingOpts{LogLevel: "error"})) ichain := IntervalChain{Interval: 42} - assert.True(t, ichain.isListed([]IntervalChain{ichain})) - assert.False(t, ichain.isListed([]IntervalChain{})) + assert.True(t, ichain.IsListed([]IntervalChain{ichain})) + assert.False(t, ichain.IsListed([]IntervalChain{})) assert.False(t, sch.isValid(ichain)) sch.intervalChains[ichain.ChainID] = ichain diff --git a/internal/scheduler/shell_test.go b/internal/scheduler/shell_test.go index df61494a..189d5cfa 100644 --- a/internal/scheduler/shell_test.go +++ b/internal/scheduler/shell_test.go @@ -12,7 +12,7 @@ import ( "github.com/cybertec-postgresql/pg_timetable/internal/log" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" "github.com/cybertec-postgresql/pg_timetable/internal/scheduler" - "github.com/pashagolub/pgxmock" + "github.com/pashagolub/pgxmock/v2" "github.com/stretchr/testify/assert" ) diff --git a/internal/scheduler/tasks_test.go b/internal/scheduler/tasks_test.go index 9efdd1d6..d915f68e 100644 --- a/internal/scheduler/tasks_test.go +++ b/internal/scheduler/tasks_test.go @@ -7,7 +7,7 @@ import ( "github.com/cybertec-postgresql/pg_timetable/internal/config" "github.com/cybertec-postgresql/pg_timetable/internal/log" "github.com/cybertec-postgresql/pg_timetable/internal/pgengine" - "github.com/pashagolub/pgxmock" + "github.com/pashagolub/pgxmock/v2" "github.com/stretchr/testify/assert" ) diff --git a/samples/Exclusive.sql b/samples/Exclusive.sql index e62060b7..62255545 100644 --- a/samples/Exclusive.sql +++ b/samples/Exclusive.sql @@ -4,7 +4,7 @@ $BODY$ BEGIN RAISE NOTICE 'Sleeping for 5 sec in %', $1; PERFORM pg_sleep_for('5 seconds'); - RAISE NOTICE 'Waiking up in %', $1; + RAISE NOTICE 'Waking up in %', $1; END; $BODY$;