Skip to content

Commit

Permalink
Merge pull request #7 from Chuiko-GIT/add-db-client-wrapper
Browse files Browse the repository at this point in the history
Added wrapper for database client to improve modularity and reusability
  • Loading branch information
Chuiko-GIT authored Aug 25, 2024
2 parents 1082361 + 3baccdd commit d542ee7
Show file tree
Hide file tree
Showing 9 changed files with 295 additions and 62 deletions.
7 changes: 3 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,17 @@ toolchain go1.22.5

require (
github.com/Masterminds/squirrel v1.5.4
github.com/fatih/color v1.17.0
github.com/georgysavva/scany v1.2.2
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
google.golang.org/grpc v1.65.0
google.golang.org/protobuf v1.34.2
)

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
Expand All @@ -24,8 +25,6 @@ require (
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
golang.org/x/net v0.26.0 // indirect
golang.org/x/sys v0.21.0 // indirect
Expand Down
57 changes: 47 additions & 10 deletions go.sum

Large diffs are not rendered by default.

37 changes: 15 additions & 22 deletions internal/app/service_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"context"
"log"

"github.com/jackc/pgx/v4/pgxpool"

"github.com/Chuiko-GIT/auth/internal/api/users"
uImpl "github.com/Chuiko-GIT/auth/internal/api/users"
db "github.com/Chuiko-GIT/auth/internal/client"
"github.com/Chuiko-GIT/auth/internal/client/db/pg"
"github.com/Chuiko-GIT/auth/internal/closer"
"github.com/Chuiko-GIT/auth/internal/config"
"github.com/Chuiko-GIT/auth/internal/config/env"
Expand All @@ -18,15 +18,12 @@ import (
)

type ServiceProvider struct {
pgConfig config.PGConfig
grpcConfig config.GRPCConfig

pgPool *pgxpool.Pool
pgConfig config.PGConfig
grpcConfig config.GRPCConfig
dbClient db.Client
usersRepository repository.Users

usersService service.Users

usersImpl *users.Implementation
usersService service.Users
usersImpl *users.Implementation
}

func newServiceProvider() *ServiceProvider {
Expand Down Expand Up @@ -58,31 +55,27 @@ func (s *ServiceProvider) GRPCConfig() config.GRPCConfig {
return s.grpcConfig
}

func (s *ServiceProvider) PGPool(ctx context.Context) *pgxpool.Pool {
if s.pgPool == nil {
poll, err := pgxpool.Connect(ctx, s.PGConfig().DSN())
func (s *ServiceProvider) DBClient(ctx context.Context) db.Client {
if s.dbClient == nil {
cl, err := pg.New(ctx, s.PGConfig().DSN())
if err != nil {
log.Fatalf("failed to create db client: %v", err)
}

if err = poll.Ping(ctx); err != nil {
if err = cl.DB().Ping(ctx); err != nil {
log.Fatalf("ping error: %s", err.Error())
}
closer.Add(cl.Close)

closer.Add(func() error {
poll.Close()
return nil
})

s.pgPool = poll
s.dbClient = cl
}

return s.pgPool
return s.dbClient
}

func (s *ServiceProvider) UsersRepository(ctx context.Context) repository.Users {
if s.usersRepository == nil {
s.usersRepository = uRepo.NewRepository(s.PGPool(ctx))
s.usersRepository = uRepo.NewRepository(s.DBClient(ctx))
}

return s.usersRepository
Expand Down
46 changes: 46 additions & 0 deletions internal/client/db.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package client

import (
"context"

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

type (
Client interface {
DB() DB
Close() error
}

SQLExec interface {
NamedExec
QueryExec
}

NamedExec interface {
ScanOneContext(ctx context.Context, dest interface{}, q Query, args ...interface{}) error
ScanAllContext(ctx context.Context, dest interface{}, q Query, args ...interface{}) error
}

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

Ping interface {
Ping(ctx context.Context) error
}

DB interface {
SQLExec
Ping
Close()
}

Query struct {
Name string
QueryRaw string
}
)
36 changes: 36 additions & 0 deletions internal/client/db/pg/client.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package pg

import (
"context"

"github.com/jackc/pgx/v4/pgxpool"
"github.com/pkg/errors"

db "github.com/Chuiko-GIT/auth/internal/client"
)

type pgClient struct {
masterDBC db.DB
}

func New(ctx context.Context, dsn string) (db.Client, error) {
dbc, err := pgxpool.Connect(ctx, dsn)
if err != nil {
return nil, errors.Errorf("failed to connect to db: %v", err)
}

return &pgClient{
masterDBC: &pg{dbc: dbc},
}, nil
}

func (c pgClient) DB() db.DB {
return c.masterDBC
}

func (c pgClient) Close() error {
if c.masterDBC != nil {
c.masterDBC.Close()
}
return nil
}
81 changes: 81 additions & 0 deletions internal/client/db/pg/pg.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
package pg

import (
"context"
"fmt"
"log"

"github.com/georgysavva/scany/pgxscan"
"github.com/jackc/pgconn"
"github.com/jackc/pgx/v4"
"github.com/jackc/pgx/v4/pgxpool"

db "github.com/Chuiko-GIT/auth/internal/client"
"github.com/Chuiko-GIT/auth/internal/client/db/prettier"
)

type pg struct {
dbc *pgxpool.Pool
}

func NewDB(dbc *pgxpool.Pool) db.DB {
return &pg{
dbc: dbc,
}
}

func (p pg) ScanOneContext(ctx context.Context, dest interface{}, q db.Query, args ...interface{}) error {
logQuery(ctx, q, args...)

rows, err := p.QueryContext(ctx, q, args...)
if err != nil {
return err
}
return pgxscan.ScanOne(dest, rows)
}

func (p pg) ScanAllContext(ctx context.Context, dest interface{}, q db.Query, args ...interface{}) error {
logQuery(ctx, q, args...)

rows, err := p.QueryContext(ctx, q, args...)
if err != nil {
return err
}

return pgxscan.ScanAll(dest, rows)
}

func (p pg) ExecContext(ctx context.Context, q db.Query, args ...interface{}) (pgconn.CommandTag, error) {
logQuery(ctx, q, args...)

return p.dbc.Exec(ctx, q.QueryRaw, args...)
}

func (p pg) QueryContext(ctx context.Context, q db.Query, args ...interface{}) (pgx.Rows, error) {
logQuery(ctx, q, args...)

return p.dbc.Query(ctx, q.QueryRaw, args...)
}

func (p pg) QueryRowContext(ctx context.Context, q db.Query, args ...interface{}) pgx.Row {
logQuery(ctx, q, args...)

return p.dbc.QueryRow(ctx, q.QueryRaw, args...)
}

func (p pg) Ping(ctx context.Context) error {
return p.dbc.Ping(ctx)
}

func (p pg) Close() {
p.dbc.Close()
}

func logQuery(ctx context.Context, q db.Query, args ...interface{}) {
prettyQuery := prettier.Pretty(q.QueryRaw, prettier.PlaceholderDollar, args...)
log.Println(
ctx,
fmt.Sprintf("sql: %s", q.Name),
fmt.Sprintf("query: %s", prettyQuery),
)
}
33 changes: 33 additions & 0 deletions internal/client/db/prettier/prettier.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package prettier

import (
"fmt"
"strconv"
"strings"
)

const (
PlaceholderDollar = "$"
PlaceholderQuestion = "?"
)

func Pretty(query, placeholder string, args ...any) string {
for i, param := range args {
var value string
switch v := param.(type) {
case string:
value = fmt.Sprintf("%q", v)
case []byte:
value = fmt.Sprintf("%q", string(v))
default:
value = fmt.Sprintf("%v", v)
}

query = strings.Replace(query, fmt.Sprintf("%s%s", placeholder, strconv.Itoa(i+1)), value, -1)
}

query = strings.ReplaceAll(query, "\t", "")
query = strings.ReplaceAll(query, "\n", " ")

return strings.TrimSpace(query)
}
2 changes: 1 addition & 1 deletion internal/repository/users/model/users.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import (
type (
UserInfoRepo struct {
Name string `db:"name"`
Email string `db:"name"`
Email string `db:"email"`
Password string `db:"password"`
PasswordConfirm string `db:"password_confirm"`
Role string `db:"role"`
Expand Down
Loading

0 comments on commit d542ee7

Please sign in to comment.