Skip to content

Commit

Permalink
Added project architecture and initial structure
Browse files Browse the repository at this point in the history
  • Loading branch information
“achuyko” committed Aug 25, 2024
1 parent 86ba548 commit 4a90915
Show file tree
Hide file tree
Showing 20 changed files with 459 additions and 95 deletions.
100 changes: 8 additions & 92 deletions cmd/grpc_server/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,16 @@ import (
"flag"
"log"
"net"
"time"

sq "github.com/Masterminds/squirrel"
"github.com/jackc/pgx/v4/pgxpool"
"google.golang.org/grpc"
"google.golang.org/grpc/reflection"
"google.golang.org/protobuf/types/known/emptypb"

usersAPI "github.com/Chuiko-GIT/auth/internal/api/users"
"github.com/Chuiko-GIT/auth/internal/config"
"github.com/Chuiko-GIT/auth/internal/config/env"
"github.com/Chuiko-GIT/auth/internal/repository/users"
srv "github.com/Chuiko-GIT/auth/internal/service/users"
"github.com/Chuiko-GIT/auth/pkg/user_api"
)

Expand All @@ -26,97 +26,11 @@ func init() {
flag.StringVar(&configPath, "config-path", ".env", "path to config file")
}

type server struct {
user_api.UnimplementedUserAPIServer
pool *pgxpool.Pool
}

func (s server) Create(ctx context.Context, req *user_api.CreateRequest) (*user_api.CreateResponse, error) {
builderInsert := sq.Insert("users").
PlaceholderFormat(sq.Dollar).
Columns("name", "email", "password", "password_confirm", "role").
Values(req.User.Name, req.User.Email, req.User.Password, req.User.PasswordConfirm, req.User.Role.String()).
Suffix("RETURNING id")

query, args, err := builderInsert.ToSql()
if err != nil {
log.Fatalf("failed to build query: %v", err)
}

var userID int
if err = s.pool.QueryRow(ctx, query, args...).Scan(&userID); err != nil {
log.Fatalf("failed to select users: %v", err)
}

log.Printf("inserted user with id: %d", userID)

return &user_api.CreateResponse{
Id: int64(userID),
}, nil
}

func (s server) Delete(ctx context.Context, req *user_api.DeleteRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, nil
}

func (s server) Update(ctx context.Context, req *user_api.UpdateRequest) (*emptypb.Empty, error) {
builderUpdate := sq.Update("users").
PlaceholderFormat(sq.Dollar).
Set("name", "Alex").
Set("email", "[email protected]").
Set("password", "test-test").
Set("password_confirm", "true").
Set("role", "admin").
Set("updated_at", time.Now()).
Where(sq.Eq{"id": req.GetId()})

query, args, err := builderUpdate.ToSql()
if err != nil {
log.Fatalf("failed to build query: %v", err)
}

res, err := s.pool.Exec(ctx, query, args...)
if err != nil {
log.Fatalf("failed to update user: %v", err)
}

log.Printf("updated %d rows", res.RowsAffected())

return &emptypb.Empty{}, nil
}

func (s server) Get(ctx context.Context, req *user_api.GetRequest) (*user_api.GetResponse, error) {
builderSelectOne := sq.Select("id", "name", "email", "password", "password_confirm", "role", "created_at", "updated_at").
From("users").
PlaceholderFormat(sq.Dollar).
Where(sq.Eq{"id": req.GetId()}).
Limit(1)

query, args, err := builderSelectOne.ToSql()
if err != nil {
log.Fatalf("failed to build query: %v", err)
}

var resp user_api.User
err = s.pool.
QueryRow(ctx, query, args...).
Scan(resp.Id, resp.User.Name, resp.User.Email, resp.User.Password, resp.User.PasswordConfirm, resp.User.Role, resp.CreatedAt, resp.UpdatedAt)
if err != nil {
log.Fatalf("failed to select user: %v", err)
}

log.Printf("id: %d, name: %s, email: %s,password: %s,passwordConfirm: %s,role: %s, created_at: %v, updated_at: %v\n",
resp.Id, resp.User.Name, resp.User.Email, resp.User.Password, resp.User.PasswordConfirm, resp.User.Role, resp.CreatedAt, resp.UpdatedAt)

return &user_api.GetResponse{User: &resp}, nil

}

func main() {
flag.Parse()
ctx := context.Background()

if err := config.Load(configPath); err != nil {
if err := config.Load("local.env"); err != nil {
log.Fatalf("failed to load config: %v", err)
}

Expand All @@ -129,9 +43,11 @@ func main() {
if err != nil {
log.Fatalf("failed to connect to database: %v", err)
}

defer pool.Close()

repoUsers := users.NewRepository(pool)
serviceUser := srv.NewService(repoUsers)

grpcConfig, err := env.NewGRPCConfig()
if err != nil {
log.Fatalf("failed to get grpc config: %v", err)
Expand All @@ -144,7 +60,7 @@ func main() {

s := grpc.NewServer()
reflection.Register(s)
user_api.RegisterUserAPIServer(s, server{pool: pool})
user_api.RegisterUserAPIServer(s, usersAPI.NewImplementation(serviceUser))

log.Printf("server listening at %v", lis.Addr())

Expand Down
1 change: 0 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ toolchain go1.22.5

require (
github.com/Masterminds/squirrel v1.5.4
github.com/brianvoe/gofakeit v3.18.0+incompatible
github.com/fatih/color v1.17.0
github.com/jackc/pgx/v4 v4.18.3
github.com/joho/godotenv v1.5.1
Expand Down
2 changes: 0 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03
github.com/Masterminds/semver/v3 v3.1.1/go.mod h1:VPu/7SZ7ePZ3QOrcuXROw5FAcLl4a0cBrbBpGY/8hQs=
github.com/Masterminds/squirrel v1.5.4 h1:uUcX/aBc8O7Fg9kaISIUsHXdKuqehiXAMQTYX8afzqM=
github.com/Masterminds/squirrel v1.5.4/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
github.com/brianvoe/gofakeit v3.18.0+incompatible h1:wDOmHc9DLG4nRjUVVaxA+CEglKOW72Y5+4WNxUIkjM8=
github.com/brianvoe/gofakeit v3.18.0+incompatible/go.mod h1:kfwdRA90vvNhPutZWfH7WPaDzUjz+CZFqG+rPkOjGOc=
github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
Expand Down
16 changes: 16 additions & 0 deletions internal/api/users/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package users

import (
"context"

"github.com/Chuiko-GIT/auth/internal/converter"
"github.com/Chuiko-GIT/auth/pkg/user_api"
)

func (i *Implementation) Create(ctx context.Context, req *user_api.CreateRequest) (*user_api.CreateResponse, error) {
id, err := i.userService.Create(ctx, converter.ToUserInfoFromDesc(req.GetUser()))
if err != nil {
return &user_api.CreateResponse{}, err
}
return &user_api.CreateResponse{Id: id}, nil
}
13 changes: 13 additions & 0 deletions internal/api/users/delete.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package users

import (
"context"

"google.golang.org/protobuf/types/known/emptypb"

"github.com/Chuiko-GIT/auth/pkg/user_api"
)

func (i *Implementation) Delete(ctx context.Context, req *user_api.DeleteRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, i.userService.Delete(ctx, req.Id)
}
17 changes: 17 additions & 0 deletions internal/api/users/get.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package users

import (
"context"

"github.com/Chuiko-GIT/auth/internal/converter"
"github.com/Chuiko-GIT/auth/pkg/user_api"
)

func (i *Implementation) Get(ctx context.Context, req *user_api.GetRequest) (*user_api.GetResponse, error) {
resp, err := i.userService.Get(ctx, req.Id)
if err != nil {
return &user_api.GetResponse{}, err
}

return &user_api.GetResponse{User: converter.ToUserFromService(resp)}, nil
}
20 changes: 20 additions & 0 deletions internal/api/users/service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package users

import (
"github.com/Chuiko-GIT/auth/internal/service"
"github.com/Chuiko-GIT/auth/pkg/user_api"
)

// В курсе решили назвать название этого файла тоже service.go
// В курсе так же не придумали название данному слою, поэтому Implementation

type Implementation struct {
user_api.UnimplementedUserAPIServer
userService service.Users
}

func NewImplementation(userService service.Users) *Implementation {
return &Implementation{
userService: userService,
}
}
14 changes: 14 additions & 0 deletions internal/api/users/update.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package users

import (
"context"

"google.golang.org/protobuf/types/known/emptypb"

"github.com/Chuiko-GIT/auth/internal/converter"
"github.com/Chuiko-GIT/auth/pkg/user_api"
)

func (i *Implementation) Update(ctx context.Context, req *user_api.UpdateRequest) (*emptypb.Empty, error) {
return &emptypb.Empty{}, i.userService.Update(ctx, converter.ToUserUpdateFromDesc(req))
}
50 changes: 50 additions & 0 deletions internal/converter/users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package converter

import (
"google.golang.org/protobuf/types/known/timestamppb"

"github.com/Chuiko-GIT/auth/internal/model"
"github.com/Chuiko-GIT/auth/pkg/user_api"
)

func ToUserFromService(user model.User) *user_api.User {
var updatedAt *timestamppb.Timestamp
if user.UpdatedAt.Valid {
updatedAt = timestamppb.New(user.UpdatedAt.Time)
}

return &user_api.User{
Id: user.ID,
User: ToUserInfoFromService(user.UserInfo),
CreatedAt: timestamppb.New(user.CreatedAt),
UpdatedAt: updatedAt,
}
}

func ToUserInfoFromService(userInfo model.UserInfo) *user_api.UserInfo {
return &user_api.UserInfo{
Name: userInfo.Name,
Email: userInfo.Email,
Password: userInfo.Password,
PasswordConfirm: userInfo.PasswordConfirm,
Role: user_api.Role(user_api.Role_value[userInfo.Role]),
}
}

func ToUserInfoFromDesc(userInfo *user_api.UserInfo) model.UserInfo {
return model.UserInfo{
Name: userInfo.Name,
Email: userInfo.Name,
Password: userInfo.Password,
PasswordConfirm: userInfo.PasswordConfirm,
Role: userInfo.Role.String(),
}
}

func ToUserUpdateFromDesc(userUpdate *user_api.UpdateRequest) model.UpdateUser {
return model.UpdateUser{
ID: userUpdate.Id,
Name: userUpdate.User.Name.Value,
Email: userUpdate.User.Email.Value,
}
}
29 changes: 29 additions & 0 deletions internal/model/users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package model

import (
"database/sql"
"time"
)

type (
UserInfo struct {
Name string
Email string
Password string
PasswordConfirm string
Role string
}

User struct {
ID int64
UserInfo UserInfo
CreatedAt time.Time
UpdatedAt sql.NullTime
}

UpdateUser struct {
ID int64
Name string
Email string
}
)
17 changes: 17 additions & 0 deletions internal/repository/repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package repository

import (
"context"

"github.com/Chuiko-GIT/auth/internal/model"
)

type (
Users interface {
Create(ctx context.Context, user model.UserInfo) (int64, error)
Get(ctx context.Context, id int64) (model.User, error)
GetAll(ctx context.Context) ([]model.User, error)
Update(ctx context.Context, req model.UpdateUser) error
Delete(ctx context.Context, id int64) error
}
)
25 changes: 25 additions & 0 deletions internal/repository/users/converter/users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package converter

import (
"github.com/Chuiko-GIT/auth/internal/model"
dbModel "github.com/Chuiko-GIT/auth/internal/repository/users/model"
)

func ToUserFromRepo(user dbModel.UserRepo) model.User {
return model.User{
ID: user.ID,
UserInfo: ToUserInfoFromRepo(user.UserInfo),
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
}
}

func ToUserInfoFromRepo(userInfo dbModel.UserInfoRepo) model.UserInfo {
return model.UserInfo{
Name: userInfo.Name,
Email: userInfo.Email,
Password: userInfo.Password,
PasswordConfirm: userInfo.PasswordConfirm,
Role: userInfo.Role,
}
}
23 changes: 23 additions & 0 deletions internal/repository/users/model/users.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package model

import (
"database/sql"
"time"
)

type (
UserInfoRepo struct {
Name string `db:"name"`
Email string `db:"name"`
Password string `db:"password"`
PasswordConfirm string `db:"password_confirm"`
Role string `db:"role"`
}

UserRepo struct {
ID int64 `db:"id"`
UserInfo UserInfoRepo `db:""`
CreatedAt time.Time `db:"created_at"`
UpdatedAt sql.NullTime `db:"updated_at"`
}
)
Loading

0 comments on commit 4a90915

Please sign in to comment.