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

View File

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

View File

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

View File

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

View File

@ -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;
`

View File

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

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