This commit is contained in:
mm 2024-09-09 03:32:10 +05:00
parent a0f879a3d4
commit 3c6748d5b3
17 changed files with 296 additions and 53 deletions

View File

@ -3,6 +3,6 @@ FROM golang:1.23-alpine
WORKDIR /root WORKDIR /root
COPY . . COPY . .
RUN go install github.com/swaggo/swag/cmd/swag@latest 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 CMD go run cmd/main.go

View File

@ -1,5 +1,5 @@
// Package docs Code generated by swaggo/swag. DO NOT EDIT // Package docs Code generated by swaggo/swag. DO NOT EDIT
package docs package http
import "github.com/swaggo/swag" import "github.com/swaggo/swag"

View File

@ -1,17 +1,6 @@
package main package main
import ( import "donat-widget/internal/app/http"
"github.com/labstack/echo/v4"
"log/slog"
"os"
)
import (
_ "donat-widget/cmd/docs"
"donat-widget/cmd/handlers"
"donat-widget/config"
"donat-widget/lib/validator"
)
// @title Widget service // @title Widget service
// @version 1.0 // @version 1.0
@ -20,20 +9,7 @@ import (
// @host localhost:8002 // @host localhost:8002
// @BasePath /api/widget // @BasePath /api/widget
func init() {
logger := slog.New(slog.NewJSONHandler(os.Stdout, nil))
slog.SetDefault(logger)
}
func main() { func main() {
app := initApp() httpServer := http.NewApp()
port := config.Config.Server.Port http.Run(httpServer)
app.Logger.Fatal(app.Start(":" + port))
}
func initApp() *echo.Echo {
app := echo.New()
app.Validator = validator.NewValidator()
handlers.IncludeRouters(app)
return app
} }

View File

@ -2,14 +2,13 @@ package pg
import ( import (
"context" "context"
"donat-widget/config"
"fmt" "fmt"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
"sync" "sync"
) )
type Postgres struct { type Postgres struct {
Db *pgxpool.Pool db *pgxpool.Pool
} }
var ( var (
@ -20,7 +19,7 @@ var (
func NewPgPool( func NewPgPool(
ctx context.Context, ctx context.Context,
username, password, host, port, dbname string, username, password, host, port, dbname string,
) (*Postgres, error) { ) *Postgres {
connString := "postgres://" + username + ":" + password + "@" + host + ":" + port + "/" + dbname + "?pool_max_conns=100" connString := "postgres://" + username + ":" + password + "@" + host + ":" + port + "/" + dbname + "?pool_max_conns=100"
pgOnce.Do(func() { pgOnce.Do(func() {
db, err := pgxpool.New(ctx, connString) db, err := pgxpool.New(ctx, connString)
@ -30,20 +29,11 @@ func NewPgPool(
pgInstance = &Postgres{db} pgInstance = &Postgres{db}
}) })
return pgInstance, nil return pgInstance
}
func (pg *Postgres) Ping(ctx context.Context) error {
err := pg.Db.Ping(ctx)
return err
}
func (pg *Postgres) Close() {
pg.Db.Close()
} }
func (pg *Postgres) CreateTable(ctx context.Context) error { 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 { if err != nil {
return err return err
} }
@ -51,11 +41,32 @@ func (pg *Postgres) CreateTable(ctx context.Context) error {
return nil return nil
} }
var Pool, _ = NewPgPool( func (pg *Postgres) DropTable(ctx context.Context) error {
context.Background(), result, err := pg.db.Exec(ctx, dropTableQuery)
config.Config.Database.Username, if err != nil {
config.Config.Database.Password, return err
config.Config.Database.Host, }
config.Config.Database.Port, fmt.Println(result)
config.Config.Database.DBName, 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
}

View File

@ -9,7 +9,7 @@ var createTableQuery = `
video TEXT DEFAULT '', video TEXT DEFAULT '',
image TEXT DEFAULT '', image TEXT DEFAULT '',
audio TEXT DEFAULT '', audio TEXT DEFAULT '',
duration TEXT DEFAULT '', duration INTEGER DEFAULT 30,
display BOOLEAN DEFAULT TRUE, display BOOLEAN DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP, created_at TIMESTAMPTZ NOT NULL DEFAULT CURRENT_TIMESTAMP,
updated_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 = ` var dropTableQuery = `
DROP TABLE IF EXISTS test_users; DROP TABLE IF EXISTS widgets;
` `

View File

@ -1 +1,52 @@
package widget 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))
}
}

73
internal/app/http/app.go Normal file
View File

@ -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
}

View File

@ -1 +1,33 @@
package config 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
}

View File

@ -1 +1,32 @@
package widget 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
}

View File

@ -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}
}

View File

@ -1 +1,17 @@
package widget 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
}

View File

@ -1 +1,16 @@
package widget 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
}
}

View File

@ -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}
}