From 3c6748d5b3e0946544d0440f93e43a765b0fc29b Mon Sep 17 00:00:00 2001 From: mm Date: Mon, 9 Sep 2024 03:32:10 +0500 Subject: [PATCH] test --- Dockerfile | 2 +- {cmd/docs => api/http}/docs.go | 2 +- {cmd/docs => api/http}/swagger.json | 0 {cmd/docs => api/http}/swagger.yaml | 0 cmd/main.go | 30 +-------- infrastructure/pg/connection.go | 55 +++++++++------- infrastructure/pg/models.go | 4 +- internal/api/http/handlers/widget/create.go | 51 ++++++++++++++ internal/app/http/app.go | 73 +++++++++++++++++++++ internal/config/config.go | 32 +++++++++ config.yaml => internal/config/config.yaml | 0 internal/repository/widget/create.go | 31 +++++++++ internal/repository/widget/init.go | 19 ++++++ internal/service/widget/create.go | 16 +++++ internal/service/widget/delete.go | 15 +++++ internal/service/widget/init.go | 19 ++++++ {lib => pkg}/validator/validator.go | 0 17 files changed, 296 insertions(+), 53 deletions(-) rename {cmd/docs => api/http}/docs.go (99%) rename {cmd/docs => api/http}/swagger.json (100%) rename {cmd/docs => api/http}/swagger.yaml (100%) create mode 100644 internal/app/http/app.go rename config.yaml => internal/config/config.yaml (100%) create mode 100644 internal/repository/widget/init.go create mode 100644 internal/service/widget/init.go rename {lib => pkg}/validator/validator.go (100%) diff --git a/Dockerfile b/Dockerfile index c0ff6f5..08ee2c0 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,6 +3,6 @@ FROM golang:1.23-alpine WORKDIR /root COPY . . RUN go install github.com/swaggo/swag/cmd/swag@latest -RUN go mod tidy && swag init -g cmd/main.go -o cmd/docs +RUN go mod tidy && swag init -g cmd/main.go -o api/http CMD go run cmd/main.go \ No newline at end of file diff --git a/cmd/docs/docs.go b/api/http/docs.go similarity index 99% rename from cmd/docs/docs.go rename to api/http/docs.go index 93cdb0e..711e2cd 100644 --- a/cmd/docs/docs.go +++ b/api/http/docs.go @@ -1,5 +1,5 @@ // Package docs Code generated by swaggo/swag. DO NOT EDIT -package docs +package http import "github.com/swaggo/swag" diff --git a/cmd/docs/swagger.json b/api/http/swagger.json similarity index 100% rename from cmd/docs/swagger.json rename to api/http/swagger.json diff --git a/cmd/docs/swagger.yaml b/api/http/swagger.yaml similarity index 100% rename from cmd/docs/swagger.yaml rename to api/http/swagger.yaml diff --git a/cmd/main.go b/cmd/main.go index 6a7b3c1..e086a3f 100644 --- a/cmd/main.go +++ b/cmd/main.go @@ -1,17 +1,6 @@ package main -import ( - "github.com/labstack/echo/v4" - "log/slog" - "os" -) - -import ( - _ "donat-widget/cmd/docs" - "donat-widget/cmd/handlers" - "donat-widget/config" - "donat-widget/lib/validator" -) +import "donat-widget/internal/app/http" // @title Widget service // @version 1.0 @@ -20,20 +9,7 @@ import ( // @host localhost:8002 // @BasePath /api/widget -func init() { - logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) - slog.SetDefault(logger) -} - func main() { - app := initApp() - port := config.Config.Server.Port - app.Logger.Fatal(app.Start(":" + port)) -} - -func initApp() *echo.Echo { - app := echo.New() - app.Validator = validator.NewValidator() - handlers.IncludeRouters(app) - return app + httpServer := http.NewApp() + http.Run(httpServer) } diff --git a/infrastructure/pg/connection.go b/infrastructure/pg/connection.go index aba4327..57a25aa 100644 --- a/infrastructure/pg/connection.go +++ b/infrastructure/pg/connection.go @@ -2,14 +2,13 @@ package pg import ( "context" - "donat-widget/config" "fmt" "github.com/jackc/pgx/v5/pgxpool" "sync" ) type Postgres struct { - Db *pgxpool.Pool + db *pgxpool.Pool } var ( @@ -20,7 +19,7 @@ var ( func NewPgPool( ctx context.Context, username, password, host, port, dbname string, -) (*Postgres, error) { +) *Postgres { connString := "postgres://" + username + ":" + password + "@" + host + ":" + port + "/" + dbname + "?pool_max_conns=100" pgOnce.Do(func() { db, err := pgxpool.New(ctx, connString) @@ -30,20 +29,11 @@ func NewPgPool( pgInstance = &Postgres{db} }) - return pgInstance, nil -} - -func (pg *Postgres) Ping(ctx context.Context) error { - err := pg.Db.Ping(ctx) - return err -} - -func (pg *Postgres) Close() { - pg.Db.Close() + return pgInstance } func (pg *Postgres) CreateTable(ctx context.Context) error { - result, err := pg.Db.Exec(ctx, createTableQuery) + result, err := pg.db.Exec(ctx, createTableQuery) if err != nil { return err } @@ -51,11 +41,32 @@ func (pg *Postgres) CreateTable(ctx context.Context) error { return nil } -var Pool, _ = NewPgPool( - context.Background(), - config.Config.Database.Username, - config.Config.Database.Password, - config.Config.Database.Host, - config.Config.Database.Port, - config.Config.Database.DBName, -) +func (pg *Postgres) DropTable(ctx context.Context) error { + result, err := pg.db.Exec(ctx, dropTableQuery) + if err != nil { + return err + } + fmt.Println(result) + return nil +} + +func (pg *Postgres) Exec(ctx context.Context, query string, args ...interface{}) (interface{}, error) { + result, err := pg.db.Exec(ctx, query, args...) + if err != nil { + return nil, err + } + return result, nil +} + +func (pg *Postgres) Query(ctx context.Context, query string, args ...interface{}) (interface{}, error) { + result, err := pg.db.Query(ctx, query, args...) + if err != nil { + return nil, err + } + return result, nil +} + +func (pg *Postgres) QueryRow(ctx context.Context, query string, args ...interface{}) interface{} { + result := pg.db.QueryRow(ctx, query, args...) + return result +} diff --git a/infrastructure/pg/models.go b/infrastructure/pg/models.go index 599bbaa..b9af5e3 100644 --- a/infrastructure/pg/models.go +++ b/infrastructure/pg/models.go @@ -9,7 +9,7 @@ var createTableQuery = ` video TEXT DEFAULT '', image TEXT DEFAULT '', audio TEXT DEFAULT '', - duration TEXT DEFAULT '', + duration INTEGER DEFAULT 30, display BOOLEAN DEFAULT TRUE, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP @@ -32,5 +32,5 @@ CREATE OR REPLACE FUNCTION update_updated_at() ` var dropTableQuery = ` - DROP TABLE IF EXISTS test_users; + DROP TABLE IF EXISTS widgets; ` diff --git a/internal/api/http/handlers/widget/create.go b/internal/api/http/handlers/widget/create.go index 3c5635c..e25a15c 100644 --- a/internal/api/http/handlers/widget/create.go +++ b/internal/api/http/handlers/widget/create.go @@ -1 +1,52 @@ package widget + +import ( + "context" + "github.com/labstack/echo/v4" + "log/slog" + "strconv" +) + +type requestModel struct { + UserId int `json:"userId" validate:"required"` +} + +type responseModel struct { + WidgetId int `json:"widgetId"` +} + +type Creator interface { + Create(ctx context.Context, userId int) (int, error) +} + +// Create @Description Create widget +// +// @Tags Widget +// @Accept json +// @Produce json +// @Param RegisterData body requestModel true "Create widget" +// @Success 200 {object} responseModel +// @Router /api/widget/create [post] +func Create(service Creator, log *slog.Logger) echo.HandlerFunc { + return func(request echo.Context) error { + ctx := context.Background() + var widgetData requestModel + if err := request.Bind(&widgetData); err != nil { + slog.Error(err.Error()) + return echo.NewHTTPError(400, err.Error()) + } + + err := request.Validate(&widgetData) + if err != nil { + slog.Error(err.Error()) + return echo.NewHTTPError(400, err.Error()) + } + + id, err := service.Create(ctx, widgetData.UserId) + if err != nil { + slog.Error(err.Error()) + return request.JSON(422, err) + } + return request.String(200, strconv.FormatUint(uint64(id), 10)) + } +} diff --git a/internal/app/http/app.go b/internal/app/http/app.go new file mode 100644 index 0000000..f82b08b --- /dev/null +++ b/internal/app/http/app.go @@ -0,0 +1,73 @@ +package http + +import ( + "context" + _ "donat-widget/api/http" + "donat-widget/infrastructure/pg" + widgetHandler "donat-widget/internal/api/http/handlers/widget" + "donat-widget/internal/config" + "donat-widget/pkg/validator" + "github.com/labstack/echo/v4" + "github.com/swaggo/echo-swagger" + "log/slog" + "os" +) + +import ( + widgetService "donat-widget/internal/service/widget" +) + +type App struct { + Config *config.Config +} + +func NewApp() *echo.Echo { + app := &App{} + cfg := app.InitConfig() + pool := app.initDB(cfg) + log := app.InitLogger() + + server := InitHTTPServer() + InitHandlers(server, pool, log) + + return server +} + +func Run(server *echo.Echo) { + server.Logger.Fatal(server.Start(":8002")) +} + +func InitHTTPServer() *echo.Echo { + server := echo.New() + server.Validator = validator.NewValidator() + return server +} + +func (a *App) InitConfig() *config.Config { + cfg := config.Init() + return cfg +} + +func (a *App) initDB(cfg *config.Config) *pg.Postgres { + pool := pg.NewPgPool( + context.Background(), + cfg.Database.Username, + cfg.Database.Password, + cfg.Database.Host, + cfg.Database.Port, + cfg.Database.DBName, + ) + return pool +} + +func InitHandlers(server *echo.Echo, pool *pg.Postgres, log *slog.Logger) { + PREFIX := "/api/widget" + server.GET("/api/docs/*", echoSwagger.WrapHandler) + widgetSvc := widgetService.New(pool) + server.GET(PREFIX+"/create", widgetHandler.Create(widgetSvc, log)) +} + +func (a *App) InitLogger() *slog.Logger { + logger := slog.New(slog.NewJSONHandler(os.Stdout, nil)) + return logger +} diff --git a/internal/config/config.go b/internal/config/config.go index d912156..73b4f1f 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -1 +1,33 @@ package config + +import ( + "gopkg.in/yaml.v2" + "os" +) + +type Config struct { + Database DatabaseConfig `yaml:"db"` +} + +type DatabaseConfig struct { + Username string `yaml:"username"` + Password string `yaml:"password"` + Host string `yaml:"host"` + Port string `yaml:"port"` + DBName string `yaml:"dbname"` +} + +func Init() *Config { + data, err := os.ReadFile("internal/config/config.yaml") + if err != nil { + panic(err) + } + + var cfg Config + + err = yaml.Unmarshal(data, &cfg) + if err != nil { + panic(err) + } + return &cfg +} diff --git a/config.yaml b/internal/config/config.yaml similarity index 100% rename from config.yaml rename to internal/config/config.yaml diff --git a/internal/repository/widget/create.go b/internal/repository/widget/create.go index 3c5635c..0876b82 100644 --- a/internal/repository/widget/create.go +++ b/internal/repository/widget/create.go @@ -1 +1,32 @@ package widget + +import ( + "context" + "fmt" + "github.com/jackc/pgx/v5" +) + +type User struct { + Id int `json:"id"` + Login string `json:"login"` +} + +func (r *Repository) Create( + ctx context.Context, + userId int, +) (int, error) { + query := ` + INSERT INTO widgets (userId) + VALUES (@userId); + ` + args := pgx.NamedArgs{ + "userId": userId, + } + result, err := r.Exec(ctx, query, args) + if err != nil { + return 0, err + } + widgetId := 9 + fmt.Println(result) + return widgetId, nil +} diff --git a/internal/repository/widget/init.go b/internal/repository/widget/init.go new file mode 100644 index 0000000..ceb81a3 --- /dev/null +++ b/internal/repository/widget/init.go @@ -0,0 +1,19 @@ +package widget + +import ( + "context" +) + +type Pool interface { + Exec(ctx context.Context, query string, args ...interface{}) (interface{}, error) + Query(ctx context.Context, query string, args ...interface{}) (interface{}, error) + QueryRow(ctx context.Context, query string, args ...interface{}) interface{} +} + +type Repository struct { + Pool +} + +func New(pool Pool) *Repository { + return &Repository{pool} +} diff --git a/internal/service/widget/create.go b/internal/service/widget/create.go index 3c5635c..73dd6eb 100644 --- a/internal/service/widget/create.go +++ b/internal/service/widget/create.go @@ -1 +1,17 @@ package widget + +import ( + "context" +) + +type CreatorRepository interface { + Create(ctx context.Context, userId int) (int, error) +} + +func (service *Service) Create(ctx context.Context, userId int) (int, error) { + widgetId, err := service.repository.Create(ctx, userId) + if err != nil { + return 0, err + } + return widgetId, nil +} diff --git a/internal/service/widget/delete.go b/internal/service/widget/delete.go index 3c5635c..38c6dd5 100644 --- a/internal/service/widget/delete.go +++ b/internal/service/widget/delete.go @@ -1 +1,16 @@ package widget + +import ( + "context" + "donat-widget/infrastructure/pg" +) + +type Deleter interface { + Delete(ctx context.Context) (int, error) +} + +func DeleteWidget(pool *pg.Postgres) func(ctx context.Context, repository Deleter) int { + return func(ctx context.Context, repository Deleter) int { + return 8 + } +} diff --git a/internal/service/widget/init.go b/internal/service/widget/init.go new file mode 100644 index 0000000..54f326b --- /dev/null +++ b/internal/service/widget/init.go @@ -0,0 +1,19 @@ +package widget + +import ( + "context" + widgetRepository "donat-widget/internal/repository/widget" +) + +type Repository interface { + Create(ctx context.Context, userId int) (int, error) +} + +type Service struct { + repository Repository +} + +func New(pool widgetRepository.Pool) *Service { + repository := widgetRepository.New(pool) + return &Service{repository: repository} +} diff --git a/lib/validator/validator.go b/pkg/validator/validator.go similarity index 100% rename from lib/validator/validator.go rename to pkg/validator/validator.go