diff --git a/.gitea/workflows/build_check.yaml b/.gitea/workflows/build_check.yaml index e5c5c81..2496e8a 100644 --- a/.gitea/workflows/build_check.yaml +++ b/.gitea/workflows/build_check.yaml @@ -3,8 +3,7 @@ run-name: ${{ gitea.actor }} is testing the build on: push: branches: - - ci/* - - dev/* + - main pull_request: branches: [ "main" ] diff --git a/go.mod b/go.mod index 8185c56..58d28b3 100644 --- a/go.mod +++ b/go.mod @@ -8,71 +8,69 @@ require ( github.com/matoous/go-nanoid/v2 v2.1.0 github.com/rubenv/sql-migrate v1.7.0 github.com/sirupsen/logrus v1.9.3 - github.com/testcontainers/testcontainers-go v0.32.0 - github.com/testcontainers/testcontainers-go/modules/postgres v0.32.0 - go.opentelemetry.io/contrib/bridges/otellogrus v0.3.0 - go.opentelemetry.io/otel v1.28.0 - go.opentelemetry.io/otel/trace v1.28.0 + github.com/testcontainers/testcontainers-go v0.33.0 + github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0 + go.opentelemetry.io/contrib/bridges/otellogrus v0.5.0 + go.opentelemetry.io/otel v1.31.0 + go.opentelemetry.io/otel/trace v1.31.0 gorm.io/driver/postgres v1.5.9 - gorm.io/gorm v1.25.11 + gorm.io/gorm v1.25.12 ) require ( - dario.cat/mergo v1.0.0 // indirect - github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 // indirect + dario.cat/mergo v1.0.1 // indirect + github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 // indirect + github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 // indirect github.com/Microsoft/go-winio v0.6.2 // indirect - github.com/Microsoft/hcsshim v0.11.5 // indirect - github.com/cenkalti/backoff/v4 v4.2.1 // indirect - github.com/containerd/containerd v1.7.18 // indirect - github.com/containerd/errdefs v0.1.0 // indirect + github.com/cenkalti/backoff/v4 v4.3.0 // indirect github.com/containerd/log v0.1.0 // indirect - github.com/cpuguy83/dockercfg v0.3.1 // indirect + github.com/containerd/platforms v0.2.1 // indirect + github.com/cpuguy83/dockercfg v0.3.2 // indirect github.com/distribution/reference v0.6.0 // indirect - github.com/docker/docker v27.0.3+incompatible // indirect + github.com/docker/docker v27.3.1+incompatible // indirect github.com/docker/go-connections v0.5.0 // indirect github.com/docker/go-units v0.5.0 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect github.com/go-gorp/gorp/v3 v3.1.0 // indirect github.com/go-logr/logr v1.4.2 // indirect github.com/go-logr/stdr v1.2.2 // indirect - github.com/go-ole/go-ole v1.2.6 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/golang/protobuf v1.5.4 // indirect github.com/google/uuid v1.6.0 // indirect github.com/jackc/pgpassfile v1.0.0 // indirect - github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect - github.com/jackc/pgx/v5 v5.5.5 // indirect - github.com/jackc/puddle/v2 v2.2.1 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.7.1 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/now v1.1.5 // indirect - github.com/klauspost/compress v1.17.4 // indirect - github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 // indirect + github.com/klauspost/compress v1.17.11 // indirect + github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 // indirect github.com/magiconair/properties v1.8.7 // indirect github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/patternmatcher v0.6.0 // indirect - github.com/moby/sys/sequential v0.5.0 // indirect - github.com/moby/sys/user v0.1.0 // indirect + github.com/moby/sys/sequential v0.6.0 // indirect + github.com/moby/sys/user v0.3.0 // indirect + github.com/moby/sys/userns v0.1.0 // indirect github.com/moby/term v0.5.0 // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/pkg/errors v0.9.1 // indirect - github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c // indirect + github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 // indirect github.com/rogpeppe/go-internal v1.10.0 // indirect - github.com/shirou/gopsutil/v3 v3.23.12 // indirect + github.com/shirou/gopsutil/v3 v3.24.5 // indirect github.com/shoenig/go-m1cpu v0.1.6 // indirect - github.com/tklauser/go-sysconf v0.3.12 // indirect - github.com/tklauser/numcpus v0.6.1 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect - go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 // indirect - go.opentelemetry.io/otel/log v0.4.0 // indirect - go.opentelemetry.io/otel/metric v1.28.0 // indirect + github.com/tklauser/go-sysconf v0.3.14 // indirect + github.com/tklauser/numcpus v0.9.0 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect + go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 // indirect + go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 // indirect + go.opentelemetry.io/otel/log v0.7.0 // indirect + go.opentelemetry.io/otel/metric v1.31.0 // indirect go.opentelemetry.io/otel/sdk v1.28.0 // indirect - golang.org/x/crypto v0.22.0 // indirect + golang.org/x/crypto v0.28.0 // indirect golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.21.0 // indirect - golang.org/x/text v0.17.0 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b // indirect - google.golang.org/grpc v1.59.0 // indirect - google.golang.org/protobuf v1.33.0 // indirect + golang.org/x/sys v0.26.0 // indirect + golang.org/x/text v0.19.0 // indirect + golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 // indirect ) diff --git a/go.sum b/go.sum index 73406fa..7cd2b70 100644 --- a/go.sum +++ b/go.sum @@ -1,23 +1,19 @@ -dario.cat/mergo v1.0.0 h1:AGCNq9Evsj31mOgNPcLyXc+4PNABt905YmuqPYYpBWk= -dario.cat/mergo v1.0.0/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= +dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= +dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24 h1:bvDV9vkmnHYOMsOr4WLk+Vo07yKIzd94sVoIqshQ4bU= github.com/AdaLogics/go-fuzz-headers v0.0.0-20230811130428-ced1acdcaa24/go.mod h1:8o94RPi1/7XTJvwPpRSzSUedZrtlirdB3r9Z20bi2f8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= -github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161 h1:L/gRVlceqvL25UVaW/CKtUDjefjrs0SPonmDGUVOYP0= +github.com/Azure/go-ansiterm v0.0.0-20230124172434-306776ec8161/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= -github.com/Microsoft/hcsshim v0.11.5 h1:haEcLNpj9Ka1gd3B3tAEs9CpE0c+1IhoL59w/exYU38= -github.com/Microsoft/hcsshim v0.11.5/go.mod h1:MV8xMfmECjl5HdO7U/3/hFVnkmSBjAjmA09d4bExKcU= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= -github.com/containerd/containerd v1.7.18 h1:jqjZTQNfXGoEaZdW1WwPU0RqSn1Bm2Ay/KJPUuO8nao= -github.com/containerd/containerd v1.7.18/go.mod h1:IYEk9/IO6wAPUz2bCMVUbsfXjzw5UNP5fLz4PsUygQ4= -github.com/containerd/errdefs v0.1.0 h1:m0wCRBiu1WJT/Fr+iOoQHMQS/eP5myQ8lCv4Dz5ZURM= -github.com/containerd/errdefs v0.1.0/go.mod h1:YgWiiHtLmSeBrvpw+UfPijzbLaB77mEG1WwJTDETIV0= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/containerd/log v0.1.0 h1:TCJt7ioM2cr/tfR8GPbGf9/VRAX8D2B4PjzCpfX540I= github.com/containerd/log v0.1.0/go.mod h1:VRRf09a7mHDIRezVKTRCrOq78v577GXq3bSa3EhrzVo= -github.com/cpuguy83/dockercfg v0.3.1 h1:/FpZ+JaygUR/lZP2NlFI2DVfrOEMAIKP5wWEJdoYe9E= -github.com/cpuguy83/dockercfg v0.3.1/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= +github.com/containerd/platforms v0.2.1 h1:zvwtM3rz2YHPQsF2CHYM8+KtB5dvhISiXh5ZpSBQv6A= +github.com/containerd/platforms v0.2.1/go.mod h1:XHCb+2/hzowdiut9rkudds9bE5yJ7npe7dG/wG+uFPw= +github.com/cpuguy83/dockercfg v0.3.2 h1:DlJTyZGBDlXqUZ2Dk2Q3xHs/FtnooJJVaad2S9GKorA= +github.com/cpuguy83/dockercfg v0.3.2/go.mod h1:sugsbF4//dDlL/i+S+rtpIWp+5h0BHJHfjj5/jFyUJc= github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY= github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -25,8 +21,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distribution/reference v0.6.0 h1:0IXCQ5g4/QMHHkarYzh5l+u8T3t73zM5QvfrDyIgxBk= github.com/distribution/reference v0.6.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v27.0.3+incompatible h1:aBGI9TeQ4MPlhquTQKq9XbK79rKFVwXNUAYz9aXyEBE= -github.com/docker/docker v27.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v27.3.1+incompatible h1:KttF0XoteNTicmUtBO0L2tP+J7FGRFTjaEF4k6WdhfI= +github.com/docker/docker v27.3.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -40,16 +36,13 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= -github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY= github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= -github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= -github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= @@ -58,28 +51,28 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0 h1:YBftPWNWd4WwGqtY2yeZL2ef8rH github.com/grpc-ecosystem/grpc-gateway/v2 v2.16.0/go.mod h1:YN5jB8ie0yfIUg6VvR9Kz84aCaG7AsGZnLjhHbUqwPg= 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/pgservicefile v0.0.0-20221227161230-091c0ba34f0a h1:bbPeKD0xmW/Y25WS6cokEszi5g+S0QxI/d45PkRi7Nk= -github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.5.5 h1:amBjrZVmksIdNjxGW/IiIMzxMKZFelXbUoPNb+8sjQw= -github.com/jackc/pgx/v5 v5.5.5/go.mod h1:ez9gk+OAat140fv9ErkZDYFWmXLfV+++K0uAOiwgm1A= -github.com/jackc/puddle/v2 v2.2.1 h1:RhxXJtFG022u4ibrCSMSiu5aOq1i77R3OHKNJj77OAk= -github.com/jackc/puddle/v2 v2.2.1/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.7.1 h1:x7SYsPBYDkHDksogeSmZZ5xzThcTgRz++I5E+ePFUcs= +github.com/jackc/pgx/v5 v5.7.1/go.mod h1:e7O26IywZZ+naJtWWos6i6fvWK+29etgITqrqHLfoZA= +github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= +github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/klauspost/compress v1.17.4 h1:Ej5ixsIri7BrIjBkRZLTo6ghwrEtHFk7ijlczPW4fZ4= -github.com/klauspost/compress v1.17.4/go.mod h1:/dCuZOvVtNoHsyb+cuJD3itjs3NbnF6KH9zAO4BDxPM= +github.com/klauspost/compress v1.17.11 h1:In6xLpyWOi1+C7tXUUWv2ot1QvBjxevKAaI6IXrJmUc= +github.com/klauspost/compress v1.17.11/go.mod h1:pMDklpSncoRMuLFrf1W9Ss9KT+0rH90U12bZKk7uwG0= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0 h1:6E+4a0GO5zZEnZ81pIr0yLvtUWk2if982qA3F3QD6H4= -github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= +github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683 h1:7UMa6KCCMjZEMDtTVdcGu0B1GmmC7QJKiCCjyTAWQy0= +github.com/lufia/plan9stats v0.0.0-20240909124753-873cd0166683/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/magiconair/properties v1.8.7 h1:IeQXZAiQcpL9mgcAe1Nu6cX9LLw6ExEHKjN0VQdvPDY= github.com/magiconair/properties v1.8.7/go.mod h1:Dhd985XPs7jluiymwWYZ0G4Z61jb3vdS329zhj2hYo0= github.com/matoous/go-nanoid/v2 v2.1.0 h1:P64+dmq21hhWdtvZfEAofnvJULaRR1Yib0+PnU669bE= @@ -90,10 +83,12 @@ github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3N github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/patternmatcher v0.6.0 h1:GmP9lR19aU5GqSSFko+5pRqHi+Ohk1O69aFiKkVGiPk= github.com/moby/patternmatcher v0.6.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc= -github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc= -github.com/moby/sys/sequential v0.5.0/go.mod h1:tH2cOOs5V9MlPiXcQzRC+eEyab644PWKGRYaaV5ZZlo= -github.com/moby/sys/user v0.1.0 h1:WmZ93f5Ux6het5iituh9x2zAG7NFY9Aqi49jjE1PaQg= -github.com/moby/sys/user v0.1.0/go.mod h1:fKJhFOnsCN6xZ5gSfbM6zaHGgDJMrqt9/reuj4T7MmU= +github.com/moby/sys/sequential v0.6.0 h1:qrx7XFUd/5DxtqcoH1h438hF5TmOvzC/lspjy7zgvCU= +github.com/moby/sys/sequential v0.6.0/go.mod h1:uyv8EUTrca5PnDsdMGXhZe6CCe8U/UiTWd+lL+7b/Ko= +github.com/moby/sys/user v0.3.0 h1:9ni5DlcW5an3SvRSx4MouotOygvzaXbaSrc/wGDFWPo= +github.com/moby/sys/user v0.3.0/go.mod h1:bG+tYYYJgaMtRKgEmuueC0hJEAZWwtIbZTB+85uoHjs= +github.com/moby/sys/userns v0.1.0 h1:tVLXkFOxVu9A64/yh59slHVv9ahO9UIev4JZusOLG/g= +github.com/moby/sys/userns v0.1.0/go.mod h1:IHUYgu/kao6N8YZlp9Cf444ySSvCmDlmzUcYfDHOl28= github.com/moby/term v0.5.0 h1:xt8Q1nalod/v7BqbG21f8mQPqH+xAaC9C3N3wfWbVP0= github.com/moby/term v0.5.0/go.mod h1:8FzsFHVUBGZdbDsJw/ot+X+d5HLUbvklYLJ9uGfcI3Y= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -106,16 +101,16 @@ github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c h1:ncq/mPwQF4JjgDlrVEn3C11VoGHZN7m8qihwgMEtzYw= -github.com/power-devops/perfstat v0.0.0-20210106213030-5aafc221ea8c/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55 h1:o4JXh1EVt9k/+g42oCprj/FisM4qX9L3sZB3upGN2ZU= +github.com/power-devops/perfstat v0.0.0-20240221224432-82ca36839d55/go.mod h1:OmDBASR4679mdNQnz2pUhc2G8CO2JrUAVFDRBDP/hJE= github.com/poy/onpar v1.1.2 h1:QaNrNiZx0+Nar5dLgTVp5mXkyoVFIbepjyEoGSnhbAY= github.com/poy/onpar v1.1.2/go.mod h1:6X8FLNoxyr9kkmnlqpK6LSoiOtrO6MICtWwEuWkLjzg= github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ= github.com/rogpeppe/go-internal v1.10.0/go.mod h1:UQnix2H7Ngw/k4C5ijL5+65zddjncjaFoBhdsK/akog= github.com/rubenv/sql-migrate v1.7.0 h1:HtQq1xyTN2ISmQDggnh0c9U3JlP8apWh8YO2jzlXpTI= github.com/rubenv/sql-migrate v1.7.0/go.mod h1:S4wtDEG1CKn+0ShpTtzWhFpHHI5PvCUtiGI+C+Z2THE= -github.com/shirou/gopsutil/v3 v3.23.12 h1:z90NtUkp3bMtmICZKpC4+WaknU1eXtp5vtbQ11DgpE4= -github.com/shirou/gopsutil/v3 v3.23.12/go.mod h1:1FrWgea594Jp7qmjHUUPlJDTPgcsb9mGnXDxavtikzM= +github.com/shirou/gopsutil/v3 v3.24.5 h1:i0t8kL+kQTvpAYToeuiVk3TgDeKOFioZO3Ztz/iZ9pI= +github.com/shirou/gopsutil/v3 v3.24.5/go.mod h1:bsoOS1aStSs9ErQ1WWfxllSeS1K5D+U30r2NfcubMVk= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -123,60 +118,55 @@ github.com/shoenig/test v0.6.4/go.mod h1:byHiCGXqrVaflBLAMq/srcZIHynQPQgeyvkvXnj github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= 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.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -github.com/testcontainers/testcontainers-go v0.32.0 h1:ug1aK08L3gCHdhknlTTwWjPHPS+/alvLJU/DRxTD/ME= -github.com/testcontainers/testcontainers-go v0.32.0/go.mod h1:CRHrzHLQhlXUsa5gXjTOfqIEJcrK5+xMDmBr/WMI88E= -github.com/testcontainers/testcontainers-go/modules/postgres v0.32.0 h1:ZE4dTdswj3P0j71nL+pL0m2e5HTXJwPoIFr+DDgdPaU= -github.com/testcontainers/testcontainers-go/modules/postgres v0.32.0/go.mod h1:njrNuyuoF2fjhVk6TG/R3Oeu82YwfYkbf5WVTyBXhV4= -github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= -github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= -github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= -github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/testcontainers/testcontainers-go v0.33.0 h1:zJS9PfXYT5O0ZFXM2xxXfk4J5UMw/kRiISng037Gxdw= +github.com/testcontainers/testcontainers-go v0.33.0/go.mod h1:W80YpTa8D5C3Yy16icheD01UTDu+LmXIA2Keo+jWtT8= +github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0 h1:c+Gt+XLJjqFAejgX4hSpnHIpC9eAhvgI/TFWL/PbrFI= +github.com/testcontainers/testcontainers-go/modules/postgres v0.33.0/go.mod h1:I4DazHBoWDyf69ByOIyt3OdNjefiUx372459txOpQ3o= +github.com/tklauser/go-sysconf v0.3.14 h1:g5vzr9iPFFz24v2KZXs/pvpvh8/V9Fw6vQK5ZZb78yU= +github.com/tklauser/go-sysconf v0.3.14/go.mod h1:1ym4lWMLUOhuBOPGtRcJm7tEGX4SCYNEEEtghGG/8uY= +github.com/tklauser/numcpus v0.9.0 h1:lmyCHtANi8aRUgkckBgoDk1nHCux3n2cgkJLXdQGPDo= +github.com/tklauser/numcpus v0.9.0/go.mod h1:SN6Nq1O3VychhC1npsWostA+oW+VOQTxZrS604NSRyI= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= -go.opentelemetry.io/contrib/bridges/otellogrus v0.3.0 h1:QHEj9AK6bEiEA9S5OdDUE9KAx4xp6pRkYMnybHDmjZU= -go.opentelemetry.io/contrib/bridges/otellogrus v0.3.0/go.mod h1:HRlW/1YWrBrbzB6FvHU7jUuz33F74PEvQVBL+b+wUhM= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0 h1:jq9TW8u3so/bN+JPT166wjOI6/vQPF6Xe7nMNIltagk= -go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw= -go.opentelemetry.io/otel v1.28.0 h1:/SqNcYk+idO0CxKEUOtKQClMK/MimZihKYMruSMViUo= -go.opentelemetry.io/otel v1.28.0/go.mod h1:q68ijF8Fc8CnMHKyzqL6akLO46ePnjkgfIMIjUIX9z4= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +go.opentelemetry.io/contrib/bridges/otellogrus v0.5.0 h1:T9cxTlfBz5go7dFWejO5E4JfeglWgWL1MRTPq9p8da0= +go.opentelemetry.io/contrib/bridges/otellogrus v0.5.0/go.mod h1:f6xZHPJ3A+RFc3Lfz4SoGIpfmVr4PEF4XM1H3fl+6/4= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0 h1:ZIg3ZT/aQ7AfKqdwp7ECpOK6vHqquXXuyTjIO8ZdmPs= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.55.0/go.mod h1:DQAwmETtZV00skUwgD6+0U89g80NKsJE3DCKeLLPQMI= +go.opentelemetry.io/otel v1.31.0 h1:NsJcKPIW0D0H3NgzPDHmo0WW6SptzPdqg/L1zsIm2hY= +go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0 h1:Mne5On7VWdx7omSrSSZvM4Kw7cS7NQkOOmLcgscI51U= go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.19.0/go.mod h1:IPtUMKL4O3tH5y+iXVyAXqpAwMuzC1IrxVS81rummfE= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg= go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU= -go.opentelemetry.io/otel/log v0.4.0 h1:/vZ+3Utqh18e8TPjuc3ecg284078KWrR8BRz+PQAj3o= -go.opentelemetry.io/otel/log v0.4.0/go.mod h1:DhGnQvky7pHy82MIRV43iXh3FlKN8UUKftn0KbLOq6I= -go.opentelemetry.io/otel/metric v1.28.0 h1:f0HGvSl1KRAU1DLgLGFjrwVyismPlnuU6JD6bOeuA5Q= -go.opentelemetry.io/otel/metric v1.28.0/go.mod h1:Fb1eVBFZmLVTMb6PPohq3TO9IIhUisDsbJoL/+uQW4s= +go.opentelemetry.io/otel/log v0.7.0 h1:d1abJc0b1QQZADKvfe9JqqrfmPYQCz2tUSO+0XZmuV4= +go.opentelemetry.io/otel/log v0.7.0/go.mod h1:2jf2z7uVfnzDNknKTO9G+ahcOAyWcp1fJmk/wJjULRo= +go.opentelemetry.io/otel/metric v1.31.0 h1:FSErL0ATQAmYHUIzSezZibnyVlft1ybhy4ozRPcF2fE= +go.opentelemetry.io/otel/metric v1.31.0/go.mod h1:C3dEloVbLuYoX41KpmAhOqNriGbA+qqH6PQ5E5mUfnY= go.opentelemetry.io/otel/sdk v1.28.0 h1:b9d7hIry8yZsgtbmM0DKyPWMMUMlK9NEKuIG4aBqWyE= go.opentelemetry.io/otel/sdk v1.28.0/go.mod h1:oYj7ClPUA7Iw3m+r7GeEjz0qckQRJK2B8zjcZEfu7Pg= -go.opentelemetry.io/otel/trace v1.28.0 h1:GhQ9cUuQGmNDd5BTCP2dAvv75RdMxEfTmYejp+lkx9g= -go.opentelemetry.io/otel/trace v1.28.0/go.mod h1:jPyXzNPg6da9+38HEwElrQiHlVMTnVfM3/yv2OlIHaI= +go.opentelemetry.io/otel/trace v1.31.0 h1:ffjsj1aRouKewfr85U2aGagJ46+MvodynlQ1HYdmJys= +go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06FJAsO1tJg480A= go.opentelemetry.io/proto/otlp v1.0.0 h1:T0TX0tmXU8a3CbNXzEKGeU5mIVOdf0oykP+u2lIVU/I= go.opentelemetry.io/proto/otlp v1.0.0/go.mod h1:Sy6pihPLfYHkr3NkUbEhGHFhINUSI/v80hjKIs5JXpM= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= -golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= +golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= -golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs= -golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ= +golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -189,17 +179,15 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20201204225414-ed752295db88/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws= -golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q= -golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.26.0 h1:KHjCJyddX0LoSTb3J+vWpupP9p0oznkqVk/IfjymZbo= +golang.org/x/sys v0.26.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/term v0.25.0 h1:WtHI/ltw4NvSUig5KARz9h521QvRC8RmF/cuYqifU24= +golang.org/x/term v0.25.0/go.mod h1:RPyXicDX+6vLxogjjRxjgD2TKtmAO6NZBsBRfrOLu7M= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= +golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= +golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8 h1:vVKdlvoWBphwdxWKrFZEuM0kGgGLxUOYcY4U/2Vjg44= golang.org/x/time v0.0.0-20220210224613-90d013bbcef8/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= @@ -210,13 +198,12 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/genproto v0.0.0-20231012201019-e917dd12ba7a h1:fwgW9j3vHirt4ObdHoYNwuO24BEZjSzbh+zPaNWoiY8= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb h1:lK0oleSc7IQsUxO3U5TjL9DWlsxpEBemh+zpB7IqhWI= -google.golang.org/genproto/googleapis/api v0.0.0-20230913181813-007df8e322eb/go.mod h1:KjSP20unUpOx5kyQUFa7k4OJg0qeJ7DEZflGDu2p6Bk= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b h1:ZlWIi1wSK56/8hn4QcBp/j9M7Gt3U/3hZw3mC7vDICo= -google.golang.org/genproto/googleapis/rpc v0.0.0-20231016165738-49dd2c1f3d0b/go.mod h1:swOH3j0KzcDDgGUWr+SNpyTen5YrXjS3eyPzFYKc6lc= -google.golang.org/grpc v1.59.0 h1:Z5Iec2pjwb+LEOqzpB2MR12/eKFhDPhuqW91O+4bwUk= -google.golang.org/grpc v1.59.0/go.mod h1:aUPDwccQo6OTjy7Hct4AfBPD1GptF4fyUjIkQ9YtF98= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237 h1:RFiFrvy37/mpSpdySBDrUdipW/dHwsRwh3J3+A9VgT4= +google.golang.org/genproto/googleapis/api v0.0.0-20240318140521-94a12d6c2237/go.mod h1:Z5Iiy3jtmioajWHDGFk7CeugTyHtPvMHA4UTmUkyalE= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 h1:NnYq6UN9ReLM9/Y01KWNOWyI5xQ9kbIms5GGJVwS/Yc= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA= +google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0= google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI= google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= @@ -227,7 +214,7 @@ 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.5.9 h1:DkegyItji119OlcaLjqN11kHoUgZ/j13E0jkJZgD6A8= gorm.io/driver/postgres v1.5.9/go.mod h1:DX3GReXH+3FPWGrrgffdvCk3DQ1dwDPdmbenSkweRGI= -gorm.io/gorm v1.25.11 h1:/Wfyg1B/je1hnDx3sMkX+gAlxrlZpn6X0BXRlwXlvHg= -gorm.io/gorm v1.25.11/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= +gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8= +gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ= gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= diff --git a/pkg/database/favorite.go b/pkg/database/favorite.go index 27384ac..a15f8da 100644 --- a/pkg/database/favorite.go +++ b/pkg/database/favorite.go @@ -183,7 +183,7 @@ func DeleteUserFavorite(ctx context.Context, id models.UserFavoriteID) error { } if len(id) != 25 { - return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.UserFavoriteIDToShort}) + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.UserFavoriteIsWrongLength}) } result := client.WithContext(ctx).Delete(&userFavorite, id) diff --git a/pkg/database/migrations/002_indexes.sql b/pkg/database/migrations/002_indexes.sql new file mode 100644 index 0000000..491e632 --- /dev/null +++ b/pkg/database/migrations/002_indexes.sql @@ -0,0 +1,3 @@ +-- +migrate Up +CREATE INDEX idx_user_post_deleted ON "UserFavorites"(user_id, deleted_at); +CREATE INDEX idx_created_at ON "UserFavorites"(created_at); \ No newline at end of file diff --git a/pkg/database/migrations/003_pools.sql b/pkg/database/migrations/003_pools.sql new file mode 100644 index 0000000..2f77be8 --- /dev/null +++ b/pkg/database/migrations/003_pools.sql @@ -0,0 +1,28 @@ +-- +migrate Up +CREATE TYPE pool_category AS ENUM ('series', 'collection'); + +CREATE TABLE "Pool" +( + id CHAR(25) PRIMARY KEY, + name VARCHAR(75), + created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, + deleted_at TIMESTAMP NULL, + category POOL_CATEGORY NOT NULL +); + +CREATE TABLE "PoolPost" +( + pool_id CHAR(25) REFERENCES "Pool" (id), + post_id CHAR(25) REFERENCES "Post" (id), + order_position INT NOT NULL DEFAULT 0, + PRIMARY KEY (pool_id, post_id) +); + +CREATE TABLE "PoolReference" +( + pool_id CHAR(25) REFERENCES "Pool" (id), + source_id CHAR(25) REFERENCES "Source" (id), + url TEXT NOT NULL, + PRIMARY KEY (pool_id, source_id, url) +); \ No newline at end of file diff --git a/pkg/database/pool.go b/pkg/database/pool.go new file mode 100644 index 0000000..e525fae --- /dev/null +++ b/pkg/database/pool.go @@ -0,0 +1,163 @@ +package database + +import ( + "context" + "errors" + + "git.anthrove.art/Anthrove/otter-space-sdk/v4/internal/utils" + otterError "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/error" + "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/models" + log "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel/attribute" + "gorm.io/gorm" +) + +func CreatePool(ctx context.Context, pool models.Pool) (models.Pool, error) { + ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "CreatePool") + defer span.End() + + localLogger = localLogger.WithFields(log.Fields{ + "pool_id": pool.ID, + }) + + span.SetAttributes( + attribute.String("pool_id", string(pool.ID)), + ) + + utils.HandleEvent(span, localLogger, "Starting pool creation") + + if client == nil { + return models.Pool{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}) + } + + result := client.WithContext(ctx).Create(&pool) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + return models.Pool{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DuplicateKey}) + } + return models.Pool{}, utils.HandleError(ctx, span, localLogger, result.Error) + } + + utils.HandleEvent(span, localLogger, "pool created successfully") + return pool, nil +} + +func GetPoolByID(ctx context.Context, id models.PoolID) (models.Pool, error) { + ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "GetPool") + defer span.End() + + localLogger = localLogger.WithFields(log.Fields{ + "pool_id": id, + }) + + span.SetAttributes( + attribute.String("pool_id", string(id)), + ) + + utils.HandleEvent(span, localLogger, "Starting get pool by ID") + + var pool models.Pool + + if client == nil { + return models.Pool{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}) + } + + if len(id) == 0 { + return models.Pool{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsEmpty}) + } + + result := client.WithContext(ctx).First(&pool, "id = ?", id) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return models.Pool{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.NoDataFound}) + } + return models.Pool{}, utils.HandleError(ctx, span, localLogger, result.Error) + } + + utils.HandleEvent(span, localLogger, "pool retrieved successfully") + return pool, nil +} + +// UpdatePool updates the pool information in the database. +// Only supports changing the Name and the Category of the Pool +func UpdatePool(ctx context.Context, pool models.Pool) error { + ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "UpdatePool") + defer span.End() + + localLogger = localLogger.WithFields(log.Fields{ + "pool_id": pool.ID, + }) + + span.SetAttributes( + attribute.String("pool_id", string(pool.ID)), + ) + + utils.HandleEvent(span, localLogger, "Starting post update") + + if client == nil { + return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}) + } + + if len(pool.ID) == 0 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsEmpty}) + } + + updatePost := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: pool.ID, + }, + Name: pool.Name, + Category: pool.Category, + } + + result := client.WithContext(ctx).Model(&updatePost).Update("deleted_at", gorm.DeletedAt{}) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.NoDataFound}) + } + return utils.HandleError(ctx, span, localLogger, result.Error) + } + + utils.HandleEvent(span, localLogger, "pool updated successfully") + return nil +} + +func DeletePool(ctx context.Context, id models.PoolID) error { + ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "DeletePool") + defer span.End() + + localLogger = localLogger.WithFields(log.Fields{ + "pool_id": id, + }) + + span.SetAttributes( + attribute.String("pool_id", string(id)), + ) + + utils.HandleEvent(span, localLogger, "Starting delete pool") + + var pool models.Pool + + if client == nil { + return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}) + } + + if len(id) == 0 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsEmpty}) + } + + if len(id) != 25 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsWrongLength}) + } + + result := client.WithContext(ctx).Delete(&pool, "id = ?", id) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.NoDataFound}) + } + return utils.HandleError(ctx, span, localLogger, result.Error) + } + + utils.HandleEvent(span, localLogger, "pool deleted successfully") + return nil +} diff --git a/pkg/database/pool_post.go b/pkg/database/pool_post.go new file mode 100644 index 0000000..80e2415 --- /dev/null +++ b/pkg/database/pool_post.go @@ -0,0 +1,117 @@ +package database + +import ( + "context" + "errors" + + "git.anthrove.art/Anthrove/otter-space-sdk/v4/internal/utils" + otterError "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/error" + "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/models" + log "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel/attribute" + "gorm.io/gorm" +) + +func CreatePoolPost(ctx context.Context, poolID models.PoolID, postID models.PostID, orderPosition int) (models.PoolPost, error) { + ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "CreatePoolPost") + defer span.End() + + localLogger = localLogger.WithFields(log.Fields{ + "pool_id": poolID, + "post_id": postID, + }) + + span.SetAttributes( + attribute.String("pool_id", string(poolID)), + attribute.String("post_id", string(postID)), + ) + + utils.HandleEvent(span, localLogger, "Starting poolPost creation") + + if client == nil { + return models.PoolPost{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}) + } + + if len(poolID) == 0 { + return models.PoolPost{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsEmpty}) + } + + if len(poolID) != 25 { + return models.PoolPost{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsWrongLength}) + } + + if len(postID) == 0 { + return models.PoolPost{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostIDIsEmpty}) + } + + if len(postID) != 25 { + return models.PoolPost{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostIDIsWrongLength}) + } + + poolPost := models.PoolPost{ + PoolID: poolID, + PostID: postID, + OrderPosition: orderPosition, + } + + result := client.WithContext(ctx).Create(&poolPost) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + return models.PoolPost{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DuplicateKey}) + } + return models.PoolPost{}, utils.HandleError(ctx, span, localLogger, result.Error) + } + + utils.HandleEvent(span, localLogger, "poolPost created successfully") + return poolPost, nil +} + +func DeletePoolPost(ctx context.Context, poolID models.PoolID, postID models.PostID) error { + ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "DeletePoolPost") + defer span.End() + + localLogger = localLogger.WithFields(log.Fields{ + "pool_id": poolID, + "post_id": postID, + }) + + span.SetAttributes( + attribute.String("pool_id", string(poolID)), + attribute.String("post_id", string(postID)), + ) + + utils.HandleEvent(span, localLogger, "Starting delete poolPost") + + var poolPost models.PoolPost + + if client == nil { + return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}) + } + + if len(poolID) == 0 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsEmpty}) + } + + if len(poolID) != 25 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsWrongLength}) + } + + if len(postID) == 0 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostIDIsEmpty}) + } + + if len(postID) != 25 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostIDIsWrongLength}) + } + + result := client.WithContext(ctx).Delete(&poolPost, "pool_id = ? AND post_id = ?", poolID, postID) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.NoDataFound}) + } + return utils.HandleError(ctx, span, localLogger, result.Error) + } + + utils.HandleEvent(span, localLogger, "poolPost deleted successfully") + return nil +} diff --git a/pkg/database/pool_post_test.go b/pkg/database/pool_post_test.go new file mode 100644 index 0000000..7b289c0 --- /dev/null +++ b/pkg/database/pool_post_test.go @@ -0,0 +1,252 @@ +package database + +import ( + "context" + "fmt" + "reflect" + "testing" + + "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/models" + "git.anthrove.art/Anthrove/otter-space-sdk/v4/test" + "go.opentelemetry.io/contrib/bridges/otellogrus" + "go.opentelemetry.io/otel" +) + +func TestCreatePoolPost(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PostgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Pool to test with + + pool := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: models.PoolID(fmt.Sprintf("%025s", "Pool1")), + }, + Name: "Test Pool 01", + Category: models.Collection, + } + + pool, err = CreatePool(ctx, pool) + if err != nil { + logger.Error(err) + } + + // -- Create Post to test with + + post := models.Post{ + BaseModel: models.BaseModel[models.PostID]{ + ID: models.PostID(fmt.Sprintf("%025s", "Post1")), + }, + Rating: models.SFW, + } + + post, err = CreatePost(ctx, post) + if err != nil { + logger.Error(err) + } + + // -- Create PoolPost to test with + validPoolPost := models.PoolPost{ + PoolID: pool.ID, + PostID: post.ID, + OrderPosition: 0, + } + // -- + + // -- -- Tests + type args struct { + ctx context.Context + poolID models.PoolID + postID models.PostID + orderPosition int + } + tests := []struct { + name string + args args + want models.PoolPost + wantErr bool + }{ + { + name: "Test 01: Valid post & pool ID", + args: args{ + ctx: ctx, + postID: post.ID, + poolID: pool.ID, + orderPosition: 0, + }, + want: validPoolPost, + wantErr: false, + }, + { + name: "Test 02: Duplicate", + args: args{ + ctx: ctx, + postID: post.ID, + poolID: pool.ID, + orderPosition: 0, + }, + want: models.PoolPost{}, + wantErr: true, + }, + { + name: "Test 03: poolID is empty", + args: args{ + ctx: ctx, + postID: post.ID, + poolID: "", + orderPosition: 0, + }, + want: models.PoolPost{}, + wantErr: true, + }, + { + name: "Test 04: postID name is empty", + args: args{ + ctx: ctx, + postID: "", + poolID: pool.ID, + orderPosition: 0, + }, + want: models.PoolPost{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := CreatePoolPost(tt.args.ctx, tt.args.poolID, tt.args.postID, tt.args.orderPosition) + if (err != nil) != tt.wantErr { + t.Errorf("CreatePoolPost() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CreatePoolPost() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDeletePoolPost(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PostgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Pool to test with + + pool := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: models.PoolID(fmt.Sprintf("%025s", "Pool1")), + }, + Name: "Test Pool 01", + Category: models.Collection, + } + + pool, err = CreatePool(ctx, pool) + if err != nil { + logger.Fatal(err) + } + + // -- Create Post to test with + + post := models.Post{ + BaseModel: models.BaseModel[models.PostID]{ + ID: models.PostID(fmt.Sprintf("%025s", "Post1")), + }, + Rating: models.SFW, + } + + post, err = CreatePost(ctx, post) + if err != nil { + logger.Fatal(err) + } + + // -- Create PoolPost to test with + validPoolPost := models.PoolPost{ + PoolID: pool.ID, + PostID: post.ID, + OrderPosition: 0, + } + validPoolPost, err = CreatePoolPost(ctx, validPoolPost.PoolID, validPoolPost.PostID, validPoolPost.OrderPosition) + if err != nil { + logger.Fatal(err) + } + + // -- + + // -- -- Tests + type args struct { + ctx context.Context + poolID models.PoolID + postID models.PostID + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Test 01: Valid Post & pool id", + args: args{ + ctx: ctx, + poolID: validPoolPost.PoolID, + postID: validPoolPost.PostID, + }, + wantErr: false, + }, + { + name: "Test 02: Not existing postID", + args: args{ + ctx: ctx, + poolID: validPoolPost.PoolID, + postID: "", + }, + wantErr: true, + }, + { + name: "Test 03: Not existing poolID", + args: args{ + ctx: ctx, + poolID: "", + postID: validPoolPost.PostID, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := DeletePoolPost(tt.args.ctx, tt.args.poolID, tt.args.postID); (err != nil) != tt.wantErr { + t.Errorf("DeletePoolPost() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/pkg/database/pool_reference.go b/pkg/database/pool_reference.go new file mode 100644 index 0000000..eefbb36 --- /dev/null +++ b/pkg/database/pool_reference.go @@ -0,0 +1,121 @@ +package database + +import ( + "context" + "errors" + + "git.anthrove.art/Anthrove/otter-space-sdk/v4/internal/utils" + otterError "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/error" + "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/models" + log "github.com/sirupsen/logrus" + "go.opentelemetry.io/otel/attribute" + "gorm.io/gorm" +) + +func CreatePoolReference(ctx context.Context, poolID models.PoolID, sourceID models.SourceID, url string) (models.PoolReference, error) { + ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "CreatePoolReference") + defer span.End() + + localLogger = localLogger.WithFields(log.Fields{ + "pool_id": poolID, + "source_id": sourceID, + }) + + span.SetAttributes( + attribute.String("pool_id", string(poolID)), + attribute.String("source_id", string(sourceID)), + ) + + utils.HandleEvent(span, localLogger, "Starting poolReference creation") + + if client == nil { + return models.PoolReference{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}) + } + + if len(poolID) == 0 { + return models.PoolReference{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsEmpty}) + } + + if len(poolID) != 25 { + return models.PoolReference{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsWrongLength}) + } + + if len(sourceID) == 0 { + return models.PoolReference{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.SourceIDIsEmpty}) + } + + if len(sourceID) != 25 { + return models.PoolReference{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.SourceIDIsWrongLength}) + } + + if url == "" { + return models.PoolReference{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolURLIsEmpty}) + } + + poolReference := models.PoolReference{ + PoolID: poolID, + SourceID: sourceID, + URL: url, + } + + result := client.WithContext(ctx).Create(&poolReference) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrDuplicatedKey) { + return models.PoolReference{}, utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DuplicateKey}) + } + return models.PoolReference{}, utils.HandleError(ctx, span, localLogger, result.Error) + } + + utils.HandleEvent(span, localLogger, "poolReference created successfully") + return poolReference, nil +} + +func DeletePoolReference(ctx context.Context, poolID models.PoolID, sourceID models.SourceID) error { + ctx, span, localLogger := utils.SetupTracing(ctx, tracer, "DeletePoolReference") + defer span.End() + + localLogger = localLogger.WithFields(log.Fields{ + "pool_id": poolID, + "source_id": sourceID, + }) + + span.SetAttributes( + attribute.String("pool_id", string(poolID)), + attribute.String("source_id", string(sourceID)), + ) + + utils.HandleEvent(span, localLogger, "Starting delete poolReference") + + var poolReference models.PoolReference + + if client == nil { + return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.DatabaseIsNotConnected}) + } + + if len(poolID) == 0 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PoolIDIsEmpty}) + } + + if len(poolID) == 0 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostIDIsWrongLength}) + } + + if len(sourceID) == 0 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.SourceIDIsEmpty}) + } + + if len(sourceID) != 25 { + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.SourceIDIsWrongLength}) + } + + result := client.WithContext(ctx).Delete(&poolReference, "pool_id = ? AND source_id = ?", poolID, sourceID) + if result.Error != nil { + if errors.Is(result.Error, gorm.ErrRecordNotFound) { + return utils.HandleError(ctx, span, localLogger, &otterError.Database{Reason: otterError.NoDataFound}) + } + return utils.HandleError(ctx, span, localLogger, result.Error) + } + + utils.HandleEvent(span, localLogger, "poolReference deleted successfully") + return nil +} diff --git a/pkg/database/pool_reference_test.go b/pkg/database/pool_reference_test.go new file mode 100644 index 0000000..0987fa0 --- /dev/null +++ b/pkg/database/pool_reference_test.go @@ -0,0 +1,239 @@ +package database + +import ( + "context" + "fmt" + "reflect" + "testing" + + "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/models" + "git.anthrove.art/Anthrove/otter-space-sdk/v4/test" + "go.opentelemetry.io/contrib/bridges/otellogrus" + "go.opentelemetry.io/otel" +) + +func TestCreatePoolReference(t *testing.T) { + // Setup throwaway container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PostgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Pool to test with + pool := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: models.PoolID(fmt.Sprintf("%025s", "Pool1")), + }, + Name: "Test Pool 01", + Category: models.Collection, + } + + pool, err = CreatePool(ctx, pool) + if err != nil { + logger.Error(err) + } + + // -- Create Source to test with + source := models.Source{ + BaseModel: models.BaseModel[models.SourceID]{ + ID: models.SourceID(fmt.Sprintf("%025s", "Source1")), + }, + DisplayName: "test", + Domain: "aaa", + Icon: "bbb", + } + + source, err = CreateSource(ctx, source) + if err != nil { + logger.Fatal(err) + } + + // -- + + // -- -- Tests + type args struct { + ctx context.Context + poolID models.PoolID + sourceID models.SourceID + url string + } + tests := []struct { + name string + args args + want models.PoolReference + wantErr bool + }{ + { + name: "Test 01: Valid pool & source ID", + args: args{ + ctx: ctx, + poolID: pool.ID, + sourceID: source.ID, + url: "http://example.com", + }, + want: models.PoolReference{ + PoolID: pool.ID, + SourceID: source.ID, + URL: "http://example.com", + }, + wantErr: false, + }, + { + name: "Test 02: Duplicate", + args: args{ + ctx: ctx, + poolID: pool.ID, + sourceID: source.ID, + url: "http://example.com", + }, + want: models.PoolReference{}, + wantErr: true, + }, + { + name: "Test 03: poolID is empty", + args: args{ + ctx: ctx, + poolID: "", + sourceID: source.ID, + url: "http://example.com", + }, + want: models.PoolReference{}, + wantErr: true, + }, + { + name: "Test 04: sourceID is empty", + args: args{ + ctx: ctx, + poolID: pool.ID, + sourceID: "", + url: "http://example.com", + }, + want: models.PoolReference{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := CreatePoolReference(tt.args.ctx, tt.args.poolID, tt.args.sourceID, tt.args.url) + if (err != nil) != tt.wantErr { + t.Errorf("CreatePoolReference() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CreatePoolReference() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestDeletePoolReference(t *testing.T) { + // Setup throwaway container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PostgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Pool to test with + pool := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: models.PoolID(fmt.Sprintf("%025s", "Pool1")), + }, + Name: "Test Pool 01", + Category: models.Collection, + } + + pool, err = CreatePool(ctx, pool) + if err != nil { + logger.Error(err) + } + + // -- Create Source to test with + source := models.Source{ + BaseModel: models.BaseModel[models.SourceID]{ + ID: models.SourceID(fmt.Sprintf("%025s", "Source1")), + }, + DisplayName: "test", + Domain: "aaa", + Icon: "bbb", + } + + source, err = CreateSource(ctx, source) + if err != nil { + logger.Fatal(err) + } + + // -- + + // -- -- Tests + type args struct { + ctx context.Context + poolID models.PoolID + sourceID models.SourceID + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Test 01: Valid Reference & pool id", + args: args{ + ctx: ctx, + poolID: pool.ID, + sourceID: source.ID, + }, + wantErr: false, + }, + { + name: "Test 02: Not existing sourceID", + args: args{ + ctx: ctx, + poolID: pool.ID, + sourceID: "", + }, + wantErr: true, + }, + { + name: "Test 03: Not existing poolID", + args: args{ + ctx: ctx, + poolID: "", + sourceID: source.ID, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := DeletePoolReference(tt.args.ctx, tt.args.poolID, tt.args.sourceID); (err != nil) != tt.wantErr { + t.Errorf("DeletePoolReference() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} diff --git a/pkg/database/pool_test.go b/pkg/database/pool_test.go new file mode 100644 index 0000000..344c874 --- /dev/null +++ b/pkg/database/pool_test.go @@ -0,0 +1,369 @@ +package database + +import ( + "context" + "fmt" + "reflect" + "testing" + "time" + + "git.anthrove.art/Anthrove/otter-space-sdk/v4/pkg/models" + "git.anthrove.art/Anthrove/otter-space-sdk/v4/test" + "go.opentelemetry.io/contrib/bridges/otellogrus" + "go.opentelemetry.io/otel" + "gorm.io/gorm" +) + +func TestCreatePool(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PoolgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Pool to test with + validPool := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: models.PoolID(fmt.Sprintf("%025s", "Pool1")), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + DeletedAt: gorm.DeletedAt{}, + }, + Name: "Test Pool 01", + Category: models.Series, + } + // -- + + // -- -- Tests + type args struct { + ctx context.Context + post models.Pool + } + tests := []struct { + name string + args args + want models.Pool + wantErr bool + }{ + { + name: "Test 01: Valid Pool", + args: args{ + ctx: ctx, + post: validPool, + }, + want: validPool, + wantErr: false, + }, + { + name: "Test 02: Duplicate Pool", + args: args{ + ctx: ctx, + post: validPool, + }, + want: models.Pool{}, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := CreatePool(tt.args.ctx, tt.args.post) + if (err != nil) != tt.wantErr { + t.Errorf("CreatePool() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CreatePool() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestGetPoolByID(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PoolgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Pool to test with + validPool := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: models.PoolID(fmt.Sprintf("%025s", "Pool1")), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + DeletedAt: gorm.DeletedAt{}, + }, + Name: "Test Pool 01", + Category: models.Series, + } + + validPool, err = CreatePool(ctx, validPool) + if err != nil { + logger.Fatal(err) + } + // -- + + // -- -- Tests + type args struct { + ctx context.Context + id models.PoolID + } + tests := []struct { + name string + args args + want models.Pool + wantErr bool + }{ + { + name: "Test 01: Valid PoolID", + args: args{ + ctx: ctx, + id: validPool.ID, + }, + want: validPool, + wantErr: false, + }, + { + name: "Test 03: Empty PoolID", + args: args{ + ctx: ctx, + id: "", + }, + wantErr: true, + }, + { + name: "Test 04: Short PoolID", + args: args{ + ctx: ctx, + id: "111", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := GetPoolByID(tt.args.ctx, tt.args.id) + if (err != nil) != tt.wantErr { + t.Errorf("GetPoolByID() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !checkPoolID(got, tt.want) { + t.Errorf("GetPoolByID() got = %v, want %v", got, tt.want) + } + }) + } +} + +func TestUpdatePool(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PoolgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Pool to test with + validPool := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: models.PoolID(fmt.Sprintf("%025s", "Pool1")), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + DeletedAt: gorm.DeletedAt{}, + }, + Name: "Test Pool 01", + Category: models.Series, + } + + validPool, err = CreatePool(ctx, validPool) + if err != nil { + logger.Fatal(err) + } + // -- + + // -- Create Updates models for Pool + validUpdatePool := validPool + validUpdatePool.Name = "Updated Test Pool" + validUpdatePool.Category = models.Collection + + invalidUpdatePool := models.Pool{} + // -- + + // -- -- Tests + type args struct { + ctx context.Context + anthrovePool models.Pool + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Test 01: Valid Update for Pool", + args: args{ + ctx: ctx, + anthrovePool: validUpdatePool, + }, + wantErr: false, + }, + { + name: "Test 02: Invalid Update for Pool", + args: args{ + ctx: ctx, + anthrovePool: invalidUpdatePool, + }, + wantErr: true, + }, + { + name: "Test 03: Empty ID for Update for Pool", + args: args{ + ctx: ctx, + anthrovePool: models.Pool{BaseModel: models.BaseModel[models.PoolID]{ID: ""}}, + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := UpdatePool(tt.args.ctx, tt.args.anthrovePool); (err != nil) != tt.wantErr { + t.Errorf("UpdatePool() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func TestDeletePool(t *testing.T) { + // Setup trow away container + ctx := context.Background() + container, gormDB, err := test.StartPostgresContainer(ctx) + if err != nil { + logger.Fatalf("Could not start PoolgreSQL container: %v", err) + } + + client = gormDB + + // Setup open telemetry + tracer = otel.Tracer(tracingName) + + hook := otellogrus.NewHook(tracingName) + logger.AddHook(hook) + + defer container.Terminate(ctx) + + // -- -- Setup Tests + + // -- Create Pool to test with + validPool := models.Pool{ + BaseModel: models.BaseModel[models.PoolID]{ + ID: models.PoolID(fmt.Sprintf("%025s", "Pool1")), + CreatedAt: time.Now(), + UpdatedAt: time.Now(), + DeletedAt: gorm.DeletedAt{}, + }, + Name: "Test Pool 01", + Category: models.Series, + } + + validPool, err = CreatePool(ctx, validPool) + if err != nil { + logger.Fatal(err) + } + // -- + + // -- -- Tests + type args struct { + ctx context.Context + id models.PoolID + } + tests := []struct { + name string + args args + wantErr bool + }{ + { + name: "Test 01: Delete Valid Pool", + args: args{ + ctx: ctx, + id: validPool.ID, + }, + wantErr: false, + }, + { + name: "Test 02: Delete not existed Pool", + args: args{ + ctx: ctx, + id: validPool.ID, + }, + wantErr: false, + }, + { + name: "Test 03: Empty PoolID", + args: args{ + ctx: ctx, + id: "", + }, + wantErr: true, + }, + { + name: "Test 04: Short PoolID", + args: args{ + ctx: ctx, + id: "111", + }, + wantErr: true, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + if err := DeletePool(tt.args.ctx, tt.args.id); (err != nil) != tt.wantErr { + t.Errorf("DeletePool() error = %v, wantErr %v", err, tt.wantErr) + } + }) + } +} + +func checkPoolID(got models.Pool, want models.Pool) bool { + if got.ID != want.ID { + return false + } + + return true +} diff --git a/pkg/database/post.go b/pkg/database/post.go index 1e0eefa..b857d81 100644 --- a/pkg/database/post.go +++ b/pkg/database/post.go @@ -191,7 +191,7 @@ func DeletePost(ctx context.Context, id models.PostID) error { } if len(id) != 25 { - return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostIDToShort}) + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.PostIDIsWrongLength}) } result := client.WithContext(ctx).Delete(&userFavorite, "id = ?", id) diff --git a/pkg/database/source.go b/pkg/database/source.go index 5c82cc3..d565252 100644 --- a/pkg/database/source.go +++ b/pkg/database/source.go @@ -155,7 +155,7 @@ func GetSourceByID(ctx context.Context, id models.SourceID) (models.Source, erro } if len(id) != 25 { - return models.Source{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.SourceIDToShort}) + return models.Source{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.SourceIDIsWrongLength}) } result := client.WithContext(ctx).First(&source, "id = ?", id) @@ -231,7 +231,7 @@ func DeleteSource(ctx context.Context, id models.SourceID) error { } if len(id) != 25 { - return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.SourceIDToShort}) + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.SourceIDIsWrongLength}) } result := client.WithContext(ctx).Delete(&source, id) diff --git a/pkg/database/userSource.go b/pkg/database/userSource.go index 6338ee4..1afd13b 100644 --- a/pkg/database/userSource.go +++ b/pkg/database/userSource.go @@ -118,7 +118,7 @@ func GetUserSourceByID(ctx context.Context, id models.UserSourceID) (models.User } if len(id) != 25 { - return models.UserSource{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.UserSourceIDToShort}) + return models.UserSource{}, utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.UserSourceIsWrongLength}) } result := client.WithContext(ctx).First(&user, "id = ?", id) @@ -157,7 +157,7 @@ func DeleteUserSource(ctx context.Context, id models.UserSourceID) error { } if len(id) != 25 { - return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.UserSourceIDToShort}) + return utils.HandleError(ctx, span, localLogger, &otterError.EntityValidationFailed{Reason: otterError.UserSourceIsWrongLength}) } result := client.WithContext(ctx).Delete(&user, id) diff --git a/pkg/error/validation.go b/pkg/error/validation.go index 889744b..f91a447 100644 --- a/pkg/error/validation.go +++ b/pkg/error/validation.go @@ -3,13 +3,13 @@ package error import "fmt" const ( - SourceListIsEmpty = "sourceList cannot be empty" - SourceIDIsEmpty = "SourceID cannot be empty" - SourceIDToShort = "sourceID needs to be 25 characters long" - SourceDomainIsEmpty = "source Domain cannot be empty" + SourceListIsEmpty = "sourceList cannot be empty" + SourceIDIsEmpty = "SourceID cannot be empty" + SourceIDIsWrongLength = "sourceID has the wrong length" + SourceDomainIsEmpty = "source Domain cannot be empty" - UserSourceIDIsEmpty = "userSourceID cannot be empty" - UserSourceIDToShort = "userSourceID needs to be 25 characters long" + UserSourceIDIsEmpty = "userSourceID cannot be empty" + UserSourceIsWrongLength = "userSourceID has the wrong length" TagNameIsEmpty = "tagName cannot be empty" TagTypeIsEmpty = "tagType cannot be empty" @@ -21,15 +21,20 @@ const ( TagGroupListIsEmpty = "tagGroupList cannot be empty" TagGroupNameIsEmpty = "tagGroupName cannot be empty" - UserFavoriteListIsEmpty = "userFavoriteList cannot be empty" - UserFavoriteIDIsEmpty = "userFavoriteID cannot be empty" - UserFavoriteIDToShort = "userFavoriteID needs to be 25 characters long" + UserFavoriteListIsEmpty = "userFavoriteList cannot be empty" + UserFavoriteIDIsEmpty = "userFavoriteID cannot be empty" + UserFavoriteIsWrongLength = "userFavoriteID has the wrong length" - PostListIsEmpty = "userFavoriteList cannot be empty" - PostIDIsEmpty = "userFavoriteID cannot be empty" - PostIDToShort = "PostID needs to be 25 characters long" + PostListIsEmpty = "userFavoriteList cannot be empty" + PostIDIsEmpty = "userFavoriteID cannot be empty" + PostIDIsWrongLength = "PostID has the wrong length" BatchSizeIsEmpty = "batchSize cannot be empty" + + PoolIDIsEmpty = "PoolID cannot be empty" + PoolIDIsWrongLength = "PoolID has the wrong length" + + PoolURLIsEmpty = "PoolURL cannot be empty" ) type EntityValidationFailed struct { diff --git a/pkg/models/const.go b/pkg/models/const.go index 092a803..9755bfd 100644 --- a/pkg/models/const.go +++ b/pkg/models/const.go @@ -6,6 +6,7 @@ type ( UserID string PostID string PostURL string + PoolID string SourceID string SourceDomain string diff --git a/pkg/models/orm.go b/pkg/models/orm.go index 2cf6cf5..4ce9b06 100644 --- a/pkg/models/orm.go +++ b/pkg/models/orm.go @@ -8,7 +8,7 @@ import ( ) type ID interface { - UserID | SourceID | PostID | UserSourceID | UserFavoriteID + UserID | SourceID | PostID | UserSourceID | UserFavoriteID | PoolID } type BaseModel[T ID] struct { diff --git a/pkg/models/pools.go b/pkg/models/pools.go new file mode 100644 index 0000000..0b4dad6 --- /dev/null +++ b/pkg/models/pools.go @@ -0,0 +1,42 @@ +package models + +type PoolCategory string + +const ( + Series PoolCategory = "series" + Collection PoolCategory = "collection" +) + +type Pool struct { + BaseModel[PoolID] + Name string `json:"name" gorm:"type:varchar(25)"` + Category PoolCategory `json:"category" gorm:"type:pool_category;type:enum('series', 'collection')"` +} + +func (Pool) TableName() string { + return "Pool" +} + +type PoolPost struct { + Pool Pool `json:"pool" gorm:"foreignKey:ID;references:PoolID"` + PoolID PoolID `json:"pool_id" gorm:""` + Post Post `json:"post" gorm:"foreignKey:ID;references:PostID"` + PostID PostID `json:"post_id" gorm:""` + OrderPosition int `json:"order_position" gorm:"not null;default:0"` +} + +func (PoolPost) TableName() string { + return "PoolPost" +} + +type PoolReference struct { + Pool Pool `json:"pool" gorm:"foreignKey:ID;references:PoolID"` + PoolID PoolID `json:"pool_id" gorm:""` + Source Source `json:"source" gorm:"foreignKey:ID;references:SourceID"` + SourceID SourceID `json:"source_id" gorm:""` + URL string `json:"url" gorm:"not null"` +} + +func (PoolReference) TableName() string { + return "PoolReference" +} diff --git a/pkg/models/pools_test.go b/pkg/models/pools_test.go new file mode 100644 index 0000000..530b0d5 --- /dev/null +++ b/pkg/models/pools_test.go @@ -0,0 +1,27 @@ +package models + +import "testing" + +func TestPool_TableName(t *testing.T) { + post := Pool{} + expectedTableName := "Pool" + if tableName := post.TableName(); tableName != expectedTableName { + t.Fatalf("expected %s, but got %s", expectedTableName, tableName) + } +} + +func TestPoolPost_TableName(t *testing.T) { + post := PoolPost{} + expectedTableName := "PoolPost" + if tableName := post.TableName(); tableName != expectedTableName { + t.Fatalf("expected %s, but got %s", expectedTableName, tableName) + } +} + +func TestPoolReference_TableName(t *testing.T) { + post := PoolReference{} + expectedTableName := "PoolReference" + if tableName := post.TableName(); tableName != expectedTableName { + t.Fatalf("expected %s, but got %s", expectedTableName, tableName) + } +}