diff --git a/Dockerfile b/Dockerfile index f452dac..2c531f9 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ # Этап сборки -FROM docker.io/library/golang:latest AS builder +FROM docker.io/library/golang:1.22.2 AS builder # Рабочая директория WORKDIR /build diff --git a/cmd/api/main.go b/cmd/api/main.go index e1a7017..b6dc021 100644 --- a/cmd/api/main.go +++ b/cmd/api/main.go @@ -1,13 +1,60 @@ package main import ( + "database/sql" + "fmt" + "log" "net/http" + "os" + "truck-company/internal/handlers" + "truck-company/internal/repository" + "truck-company/internal/usecase" "github.com/gorilla/mux" + "github.com/joho/godotenv" ) func main() { - r := mux.NewRouter() + // Загружаем переменные из .env + err := godotenv.Load() + if err != nil { + log.Fatal("Ошибка загрузки .env файла") + } - http.ListenAndServe(":8080", r) + // Читаем переменные + dbHost := os.Getenv("DB_HOST") + dbPort := os.Getenv("DB_PORT") + dbUser := os.Getenv("POSTGRES_USER") + dbPassword := os.Getenv("POSTGRES_PASSWORD") + dbName := os.Getenv("POSTGRES_DB") + sslMode := os.Getenv("DB_SSLMODE") + + // Формируем строку подключения + dsn := fmt.Sprintf("host=%s port=%s user=%s password=%s dbname=%s sslmode=%s", + dbHost, dbPort, dbUser, dbPassword, dbName, sslMode) + + db, err := sql.Open("postgres", dsn) + + if err != nil { + log.Fatal("Ошибка подключения к БД:", err) + } + defer db.Close() + // Проверяем соединение + + err = db.Ping() + if err != nil { + log.Fatal("БД не отвечает:", err) + } + log.Println("Подключение к PostgreSQL успешно!") + + repo := repository.NewAppRepo(db) + usecase := usecase.NewUseCase(*repo) + + r := mux.NewRouter() + h := handlers.NewTruckCompanyHandler(usecase) + h.RegisterRoutes(r) + + // Запуск сервера + log.Println("Server running on :8080") + log.Fatal(http.ListenAndServe(":8080", r)) } diff --git a/go.mod b/go.mod index e8771d1..1618e37 100644 --- a/go.mod +++ b/go.mod @@ -3,3 +3,5 @@ module truck-company go 1.22.2 require github.com/gorilla/mux v1.8.1 + +require github.com/joho/godotenv v1.5.1 diff --git a/go.sum b/go.sum index 7128337..2788c54 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,4 @@ github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= github.com/gorilla/mux v1.8.1/go.mod h1:AKf9I4AEqPTmMytcMc0KkNouC66V3BtZ4qD5fmWSiMQ= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= diff --git a/internal/domain/cargo/cargo.go b/internal/domain/cargo.go similarity index 100% rename from internal/domain/cargo/cargo.go rename to internal/domain/cargo.go diff --git a/internal/domain/client/client.go b/internal/domain/client.go similarity index 100% rename from internal/domain/client/client.go rename to internal/domain/client.go diff --git a/internal/domain/domain.go b/internal/domain/domain.go new file mode 100644 index 0000000..4188b5a --- /dev/null +++ b/internal/domain/domain.go @@ -0,0 +1 @@ +package domain diff --git a/internal/domain/route/route.go b/internal/domain/route.go similarity index 100% rename from internal/domain/route/route.go rename to internal/domain/route.go diff --git a/internal/domain/shipment/shipment.go b/internal/domain/shipment.go similarity index 100% rename from internal/domain/shipment/shipment.go rename to internal/domain/shipment.go diff --git a/internal/domain/transport/transport.go b/internal/domain/transport.go similarity index 96% rename from internal/domain/transport/transport.go rename to internal/domain/transport.go index ce74aef..71888eb 100644 --- a/internal/domain/transport/transport.go +++ b/internal/domain/transport.go @@ -1,4 +1,4 @@ -package main +package domain // Transport представляет конкретное транспортное средство type Transport struct { diff --git a/internal/handlers/handlers.go b/internal/handlers/handlers.go index b6ab7f0..e8faa0f 100644 --- a/internal/handlers/handlers.go +++ b/internal/handlers/handlers.go @@ -1,21 +1,40 @@ package handlers import ( + "encoding/json" "net/http" + "truck-company/internal/usecase" "github.com/gorilla/mux" ) type TruckCompanyHandler struct { + uc *usecase.UseCase } -func NewTruckCompanyHandler() *TruckCompanyHandler { - return &TruckCompanyHandler{} +func NewTruckCompanyHandler(u *usecase.UseCase) *TruckCompanyHandler { + return &TruckCompanyHandler{ + uc: u, + } } -func (h *TruckCompanyHandler) RegisterRoutes(router *mux.Router) { +func (h *TruckCompanyHandler) RegisterRoutes(r *mux.Router) { - // router.HandleFunc("/routes").Methods(http.MethodGet) - // router.HandleFunc("").Methods(http.MethodGet) - router.HandleFunc("/", http.NotFound) + r.HandleFunc("/routes", h.GetRoutes).Methods("GET") + r.HandleFunc("/routes/{route_id}/transport", h.GetTransportByRoute).Methods("GET") + r.HandleFunc("/routes/{route_id}/transport-types", h.GetTransportTypesByRoute).Methods("GET") + r.HandleFunc("/shipments/cost", h.GetShipmentCost).Methods("GET") + r.HandleFunc("/routes/{route_id}/cargo-turnover", h.GetCargoTurnoverByRoute).Methods("GET") + + //404 для всех остальных + r.HandleFunc("/", http.NotFound) +} + +func (h *TruckCompanyHandler) GetRoutes(w http.ResponseWriter, r *http.Request) { + routes, err := h.uc.GetAllRoutes() + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + return + } + json.NewEncoder(w).Encode(routes) } diff --git a/internal/repository/interface.go b/internal/repository/interface.go new file mode 100644 index 0000000..1ba2a3b --- /dev/null +++ b/internal/repository/interface.go @@ -0,0 +1,11 @@ +package repository + +import ( + domain "truck-company/internal/domain" +) + +type RepositoryInterface interface { + GetAllRoutes() ([]domain.Route, error) + GetTransportByRoute(routeID int64) ([]domain.Transport, error) + GetShipmentCosts() ([]domain.Shipment, error) +} diff --git a/internal/repository/postgres.go b/internal/repository/postgres.go new file mode 100644 index 0000000..debc7b3 --- /dev/null +++ b/internal/repository/postgres.go @@ -0,0 +1,39 @@ +package repository + +import ( + "database/sql" + "errors" + domain "truck-company/internal/domain" +) + +type AppRepo struct { + db *sql.DB +} + +func NewAppRepo(db *sql.DB) *AppRepo { + return &AppRepo{ + db: db, + } +} + +func (r *AppRepo) GetAllRoutes() ([]domain.Route, error) { + if r.db == nil { + return nil, errors.New("Ошибка подключения к бд. *db == nil") + } + rows, err := r.db.Query("SELECT id, name, price FROM route") + if err != nil { + return nil, err + } + defer rows.Close() + + var routes []domain.Route + + for rows.Next() { + var route domain.Route + if err := rows.Scan(&route.ID, &route.Name, &route.Price); err != nil { + return nil, err + } + routes = append(routes, route) + } + return routes, nil +} diff --git a/internal/usecase/usecase.go b/internal/usecase/usecase.go new file mode 100644 index 0000000..28bff64 --- /dev/null +++ b/internal/usecase/usecase.go @@ -0,0 +1,20 @@ +package usecase + +import ( + "truck-company/internal/domain" + "truck-company/internal/repository" +) + +type UseCase struct { + AppRepo repository.AppRepo +} + +func NewUseCase(r repository.AppRepo) *UseCase { + return &UseCase{ + AppRepo: r, + } +} + +func (u *UseCase) GetAllRoutes() ([]domain.Route, error) { + return u.AppRepo.GetAllRoutes() +}