Skip to content

Commit

Permalink
Started with layers
Browse files Browse the repository at this point in the history
  • Loading branch information
artemzi committed Sep 17, 2024
1 parent 986e110 commit bc635e5
Show file tree
Hide file tree
Showing 9 changed files with 270 additions and 2 deletions.
5 changes: 4 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@ module github.com/artemzi/auth
go 1.23

require (
github.com/Masterminds/squirrel v1.5.4
github.com/fatih/color v1.17.0
github.com/jackc/pgconn v1.14.3
github.com/jackc/pgx/v4 v4.18.3
github.com/joho/godotenv v1.5.1
github.com/pkg/errors v0.9.1
Expand All @@ -14,13 +16,14 @@ require (

require (
github.com/jackc/chunkreader/v2 v2.0.1 // indirect
github.com/jackc/pgconn v1.14.3 // indirect
github.com/jackc/pgio v1.0.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgproto3/v2 v2.3.3 // indirect
github.com/jackc/pgservicefile v0.0.0-20221227161230-091c0ba34f0a // indirect
github.com/jackc/pgtype v1.14.0 // indirect
github.com/jackc/puddle v1.3.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 // indirect
github.com/mattn/go-colorable v0.1.13 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
golang.org/x/crypto v0.24.0 // indirect
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
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/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 Expand Up @@ -76,6 +78,10 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 h1:SOEGU9fKiNWd/HOJuq6+3iTQz8KNCLtVX6idSoTLdUw=
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0/go.mod h1:dXGbAdH5GtBTC4WfIxhKZfyBF/HBFgRZSWwZ9g/He9o=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0 h1:P6pPBnrTSX3DEVR4fDembhRWSsG5rVo6hYhAB/ADZrk=
github.com/lann/ps v0.0.0-20150810152359-62de8c46ede0/go.mod h1:vmVJ0l/dxyfGW6FmdpVm2joNMFikkuWg0EoCKLGUMNw=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
Expand Down
66 changes: 66 additions & 0 deletions internal/client/db/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
package db

import (
"context"

"github.com/jackc/pgconn"
"github.com/jackc/pgx/v4"
)

// Handler - функция, которая выполняется в транзакции
type Handler func(ctx context.Context) error

// Client клиент для работы с БД
type Client interface {
DB() DB
Close() error
}

// TxManager менеджер транзакций, который выполняет указанный пользователем обработчик в транзакции
type TxManager interface {
ReadCommitted(ctx context.Context, f Handler) error
}

// Query обертка над запросом, хранящая имя запроса и сам запрос
// Имя запроса используется для логирования и потенциально может использоваться еще где-то, например, для трейсинга
type Query struct {
Name string
QueryRaw string
}

// Transactor интерфейс для работы с транзакциями
type Transactor interface {
BeginTx(ctx context.Context, txOptions pgx.TxOptions) (pgx.Tx, error)
}

// SQLExecer комбинирует NamedExecer и QueryExecer
type SQLExecer interface {
NamedExecer
QueryExecer
}

// NamedExecer интерфейс для работы с именованными запросами с помощью тегов в структурах
type NamedExecer interface {
ScanOneContext(ctx context.Context, dest interface{}, q Query, args ...interface{}) error
ScanAllContext(ctx context.Context, dest interface{}, q Query, args ...interface{}) error
}

// QueryExecer интерфейс для работы с обычными запросами
type QueryExecer interface {
ExecContext(ctx context.Context, q Query, args ...interface{}) (pgconn.CommandTag, error)
QueryContext(ctx context.Context, q Query, args ...interface{}) (pgx.Rows, error)
QueryRowContext(ctx context.Context, q Query, args ...interface{}) pgx.Row
}

// Pinger интерфейс для проверки соединения с БД
type Pinger interface {
Ping(ctx context.Context) error
}

// DB интерфейс для работы с БД
type DB interface {
SQLExecer
Transactor
Pinger
Close()
}
21 changes: 21 additions & 0 deletions internal/model/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package model

import (
"database/sql"
"time"
)

type User struct {

Check failure on line 8 in internal/model/user.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported type User should have comment or be unexported (revive)
ID int64
Info UserInfo
CreatedAt time.Time
UpdatedAt sql.NullTime
}

type UserInfo struct {

Check failure on line 15 in internal/model/user.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported type UserInfo should have comment or be unexported (revive)
Name string
Email string
Password string
PasswordConfirm string
Role string // todo: enum
}
15 changes: 15 additions & 0 deletions internal/repository/repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package repository

import (
"context"

"github.com/artemzi/auth/internal/model"
)

type UserRepository interface {

Check failure on line 9 in internal/repository/repository.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported type UserRepository should have comment or be unexported (revive)
Create(ctx context.Context, info *model.UserInfo) (int64, error)
Get(ctx context.Context, id int64) (*model.User, error)
// TODO: implement it
// Update(ctx context.Context, info *model.User) error
// Delete(ctx context.Context, id int64) error
}
21 changes: 21 additions & 0 deletions internal/repository/user/entity/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package entity

import (
"database/sql"
"time"
)

type User struct {

Check failure on line 8 in internal/repository/user/entity/user.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported type User should have comment or be unexported (revive)
ID int64
Info UserInfo
CreatedAt time.Time
UpdatedAt sql.NullTime
}

type UserInfo struct {

Check failure on line 15 in internal/repository/user/entity/user.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported type UserInfo should have comment or be unexported (revive)
Name string
Email string
Passowrd string
PasswordConfirm string
Role string // todo: enum
}
25 changes: 25 additions & 0 deletions internal/repository/user/mapper/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package mapper

import (
"github.com/artemzi/auth/internal/model"
entity "github.com/artemzi/auth/internal/repository/user/entity"
)

func ToUserFromEntity(user *entity.User) *model.User {

Check failure on line 8 in internal/repository/user/mapper/user.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported function ToUserFromEntity should have comment or be unexported (revive)
return &model.User{
ID: user.ID,
Info: ToUserInfoFromEntity(user.Info),
CreatedAt: user.CreatedAt,
UpdatedAt: user.UpdatedAt,
}
}

func ToUserInfoFromEntity(info entity.UserInfo) model.UserInfo {

Check failure on line 17 in internal/repository/user/mapper/user.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported function ToUserInfoFromEntity should have comment or be unexported (revive)
return model.UserInfo{
Name: info.Name,
Email: info.Email,
Password: info.Passowrd,
PasswordConfirm: info.PasswordConfirm,
Role: info.Role,
}
}
111 changes: 111 additions & 0 deletions internal/repository/user/repository.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
package user

import (
"context"

sq "github.com/Masterminds/squirrel"
"github.com/artemzi/auth/internal/client/db"
"github.com/artemzi/auth/internal/model"
"github.com/artemzi/auth/internal/repository"
entity "github.com/artemzi/auth/internal/repository/user/entity"
"github.com/artemzi/auth/internal/repository/user/mapper"
"github.com/fatih/color"
log "github.com/sirupsen/logrus"
)

const (
tableName = "user"

idColumn = "id"
nameColumn = "name"
emailColumn = "email"
passwordColumn = "password"
passwordConfirmColumn = "password_confirm"
roleColumn = "role"
createdAtColumn = "created_at"
updatedAtColumn = "updated_at"
)

type repo struct {
db db.Client
}

func NewRepository(db db.Client) repository.UserRepository {

Check failure on line 33 in internal/repository/user/repository.go

View workflow job for this annotation

GitHub Actions / lint

exported: exported function NewRepository should have comment or be unexported (revive)
return &repo{db: db}
}

func (r *repo) Create(ctx context.Context, info *model.UserInfo) (int64, error) {
builder := sq.Insert(tableName).
PlaceholderFormat(sq.Dollar).
Columns(nameColumn, emailColumn, passwordColumn, passwordConfirmColumn, roleColumn).
Values(info.Name, info.Email, info.Password, info.PasswordConfirm, info.Role).
Suffix("RETURNING id")

query, args, err := builder.ToSql()
if err != nil {
return 0, err
}

q := db.Query{
Name: "user_repository.Create",
QueryRaw: query,
}

var userID int64
err = r.db.DB().QueryRowContext(ctx, q, args...).Scan(&userID)
if err != nil {
log.Errorf("failed to INSERT user: %v", err)
return 0, err
}

log.WithContext(ctx).Infof("inserted user with id: %d", userID)
return userID, nil
}

func (r *repo) Get(ctx context.Context, id int64) (*model.User, error) {
query := "SELECT id, name, email, role, created_at, updated_at FROM \"user\" WHERE id = $1;"

q := db.Query{
Name: "user_repository.Get",
QueryRaw: query,
}

var user entity.User
err := r.db.DB().QueryRowContext(ctx, q, id).
Scan(&user.ID, &user.Info.Name, &user.Info.Email, &user.Info.Role, &user.CreatedAt, &user.UpdatedAt)
if err != nil {
log.Errorf("failed to GET user: %v", err)
return nil, err
}

log.WithContext(ctx).Info(color.GreenString("Got User id: "), id)
return mapper.ToUserFromEntity(&user), nil
}

// func (s *repo) Update(ctx context.Context, req *desc.UpdateRequest) (*emptypb.Empty, error) {
// query := "UPDATE \"user\" SET name = $1, email = $2 WHERE id = $3;"

// _, err := s.pool.Exec(ctx, query, req.GetInfo().GetName().Value, req.GetInfo().GetEmail().Value, req.GetId())
// if err != nil {
// log.Errorf("failed to UPDATE user: %v", err)
// return nil, err
// }

// log.WithContext(ctx).Info(color.GreenString("Updated User id: "), req.GetId())
// out := new(emptypb.Empty)

// return out, nil
// }

// func (r *repo) Delete(ctx context.Context, id int64) error {
// query := "DELETE FROM \"user\" WHERE id = $1;"

// _, err := r.db.DB().pool.Exec(ctx, query, id)
// if err != nil {
// log.Errorf("failed to DELETE user: %v", err)
// return err
// }

// log.WithContext(ctx).Info(color.GreenString("Deleted User id: "), id)
// return nil
// }
2 changes: 1 addition & 1 deletion migrations/20240912125510_001_create_auth_table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ CREATE TABLE "user" (
password_confirm text not null,
role ROLE default '1',
created_at timestamp not null default now(),
updated_at timestamp not null default now()
updated_at timestamp
);

-- +goose Down
Expand Down

0 comments on commit bc635e5

Please sign in to comment.