diff --git a/.idea/.gitignore b/.idea/.gitignore deleted file mode 100644 index 13566b8..0000000 --- a/.idea/.gitignore +++ /dev/null @@ -1,8 +0,0 @@ -# Default ignored files -/shelf/ -/workspace.xml -# Editor-based HTTP Client requests -/httpRequests/ -# Datasource local storage ignored files -/dataSources/ -/dataSources.local.xml diff --git a/.idea/modules.xml b/.idea/modules.xml deleted file mode 100644 index 3aaeec2..0000000 --- a/.idea/modules.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - \ No newline at end of file diff --git a/.idea/protoeditor.xml b/.idea/protoeditor.xml deleted file mode 100644 index 2b7f969..0000000 --- a/.idea/protoeditor.xml +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml deleted file mode 100644 index 35eb1dd..0000000 --- a/.idea/vcs.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - \ No newline at end of file diff --git a/.idea/workout-training-api.iml b/.idea/workout-training-api.iml deleted file mode 100644 index 5e764c4..0000000 --- a/.idea/workout-training-api.iml +++ /dev/null @@ -1,9 +0,0 @@ - - - - - - - - - \ No newline at end of file diff --git a/docker-compose.askar.yml b/docker-compose.askar.yml new file mode 100644 index 0000000..2546cec --- /dev/null +++ b/docker-compose.askar.yml @@ -0,0 +1,17 @@ +version: '3.9' + +services: + postgres: + container_name: workout_postgres_container + image: postgres:17.3 + ports: + - 5432:5432 + environment: + POSTGRES_DB: "workoutdb" + POSTGRES_USER: "postgres" + POSTGRES_PASSWORD: "admin" + volumes: + - pgdata:/var/lib/postgresql/data + +volumes: + pgdata: \ No newline at end of file diff --git a/go.mod b/go.mod index 9c421ad..63f6b2e 100644 --- a/go.mod +++ b/go.mod @@ -36,4 +36,4 @@ require ( golang.org/x/tools v0.24.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect -) \ No newline at end of file +) diff --git a/go.sum b/go.sum index 0b8c4ba..bef4278 100644 --- a/go.sum +++ b/go.sum @@ -1,31 +1,3 @@ -<<<<<<< HEAD -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM= -github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761 h1:iCEnooe7UlwOQYpKFhBabPMi4aNAfoODPEFNiAnClxo= -github.com/jackc/pgservicefile v0.0.0-20240606120523-5a60cdf6a761/go.mod h1:5TJZWKEWniPve33vlWYSoGYefn3gLQRzjfDlhSJ9ZKM= -github.com/jackc/pgx/v5 v5.7.2 h1:mLoDLV6sonKlvjIEsV56SkWNCnuNv531l94GaIzO+XI= -github.com/jackc/pgx/v5 v5.7.2/go.mod h1:ncY89UGWxg82EykZUwSpUKEfccBGGYq1xjrOpsbsfGQ= -github.com/jackc/puddle/v2 v2.2.2 h1:PR8nw+E/1w0GLuRFSmiioY6UooMp6KJv0/61nB7icHo= -github.com/jackc/puddle/v2 v2.2.2/go.mod h1:vriiEXHvEE654aYKXXjOvZM39qJ0q+azkZFrfEOc3H4= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= -github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= -golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= -golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= -golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= -golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -======= github.com/99designs/gqlgen v0.17.64 h1:BzpqO5ofQXyy2XOa93Q6fP1BHLRjTOeU35ovTEsbYlw= github.com/99designs/gqlgen v0.17.64/go.mod h1:kaxLetFxPGeBBwiuKk75NxuI1fe9HRvob17In74v/Zc= github.com/PuerkitoBio/goquery v1.9.3 h1:mpJr/ikUA9/GNJB/DBZcGeFDXUtosHRyRrwh7KGdTG0= @@ -114,6 +86,5 @@ google.golang.org/protobuf v1.36.4 h1:6A3ZDJHn/eNqc1i+IdefRzy/9PokBTPvcqMySR7NNI google.golang.org/protobuf v1.36.4/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= ->>>>>>> 12012e7eedb63c6cad288001c5cd429cb4ec7dde gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= \ No newline at end of file +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/internal/askar-postgres/main.go b/internal/askar-postgres/main.go new file mode 100644 index 0000000..731ad50 --- /dev/null +++ b/internal/askar-postgres/main.go @@ -0,0 +1,48 @@ +package askar_postgres + +import ( + "context" + "database/sql" + _ "github.com/lib/pq" + "log/slog" + "time" + "workout-training-api/internal/askar-postgres/model" + "workout-training-api/internal/config" +) + +type Postgres struct { + *model.Model +} + +func New(conf *config.AskarPostgresConfig, logger *slog.Logger) (*Postgres, error) { + db, err := NewDatabase(conf) + if err != nil { + return nil, err + } + //defer db.Close() + + return &Postgres{ + Model: model.New(conf, logger.With(slog.String("module", "model")), db), + }, nil +} + +func NewDatabase(conf *config.AskarPostgresConfig) (*sql.DB, error) { + //psqlInfo := fmt.Sprintf( + // "host=%s port=%d user=%s password=%s dbname=%s sslmode=disable", + // conf.Host, conf.Port, conf.User, conf.Password, conf.Name, + //) + db, err := sql.Open("postgres", conf.DSN) + if err != nil { + return nil, err + } + + ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cancel() + + err = db.PingContext(ctx) + if err != nil { + return nil, err + } + + return db, nil +} diff --git a/internal/askar-postgres/migrations/000001_create_exercises_table.down.sql b/internal/askar-postgres/migrations/000001_create_exercises_table.down.sql new file mode 100644 index 0000000..1b6d9a4 --- /dev/null +++ b/internal/askar-postgres/migrations/000001_create_exercises_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS exercises; \ No newline at end of file diff --git a/internal/askar-postgres/migrations/000001_create_exercises_table.up.sql b/internal/askar-postgres/migrations/000001_create_exercises_table.up.sql new file mode 100644 index 0000000..3bfb1c5 --- /dev/null +++ b/internal/askar-postgres/migrations/000001_create_exercises_table.up.sql @@ -0,0 +1,12 @@ +CREATE TABLE IF NOT EXISTS exercises ( + id bigserial PRIMARY KEY, + name VARCHAR(255) NOT NULL, + description TEXT, + repetitions INTEGER NOT NULL, + sets INTEGER NOT NULL, + weight INTEGER NOT NULL, + muscle_groups text [] NOT NULL, + categories text [] NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); \ No newline at end of file diff --git a/internal/askar-postgres/migrations/000002_create_workouts_table.down.sql b/internal/askar-postgres/migrations/000002_create_workouts_table.down.sql new file mode 100644 index 0000000..644b25f --- /dev/null +++ b/internal/askar-postgres/migrations/000002_create_workouts_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS workouts; \ No newline at end of file diff --git a/internal/askar-postgres/migrations/000002_create_workouts_table.up.sql b/internal/askar-postgres/migrations/000002_create_workouts_table.up.sql new file mode 100644 index 0000000..78b4013 --- /dev/null +++ b/internal/askar-postgres/migrations/000002_create_workouts_table.up.sql @@ -0,0 +1,9 @@ +CREATE TABLE IF NOT EXISTS workouts ( + id bigserial PRIMARY KEY, + name VARCHAR(255) NOT NULL, + status VARCHAR(255) NOT NULL, + scheduled_times TIMESTAMP WITH TIME ZONE[] NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP +); + diff --git a/internal/askar-postgres/migrations/000003_exercise_workout_table.down.sql b/internal/askar-postgres/migrations/000003_exercise_workout_table.down.sql new file mode 100644 index 0000000..5cd3187 --- /dev/null +++ b/internal/askar-postgres/migrations/000003_exercise_workout_table.down.sql @@ -0,0 +1 @@ +DROP TABLE IF EXISTS exercise_workout; \ No newline at end of file diff --git a/internal/askar-postgres/migrations/000003_exercise_workout_table.up.sql b/internal/askar-postgres/migrations/000003_exercise_workout_table.up.sql new file mode 100644 index 0000000..52bf51c --- /dev/null +++ b/internal/askar-postgres/migrations/000003_exercise_workout_table.up.sql @@ -0,0 +1,15 @@ +CREATE TABLE IF NOT EXISTS exercise_workout ( + id bigserial PRIMARY KEY, + exercise_id BIGINT NOT NULL, + workout_id BIGINT NOT NULL, + created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP, + CONSTRAINT fk_exercise + FOREIGN KEY (exercise_id) + REFERENCES exercises (id) + ON DELETE CASCADE, + CONSTRAINT fk_workout + FOREIGN KEY (workout_id) + REFERENCES workouts (id) + ON DELETE CASCADE +); diff --git a/internal/askar-postgres/migrations/000004_add_indexes_to_exercise_workout.down.sql b/internal/askar-postgres/migrations/000004_add_indexes_to_exercise_workout.down.sql new file mode 100644 index 0000000..47800ca --- /dev/null +++ b/internal/askar-postgres/migrations/000004_add_indexes_to_exercise_workout.down.sql @@ -0,0 +1,3 @@ +DROP INDEX IF EXISTS idx_exercise_workout_exercise_id; +DROP INDEX IF EXISTS idx_exercise_workout_workout_id; + diff --git a/internal/askar-postgres/migrations/000004_add_indexes_to_exercise_workout.up.sql b/internal/askar-postgres/migrations/000004_add_indexes_to_exercise_workout.up.sql new file mode 100644 index 0000000..b8bbee0 --- /dev/null +++ b/internal/askar-postgres/migrations/000004_add_indexes_to_exercise_workout.up.sql @@ -0,0 +1,2 @@ +CREATE INDEX IF NOT EXISTS idx_exercise_workout_exercise_id ON exercise_workout (exercise_id); +CREATE INDEX IF NOT EXISTS idx_exercise_workout_workout_id ON exercise_workout (workout_id); diff --git a/internal/askar-postgres/model/exercise/create_exercise.go b/internal/askar-postgres/model/exercise/create_exercise.go new file mode 100644 index 0000000..969940c --- /dev/null +++ b/internal/askar-postgres/model/exercise/create_exercise.go @@ -0,0 +1,54 @@ +package exercise + +import ( + "context" + "fmt" + "github.com/lib/pq" + "time" + "workout-training-api/internal/types/database" +) + +func (m *ExerciseModel) CreateExercise(ctx context.Context, req database.CreateExerciseReq) (database.CreateExerciseResp, error) { + + log := m.logger.With("exercise", "CreateExercise") + + if req == nil { + log.ErrorContext(ctx, "req is nil") + return nil, fmt.Errorf("req is nil") + } + + mdl := &Exercise{ + Name: req.GetName(), + Description: req.GetDescription(), + Repetitions: req.GetRepetitions(), + Sets: req.GetSets(), + Weight: req.GetWeight(), + MuscleGroups: req.GetMuscleGroups(), + Categories: req.GetCategories(), + } + + query := ` + INSERT INTO exercises (name, description, repetitions, sets, weight, muscle_groups, categories) + VALUES ($1, $2, $3, $4, $5, $6, $7)` + + args := []interface{}{ + mdl.Name, + mdl.Description, + mdl.Repetitions, + mdl.Sets, + mdl.Weight, + pq.Array(mdl.MuscleGroups), + pq.Array(mdl.Categories), + } + + ctx, cancel := context.WithTimeout(ctx, 3*time.Second) + defer cancel() + + _, err := m.db.ExecContext(ctx, query, args...) + if err != nil { + log.ErrorContext(ctx, "failed to execute query", "error", err) + return nil, fmt.Errorf("failed to execute query: %w", err) + } + + return true, nil +} diff --git a/internal/askar-postgres/model/exercise/delete_exercise.go b/internal/askar-postgres/model/exercise/delete_exercise.go new file mode 100644 index 0000000..637b472 --- /dev/null +++ b/internal/askar-postgres/model/exercise/delete_exercise.go @@ -0,0 +1,43 @@ +package exercise + +import ( + "context" + "fmt" + "time" + "workout-training-api/internal/types/database" +) + +func (m *ExerciseModel) DeleteExercise(ctx context.Context, req database.DeleteExerciseReq) (database.DeleteExerciseResp, error) { + log := m.logger.With("exercise", "DeleteExercise") + + if req == nil { + log.ErrorContext(ctx, "req is nil") + return nil, fmt.Errorf("req is nil") + } + + query := ` + DELETE FROM exercises + WHERE id = $1` + + ctx, cancel := context.WithTimeout(ctx, 3*time.Second) + defer cancel() + + result, err := m.db.ExecContext(ctx, query, req.GetID()) + if err != nil { + log.ErrorContext(ctx, "failed to delete exercise", "id", req.GetID()) + return nil, fmt.Errorf("failed to delete exercise: %w", err) + } + + rowsAffected, err := result.RowsAffected() + if err != nil { + log.ErrorContext(ctx, "failed to call rowsAffected", "id", req.GetID()) + return nil, fmt.Errorf("failed to call rowsAffected: %w", err) + } + + if rowsAffected == 0 { + log.ErrorContext(ctx, "failed to find an exercise with id", "id", req.GetID()) + return nil, fmt.Errorf("failed to find an exercise") + } + + return true, nil +} diff --git a/internal/askar-postgres/model/exercise/exercise.go b/internal/askar-postgres/model/exercise/exercise.go new file mode 100644 index 0000000..4092966 --- /dev/null +++ b/internal/askar-postgres/model/exercise/exercise.go @@ -0,0 +1,57 @@ +package exercise + +import ( + "strconv" + "time" +) + +type Exercise struct { + ID int64 + Name string + Description string + Repetitions int32 + Sets int32 + Weight int32 + MuscleGroups []string + Categories []string + CreatedAt time.Time + UpdatedAt time.Time +} + +func (e *Exercise) GetWorkoutID() string { + return "id" +} + +func (e *Exercise) GetID() string { + return strconv.FormatInt(e.ID, 10) +} + +func (e *Exercise) GetName() string { + return e.Name +} + +func (e *Exercise) GetDescription() string { + return e.Description +} + +func (e *Exercise) GetRepetitions() int32 { return e.Repetitions } + +func (e *Exercise) GetSets() int32 { return e.Sets } + +func (e *Exercise) GetWeight() int32 { return e.Weight } + +func (e *Exercise) GetMuscleGroups() []string { + return e.MuscleGroups +} + +func (e *Exercise) GetCategories() []string { + return e.Categories +} + +func (e *Exercise) GetCreatedAt() time.Time { + return e.CreatedAt +} + +func (e *Exercise) GetUpdatedAt() time.Time { + return e.UpdatedAt +} diff --git a/internal/askar-postgres/model/exercise/list_exercise.go b/internal/askar-postgres/model/exercise/list_exercise.go new file mode 100644 index 0000000..253f5ed --- /dev/null +++ b/internal/askar-postgres/model/exercise/list_exercise.go @@ -0,0 +1,61 @@ +package exercise + +import ( + "context" + "fmt" + "github.com/lib/pq" + "time" + "workout-training-api/internal/types/database" +) + +type ExerciseList struct { + exercises []database.ExerciseResp +} + +func (e ExerciseList) GetList() []database.ExerciseResp { + return e.exercises +} + +func (m *ExerciseModel) ListExercise(ctx context.Context, _ database.ListExerciseReq) (database.ListExerciseResp, error) { + log := m.logger.With("exercise", "ListExercise") + + query := ` + SELECT id, name, description, repetitions, sets, weight, muscle_groups, categories, created_at, updated_at + FROM exercises` + + ctx, cancel := context.WithTimeout(ctx, 3*time.Second) + defer cancel() + + rows, err := m.db.QueryContext(ctx, query) + if err != nil { + log.ErrorContext(ctx, "failed to query exercises") + return nil, fmt.Errorf("failed to query exercises: %w", err) + } + + exercises := []database.ExerciseResp{} + + for rows.Next() { + var exercise Exercise + + err := rows.Scan( + &exercise.ID, + &exercise.Name, + &exercise.Description, + &exercise.Repetitions, + &exercise.Sets, + &exercise.Weight, + pq.Array(&exercise.MuscleGroups), + pq.Array(&exercise.Categories), + &exercise.CreatedAt, + &exercise.UpdatedAt, + ) + if err != nil { + log.ErrorContext(ctx, "failed to scan exercise") + return nil, fmt.Errorf("failed to scan exercise: %w", err) + } + + exercises = append(exercises, &exercise) + } + + return ExerciseList{exercises: exercises}, nil +} diff --git a/internal/askar-postgres/model/exercise/main.go b/internal/askar-postgres/model/exercise/main.go new file mode 100644 index 0000000..ceef21d --- /dev/null +++ b/internal/askar-postgres/model/exercise/main.go @@ -0,0 +1,17 @@ +package exercise + +import ( + "database/sql" + "log/slog" + "workout-training-api/internal/config" +) + +type ExerciseModel struct { + conf *config.AskarPostgresConfig + logger *slog.Logger + db *sql.DB +} + +func New(conf *config.AskarPostgresConfig, logger *slog.Logger, db *sql.DB) *ExerciseModel { + return &ExerciseModel{conf: conf, logger: logger, db: db} +} diff --git a/internal/askar-postgres/model/exercise/update_exercise.go b/internal/askar-postgres/model/exercise/update_exercise.go new file mode 100644 index 0000000..66a864d --- /dev/null +++ b/internal/askar-postgres/model/exercise/update_exercise.go @@ -0,0 +1,42 @@ +package exercise + +import ( + "context" + "fmt" + "github.com/lib/pq" + "time" + "workout-training-api/internal/types/database" +) + +func (m *ExerciseModel) UpdateExercise(ctx context.Context, req database.UpdateExerciseReq) (database.UpdateExerciseResp, error) { + log := m.logger.With("exercise", "UpdateExercise") + + if req == nil { + log.ErrorContext(ctx, "req is nil") + return nil, fmt.Errorf("req is nil") + } + + query := ` + UPDATE exercises + SET name = $1, description = $2, categories = $3, muscle_groups = $4, updated_at = now() + WHERE id = $5` + + args := []interface{}{ + req.GetName(), + req.GetDescription(), + pq.Array(req.GetCategories()), + pq.Array(req.GetMuscleGroups()), + req.GetID(), + } + + ctx, cancel := context.WithTimeout(ctx, 3*time.Second) + defer cancel() + + _, err := m.db.ExecContext(ctx, query, args...) + if err != nil { + log.ErrorContext(ctx, "failed to update exercise", "error", err) + return nil, fmt.Errorf("failed to update exercise: %w", err) + } + + return true, nil +} diff --git a/internal/askar-postgres/model/main.go b/internal/askar-postgres/model/main.go new file mode 100644 index 0000000..1998098 --- /dev/null +++ b/internal/askar-postgres/model/main.go @@ -0,0 +1,17 @@ +package model + +import ( + "database/sql" + "log/slog" + "workout-training-api/internal/askar-postgres/model/exercise" + "workout-training-api/internal/config" +) + +type Model struct { + *exercise.ExerciseModel +} + +func New(conf *config.AskarPostgresConfig, logger *slog.Logger, db *sql.DB) *Model { + + return &Model{ExerciseModel: exercise.New(conf, logger.With(slog.String("component", "exercise")), db)} +} diff --git a/internal/askar-postgres/model/seeds/main.go b/internal/askar-postgres/model/seeds/main.go new file mode 100644 index 0000000..e504564 --- /dev/null +++ b/internal/askar-postgres/model/seeds/main.go @@ -0,0 +1,106 @@ +package seeds + +import ( + "context" + "fmt" + "log/slog" + askar_postgres "workout-training-api/internal/askar-postgres" + "workout-training-api/internal/askar-postgres/model/exercise" +) + +type Seed interface { + Populate() error + TestMethods() error +} + +type seeder struct { + postgres *askar_postgres.Postgres +} + +func New(postgres *askar_postgres.Postgres) Seed { + return &seeder{postgres: postgres} +} + +func (s *seeder) Populate() error { + + exercises := []*exercise.Exercise{ + { + Name: "Push-ups", + Description: "A bodyweight exercise that targets the chest, shoulders, and triceps.", + Repetitions: 15, + Sets: 3, + Weight: 0, + MuscleGroups: []string{"Chest", "Triceps", "Shoulders"}, + Categories: []string{"Bodyweight", "Strength"}, + }, + { + Name: "Squats", + Description: "A compound exercise that targets the legs and glutes.", + Repetitions: 12, + Sets: 3, + Weight: 50, + MuscleGroups: []string{"Quadriceps", "Hamstrings", "Glutes"}, + Categories: []string{"Legs", "Strength"}, + }, + { + Name: "Deadlifts", + Description: "A strength exercise that targets the back, legs, and core.", + Repetitions: 8, + Sets: 4, + Weight: 100, + MuscleGroups: []string{"Back", "Hamstrings", "Core"}, + Categories: []string{"Powerlifting", "Strength"}, + }, + } + + for _, exercise := range exercises { + _, err := s.postgres.ExerciseModel.CreateExercise(context.Background(), exercise) + if err != nil { + slog.Error("Error on create exercise", err.Error()) + } + } + + return nil +} + +func (s *seeder) TestMethods() error { + s.listExercise() + return nil +} + +func (s *seeder) deleteExercise() { + req := &exercise.Exercise{ + ID: 1, + } + _, err := s.postgres.DeleteExercise(context.Background(), req) + if err != nil { + slog.Error("Error on deleting exercise", err.Error()) + } +} + +func (s *seeder) listExercise() { + res, err := s.postgres.ExerciseModel.ListExercise(context.Background(), nil) + if err != nil { + slog.Error("Error on list exercise", err.Error()) + } + + for _, exercise := range res.GetList() { + fmt.Printf("exercise id %s and name %s\n", exercise.GetID(), exercise.GetName()) + } +} + +func (s *seeder) updateExercise() { + exercise := &exercise.Exercise{ + ID: 2, + Name: "Updated Squats", + Description: "Updated A compound exercise that targets the legs and glutes.", + MuscleGroups: []string{"Updated Quadriceps", "Hamstrings", "Glutes"}, + Categories: []string{"Updated Legs", "Strength"}, + } + + _, err := s.postgres.UpdateExercise(context.Background(), exercise) + if err != nil { + slog.Error("Error on update exercise", err.Error()) + } + slog.Info("Exercise updated") +} diff --git a/internal/config/askar_postgres.go b/internal/config/askar_postgres.go new file mode 100644 index 0000000..7beb2da --- /dev/null +++ b/internal/config/askar_postgres.go @@ -0,0 +1,30 @@ +package config + +import ( + "context" + "flag" +) + +type AskarPostgresConfig struct { + DSN string +} + +func newAskarPostgresConfig(_ context.Context) *AskarPostgresConfig { + var c AskarPostgresConfig + + // postgres://workoutdb:admin@localhost/workoutdb?sslmode=disable + // postgres://postgres:admin@localhost/workoutdb + // postgres://postgres:admin@localhost/workoutdb?sslmode=disable + + //flag.StringVar(&c.Host, "localhost", c.Host, "postgreSQL host [PG_HOST]") + //flag.IntVar(&c.Port, "pg-port", c.Port, "postgreSQL port [PG_PORT]") + //flag.StringVar(&c.Name, "pg-name", c.Name, "postgreSQL name [PG_NAME]") + //flag.StringVar(&c.User, "pg-user", c.User, "postgreSQL user [PG_USER]") + //flag.StringVar(&c.Password, "pg-password", c.Password, "postgreSQL password [PG_PASSWORD]") + + flag.StringVar(&c.DSN, "askar-db-dsn", "postgres://postgres:admin@localhost/workoutdb?sslmode=disable", "Askar PostgreSQL DSN") + + flag.Parse() + + return &c +} diff --git a/internal/config/main.go b/internal/config/main.go index 663598e..65b6523 100644 --- a/internal/config/main.go +++ b/internal/config/main.go @@ -3,16 +3,16 @@ package config import ( "context" "flag" - "os" - "github.com/joho/godotenv" + "os" "workout-training-api/internal/constant" ) type Config struct { - ENV constant.Environment - API *APIConfig - Postgres *PostgresConfig + ENV constant.Environment + API *APIConfig + Postgres *PostgresConfig + AskarPostgres *AskarPostgresConfig } func New(ctx context.Context) *Config { @@ -27,9 +27,10 @@ func New(ctx context.Context) *Config { load(env) conf := &Config{ - ENV: env, - API: newApiConfig(ctx), - Postgres: newPostgresConfig(ctx), + ENV: env, + API: newApiConfig(ctx), + Postgres: newPostgresConfig(ctx), + AskarPostgres: newAskarPostgresConfig(ctx), } flag.Parse() diff --git a/internal/config/postgres.go b/internal/config/postgres.go index 6806709..c057dd9 100644 --- a/internal/config/postgres.go +++ b/internal/config/postgres.go @@ -18,19 +18,39 @@ type PostgresConfig struct { func newPostgresConfig(_ context.Context) *PostgresConfig { port, _ := strconv.Atoi(os.Getenv("PG_PORT")) + // c := &PostgresConfig{ + // Host: os.Getenv("PG_HOST"), + // Port: port, + // Name: os.Getenv("PG_NAME"), + // User: os.Getenv("PG_USER"), + // Password: os.Getenv("PG_PASSWORD"), + // } + + // flag.StringVar(&c.Host, "pg-host", c.Host, "postgreSQL host [PG_HOST]") + // flag.IntVar(&c.Port, "pg-port", c.Port, "postgreSQL port [PG_PORT]") + // flag.StringVar(&c.Name, "pg-name", c.Name, "postgreSQL name [PG_NAME]") + // flag.StringVar(&c.User, "pg-user", c.User, "postgreSQL user [PG_USER]") + // flag.StringVar(&c.Password, "pg-password", c.Password, "postgreSQL password [PG_PASSWORD]") + c := &PostgresConfig{ - Host: os.Getenv("PG_HOST"), + Host: "localhost", Port: port, - Name: os.Getenv("PG_NAME"), - User: os.Getenv("PG_USER"), - Password: os.Getenv("PG_PASSWORD"), + Name: "postgres", + User: "postgres", + Password: "postgres", } - flag.StringVar(&c.Host, "pg-host", c.Host, "postgreSQL host [PG_HOST]") + // postgres://workoutdb:admin@localhost/workoutdb?sslmode=disable + // postgres://postgres:admin@localhost/workoutdb + // postgres://postgres:admin@localhost/workoutdb?sslmode=disable + + flag.StringVar(&c.Host, "localhost", c.Host, "postgreSQL host [PG_HOST]") flag.IntVar(&c.Port, "pg-port", c.Port, "postgreSQL port [PG_PORT]") flag.StringVar(&c.Name, "pg-name", c.Name, "postgreSQL name [PG_NAME]") flag.StringVar(&c.User, "pg-user", c.User, "postgreSQL user [PG_USER]") flag.StringVar(&c.Password, "pg-password", c.Password, "postgreSQL password [PG_PASSWORD]") + flag.Parse() + return c } diff --git a/internal/constant/env.go b/internal/constant/env.go index e96307a..ad2aa11 100644 --- a/internal/constant/env.go +++ b/internal/constant/env.go @@ -1,6 +1,5 @@ package constant - type Environment string const ( diff --git a/internal/types/database/create_exercise.go b/internal/types/database/create_exercise.go index 1c505d5..b7b8ff8 100644 --- a/internal/types/database/create_exercise.go +++ b/internal/types/database/create_exercise.go @@ -1,54 +1,14 @@ package database -import "context" - type CreateExerciseReq interface { GetWorkoutID() string GetName() string - GetCategory() string - GetMuscleGroup() string - GetSets() int - GetRepsPerSet() int - GetWeightKg() float64 - GetNotes() string + GetDescription() string + GetRepetitions() int32 + GetSets() int32 + GetWeight() int32 + GetMuscleGroups() []string + GetCategories() []string } type CreateExerciseResp interface{} - -func (d *Database) CreateExercise(ctx context.Context, req CreateExerciseReq) (CreateWorkoutResp, error) { - _, err := d.DB.ExecContext(ctx, ` - INSERT INTO exercises (name, description, categories, muscle_groups) - VALUES ($1, $2, $3, $4)`, - req.GetName(), req.GetDescription(), req.GetCategories(), req.GetMuscleGroups(), - ) - if err != nil { - return nil, err - } - - return struct{}{}, nil -} - -type ExerciseModel struct { - ID uint `gorm:"primaryKey"` - WorkoutID uint `gorm:"index"` - Name string - Description string - Categories []string `gorm:"type:text[]"` - MuscleGroups []string `gorm:"type:text[]"` - Reps int - Sets int -} - -func CreateExercise(ctx context.Context, wourkoutID uint, req CreateExerciseReq) (*ExerciseModel, error) { - exercise := ExerciseModel{ - WorkoutID: wourkoutID, - Name: req.GetName(), - Description: req.GetDescription(), - Categories: req.GetCategories(), - MuscleGroups: req.GetMuscleGroups(), - } - if err := DB.WithContext(ctx).Create(&exercise).Error; err != nil { - return nil, err - } - return &exercise, nil -} diff --git a/internal/types/database/create_user.go b/internal/types/database/create_user.go index 8a6866c..58f0dc1 100644 --- a/internal/types/database/create_user.go +++ b/internal/types/database/create_user.go @@ -1,20 +1,9 @@ package database -<<<<<<< HEAD import ( - "context" - "fmt" + "time" ) -type User struct { - ID uint `gorm:"primaryKey"` - Email string `gorm:"unique"` - PasswordHash string -} -======= -import "time" ->>>>>>> 12012e7eedb63c6cad288001c5cd429cb4ec7dde - type CreateUserReq interface { GetEmail() string GetPasswordHash() string @@ -27,19 +16,3 @@ type CreateUserResp interface { GetCreatedAt() time.Time GetUpdatedAt() time.Time } - -type createUserResp struct { - ID string -} - -func (r createUserResp) GetID() string { - return r.ID -} - -func (d *Database) CreateUser(ctx context.Context, req CreateUserReq) (CreateUserResp, error) { - user := User{Email: req.GetEmail(), PasswordHash: req.GetPasswordHash()} - if err := d.DB.WithContext(ctx).Create(&user).Error; err != nil { - return nil, err - } - return createUserResp{ID: fmt.Sprintf("%d", user.ID)}, nil -} diff --git a/internal/types/database/create_workout.go b/internal/types/database/create_workout.go index cf86bd7..fb6261f 100644 --- a/internal/types/database/create_workout.go +++ b/internal/types/database/create_workout.go @@ -1,14 +1,9 @@ package database import ( -<<<<<<< HEAD - "context" - "time" -======= "time" "workout-training-api/internal/constant" "workout-training-api/internal/postgres/db_types/workout" ->>>>>>> 12012e7eedb63c6cad288001c5cd429cb4ec7dde ) type CreateWorkoutReq interface { @@ -20,38 +15,6 @@ type CreateWorkoutReq interface { GetScheduledDate() []time.Time } -<<<<<<< HEAD -type CreateWorkoutResp interface{} - -func (d *Database) CreateWorkout(ctx context.Context, req CreateWorkoutReq) (CreateWorkoutResp, error) { - _, err := d.DB.ExecContext(ctx, ` - INSERT INTO workouts (user_id, exercise_ids, scheduled_times) - VALUES ($1, $2, $3)`, - req.GetUserID(), req.GetExerciseIDs(), req.GetScheduledTimes(), - ) - if err != nil { - return nil, err - } - - return struct{}{}, nil -======= type CreateWorkoutResp interface { GetWorkout() workout.Workout ->>>>>>> 12012e7eedb63c6cad288001c5cd429cb4ec7dde -} - -/* - -type Workout struct { - WorkoutID string `db:"workout_id" json:"workout_id"` - UserID string `db:"user_id" json:"user_id"` - Name string `db:"name" json:"name"` - Description string `db:"description" json:"description,omitempty"` - Exercises []Exercise `json:"exercises,omitempty"` // Loaded separately - Status constant.WorkoutStatus `db:"status" json:"status"` - Comments []Comment `json:"comments,omitempty"` // Loaded separately - ScheduledDate []*time.Time `db:"scheduled_date" json:"scheduled_date,omitempty"` - CreatedAt *time.Time `db:"created_at" json:"created_at"` - UpdatedAt *time.Time `db:"updated_at" json:"updated_at"` } -*/ diff --git a/internal/types/database/delete_exercise.go b/internal/types/database/delete_exercise.go index ef3132a..dcc022b 100644 --- a/internal/types/database/delete_exercise.go +++ b/internal/types/database/delete_exercise.go @@ -1,24 +1,7 @@ package database -import "context" - -// Интерфейс запроса на удаление упражнения type DeleteExerciseReq interface { GetID() string } -// Интерфейс ответа на удаление упражнения type DeleteExerciseResp interface{} - -// Структура, реализующая DeleteExerciseResp (пустая, так как ответ не требуется) -type deleteExerciseResp struct{} - -// Метод удаления упражнения в `Database` -func (d *Database) DeleteExercise(ctx context.Context, req DeleteExerciseReq) (DeleteExerciseResp, error) { - _, err := d.DB.ExecContext(ctx, `DELETE FROM exercises WHERE id = $1`, req.GetID()) - if err != nil { - return nil, err - } - - return deleteExerciseResp{}, nil -} diff --git a/internal/types/database/delete_workout.go b/internal/types/database/delete_workout.go index 2ac602e..6bea991 100644 --- a/internal/types/database/delete_workout.go +++ b/internal/types/database/delete_workout.go @@ -1,19 +1,8 @@ package database -import "context" - type DeleteWorkoutReq interface { GetUserID() string GetID() string } type DeleteWorkoutResp interface{} - -func (d *Database) DeleteWorkout(ctx context.Context, req DeleteWorkoutReq) (DeleteWorkoutResp, error) { - _, err := d.DB.ExecContext(ctx, `DELETE FROM workouts WHERE id = $1 AND user_id = $2`, req.GetID(), req.GetUserID()) - if err != nil { - return nil, err - } - - return struct{}{}, nil -} diff --git a/internal/types/database/find_user.go b/internal/types/database/find_user.go index b486cd2..4294a55 100644 --- a/internal/types/database/find_user.go +++ b/internal/types/database/find_user.go @@ -1,10 +1,8 @@ package database -<<<<<<< HEAD -import "context" -======= -import "time" ->>>>>>> 12012e7eedb63c6cad288001c5cd429cb4ec7dde +import ( + "time" +) type FindUserReq interface { GetEmail() string @@ -18,30 +16,3 @@ type FindUserResp interface { GetCreatedAt() time.Time GetUpdatedAt() time.Time } - -type findUserResp struct { - ID string - Email string -} - -func (r findUserResp) GetID() string { - return r.ID -} - -func (r findUserResp) GetEmail() string { - return r.Email -} - -func (d *Database) FindUser(ctx context.Context, req FindUserReq) (FindUserResp, error) { - var id, email string - err := d.DB.QueryRowContext(ctx, ` - SELECT id, email FROM users WHERE email = $1 AND password_hash = $2`, - req.GetEmail(), req.GetPasswordHash(), - ).Scan(&id, &email) - - if err != nil { - return nil, err - } - - return findUserResp{ID: id, Email: email}, nil -} diff --git a/internal/types/database/generate_workout_reports.go b/internal/types/database/generate_workout_reports.go index 1fdba2d..ed8aca9 100644 --- a/internal/types/database/generate_workout_reports.go +++ b/internal/types/database/generate_workout_reports.go @@ -1,79 +1,10 @@ package database -import ( - "context" - "time" -) - -// Интерфейс запроса отчета по тренировкам type GenerateWorkoutReportsReq interface { GetUserID() string } -// Интерфейс ответа отчета по тренировкам type GenerateWorkoutReportsRes interface { GetProgress() string - GetWorkouts() []WorkoutResp -} - -// Интерфейс для Workout -type WorkoutResp interface { - GetID() string - GetUserID() string - GetExerciseIDs() []string - GetScheduledTimes() []time.Time -} - -// Внутренняя структура данных для сканирования из базы -type workoutData struct { - ID string - UserID string - ExerciseIDs []string - ScheduledTimes []time.Time -} - -// Реализация методов для WorkoutResp -func (w workoutData) GetID() string { return w.ID } -func (w workoutData) GetUserID() string { return w.UserID } -func (w workoutData) GetExerciseIDs() []string { return w.ExerciseIDs } -func (w workoutData) GetScheduledTimes() []time.Time { return w.ScheduledTimes } - -// Реализация ответа для GenerateWorkoutReportsRes -type generateWorkoutReportsRes struct { - Progress string - Workouts []WorkoutResp -} - -func (r generateWorkoutReportsRes) GetProgress() string { - return r.Progress -} - -func (r generateWorkoutReportsRes) GetWorkouts() []WorkoutResp { - return r.Workouts -} - -// Метод GenerateWorkoutReports теперь работает через Database -func (d *Database) GenerateWorkoutReports(ctx context.Context, req GenerateWorkoutReportsReq) (GenerateWorkoutReportsRes, error) { - rows, err := d.DB.QueryContext(ctx, ` - SELECT id, user_id, exercise_ids, scheduled_times FROM workouts WHERE user_id = $1`, req.GetUserID()) - if err != nil { - return nil, err - } - defer rows.Close() - - var workouts []WorkoutResp - for rows.Next() { - var w workoutData - err := rows.Scan(&w.ID, &w.UserID, &w.ExerciseIDs, &w.ScheduledTimes) - if err != nil { - return nil, err - } - workouts = append(workouts, w) - } - - // Возвращаем структуру, реализующую интерфейс - return generateWorkoutReportsRes{ - Progress: "In Progress", // Можно добавить реальную логику расчета прогресса - Workouts: workouts, - }, nil + GetWorkouts() WorkoutListResp } diff --git a/internal/types/database/list_exercise.go b/internal/types/database/list_exercise.go index f437883..3bb7d58 100644 --- a/internal/types/database/list_exercise.go +++ b/internal/types/database/list_exercise.go @@ -1,19 +1,14 @@ package database -import ( - "context" - "time" -) +import "time" -// Интерфейс запроса списка упражнений -type ListExerciseReq interface{} +type ListExerciseReq interface { +} -// Интерфейс ответа, содержащего список упражнений type ListExerciseResp interface { GetList() []ExerciseResp } -// Интерфейс одного упражнения type ExerciseResp interface { GetID() string GetName() string @@ -23,55 +18,3 @@ type ExerciseResp interface { GetCreatedAt() time.Time GetUpdatedAt() time.Time } - -// Реализация `ExerciseResp` -type exerciseData struct { - ID string - Name string - Description string - Categories []string - MuscleGroups []string - CreatedAt time.Time - UpdatedAt time.Time -} - -// Методы для реализации `ExerciseResp` -func (e exerciseData) GetID() string { return e.ID } -func (e exerciseData) GetName() string { return e.Name } -func (e exerciseData) GetDescription() string { return e.Description } -func (e exerciseData) GetCategories() []string { return e.Categories } -func (e exerciseData) GetMuscleGroups() []string { return e.MuscleGroups } -func (e exerciseData) GetCreatedAt() time.Time { return e.CreatedAt } -func (e exerciseData) GetUpdatedAt() time.Time { return e.UpdatedAt } - -// Ответ `ListExerciseResp`, содержащий список упражнений -type listExerciseResp struct { - List []ExerciseResp -} - -// Реализация метода `GetList()` -func (r listExerciseResp) GetList() []ExerciseResp { - return r.List -} - -// Метод получения списка упражнений -func (d *Database) ListExpense(ctx context.Context, req ListExerciseReq) (ListExerciseResp, error) { - rows, err := d.DB.QueryContext(ctx, ` - SELECT id, name, description, categories, muscle_groups, created_at, updated_at FROM exercises`) - if err != nil { - return nil, err - } - defer rows.Close() - - var exercises []ExerciseResp - for rows.Next() { - var e exerciseData - err := rows.Scan(&e.ID, &e.Name, &e.Description, &e.Categories, &e.MuscleGroups, &e.CreatedAt, &e.UpdatedAt) - if err != nil { - return nil, err - } - exercises = append(exercises, e) - } - - return listExerciseResp{List: exercises}, nil -} diff --git a/internal/types/database/main.go b/internal/types/database/main.go index 094ffd8..dc34eaf 100644 --- a/internal/types/database/main.go +++ b/internal/types/database/main.go @@ -2,16 +2,9 @@ package database import ( "context" -<<<<<<< HEAD - "database/sql" - "fmt" -======= ->>>>>>> 12012e7eedb63c6cad288001c5cd429cb4ec7dde ) -var DB *gorm.DB - -type UserService interface { +type User interface { CreateUser(context.Context, CreateUserReq) (CreateUserResp, error) FindUserByEmail(context.Context, FindUserReq) (FindUserResp, error) } @@ -29,7 +22,7 @@ type Exercise interface { CreateExercise(context.Context, CreateExerciseReq) (CreateExerciseResp, error) UpdateExercise(context.Context, UpdateExerciseReq) (UpdateExerciseResp, error) DeleteExercise(context.Context, DeleteExerciseReq) (DeleteExerciseResp, error) - ListExpense(context.Context, ListExerciseReq) (ListWorkoutResp, error) + ListExercise(context.Context, ListExerciseReq) (ListExerciseResp, error) } type Workout interface { @@ -40,29 +33,8 @@ type Workout interface { GenerateWorkoutReports(context.Context, GenerateWorkoutReportsReq) (GenerateWorkoutReportsRes, error) } -<<<<<<< HEAD -type Database struct { - DB *sql.DB -} - -func InitDB() (*Database, error) { - connStr := "postgres://postgres:yourpassword@localhost:5432/postgres?sslmode=disable" // Замени пароль - - db, err := sql.Open("postgres", connStr) - if err != nil { - panic(fmt.Sprintf("Failed to connect to database: %v", err)) - } - - if err := db.Ping(); err != nil { - panic(fmt.Sprintf("Database is not responding: %v", err)) - } - - fmt.Println("Connected to the database") - return &Database{DB: db}, nil -======= type Database interface { User Exercise Workout ->>>>>>> 12012e7eedb63c6cad288001c5cd429cb4ec7dde } diff --git a/internal/types/database/update_exercise.go b/internal/types/database/update_exercise.go index ae7a1af..7ca31a7 100644 --- a/internal/types/database/update_exercise.go +++ b/internal/types/database/update_exercise.go @@ -1,13 +1,12 @@ package database -import "time" - type UpdateExerciseReq interface { + GetID() string GetName() string GetDescription() string GetCategories() []string GetMuscleGroups() []string - GetScheduledTimes() []time.Time + //GetScheduledTimes() []time.Time } type UpdateExerciseResp interface { diff --git a/main.go b/main.go index b549cb3..385dff5 100644 --- a/main.go +++ b/main.go @@ -2,66 +2,82 @@ package main import ( "context" - "fmt" "log/slog" - "os" - "os/signal" - + askar_postgres "workout-training-api/internal/askar-postgres" + "workout-training-api/internal/askar-postgres/model/seeds" "workout-training-api/internal/config" "workout-training-api/internal/constant" - "workout-training-api/internal/controller" - "workout-training-api/internal/graphql" - "workout-training-api/internal/grpc" - "workout-training-api/internal/postgres" "workout-training-api/pkg/logger" ) func main() { - ctx, cancel := context.WithCancel(context.Background()) + // ctx, cancel := context.WithCancel(context.Background()) - // config - conf := config.New(ctx) + // // config + // conf := config.New(ctx) - // logger - log := logger.New(conf.ENV != constant.EnvironmentLocal) + // // logger + // log := logger.New(conf.ENV != constant.EnvironmentLocal) - p, err := postgres.New(conf.Postgres, log.With(slog.String("service", "postgre"))) - if err != nil { - log.ErrorContext(ctx, "failed to start postgre", slog.Any("error", err)) - panic(err) - } + // p, err := postgres.New(conf.Postgres, log.With(slog.String("service", "postgre"))) + // if err != nil { + // log.ErrorContext(ctx, "failed to start postgre", slog.Any("error", err)) + // panic(err) + // } + + // ctrl := controller.New(conf, p) + + // gr := grpc.New(conf.API.Grpc, log.With(slog.String("service", "grpc")), ctrl) + // go func(ctx context.Context, cancelFunc context.CancelFunc) { + // if err := gr.Start(ctx); err != nil { + // log.ErrorContext(ctx, "failed to start grpc", slog.Any("error", err)) + // } + + // cancelFunc() + // }(ctx, cancel) - ctrl := controller.New(conf, p) + // gql := graphql.New(conf.API.GraphQL, log.With(slog.String("service", "graphql")), ctrl) + // go func(ctx context.Context, cancelFunc context.CancelFunc) { + // if err := gql.Start(ctx); err != nil { + // log.ErrorContext(ctx, "failed to start graphql", slog.Any("error", err)) + // } - gr := grpc.New(conf.API.Grpc, log.With(slog.String("service", "grpc")), ctrl) - go func(ctx context.Context, cancelFunc context.CancelFunc) { - if err := gr.Start(ctx); err != nil { - log.ErrorContext(ctx, "failed to start grpc", slog.Any("error", err)) - } + // cancelFunc() + // }(ctx, cancel) - cancelFunc() - }(ctx, cancel) + // go func(cancelFunc context.CancelFunc) { + // shutdown := make(chan os.Signal, 1) // Create channel to signify s signal being sent + // signal.Notify(shutdown, os.Interrupt) // When an interrupt is sent, notify the channel - gql := graphql.New(conf.API.GraphQL, log.With(slog.String("service", "graphql")), ctrl) - go func(ctx context.Context, cancelFunc context.CancelFunc) { - if err := gql.Start(ctx); err != nil { - log.ErrorContext(ctx, "failed to start graphql", slog.Any("error", err)) - } + // sig := <-shutdown + // log.WarnContext(ctx, "signal received - shutting down...", slog.Any("signal", sig)) - cancelFunc() - }(ctx, cancel) + // cancelFunc() + // }(cancel) - go func(cancelFunc context.CancelFunc) { - shutdown := make(chan os.Signal, 1) // Create channel to signify s signal being sent - signal.Notify(shutdown, os.Interrupt) // When an interrupt is sent, notify the channel + // <-ctx.Done() - sig := <-shutdown - log.WarnContext(ctx, "signal received - shutting down...", slog.Any("signal", sig)) + // fmt.Println("shutting down gracefully") - cancelFunc() - }(cancel) + ctx, cancel := context.WithCancel(context.Background()) + defer cancel() + + // config + conf := config.New(ctx) + + // logger + log := logger.New(conf.ENV != constant.EnvironmentLocal) + + // postgres + p, err := askar_postgres.New(conf.AskarPostgres, log) + if err != nil { + log.ErrorContext(ctx, "failed to start postgres", slog.Any("error", err)) + } - <-ctx.Done() + seeder := seeds.New(p) + //seeder.Populate() + seeder.TestMethods() + //fmt.Print(db) + log.InfoContext(ctx, "postgres connection pool established", nil) - fmt.Println("shutting down gracefully") }