From 7f6cd8e5579e45027cbf8eafbfa7be9a0c35dcc9 Mon Sep 17 00:00:00 2001 From: yash Date: Wed, 25 Feb 2026 20:22:13 +0300 Subject: [PATCH] postgresql & migrations --- Makefile | 3 + cmd/app/main.go | 25 +++--- go.mod | 22 +++-- go.sum | 83 ++++++++++++++++++- internal/config/config.go | 12 ++- internal/logger/logger.go | 3 +- internal/provider/bybit/bybit.go | 7 +- internal/provider/provider.go | 3 +- internal/repository/postgresql/alert.go | 1 + internal/repository/postgresql/instrument.go | 1 + .../migrations/000001_init.down.sql | 4 + .../postgresql/migrations/000001_init.up.sql | 32 +++++++ .../repository/postgresql/migrations/embed.go | 8 ++ internal/repository/postgresql/postgresql.go | 76 +++++++++++++++++ internal/repository/postgresql/user.go | 1 + 15 files changed, 254 insertions(+), 27 deletions(-) create mode 100644 internal/repository/postgresql/alert.go create mode 100644 internal/repository/postgresql/instrument.go create mode 100644 internal/repository/postgresql/migrations/000001_init.down.sql create mode 100644 internal/repository/postgresql/migrations/000001_init.up.sql create mode 100644 internal/repository/postgresql/migrations/embed.go create mode 100644 internal/repository/postgresql/postgresql.go create mode 100644 internal/repository/postgresql/user.go diff --git a/Makefile b/Makefile index d4ff95a..f6a8bf4 100644 --- a/Makefile +++ b/Makefile @@ -3,3 +3,6 @@ run: build: go build -o crypro_alert_bot ./cmd/app/main.go + +migrate_create: + migrate create -ext sql -dir ./internal/repository/postgresql/migrations -seq ${NAME} diff --git a/cmd/app/main.go b/cmd/app/main.go index dd4f94c..29f3076 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -2,27 +2,26 @@ package main import ( "context" - "crypto_alert_bot/internal/config" - "crypto_alert_bot/internal/entities" - "crypto_alert_bot/internal/logger" - "crypto_alert_bot/internal/provider/bybit" - "fmt" + "os" + + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/config" + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/logger" + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/repository/postgresql" ) func main() { + ctx := context.Background() // read config cfg := config.MustLoad() // init logger log := logger.NewAppLogger(&cfg.Logger) log.Info("app started") - // init telegram bot - b := bybit.New(log, &cfg.Providers.Bybit) - price, err := b.Price(context.Background(), entities.Pair{ - BaseCurrency: "BTC", - QuoteCurrency: "USDT", - }) + // init storage + storage, err := postgresql.New(ctx, log, &cfg.Postgresql) if err != nil { - panic(err) + log.Error("failed to connect to postgresql", "err", err) + os.Exit(1) } - fmt.Printf("%+v\n", price) + _ = storage + // init telegram bot } diff --git a/go.mod b/go.mod index f302d3b..e1e8900 100644 --- a/go.mod +++ b/go.mod @@ -1,28 +1,40 @@ -module crypto_alert_bot +module gitea.computernetthings.ru/yash/crypto_alert_bot go 1.25.5 +require ( + github.com/charmbracelet/log v0.4.2 + github.com/golang-migrate/migrate/v4 v4.19.1 + github.com/ilyakaznacheev/cleanenv v1.5.0 + github.com/shopspring/decimal v1.4.0 +) + require ( github.com/BurntSushi/toml v1.2.1 // indirect github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect github.com/charmbracelet/lipgloss v1.1.0 // indirect - github.com/charmbracelet/log v0.4.2 // indirect github.com/charmbracelet/x/ansi v0.8.0 // indirect github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect github.com/charmbracelet/x/term v0.2.1 // indirect github.com/go-logfmt/logfmt v0.6.0 // indirect - github.com/ilyakaznacheev/cleanenv v1.5.0 // indirect + github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa // indirect + github.com/jackc/pgpassfile v1.0.0 // indirect + github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 // indirect + github.com/jackc/pgx/v5 v5.8.0 // indirect + github.com/jackc/puddle/v2 v2.2.2 // indirect github.com/joho/godotenv v1.5.1 // indirect + github.com/lib/pq v1.10.9 // indirect github.com/lucasb-eyer/go-colorful v1.2.0 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect github.com/muesli/termenv v0.16.0 // indirect github.com/rivo/uniseg v0.4.7 // indirect - github.com/shopspring/decimal v1.4.0 // indirect github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect golang.org/x/exp v0.0.0-20231006140011-7918f672742d // indirect - golang.org/x/sys v0.30.0 // indirect + golang.org/x/sync v0.18.0 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/text v0.31.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 // indirect ) diff --git a/go.sum b/go.sum index 4a7b5d5..5aea3d9 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,9 @@ +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/BurntSushi/toml v1.2.1 h1:9F2/+DoOYIOksmaJFPw1tGFy1eDnIJXg+UHjuD8lTak= github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= @@ -14,33 +18,108 @@ github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0G github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= +github.com/containerd/errdefs v1.0.0 h1:tg5yIfIlQIrxYtu9ajqY42W3lpS19XqdxRQeEwYG8PI= +github.com/containerd/errdefs v1.0.0/go.mod h1:+YBYIdtsnF4Iw6nWZhJcqGSg/dwvV7tyJ/kCkyJ2k+M= +github.com/containerd/errdefs/pkg v0.3.0 h1:9IKJ06FvyNlexW690DXuQNx2KA2cUJXx151Xdx3ZPPE= +github.com/containerd/errdefs/pkg v0.3.0/go.mod h1:NJw6s9HwNuRhnjJhM7pylWwMyAkmCQvQ4GpJHEqRLVk= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= +github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dhui/dktest v0.4.6 h1:+DPKyScKSEp3VLtbMDHcUq6V5Lm5zfZZVb0Sk7Ahom4= +github.com/dhui/dktest v0.4.6/go.mod h1:JHTSYDtKkvFNFHJKqCzVzqXecyv+tKt8EzceOmQOgbU= +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 v28.3.3+incompatible h1:Dypm25kh4rmk49v1eiVbsAtpAsYURjYkaKubwuBdxEI= +github.com/docker/docker v28.3.3+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= +github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk= +github.com/felixge/httpsnoop v1.0.4 h1:NFTV2Zj1bL4mc9sqWACXbQFVBBg2W3GPvqp8/ESS2Wg= +github.com/felixge/httpsnoop v1.0.4/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U= github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= +github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI= +github.com/go-logr/logr v1.4.3/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/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-migrate/migrate/v4 v4.19.1 h1:OCyb44lFuQfYXYLx1SCxPZQGU7mcaZ7gH9yH4jSFbBA= +github.com/golang-migrate/migrate/v4 v4.19.1/go.mod h1:CTcgfjxhaUtsLipnLoQRWCrjYXycRz/g5+RWDuYgPrE= github.com/ilyakaznacheev/cleanenv v1.5.0 h1:0VNZXggJE2OYdXE87bfSSwGxeiGt9moSR2lOrsHHvr4= github.com/ilyakaznacheev/cleanenv v1.5.0/go.mod h1:a5aDzaJrLCQZsazHol1w8InnDcOX0OColm64SlIi6gk= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa h1:s+4MhCQ6YrzisK6hFJUX53drDT4UsSW3DEhKn0ifuHw= +github.com/jackc/pgerrcode v0.0.0-20220416144525-469b46aa5efa/go.mod h1:a/s9Lp5W7n/DD0VrVoyJ00FbP2ytTPDVOivvn2bMlds= +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-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= +github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= +github.com/jackc/pgx/v5 v5.8.0 h1:TYPDoleBBme0xGSAX3/+NujXXtpZn9HBONkQC7IEZSo= +github.com/jackc/pgx/v5 v5.8.0/go.mod h1:QVeDInX2m9VyzvNeiCJVjCkNFqzsNb43204HshNSZKw= +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/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= +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= +github.com/morikuni/aec v1.0.0/go.mod h1:BbKIizmSmc5MMPqRYbxO4ZU0S0+P200+tUnFx7PXmsc= github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= +github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM= +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/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= +github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= github.com/shopspring/decimal v1.4.0 h1:bxl37RwXBklmTi0C79JfXCEBD1cqqHt0bbgBAGFp81k= github.com/shopspring/decimal v1.4.0/go.mod h1:gawqmDU56v4yIKSwfBSFip1HdCCXN8/+DMd9qYNcwME= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +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.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= +github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= +go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA= +go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0 h1:F7Jx+6hwnZ41NSFTO5q4LYDtJRXBf2PD0rNBkeB/lus= +go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q= +go.opentelemetry.io/otel v1.37.0 h1:9zhNfelUvx0KBfu/gb+ZgeAfAgtWrfHJZcAqFC228wQ= +go.opentelemetry.io/otel v1.37.0/go.mod h1:ehE/umFRLnuLa/vSccNq9oS1ErUlkkK71gMcN34UG8I= +go.opentelemetry.io/otel/metric v1.37.0 h1:mvwbQS5m0tbmqML4NqK+e3aDiO02vsf/WgbsdpcPoZE= +go.opentelemetry.io/otel/metric v1.37.0/go.mod h1:04wGrZurHYKOc+RKeye86GwKiTb9FKm1WHtO+4EVr2E= +go.opentelemetry.io/otel/trace v1.37.0 h1:HLdcFNbRQBE2imdSEgm/kwqmQj1Or1l/7bW6mxVK7z4= +go.opentelemetry.io/otel/trace v1.37.0/go.mod h1:TlgrlQ+PtQO5XFerSPUYG0JSgGyryXewPGyayAWSBS0= golang.org/x/exp v0.0.0-20231006140011-7918f672742d h1:jtJma62tbqLibJ5sFQz8bKtEM8rJBtfilJ2qTU199MI= golang.org/x/exp v0.0.0-20231006140011-7918f672742d/go.mod h1:ldy0pHrwJyGW56pPQzzkH36rKxoZW1tw7ZJpeKx+hdo= +golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= +golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc= -golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +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= olympos.io/encoding/edn v0.0.0-20201019073823-d3554ca0b0a3 h1:slmdOY3vp8a7KQbHkL+FLbvbkgMqmXojpFUO/jENuqQ= diff --git a/internal/config/config.go b/internal/config/config.go index db15e9b..c3c4fba 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -8,8 +8,9 @@ import ( ) type Config struct { - Logger Logger `yaml:"logger"` - Providers struct { + Logger Logger `yaml:"logger"` + Postgresql Postgresql `yaml:"postgresql"` + Providers struct { Bybit Bybit `yaml:"bybit"` } `yaml:"providers"` } @@ -24,6 +25,13 @@ type Bybit struct { BaseURL string `yaml:"base_url" env-default:"https://api.bybit.com"` // bybit api url } +type Postgresql struct { + Address string `yaml:"address" env-required:"true"` + User string `yaml:"user" env-required:"true"` + Password string `yaml:"password" env-required:"true"` + DBName string `yaml:"db_name" env-required:"true"` +} + // MustLoad returns config or panic. func MustLoad() *Config { configPath := os.Getenv("CONFIG_PATH") diff --git a/internal/logger/logger.go b/internal/logger/logger.go index b1a5b58..1a6a801 100644 --- a/internal/logger/logger.go +++ b/internal/logger/logger.go @@ -1,11 +1,12 @@ package logger import ( - "crypto_alert_bot/internal/config" "fmt" "log/slog" "os" + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/config" + prettyLogger "github.com/charmbracelet/log" ) diff --git a/internal/provider/bybit/bybit.go b/internal/provider/bybit/bybit.go index de58b35..65e77d6 100644 --- a/internal/provider/bybit/bybit.go +++ b/internal/provider/bybit/bybit.go @@ -3,14 +3,15 @@ package bybit import ( "context" - "crypto_alert_bot/internal/config" - "crypto_alert_bot/internal/entities" - "crypto_alert_bot/internal/provider" "fmt" "log/slog" "net/http" "time" + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/config" + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/entities" + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/provider" + "github.com/shopspring/decimal" ) diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 0ae00b3..78df467 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -2,7 +2,8 @@ package provider import ( "context" - "crypto_alert_bot/internal/entities" + + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/entities" ) type Provider interface { diff --git a/internal/repository/postgresql/alert.go b/internal/repository/postgresql/alert.go new file mode 100644 index 0000000..4e9a54a --- /dev/null +++ b/internal/repository/postgresql/alert.go @@ -0,0 +1 @@ +package postgresql diff --git a/internal/repository/postgresql/instrument.go b/internal/repository/postgresql/instrument.go new file mode 100644 index 0000000..4e9a54a --- /dev/null +++ b/internal/repository/postgresql/instrument.go @@ -0,0 +1 @@ +package postgresql diff --git a/internal/repository/postgresql/migrations/000001_init.down.sql b/internal/repository/postgresql/migrations/000001_init.down.sql new file mode 100644 index 0000000..a0d959b --- /dev/null +++ b/internal/repository/postgresql/migrations/000001_init.down.sql @@ -0,0 +1,4 @@ +drop table if exists alert; +drop table if exists instrument; +drop table if exists currency; +drop table if exists users; diff --git a/internal/repository/postgresql/migrations/000001_init.up.sql b/internal/repository/postgresql/migrations/000001_init.up.sql new file mode 100644 index 0000000..bbabd71 --- /dev/null +++ b/internal/repository/postgresql/migrations/000001_init.up.sql @@ -0,0 +1,32 @@ +create table if not exists users ( + id uuid primary key not null default gen_random_uuid(), + telegram_id bigint not null UNIQUE +); + +create table if not exists currency ( + id serial primary key not null, + symbol text not null UNIQUE + -- decimals integer not null +); + +create table if not exists instrument ( + id uuid primary key not null default gen_random_uuid(), + base_currency_id integer references currency(id) not null, + quoted_currency_id integer references currency(id) not null, + CHECK (base_currency_id <> quoted_currency_id), + UNIQUE (base_currency_id, quoted_currency_id) +); + +create table if not exists alert ( + id uuid primary key not null default gen_random_uuid(), + instrument_id uuid references instrument(id) not null, + price text not null, + active bool not null default true +); + +insert into currency(symbol) values ('USDT'), ('BTC'), ('ETH'), ('SOL'); + +insert into instrument (base_currency_id, quoted_currency_id) values + ((select id from currency where symbol = 'BTC'), (select id from currency where symbol = 'USDT')), + ((select id from currency where symbol = 'ETH'), (select id from currency where symbol = 'USDT')), + ((select id from currency where symbol = 'SOL'), (select id from currency where symbol = 'USDT')); diff --git a/internal/repository/postgresql/migrations/embed.go b/internal/repository/postgresql/migrations/embed.go new file mode 100644 index 0000000..956dd88 --- /dev/null +++ b/internal/repository/postgresql/migrations/embed.go @@ -0,0 +1,8 @@ +package migrations + +import ( + "embed" +) + +//go:embed *.sql +var Folder embed.FS diff --git a/internal/repository/postgresql/postgresql.go b/internal/repository/postgresql/postgresql.go new file mode 100644 index 0000000..c2af618 --- /dev/null +++ b/internal/repository/postgresql/postgresql.go @@ -0,0 +1,76 @@ +package postgresql + +import ( + "context" + "database/sql" + "errors" + "fmt" + "log/slog" + + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/config" + "gitea.computernetthings.ru/yash/crypto_alert_bot/internal/repository/postgresql/migrations" + + "github.com/jackc/pgx/v5/pgxpool" + + "github.com/golang-migrate/migrate/v4" + pgx "github.com/golang-migrate/migrate/v4/database/pgx/v5" + "github.com/golang-migrate/migrate/v4/source/iofs" + _ "github.com/jackc/pgx/v5/stdlib" +) + +type Postgresql struct { + db *pgxpool.Pool +} + +func New(ctx context.Context, log *slog.Logger, cfg *config.Postgresql) (*Postgresql, error) { + pool, err := pgxpool.New(ctx, fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable", cfg.User, cfg.Password, cfg.Address, cfg.DBName)) + if err != nil { + return nil, fmt.Errorf("failed to connect to postgres: %w", err) + } + + if err = pool.Ping(ctx); err != nil { + return nil, err + } + + // apply migrations automatically + if err = applyMigrations(cfg, log); err != nil { + return nil, fmt.Errorf("failed to apply migrations: %w", err) + } + + return &Postgresql{db: pool}, nil +} + +func applyMigrations(cfg *config.Postgresql, log *slog.Logger) error { + dsn := fmt.Sprintf("postgres://%s:%s@%s/%s?sslmode=disable", cfg.User, cfg.Password, cfg.Address, cfg.DBName) + + sqlDB, err := sql.Open("pgx", dsn) + if err != nil { + return fmt.Errorf("failed to open sql db for migrations: %w", err) + } + defer sqlDB.Close() + + driver, err := pgx.WithInstance(sqlDB, &pgx.Config{}) + if err != nil { + return fmt.Errorf("failed to create pgx driver: %w", err) + } + + d, err := iofs.New(migrations.Folder, ".") + if err != nil { + return fmt.Errorf("failed to create iofs source: %w", err) + } + + m, err := migrate.NewWithInstance("iofs", d, "postgres", driver) + if err != nil { + return fmt.Errorf("failed to create postgresql db migration: %w", err) + } + + if err := m.Up(); err != nil { + if errors.Is(err, migrate.ErrNoChange) { + log.Info("no migrations to process") + return nil + } + return err + } + log.Info("migrations processed") + return nil +} diff --git a/internal/repository/postgresql/user.go b/internal/repository/postgresql/user.go new file mode 100644 index 0000000..4e9a54a --- /dev/null +++ b/internal/repository/postgresql/user.go @@ -0,0 +1 @@ +package postgresql