mirror of
https://github.com/SamyRai/tercul-backend.git
synced 2025-12-27 05:11:34 +00:00
This is a work-in-progress commit for the core architectural refactoring of configuration handling.
The goal of this refactoring is to eliminate the global configuration singleton (`config.Cfg`) and replace it with explicit dependency injection of a `Config` struct. This commit includes the following partial changes: - The `Config` struct in `internal/platform/config/config.go` has been updated with all necessary fields. - Several platform packages (`db`, `cache`, `auth`, `http`, `jobs/sync`) have been modified to accept the `*config.Config` struct. - The API server entry point (`cmd/api/main.go`) has been updated to load and provide the configuration. - A new worker entry point (`cmd/worker/main.go`) has been created to house the background job runner, as per the architecture defined in `refactor.md`. NOTE: The build is currently broken as this refactoring is incomplete. This commit is for saving progress as requested.
This commit is contained in:
parent
ef4077b5d6
commit
ac29aaa1d5
12
TASKS.md
12
TASKS.md
@ -8,7 +8,7 @@ This document is the single source of truth for all outstanding development task
|
|||||||
|
|
||||||
### Stabilize Core Logic (Prevent Panics)
|
### Stabilize Core Logic (Prevent Panics)
|
||||||
|
|
||||||
- [x] **Fix Background Job Panic:** The background job queue in `internal/jobs/sync/queue.go` can panic on error. This has been refactored to handle errors gracefully by using `log.Printf` instead of `log.Fatalf`.
|
- [ ] **Fix Background Job Panic:** The background job queue in `internal/jobs/sync/queue.go` can panic on error. This must be refactored to handle errors gracefully.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -54,10 +54,10 @@ This document is the single source of truth for all outstanding development task
|
|||||||
|
|
||||||
### EPIC: Robust Testing Framework
|
### EPIC: Robust Testing Framework
|
||||||
|
|
||||||
- [x] **Refactor Testing Utilities:** Decouple our tests from a live database to make them faster and more reliable.
|
- [ ] **Refactor Testing Utilities:** Decouple our tests from a live database to make them faster and more reliable.
|
||||||
- [x] Verified that `internal/testutil/testutil.go` is already database-agnostic.
|
- [ ] Remove all database connection logic from `internal/testutil/testutil.go`.
|
||||||
- [x] **Implement Mock Repositories:** The test mocks that were incomplete and causing `panic`s have been implemented.
|
- [ ] **Implement Mock Repositories:** The test mocks are incomplete and `panic`.
|
||||||
- [x] Implemented the `panic("not implemented")` methods in `internal/adapters/graphql/like_repo_mock_test.go`, `internal/adapters/graphql/work_repo_mock_test.go`, and `internal/testutil/mock_user_repository.go`.
|
- [ ] Implement the `panic("not implemented")` methods in `internal/adapters/graphql/like_repo_mock_test.go`, `internal/adapters/graphql/work_repo_mock_test.go`, and `internal/testutil/mock_user_repository.go`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ This document is the single source of truth for all outstanding development task
|
|||||||
### EPIC: Further Architectural Improvements
|
### EPIC: Further Architectural Improvements
|
||||||
|
|
||||||
- [ ] **Refactor Caching:** Replace the bespoke cached repositories with a decorator pattern in `internal/data/cache`.
|
- [ ] **Refactor Caching:** Replace the bespoke cached repositories with a decorator pattern in `internal/data/cache`.
|
||||||
- [x] **Consolidate Duplicated Structs:** The duplicated `WorkAnalytics` and `TranslationAnalytics` structs have been consolidated into a new `internal/domain/analytics` package.
|
- [ ] **Consolidate Duplicated Structs:** The `WorkAnalytics` and `TranslationAnalytics` structs are defined in two different packages. Consolidate them.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
11
go.mod
11
go.mod
@ -17,6 +17,7 @@ require (
|
|||||||
github.com/prometheus/client_golang v1.20.5
|
github.com/prometheus/client_golang v1.20.5
|
||||||
github.com/redis/go-redis/v9 v9.13.0
|
github.com/redis/go-redis/v9 v9.13.0
|
||||||
github.com/rs/zerolog v1.34.0
|
github.com/rs/zerolog v1.34.0
|
||||||
|
github.com/spf13/viper v1.21.0
|
||||||
github.com/stretchr/testify v1.11.1
|
github.com/stretchr/testify v1.11.1
|
||||||
github.com/vektah/gqlparser/v2 v2.5.30
|
github.com/vektah/gqlparser/v2 v2.5.30
|
||||||
github.com/weaviate/weaviate v1.33.0-rc.1
|
github.com/weaviate/weaviate v1.33.0-rc.1
|
||||||
@ -47,6 +48,7 @@ require (
|
|||||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||||
github.com/elastic/go-sysinfo v1.15.4 // indirect
|
github.com/elastic/go-sysinfo v1.15.4 // indirect
|
||||||
github.com/elastic/go-windows v1.0.2 // indirect
|
github.com/elastic/go-windows v1.0.2 // indirect
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 // indirect
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
github.com/gabriel-vasile/mimetype v1.4.8 // indirect
|
||||||
github.com/go-faster/city v1.0.1 // indirect
|
github.com/go-faster/city v1.0.1 // indirect
|
||||||
github.com/go-faster/errors v0.7.1 // indirect
|
github.com/go-faster/errors v0.7.1 // indirect
|
||||||
@ -92,6 +94,7 @@ require (
|
|||||||
github.com/oklog/ulid v1.3.1 // indirect
|
github.com/oklog/ulid v1.3.1 // indirect
|
||||||
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
github.com/opentracing/opentracing-go v1.2.0 // indirect
|
||||||
github.com/paulmach/orb v0.11.1 // indirect
|
github.com/paulmach/orb v0.11.1 // indirect
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 // indirect
|
||||||
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
github.com/pierrec/lz4/v4 v4.1.22 // indirect
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
github.com/pkg/errors v0.9.1 // indirect
|
||||||
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect
|
||||||
@ -101,12 +104,17 @@ require (
|
|||||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||||
github.com/robfig/cron/v3 v3.0.1 // indirect
|
github.com/robfig/cron/v3 v3.0.1 // indirect
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
github.com/russross/blackfriday/v2 v2.1.0 // indirect
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0 // indirect
|
||||||
github.com/segmentio/asm v1.2.0 // indirect
|
github.com/segmentio/asm v1.2.0 // indirect
|
||||||
github.com/sethvargo/go-retry v0.3.0 // indirect
|
github.com/sethvargo/go-retry v0.3.0 // indirect
|
||||||
github.com/shopspring/decimal v1.4.0 // indirect
|
github.com/shopspring/decimal v1.4.0 // indirect
|
||||||
github.com/sosodev/duration v1.3.1 // indirect
|
github.com/sosodev/duration v1.3.1 // indirect
|
||||||
github.com/spf13/cast v1.7.0 // indirect
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 // indirect
|
||||||
|
github.com/spf13/afero v1.15.0 // indirect
|
||||||
|
github.com/spf13/cast v1.10.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.10 // indirect
|
||||||
github.com/stretchr/objx v0.5.2 // indirect
|
github.com/stretchr/objx v0.5.2 // indirect
|
||||||
|
github.com/subosito/gotenv v1.6.0 // indirect
|
||||||
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d // indirect
|
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d // indirect
|
||||||
github.com/urfave/cli/v2 v2.27.7 // indirect
|
github.com/urfave/cli/v2 v2.27.7 // indirect
|
||||||
github.com/vertica/vertica-sql-go v1.3.3 // indirect
|
github.com/vertica/vertica-sql-go v1.3.3 // indirect
|
||||||
@ -118,6 +126,7 @@ require (
|
|||||||
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
|
||||||
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
go.opentelemetry.io/otel/metric v1.38.0 // indirect
|
||||||
go.uber.org/multierr v1.11.0 // indirect
|
go.uber.org/multierr v1.11.0 // indirect
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4 // indirect
|
||||||
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect
|
||||||
golang.org/x/mod v0.26.0 // indirect
|
golang.org/x/mod v0.26.0 // indirect
|
||||||
golang.org/x/net v0.42.0 // indirect
|
golang.org/x/net v0.42.0 // indirect
|
||||||
|
|||||||
22
go.sum
22
go.sum
@ -94,6 +94,8 @@ github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7
|
|||||||
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k=
|
||||||
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8=
|
||||||
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
|
||||||
|
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
github.com/gabriel-vasile/mimetype v1.4.8 h1:FfZ3gj38NjllZIeJAmMhr+qKL8Wu+nOoI3GqacKw1NM=
|
||||||
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
github.com/gabriel-vasile/mimetype v1.4.8/go.mod h1:ByKUIKGjh1ODkGM1asKUbQZOLGrPjydw3hYPU2YU9t8=
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
@ -315,6 +317,8 @@ github.com/paulmach/orb v0.11.1 h1:3koVegMC4X/WeiXYz9iswopaTwMem53NzTJuTF20JzU=
|
|||||||
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
github.com/paulmach/orb v0.11.1/go.mod h1:5mULz1xQfs3bmQm63QEJA6lNGujuRafwA5S/EnuLaLU=
|
||||||
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
github.com/paulmach/protoscan v0.2.1/go.mod h1:SpcSwydNLrxUGSDvXvO0P7g7AuhJ7lcKfDlhJCDw2gY=
|
||||||
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
|
||||||
|
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
|
||||||
github.com/pemistahl/lingua-go v1.4.0 h1:ifYhthrlW7iO4icdubwlduYnmwU37V1sbNrwhKBR4rM=
|
github.com/pemistahl/lingua-go v1.4.0 h1:ifYhthrlW7iO4icdubwlduYnmwU37V1sbNrwhKBR4rM=
|
||||||
github.com/pemistahl/lingua-go v1.4.0/go.mod h1:ECuM1Hp/3hvyh7k8aWSqNCPlTxLemFZsRjocUf3KgME=
|
github.com/pemistahl/lingua-go v1.4.0/go.mod h1:ECuM1Hp/3hvyh7k8aWSqNCPlTxLemFZsRjocUf3KgME=
|
||||||
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
github.com/pierrec/lz4/v4 v4.1.22 h1:cKFw6uJDK+/gfw5BcDL0JL5aBsAFdsIT18eRtLj7VIU=
|
||||||
@ -359,6 +363,8 @@ github.com/rs/zerolog v1.34.0 h1:k43nTLIwcTVQAncfCw4KZ2VY6ukYoZaBPNOE8txlOeY=
|
|||||||
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
github.com/rs/zerolog v1.34.0/go.mod h1:bJsvje4Z08ROH4Nhs5iH600c3IkWhwp44iRc54W6wYQ=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
|
||||||
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0 h1:1iurJgmM9G3PA/I+wWYIOw/5SyBtxapeHDcg+AAIFXc=
|
||||||
|
github.com/sagikazarmark/locafero v0.11.0/go.mod h1:nVIGvgyzw595SUSUE6tvCp3YYTeHs15MvlmU87WwIik=
|
||||||
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
github.com/segmentio/asm v1.2.0 h1:9BQrFxC+YOHJlTlHGkTrFWf59nbL3XnCoFLTwDCI7ys=
|
||||||
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
github.com/segmentio/asm v1.2.0/go.mod h1:BqMnlJP91P8d+4ibuonYZw9mfnzI9HfxselHZr5aAcs=
|
||||||
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
github.com/sergi/go-diff v1.3.1 h1:xkr+Oxo4BOQKmkn/B9eMK0g5Kg/983T9DqqPHwYqD+8=
|
||||||
@ -372,10 +378,18 @@ github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMB
|
|||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
|
github.com/sosodev/duration v1.3.1 h1:qtHBDMQ6lvMQsL15g4aopM4HEfOaYuhWBw3NPTtlqq4=
|
||||||
github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
github.com/sosodev/duration v1.3.1/go.mod h1:RQIBBX0+fMLc/D9+Jb/fwvVmo0eZvDDEERAikUR6SDg=
|
||||||
github.com/spf13/cast v1.7.0 h1:ntdiHjuueXFgm5nzDRdOS4yfT43P5Fnud6DH50rz/7w=
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8 h1:+jumHNA0Wrelhe64i8F6HNlS8pkoyMv5sreGx2Ry5Rw=
|
||||||
github.com/spf13/cast v1.7.0/go.mod h1:ancEpBxwJDODSW/UG4rDrAqiKolqNNh2DX3mk86cAdo=
|
github.com/sourcegraph/conc v0.3.1-0.20240121214520-5f936abd7ae8/go.mod h1:3n1Cwaq1E1/1lhQhtRK2ts/ZwZEhjcQeJQ1RuC6Q/8U=
|
||||||
|
github.com/spf13/afero v1.15.0 h1:b/YBCLWAJdFWJTN9cLhiXXcD7mzKn9Dm86dNnfyQw1I=
|
||||||
|
github.com/spf13/afero v1.15.0/go.mod h1:NC2ByUVxtQs4b3sIUphxK0NioZnmxgyCrfzeuq8lxMg=
|
||||||
|
github.com/spf13/cast v1.10.0 h1:h2x0u2shc1QuLHfxi+cTJvs30+ZAHOGRic8uyGTDWxY=
|
||||||
|
github.com/spf13/cast v1.10.0/go.mod h1:jNfB8QC9IA6ZuY2ZjDp0KtFO2LZZlg4S/7bzP6qqeHo=
|
||||||
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ=
|
||||||
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4=
|
||||||
|
github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk=
|
||||||
|
github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
|
||||||
|
github.com/spf13/viper v1.21.0 h1:x5S+0EU27Lbphp4UKm1C+1oQO+rKx36vfCoaVebLFSU=
|
||||||
|
github.com/spf13/viper v1.21.0/go.mod h1:P0lhsswPGWD/1lZJ9ny3fYnVqxiegrlNrEmgLjbTCAY=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
|
||||||
@ -387,6 +401,8 @@ github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
|
|||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
github.com/subosito/gotenv v1.6.0 h1:9NlTDc1FTs4qu0DDq7AEtTPNw6SVm7uBMsUCUjABIf8=
|
||||||
|
github.com/subosito/gotenv v1.6.0/go.mod h1:Dk4QP5c2W3ibzajGcXpNraDfq2IrhjMIvMSWPKKo0FU=
|
||||||
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
|
||||||
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=
|
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d h1:dOMI4+zEbDI37KGb0TI44GUAwxHF9cMsIoDTJ7UmgfU=
|
||||||
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=
|
github.com/tursodatabase/libsql-client-go v0.0.0-20240902231107-85af5b9d094d/go.mod h1:l8xTsYB90uaVdMHXMCxKKLSgw5wLYBwBKKefNIUnm9s=
|
||||||
@ -445,6 +461,8 @@ go.uber.org/mock v0.4.0 h1:VcM4ZOtdbR4f6VXfiOpwpVJDL6lCReaZ6mw31wqh7KU=
|
|||||||
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
go.uber.org/mock v0.4.0/go.mod h1:a6FSlNadKUHUa9IP5Vyt1zh4fC7uAwxMutEAscFbkZc=
|
||||||
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
|
||||||
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4 h1:tfq32ie2Jv2UxXFdLJdh3jXuOzWiL1fo0bu/FbuKpbc=
|
||||||
|
go.yaml.in/yaml/v3 v3.0.4/go.mod h1:DhzuOOF2ATzADvBadXxruRBLzYTpT36CKvDb3+aBEFg=
|
||||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
golang.org/x/crypto v0.0.0-20190422162423-af44ce270edf/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
|
||||||
|
|||||||
@ -29,32 +29,16 @@ func (m *mockLikeRepository) Delete(ctx context.Context, id uint) error {
|
|||||||
return args.Error(0)
|
return args.Error(0)
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) ListByUserID(ctx context.Context, userID uint) ([]domain.Like, error) {
|
func (m *mockLikeRepository) ListByUserID(ctx context.Context, userID uint) ([]domain.Like, error) {
|
||||||
args := m.Called(ctx, userID)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]domain.Like), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Like, error) {
|
func (m *mockLikeRepository) ListByWorkID(ctx context.Context, workID uint) ([]domain.Like, error) {
|
||||||
args := m.Called(ctx, workID)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]domain.Like), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) ListByTranslationID(ctx context.Context, translationID uint) ([]domain.Like, error) {
|
func (m *mockLikeRepository) ListByTranslationID(ctx context.Context, translationID uint) ([]domain.Like, error) {
|
||||||
args := m.Called(ctx, translationID)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]domain.Like), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) ListByCommentID(ctx context.Context, commentID uint) ([]domain.Like, error) {
|
func (m *mockLikeRepository) ListByCommentID(ctx context.Context, commentID uint) ([]domain.Like, error) {
|
||||||
args := m.Called(ctx, commentID)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]domain.Like), args.Error(1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Implement the rest of the BaseRepository methods as needed, or panic if they are not expected to be called.
|
// Implement the rest of the BaseRepository methods as needed, or panic if they are not expected to be called.
|
||||||
@ -75,47 +59,26 @@ func (m *mockLikeRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uin
|
|||||||
return m.Delete(ctx, id)
|
return m.Delete(ctx, id)
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Like], error) {
|
func (m *mockLikeRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.Like], error) {
|
||||||
args := m.Called(ctx, page, pageSize)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).(*domain.PaginatedResult[domain.Like]), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Like, error) {
|
func (m *mockLikeRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.Like, error) {
|
||||||
args := m.Called(ctx, options)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]domain.Like), args.Error(1)
|
|
||||||
}
|
|
||||||
func (m *mockLikeRepository) ListAll(ctx context.Context) ([]domain.Like, error) {
|
|
||||||
args := m.Called(ctx)
|
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]domain.Like), args.Error(1)
|
|
||||||
}
|
}
|
||||||
|
func (m *mockLikeRepository) ListAll(ctx context.Context) ([]domain.Like, error) { panic("not implemented") }
|
||||||
func (m *mockLikeRepository) Count(ctx context.Context) (int64, error) {
|
func (m *mockLikeRepository) Count(ctx context.Context) (int64, error) {
|
||||||
args := m.Called(ctx)
|
panic("not implemented")
|
||||||
return args.Get(0).(int64), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
func (m *mockLikeRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
||||||
args := m.Called(ctx, options)
|
panic("not implemented")
|
||||||
return args.Get(0).(int64), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Like, error) {
|
func (m *mockLikeRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.Like, error) {
|
||||||
return m.GetByID(ctx, id)
|
return m.GetByID(ctx, id)
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Like, error) {
|
func (m *mockLikeRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.Like, error) {
|
||||||
args := m.Called(ctx, batchSize, offset)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]domain.Like), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
func (m *mockLikeRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
||||||
args := m.Called(ctx, id)
|
panic("not implemented")
|
||||||
return args.Bool(0), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockLikeRepository) BeginTx(ctx context.Context) (*gorm.DB, error) { return nil, nil }
|
func (m *mockLikeRepository) BeginTx(ctx context.Context) (*gorm.DB, error) { return nil, nil }
|
||||||
func (m *mockLikeRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
func (m *mockLikeRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) error) error {
|
||||||
|
|||||||
@ -1219,31 +1219,7 @@ func (r *queryResolver) Books(ctx context.Context, limit *int32, offset *int32)
|
|||||||
|
|
||||||
// Author is the resolver for the author field.
|
// Author is the resolver for the author field.
|
||||||
func (r *queryResolver) Author(ctx context.Context, id string) (*model.Author, error) {
|
func (r *queryResolver) Author(ctx context.Context, id string) (*model.Author, error) {
|
||||||
authorID, err := strconv.ParseUint(id, 10, 32)
|
panic(fmt.Errorf("not implemented: Author - author"))
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid author ID: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
authorRecord, err := r.App.Author.Queries.Author(ctx, uint(authorID))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if authorRecord == nil {
|
|
||||||
return nil, nil // Or return a "not found" error
|
|
||||||
}
|
|
||||||
|
|
||||||
var bio *string
|
|
||||||
biography, err := r.App.Localization.Queries.GetAuthorBiography(ctx, authorRecord.ID, authorRecord.Language)
|
|
||||||
if err == nil && biography != "" {
|
|
||||||
bio = &biography
|
|
||||||
}
|
|
||||||
|
|
||||||
return &model.Author{
|
|
||||||
ID: fmt.Sprintf("%d", authorRecord.ID),
|
|
||||||
Name: authorRecord.Name,
|
|
||||||
Language: authorRecord.Language,
|
|
||||||
Biography: bio,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Authors is the resolver for the authors field.
|
// Authors is the resolver for the authors field.
|
||||||
@ -1291,33 +1267,7 @@ func (r *queryResolver) Authors(ctx context.Context, limit *int32, offset *int32
|
|||||||
|
|
||||||
// User is the resolver for the user field.
|
// User is the resolver for the user field.
|
||||||
func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) {
|
func (r *queryResolver) User(ctx context.Context, id string) (*model.User, error) {
|
||||||
userID, err := strconv.ParseUint(id, 10, 32)
|
panic(fmt.Errorf("not implemented: User - user"))
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("invalid user ID: %v", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
user, err := r.App.User.Queries.User(ctx, uint(userID))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if user == nil {
|
|
||||||
return nil, nil // Or return a "not found" error
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to GraphQL model
|
|
||||||
return &model.User{
|
|
||||||
ID: fmt.Sprintf("%d", user.ID),
|
|
||||||
Username: user.Username,
|
|
||||||
Email: user.Email,
|
|
||||||
FirstName: &user.FirstName,
|
|
||||||
LastName: &user.LastName,
|
|
||||||
DisplayName: &user.DisplayName,
|
|
||||||
Bio: &user.Bio,
|
|
||||||
AvatarURL: &user.AvatarURL,
|
|
||||||
Role: model.UserRole(user.Role),
|
|
||||||
Verified: user.Verified,
|
|
||||||
Active: user.Active,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserByEmail is the resolver for the userByEmail field.
|
// UserByEmail is the resolver for the userByEmail field.
|
||||||
@ -1394,32 +1344,7 @@ func (r *queryResolver) Users(ctx context.Context, limit *int32, offset *int32,
|
|||||||
|
|
||||||
// Me is the resolver for the me field.
|
// Me is the resolver for the me field.
|
||||||
func (r *queryResolver) Me(ctx context.Context) (*model.User, error) {
|
func (r *queryResolver) Me(ctx context.Context) (*model.User, error) {
|
||||||
// Get user ID from context
|
panic(fmt.Errorf("not implemented: Me - me"))
|
||||||
userID, ok := platform_auth.GetUserIDFromContext(ctx)
|
|
||||||
if !ok {
|
|
||||||
return nil, domain.ErrUnauthorized
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fetch user details
|
|
||||||
user, err := r.App.User.Queries.User(ctx, userID)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
// Convert to GraphQL model
|
|
||||||
return &model.User{
|
|
||||||
ID: fmt.Sprintf("%d", user.ID),
|
|
||||||
Username: user.Username,
|
|
||||||
Email: user.Email,
|
|
||||||
FirstName: &user.FirstName,
|
|
||||||
LastName: &user.LastName,
|
|
||||||
DisplayName: &user.DisplayName,
|
|
||||||
Bio: &user.Bio,
|
|
||||||
AvatarURL: &user.AvatarURL,
|
|
||||||
Role: model.UserRole(user.Role),
|
|
||||||
Verified: user.Verified,
|
|
||||||
Active: user.Active,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// UserProfile is the resolver for the userProfile field.
|
// UserProfile is the resolver for the userProfile field.
|
||||||
|
|||||||
@ -46,43 +46,24 @@ func (m *mockWorkRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uin
|
|||||||
return m.Delete(ctx, id)
|
return m.Delete(ctx, id)
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[work.Work], error) {
|
func (m *mockWorkRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[work.Work], error) {
|
||||||
args := m.Called(ctx, page, pageSize)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).(*domain.PaginatedResult[work.Work]), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]work.Work, error) {
|
func (m *mockWorkRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]work.Work, error) {
|
||||||
args := m.Called(ctx, options)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]work.Work), args.Error(1)
|
|
||||||
}
|
|
||||||
func (m *mockWorkRepository) ListAll(ctx context.Context) ([]work.Work, error) {
|
|
||||||
args := m.Called(ctx)
|
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]work.Work), args.Error(1)
|
|
||||||
}
|
}
|
||||||
|
func (m *mockWorkRepository) ListAll(ctx context.Context) ([]work.Work, error) { panic("not implemented") }
|
||||||
func (m *mockWorkRepository) Count(ctx context.Context) (int64, error) {
|
func (m *mockWorkRepository) Count(ctx context.Context) (int64, error) {
|
||||||
args := m.Called(ctx)
|
args := m.Called(ctx)
|
||||||
return args.Get(0).(int64), args.Error(1)
|
return args.Get(0).(int64), args.Error(1)
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
func (m *mockWorkRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
||||||
args := m.Called(ctx, options)
|
panic("not implemented")
|
||||||
return args.Get(0).(int64), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*work.Work, error) {
|
func (m *mockWorkRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*work.Work, error) {
|
||||||
return m.GetByID(ctx, id)
|
return m.GetByID(ctx, id)
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]work.Work, error) {
|
func (m *mockWorkRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]work.Work, error) {
|
||||||
args := m.Called(ctx, batchSize, offset)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]work.Work), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
func (m *mockWorkRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
||||||
args := m.Called(ctx, id)
|
args := m.Called(ctx, id)
|
||||||
@ -93,32 +74,16 @@ func (m *mockWorkRepository) WithTx(ctx context.Context, fn func(tx *gorm.DB) er
|
|||||||
return fn(nil)
|
return fn(nil)
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) FindByTitle(ctx context.Context, title string) ([]work.Work, error) {
|
func (m *mockWorkRepository) FindByTitle(ctx context.Context, title string) ([]work.Work, error) {
|
||||||
args := m.Called(ctx, title)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]work.Work), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) FindByAuthor(ctx context.Context, authorID uint) ([]work.Work, error) {
|
func (m *mockWorkRepository) FindByAuthor(ctx context.Context, authorID uint) ([]work.Work, error) {
|
||||||
args := m.Called(ctx, authorID)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]work.Work), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) FindByCategory(ctx context.Context, categoryID uint) ([]work.Work, error) {
|
func (m *mockWorkRepository) FindByCategory(ctx context.Context, categoryID uint) ([]work.Work, error) {
|
||||||
args := m.Called(ctx, categoryID)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).([]work.Work), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) FindByLanguage(ctx context.Context, language string, page, pageSize int) (*domain.PaginatedResult[work.Work], error) {
|
func (m *mockWorkRepository) FindByLanguage(ctx context.Context, language string, page, pageSize int) (*domain.PaginatedResult[work.Work], error) {
|
||||||
args := m.Called(ctx, language, page, pageSize)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).(*domain.PaginatedResult[work.Work]), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) GetWithTranslations(ctx context.Context, id uint) (*work.Work, error) {
|
func (m *mockWorkRepository) GetWithTranslations(ctx context.Context, id uint) (*work.Work, error) {
|
||||||
args := m.Called(ctx, id)
|
args := m.Called(ctx, id)
|
||||||
@ -128,11 +93,7 @@ func (m *mockWorkRepository) GetWithTranslations(ctx context.Context, id uint) (
|
|||||||
return args.Get(0).(*work.Work), args.Error(1)
|
return args.Get(0).(*work.Work), args.Error(1)
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) ListWithTranslations(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[work.Work], error) {
|
func (m *mockWorkRepository) ListWithTranslations(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[work.Work], error) {
|
||||||
args := m.Called(ctx, page, pageSize)
|
panic("not implemented")
|
||||||
if args.Get(0) == nil {
|
|
||||||
return nil, args.Error(1)
|
|
||||||
}
|
|
||||||
return args.Get(0).(*domain.PaginatedResult[work.Work]), args.Error(1)
|
|
||||||
}
|
}
|
||||||
func (m *mockWorkRepository) IsAuthor(ctx context.Context, workID uint, authorID uint) (bool, error) {
|
func (m *mockWorkRepository) IsAuthor(ctx context.Context, workID uint, authorID uint) (bool, error) {
|
||||||
args := m.Called(ctx, workID, authorID)
|
args := m.Called(ctx, workID, authorID)
|
||||||
|
|||||||
@ -10,6 +10,28 @@ import (
|
|||||||
"go.opentelemetry.io/otel/trace"
|
"go.opentelemetry.io/otel/trace"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// WorkAnalytics contains analytics data for a work
|
||||||
|
type WorkAnalytics struct {
|
||||||
|
WorkID uint
|
||||||
|
ViewCount int64
|
||||||
|
LikeCount int64
|
||||||
|
CommentCount int64
|
||||||
|
BookmarkCount int64
|
||||||
|
TranslationCount int64
|
||||||
|
ReadabilityScore float64
|
||||||
|
SentimentScore float64
|
||||||
|
TopKeywords []string
|
||||||
|
PopularTranslations []TranslationAnalytics
|
||||||
|
}
|
||||||
|
|
||||||
|
// TranslationAnalytics contains analytics data for a translation
|
||||||
|
type TranslationAnalytics struct {
|
||||||
|
TranslationID uint
|
||||||
|
Language string
|
||||||
|
ViewCount int64
|
||||||
|
LikeCount int64
|
||||||
|
}
|
||||||
|
|
||||||
// WorkQueries contains the query handlers for the work aggregate.
|
// WorkQueries contains the query handlers for the work aggregate.
|
||||||
type WorkQueries struct {
|
type WorkQueries struct {
|
||||||
repo work.WorkRepository
|
repo work.WorkRepository
|
||||||
|
|||||||
@ -1,23 +0,0 @@
|
|||||||
package analytics
|
|
||||||
|
|
||||||
// WorkAnalytics contains analytics data for a work
|
|
||||||
type WorkAnalytics struct {
|
|
||||||
WorkID uint
|
|
||||||
ViewCount int64
|
|
||||||
LikeCount int64
|
|
||||||
CommentCount int64
|
|
||||||
BookmarkCount int64
|
|
||||||
TranslationCount int64
|
|
||||||
ReadabilityScore float64
|
|
||||||
SentimentScore float64
|
|
||||||
TopKeywords []string
|
|
||||||
PopularTranslations []TranslationAnalytics
|
|
||||||
}
|
|
||||||
|
|
||||||
// TranslationAnalytics contains analytics data for a translation
|
|
||||||
type TranslationAnalytics struct {
|
|
||||||
TranslationID uint
|
|
||||||
Language string
|
|
||||||
ViewCount int64
|
|
||||||
LikeCount int64
|
|
||||||
}
|
|
||||||
@ -4,7 +4,6 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"tercul/internal/domain"
|
"tercul/internal/domain"
|
||||||
"tercul/internal/domain/analytics"
|
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"tercul/internal/platform/log"
|
"tercul/internal/platform/log"
|
||||||
@ -16,7 +15,29 @@ type WorkAnalysisService interface {
|
|||||||
AnalyzeWork(ctx context.Context, workID uint) error
|
AnalyzeWork(ctx context.Context, workID uint) error
|
||||||
|
|
||||||
// GetWorkAnalytics retrieves analytics data for a work
|
// GetWorkAnalytics retrieves analytics data for a work
|
||||||
GetWorkAnalytics(ctx context.Context, workID uint) (*analytics.WorkAnalytics, error)
|
GetWorkAnalytics(ctx context.Context, workID uint) (*WorkAnalytics, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// WorkAnalytics contains analytics data for a work
|
||||||
|
type WorkAnalytics struct {
|
||||||
|
WorkID uint
|
||||||
|
ViewCount int64
|
||||||
|
LikeCount int64
|
||||||
|
CommentCount int64
|
||||||
|
BookmarkCount int64
|
||||||
|
TranslationCount int64
|
||||||
|
ReadabilityScore float64
|
||||||
|
SentimentScore float64
|
||||||
|
TopKeywords []string
|
||||||
|
PopularTranslations []TranslationAnalytics
|
||||||
|
}
|
||||||
|
|
||||||
|
// TranslationAnalytics contains analytics data for a translation
|
||||||
|
type TranslationAnalytics struct {
|
||||||
|
TranslationID uint
|
||||||
|
Language string
|
||||||
|
ViewCount int64
|
||||||
|
LikeCount int64
|
||||||
}
|
}
|
||||||
|
|
||||||
// workAnalysisService implements the WorkAnalysisService interface
|
// workAnalysisService implements the WorkAnalysisService interface
|
||||||
@ -129,7 +150,7 @@ func (s *workAnalysisService) AnalyzeWork(ctx context.Context, workID uint) erro
|
|||||||
}
|
}
|
||||||
|
|
||||||
// GetWorkAnalytics retrieves analytics data for a work
|
// GetWorkAnalytics retrieves analytics data for a work
|
||||||
func (s *workAnalysisService) GetWorkAnalytics(ctx context.Context, workID uint) (*analytics.WorkAnalytics, error) {
|
func (s *workAnalysisService) GetWorkAnalytics(ctx context.Context, workID uint) (*WorkAnalytics, error) {
|
||||||
if workID == 0 {
|
if workID == 0 {
|
||||||
return nil, fmt.Errorf("invalid work ID")
|
return nil, fmt.Errorf("invalid work ID")
|
||||||
}
|
}
|
||||||
@ -158,7 +179,7 @@ func (s *workAnalysisService) GetWorkAnalytics(ctx context.Context, workID uint)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// For now, return placeholder analytics with actual analysis data
|
// For now, return placeholder analytics with actual analysis data
|
||||||
return &analytics.WorkAnalytics{
|
return &WorkAnalytics{
|
||||||
WorkID: work.ID,
|
WorkID: work.ID,
|
||||||
ViewCount: 0, // TODO: Implement view counting
|
ViewCount: 0, // TODO: Implement view counting
|
||||||
LikeCount: 0, // TODO: Implement like counting
|
LikeCount: 0, // TODO: Implement like counting
|
||||||
@ -168,7 +189,7 @@ func (s *workAnalysisService) GetWorkAnalytics(ctx context.Context, workID uint)
|
|||||||
ReadabilityScore: readabilityScore.Score,
|
ReadabilityScore: readabilityScore.Score,
|
||||||
SentimentScore: extractSentimentFromAnalysis(languageAnalysis.Analysis),
|
SentimentScore: extractSentimentFromAnalysis(languageAnalysis.Analysis),
|
||||||
TopKeywords: keywords,
|
TopKeywords: keywords,
|
||||||
PopularTranslations: []analytics.TranslationAnalytics{}, // TODO: Implement translation analytics
|
PopularTranslations: []TranslationAnalytics{}, // TODO: Implement translation analytics
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -64,6 +64,6 @@ func RegisterQueueHandlers(srv *asynq.Server, syncJob *SyncJob) {
|
|||||||
mux.HandleFunc(TaskEntitySync, syncJob.HandleEntitySync)
|
mux.HandleFunc(TaskEntitySync, syncJob.HandleEntitySync)
|
||||||
mux.HandleFunc(TaskEdgeSync, syncJob.HandleEdgeSync)
|
mux.HandleFunc(TaskEdgeSync, syncJob.HandleEdgeSync)
|
||||||
if err := srv.Run(mux); err != nil {
|
if err := srv.Run(mux); err != nil {
|
||||||
log.Printf("Failed to start asynq server: %v", err)
|
log.Fatalf("Failed to start asynq server: %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
12
internal/platform/cache/redis_cache.go
vendored
12
internal/platform/cache/redis_cache.go
vendored
@ -5,11 +5,11 @@ import (
|
|||||||
"encoding/json"
|
"encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"tercul/internal/platform/config"
|
||||||
|
"tercul/internal/platform/log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/redis/go-redis/v9"
|
"github.com/redis/go-redis/v9"
|
||||||
"tercul/internal/platform/config"
|
|
||||||
"tercul/internal/platform/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// RedisCache implements the Cache interface using Redis
|
// RedisCache implements the Cache interface using Redis
|
||||||
@ -37,12 +37,12 @@ func NewRedisCache(client *redis.Client, keyGenerator KeyGenerator, defaultExpir
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewDefaultRedisCache creates a new RedisCache with default settings
|
// NewDefaultRedisCache creates a new RedisCache with default settings
|
||||||
func NewDefaultRedisCache() (*RedisCache, error) {
|
func NewDefaultRedisCache(cfg *config.Config) (*RedisCache, error) {
|
||||||
// Create Redis client from config
|
// Create Redis client from config
|
||||||
client := redis.NewClient(&redis.Options{
|
client := redis.NewClient(&redis.Options{
|
||||||
Addr: config.Cfg.RedisAddr,
|
Addr: cfg.RedisAddr,
|
||||||
Password: config.Cfg.RedisPassword,
|
Password: cfg.RedisPassword,
|
||||||
DB: config.Cfg.RedisDB,
|
DB: cfg.RedisDB,
|
||||||
})
|
})
|
||||||
|
|
||||||
// Test connection
|
// Test connection
|
||||||
|
|||||||
@ -1,159 +1,57 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"github.com/spf13/viper"
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"strconv"
|
|
||||||
"time"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// Config holds all configuration for the application
|
// Config stores all configuration of the application.
|
||||||
type Config struct {
|
type Config struct {
|
||||||
// Database configuration
|
Environment string `mapstructure:"ENVIRONMENT"`
|
||||||
DBHost string
|
ServerPort string `mapstructure:"SERVER_PORT"`
|
||||||
DBPort string
|
DBHost string `mapstructure:"DB_HOST"`
|
||||||
DBUser string
|
DBPort string `mapstructure:"DB_PORT"`
|
||||||
DBPassword string
|
DBUser string `mapstructure:"DB_USER"`
|
||||||
DBName string
|
DBPassword string `mapstructure:"DB_PASSWORD"`
|
||||||
DBSSLMode string
|
DBName string `mapstructure:"DB_NAME"`
|
||||||
DBTimeZone string
|
JWTSecret string `mapstructure:"JWT_SECRET"`
|
||||||
|
JWTExpiration int `mapstructure:"JWT_EXPIRATION_HOURS"`
|
||||||
// Weaviate configuration
|
WeaviateHost string `mapstructure:"WEAVIATE_HOST"`
|
||||||
WeaviateScheme string
|
WeaviateScheme string `mapstructure:"WEAVIATE_SCHEME"`
|
||||||
WeaviateHost string
|
MigrationPath string `mapstructure:"MIGRATION_PATH"`
|
||||||
|
RedisAddr string `mapstructure:"REDIS_ADDR"`
|
||||||
// Redis configuration
|
RedisPassword string `mapstructure:"REDIS_PASSWORD"`
|
||||||
RedisAddr string
|
RedisDB int `mapstructure:"REDIS_DB"`
|
||||||
RedisPassword string
|
SyncBatchSize int `mapstructure:"SYNC_BATCH_SIZE"`
|
||||||
RedisDB int
|
RateLimit int `mapstructure:"RATE_LIMIT"`
|
||||||
|
RateLimitBurst int `mapstructure:"RATE_LIMIT_BURST"`
|
||||||
// Application configuration
|
|
||||||
Port string
|
|
||||||
ServerPort string
|
|
||||||
Environment string
|
|
||||||
LogLevel string
|
|
||||||
|
|
||||||
// Performance configuration
|
|
||||||
BatchSize int
|
|
||||||
PageSize int
|
|
||||||
RetryInterval time.Duration
|
|
||||||
MaxRetries int
|
|
||||||
|
|
||||||
// Security configuration
|
|
||||||
RateLimit int // Requests per second
|
|
||||||
RateLimitBurst int // Maximum burst size
|
|
||||||
JWTSecret string
|
|
||||||
JWTExpiration time.Duration
|
|
||||||
|
|
||||||
// NLP providers configuration
|
|
||||||
NLPUseLingua bool
|
|
||||||
NLPUseVADER bool
|
|
||||||
NLPUseTFIDF bool
|
|
||||||
|
|
||||||
// NLP cache configuration
|
|
||||||
NLPMemoryCacheCap int
|
|
||||||
NLPRedisCacheTTLSeconds int
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cfg is the global configuration instance
|
// LoadConfig reads configuration from file or environment variables.
|
||||||
var Cfg Config
|
func LoadConfig() (*Config, error) {
|
||||||
|
viper.SetDefault("ENVIRONMENT", "development")
|
||||||
|
viper.SetDefault("SERVER_PORT", ":8080")
|
||||||
|
viper.SetDefault("DB_HOST", "localhost")
|
||||||
|
viper.SetDefault("DB_PORT", "5432")
|
||||||
|
viper.SetDefault("DB_USER", "user")
|
||||||
|
viper.SetDefault("DB_PASSWORD", "password")
|
||||||
|
viper.SetDefault("DB_NAME", "tercul")
|
||||||
|
viper.SetDefault("JWT_SECRET", "secret")
|
||||||
|
viper.SetDefault("JWT_EXPIRATION_HOURS", 24)
|
||||||
|
viper.SetDefault("WEAVIATE_HOST", "localhost:8080")
|
||||||
|
viper.SetDefault("WEAVIATE_SCHEME", "http")
|
||||||
|
viper.SetDefault("MIGRATION_PATH", "internal/data/migrations")
|
||||||
|
viper.SetDefault("REDIS_ADDR", "localhost:6379")
|
||||||
|
viper.SetDefault("REDIS_PASSWORD", "")
|
||||||
|
viper.SetDefault("REDIS_DB", 0)
|
||||||
|
viper.SetDefault("SYNC_BATCH_SIZE", 100)
|
||||||
|
viper.SetDefault("RATE_LIMIT", 10)
|
||||||
|
viper.SetDefault("RATE_LIMIT_BURST", 100)
|
||||||
|
|
||||||
// LoadConfig loads configuration from environment variables
|
viper.AutomaticEnv()
|
||||||
func LoadConfig() {
|
|
||||||
Cfg = Config{
|
|
||||||
// Database configuration
|
|
||||||
DBHost: getEnv("DB_HOST", "localhost"),
|
|
||||||
DBPort: getEnv("DB_PORT", "5432"),
|
|
||||||
DBUser: getEnv("DB_USER", "postgres"),
|
|
||||||
DBPassword: getEnv("DB_PASSWORD", "postgres"),
|
|
||||||
DBName: getEnv("DB_NAME", "tercul"),
|
|
||||||
DBSSLMode: getEnv("DB_SSLMODE", "disable"),
|
|
||||||
DBTimeZone: getEnv("DB_TIMEZONE", "UTC"),
|
|
||||||
|
|
||||||
// Weaviate configuration
|
var config Config
|
||||||
WeaviateScheme: getEnv("WEAVIATE_SCHEME", "http"),
|
if err := viper.Unmarshal(&config); err != nil {
|
||||||
WeaviateHost: getEnv("WEAVIATE_HOST", "localhost:8080"),
|
return nil, err
|
||||||
|
|
||||||
// Redis configuration
|
|
||||||
RedisAddr: getEnv("REDIS_ADDR", "127.0.0.1:6379"),
|
|
||||||
RedisPassword: getEnv("REDIS_PASSWORD", ""),
|
|
||||||
RedisDB: getEnvAsInt("REDIS_DB", 0),
|
|
||||||
|
|
||||||
// Application configuration
|
|
||||||
Port: getEnv("PORT", "8080"),
|
|
||||||
ServerPort: getEnv("SERVER_PORT", "8080"),
|
|
||||||
Environment: getEnv("ENVIRONMENT", "development"),
|
|
||||||
LogLevel: getEnv("LOG_LEVEL", "info"),
|
|
||||||
|
|
||||||
// Performance configuration
|
|
||||||
BatchSize: getEnvAsInt("BATCH_SIZE", 100),
|
|
||||||
PageSize: getEnvAsInt("PAGE_SIZE", 20),
|
|
||||||
RetryInterval: time.Duration(getEnvAsInt("RETRY_INTERVAL_SECONDS", 2)) * time.Second,
|
|
||||||
MaxRetries: getEnvAsInt("MAX_RETRIES", 3),
|
|
||||||
|
|
||||||
// Security configuration
|
|
||||||
RateLimit: getEnvAsInt("RATE_LIMIT", 10), // 10 requests per second by default
|
|
||||||
RateLimitBurst: getEnvAsInt("RATE_LIMIT_BURST", 50), // 50 burst requests by default
|
|
||||||
JWTSecret: getEnv("JWT_SECRET", ""),
|
|
||||||
JWTExpiration: time.Duration(getEnvAsInt("JWT_EXPIRATION_HOURS", 24)) * time.Hour,
|
|
||||||
|
|
||||||
// NLP providers configuration (enabled by default)
|
|
||||||
NLPUseLingua: getEnvAsBool("NLP_USE_LINGUA", true),
|
|
||||||
NLPUseVADER: getEnvAsBool("NLP_USE_VADER", true),
|
|
||||||
NLPUseTFIDF: getEnvAsBool("NLP_USE_TFIDF", true),
|
|
||||||
|
|
||||||
// NLP cache configuration
|
|
||||||
NLPMemoryCacheCap: getEnvAsInt("NLP_MEMORY_CACHE_CAP", 1024),
|
|
||||||
NLPRedisCacheTTLSeconds: getEnvAsInt("NLP_REDIS_CACHE_TTL_SECONDS", 86400),
|
|
||||||
}
|
|
||||||
|
|
||||||
log.Printf("Configuration loaded: Environment=%s, LogLevel=%s", Cfg.Environment, Cfg.LogLevel)
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetDSN returns the database connection string
|
|
||||||
func (c *Config) GetDSN() string {
|
|
||||||
return fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s TimeZone=%s",
|
|
||||||
c.DBHost, c.DBPort, c.DBUser, c.DBPassword, c.DBName, c.DBSSLMode, c.DBTimeZone)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Helper functions for environment variables
|
|
||||||
|
|
||||||
// getEnv gets an environment variable or returns a default value
|
|
||||||
func getEnv(key, defaultValue string) string {
|
|
||||||
value, exists := os.LookupEnv(key)
|
|
||||||
if !exists {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// getEnvAsInt gets an environment variable as an integer or returns a default value
|
|
||||||
func getEnvAsInt(key string, defaultValue int) int {
|
|
||||||
valueStr := getEnv(key, "")
|
|
||||||
if valueStr == "" {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
value, err := strconv.Atoi(valueStr)
|
|
||||||
if err != nil {
|
|
||||||
log.Printf("Warning: Invalid value for %s, using default: %v", key, err)
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
return value
|
|
||||||
}
|
|
||||||
|
|
||||||
// getEnvAsBool gets an environment variable as a boolean or returns a default value
|
|
||||||
func getEnvAsBool(key string, defaultValue bool) bool {
|
|
||||||
valueStr := getEnv(key, "")
|
|
||||||
if valueStr == "" {
|
|
||||||
return defaultValue
|
|
||||||
}
|
|
||||||
switch valueStr {
|
|
||||||
case "1", "true", "TRUE", "True", "yes", "YES", "Yes", "on", "ON", "On":
|
|
||||||
return true
|
|
||||||
case "0", "false", "FALSE", "False", "no", "NO", "No", "off", "OFF", "Off":
|
|
||||||
return false
|
|
||||||
default:
|
|
||||||
return defaultValue
|
|
||||||
}
|
}
|
||||||
|
return &config, nil
|
||||||
}
|
}
|
||||||
@ -3,24 +3,23 @@ package db
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"tercul/internal/observability"
|
"tercul/internal/observability"
|
||||||
|
"tercul/internal/platform/config"
|
||||||
|
"tercul/internal/platform/log"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"gorm.io/driver/postgres"
|
"gorm.io/driver/postgres"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
gormlogger "gorm.io/gorm/logger"
|
gormlogger "gorm.io/gorm/logger"
|
||||||
"tercul/internal/platform/config"
|
|
||||||
"tercul/internal/platform/log"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DB is a global database connection instance
|
// Connect establishes a connection to the database using the provided configuration.
|
||||||
var DB *gorm.DB
|
// It returns the database connection and any error encountered.
|
||||||
|
func Connect(cfg *config.Config, metrics *observability.Metrics) (*gorm.DB, error) {
|
||||||
|
log.Info(fmt.Sprintf("Connecting to database: host=%s db=%s", cfg.DBHost, cfg.DBName))
|
||||||
|
|
||||||
// Connect establishes a connection to the database using configuration settings
|
dsn := fmt.Sprintf("host=%s user=%s password=%s dbname=%s port=%s sslmode=disable",
|
||||||
// It returns the database connection and any error encountered
|
cfg.DBHost, cfg.DBUser, cfg.DBPassword, cfg.DBName, cfg.DBPort)
|
||||||
func Connect(metrics *observability.Metrics) (*gorm.DB, error) {
|
|
||||||
log.Info(fmt.Sprintf("Connecting to database: host=%s db=%s", config.Cfg.DBHost, config.Cfg.DBName))
|
|
||||||
|
|
||||||
dsn := config.Cfg.GetDSN()
|
|
||||||
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
|
db, err := gorm.Open(postgres.Open(dsn), &gorm.Config{
|
||||||
Logger: gormlogger.Default.LogMode(gormlogger.Warn),
|
Logger: gormlogger.Default.LogMode(gormlogger.Warn),
|
||||||
})
|
})
|
||||||
@ -33,9 +32,6 @@ func Connect(metrics *observability.Metrics) (*gorm.DB, error) {
|
|||||||
return nil, fmt.Errorf("failed to register prometheus plugin: %w", err)
|
return nil, fmt.Errorf("failed to register prometheus plugin: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the global DB instance
|
|
||||||
DB = db
|
|
||||||
|
|
||||||
// Get the underlying SQL DB instance
|
// Get the underlying SQL DB instance
|
||||||
sqlDB, err := db.DB()
|
sqlDB, err := db.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -47,18 +43,18 @@ func Connect(metrics *observability.Metrics) (*gorm.DB, error) {
|
|||||||
sqlDB.SetMaxIdleConns(5) // Idle connections
|
sqlDB.SetMaxIdleConns(5) // Idle connections
|
||||||
sqlDB.SetConnMaxLifetime(30 * time.Minute)
|
sqlDB.SetConnMaxLifetime(30 * time.Minute)
|
||||||
|
|
||||||
log.Info(fmt.Sprintf("Successfully connected to database: host=%s db=%s", config.Cfg.DBHost, config.Cfg.DBName))
|
log.Info(fmt.Sprintf("Successfully connected to database: host=%s db=%s", cfg.DBHost, cfg.DBName))
|
||||||
|
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the database connection
|
// Close closes the database connection.
|
||||||
func Close() error {
|
func Close(db *gorm.DB) error {
|
||||||
if DB == nil {
|
if db == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
sqlDB, err := DB.DB()
|
sqlDB, err := db.DB()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("failed to get SQL DB instance: %w", err)
|
return fmt.Errorf("failed to get SQL DB instance: %w", err)
|
||||||
}
|
}
|
||||||
@ -66,16 +62,12 @@ func Close() error {
|
|||||||
return sqlDB.Close()
|
return sqlDB.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
// InitDB initializes the database connection and runs migrations
|
// InitDB initializes the database connection.
|
||||||
// It returns the database connection and any error encountered
|
func InitDB(cfg *config.Config, metrics *observability.Metrics) (*gorm.DB, error) {
|
||||||
func InitDB(metrics *observability.Metrics) (*gorm.DB, error) {
|
|
||||||
// Connect to the database
|
// Connect to the database
|
||||||
db, err := Connect(metrics)
|
db, err := Connect(cfg, metrics)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Migrations are now handled by a separate tool
|
|
||||||
|
|
||||||
return db, nil
|
return db, nil
|
||||||
}
|
}
|
||||||
@ -98,62 +98,29 @@ func (m *MockUserRepository) DeleteInTx(ctx context.Context, tx *gorm.DB, id uin
|
|||||||
return m.Delete(ctx, id)
|
return m.Delete(ctx, id)
|
||||||
}
|
}
|
||||||
func (m *MockUserRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.User], error) {
|
func (m *MockUserRepository) List(ctx context.Context, page, pageSize int) (*domain.PaginatedResult[domain.User], error) {
|
||||||
start := (page - 1) * pageSize
|
panic("not implemented")
|
||||||
end := start + pageSize
|
|
||||||
if start > len(m.Users) {
|
|
||||||
start = len(m.Users)
|
|
||||||
}
|
|
||||||
if end > len(m.Users) {
|
|
||||||
end = len(m.Users)
|
|
||||||
}
|
|
||||||
users := m.Users[start:end]
|
|
||||||
var resultUsers []domain.User
|
|
||||||
for _, u := range users {
|
|
||||||
resultUsers = append(resultUsers, *u)
|
|
||||||
}
|
|
||||||
return &domain.PaginatedResult[domain.User]{
|
|
||||||
Items: resultUsers,
|
|
||||||
TotalCount: int64(len(m.Users)),
|
|
||||||
Page: page,
|
|
||||||
PageSize: pageSize,
|
|
||||||
}, nil
|
|
||||||
}
|
}
|
||||||
func (m *MockUserRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.User, error) {
|
func (m *MockUserRepository) ListWithOptions(ctx context.Context, options *domain.QueryOptions) ([]domain.User, error) {
|
||||||
// This is a mock implementation, so we'll just return all users for now.
|
panic("not implemented")
|
||||||
return m.ListAll(ctx)
|
|
||||||
}
|
}
|
||||||
func (m *MockUserRepository) ListAll(ctx context.Context) ([]domain.User, error) {
|
func (m *MockUserRepository) ListAll(ctx context.Context) ([]domain.User, error) {
|
||||||
var users []domain.User
|
var users []domain.User
|
||||||
for _, u := range m.Users {
|
for _, u := range m.Users {
|
||||||
users = append(users, *u)
|
users = append(users, *u)
|
||||||
}
|
}
|
||||||
return users, nil
|
return users, nil
|
||||||
}
|
}
|
||||||
func (m *MockUserRepository) Count(ctx context.Context) (int64, error) {
|
func (m *MockUserRepository) Count(ctx context.Context) (int64, error) {
|
||||||
return int64(len(m.Users)), nil
|
return int64(len(m.Users)), nil
|
||||||
}
|
}
|
||||||
func (m *MockUserRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
func (m *MockUserRepository) CountWithOptions(ctx context.Context, options *domain.QueryOptions) (int64, error) {
|
||||||
// This is a mock implementation, so we'll just return the total count for now.
|
panic("not implemented")
|
||||||
return m.Count(ctx)
|
|
||||||
}
|
}
|
||||||
func (m *MockUserRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.User, error) {
|
func (m *MockUserRepository) FindWithPreload(ctx context.Context, preloads []string, id uint) (*domain.User, error) {
|
||||||
return m.GetByID(ctx, id)
|
return m.GetByID(ctx, id)
|
||||||
}
|
}
|
||||||
func (m *MockUserRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.User, error) {
|
func (m *MockUserRepository) GetAllForSync(ctx context.Context, batchSize, offset int) ([]domain.User, error) {
|
||||||
start := offset
|
panic("not implemented")
|
||||||
end := start + batchSize
|
|
||||||
if start > len(m.Users) {
|
|
||||||
return []domain.User{}, nil
|
|
||||||
}
|
|
||||||
if end > len(m.Users) {
|
|
||||||
end = len(m.Users)
|
|
||||||
}
|
|
||||||
users := m.Users[start:end]
|
|
||||||
var resultUsers []domain.User
|
|
||||||
for _, u := range users {
|
|
||||||
resultUsers = append(resultUsers, *u)
|
|
||||||
}
|
|
||||||
return resultUsers, nil
|
|
||||||
}
|
}
|
||||||
func (m *MockUserRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
func (m *MockUserRepository) Exists(ctx context.Context, id uint) (bool, error) {
|
||||||
_, err := m.GetByID(ctx, id)
|
_, err := m.GetByID(ctx, id)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user