Compare commits

...

2 Commits

Author SHA1 Message Date
b3eb75646a feat: add logrus logger 2026-03-30 17:01:32 -05:00
5e23e20e5a refactor: extract connection to database logic to db module 2026-03-30 11:44:27 -05:00
8 changed files with 75 additions and 40 deletions

View File

@@ -3,35 +3,26 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"os" "os"
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/config" "git.ksdemosapps.com/kylesoda/pgx-learning/internal/config"
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/db"
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/db/postgres" "git.ksdemosapps.com/kylesoda/pgx-learning/internal/db/postgres"
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/models" "git.ksdemosapps.com/kylesoda/pgx-learning/internal/models"
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/repository" "git.ksdemosapps.com/kylesoda/pgx-learning/internal/repository"
"github.com/jackc/pgx/v5/pgxpool" "github.com/sirupsen/logrus"
"github.com/urfave/cli/v2" "github.com/urfave/cli/v2"
) )
var pool *pgxpool.Pool
var ctx = context.Background()
func init() {
var err error
pool, err = pgxpool.New(ctx, config.Db.Url)
if err != nil {
log.Fatal("Unable to connect to database:", err)
}
if err := pool.Ping(ctx); err != nil {
log.Fatal("Unable to ping database:", err)
}
// fmt.Println("Connected to PostgreSQL database!")
}
func main() { func main() {
ctx := context.Background()
pool, err := db.Connect(ctx, config.Db.Url)
if err != nil {
logrus.Fatal(err)
}
defer db.Close(pool)
taskRespository := postgres.NewTaskRepository(pool) taskRespository := postgres.NewTaskRepository(pool)
app := &cli.App{ app := &cli.App{
@@ -175,9 +166,9 @@ func main() {
}, },
} }
err := app.Run(os.Args) err = app.Run(os.Args)
if err != nil { if err != nil {
log.Fatal(err) logrus.Fatal(err)
} }
} }

2
go.mod
View File

@@ -5,6 +5,7 @@ go 1.25.7
require ( require (
github.com/jackc/pgx/v5 v5.9.1 github.com/jackc/pgx/v5 v5.9.1
github.com/joho/godotenv v1.5.1 github.com/joho/godotenv v1.5.1
github.com/sirupsen/logrus v1.9.4
github.com/urfave/cli/v2 v2.27.7 github.com/urfave/cli/v2 v2.27.7
) )
@@ -16,5 +17,6 @@ require (
github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 // indirect
golang.org/x/sync v0.17.0 // indirect golang.org/x/sync v0.17.0 // indirect
golang.org/x/sys v0.13.0 // indirect
golang.org/x/text v0.29.0 // indirect golang.org/x/text v0.29.0 // indirect
) )

4
go.sum
View File

@@ -17,6 +17,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w=
github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 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.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.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@@ -28,6 +30,8 @@ github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGC
github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM=
golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug=
golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE=
golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk= golang.org/x/text v0.29.0 h1:1neNs90w9YzJ9BocxfsQNHKuAT4pkghyXc4nhZ6sJvk=
golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4= golang.org/x/text v0.29.0/go.mod h1:7MhJOA9CD2qZyOKYazxdYMF85OwPdEr9jTtBpO7ydH4=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=

View File

@@ -1,10 +1,10 @@
package config package config
import ( import (
"log"
"os" "os"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/sirupsen/logrus"
) )
type dbConfig struct { type dbConfig struct {
@@ -14,7 +14,7 @@ type dbConfig struct {
func loadEnv() { func loadEnv() {
err := godotenv.Load() err := godotenv.Load()
if err != nil { if err != nil {
log.Println("Warning: could not load .env file") logrus.Warn("Warning: could not load .env file")
} }
} }
@@ -23,7 +23,7 @@ func getDbConfig() *dbConfig {
dbUrl := os.Getenv("PG_FROM_DB_URL") dbUrl := os.Getenv("PG_FROM_DB_URL")
if dbUrl == "" { if dbUrl == "" {
log.Fatal("PG_FROM_DB_URL environment variable not set") logrus.Fatal("PG_FROM_DB_URL environment variable not set")
} }
return &dbConfig{ return &dbConfig{

28
internal/db/connection.go Normal file
View File

@@ -0,0 +1,28 @@
package db
import (
"context"
"fmt"
"github.com/jackc/pgx/v5/pgxpool"
)
func Connect(ctx context.Context, dbURL string) (*pgxpool.Pool, error) {
pool, err := pgxpool.New(ctx, dbURL)
if err != nil {
return nil, fmt.Errorf("unable to connect to database: %w", err)
}
if err := pool.Ping(ctx); err != nil {
pool.Close()
return nil, fmt.Errorf("unable to ping database: %w", err)
}
return pool, nil
}
func Close(pool *pgxpool.Pool) {
if pool != nil {
pool.Close()
}
}

View File

@@ -3,11 +3,11 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"time" "time"
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/config" "git.ksdemosapps.com/kylesoda/pgx-learning/internal/config"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
"github.com/sirupsen/logrus"
) )
func dropTables(db *pgxpool.Pool, ctx context.Context) error { func dropTables(db *pgxpool.Pool, ctx context.Context) error {
@@ -27,13 +27,13 @@ func main() {
db, err := pgxpool.New(ctx, config.Db.Url) db, err := pgxpool.New(ctx, config.Db.Url)
if err != nil { if err != nil {
log.Fatalf("Unable to create connection pool: %v", err) logrus.Fatalf("Unable to create connection pool: %v", err)
} }
if err := dropTables(db, ctx); err != nil { if err := dropTables(db, ctx); err != nil {
log.Fatalf("Unexpected error: %v", err) logrus.Fatalf("Unexpected error: %v", err)
} else { } else {
fmt.Println("Database reset completed succesfully") logrus.Info("Database reset completed succesfully")
} }
defer db.Close() defer db.Close()

View File

@@ -3,7 +3,6 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"math/rand" "math/rand"
"time" "time"
@@ -11,6 +10,7 @@ import (
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/models" "git.ksdemosapps.com/kylesoda/pgx-learning/internal/models"
"github.com/jackc/pgx/v5" "github.com/jackc/pgx/v5"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
"github.com/sirupsen/logrus"
) )
func generateTasks(count int) []models.Task { func generateTasks(count int) []models.Task {
@@ -46,32 +46,37 @@ func saveTasks(db *pgxpool.Pool, ctx context.Context, tasks []models.Task) error
} }
duration := time.Since(start) duration := time.Since(start)
fmt.Printf("Se insertaron exitosamente %d registros en %v\n", rowsCopied, duration) logrus.Infof("Se insertaron exitosamente %d registros en %v\n", rowsCopied, duration)
return nil return nil
} }
func main() { func main() {
fmt.Println("Starting seed process") logrus.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: time.StampMilli,
})
logrus.Info("Starting seed process")
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel() defer cancel()
db, err := pgxpool.New(ctx, config.Db.Url) db, err := pgxpool.New(ctx, config.Db.Url)
if err != nil { if err != nil {
log.Fatalf("Unable to create connection pool: %v", err) logrus.Fatalf("Unable to create connection pool: %v", err)
} else { } else {
fmt.Println("Successfully connected to the database") logrus.Info("Successfully connected to the database")
} }
defer db.Close() defer db.Close()
count := 100000 count := 100000
fmt.Printf("Generando %d registros...\n", count) logrus.Infof("Generando %d registros...\n", count)
tasks := generateTasks(count) tasks := generateTasks(count)
if err := saveTasks(db, ctx, tasks); err != nil { if err := saveTasks(db, ctx, tasks); err != nil {
log.Fatalf("Unexpected error: %v", err) logrus.Fatalf("Unexpected error: %v", err)
} else { } else {
fmt.Println("Database seed completed succesfully") logrus.Info("Database seed completed succesfully")
} }
} }

View File

@@ -3,11 +3,11 @@ package main
import ( import (
"context" "context"
"fmt" "fmt"
"log"
"time" "time"
"git.ksdemosapps.com/kylesoda/pgx-learning/internal/config" "git.ksdemosapps.com/kylesoda/pgx-learning/internal/config"
"github.com/jackc/pgx/v5/pgxpool" "github.com/jackc/pgx/v5/pgxpool"
"github.com/sirupsen/logrus"
) )
func createTasksTable(db *pgxpool.Pool, ctx context.Context) error { func createTasksTable(db *pgxpool.Pool, ctx context.Context) error {
@@ -30,18 +30,23 @@ CREATE TABLE IF NOT EXISTS tasks (
} }
func main() { func main() {
logrus.SetFormatter(&logrus.TextFormatter{
FullTimestamp: true,
TimestampFormat: time.StampMilli,
})
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second) ctx, cancel := context.WithTimeout(context.Background(), 20*time.Second)
defer cancel() defer cancel()
db, err := pgxpool.New(ctx, config.Db.Url) db, err := pgxpool.New(ctx, config.Db.Url)
if err != nil { if err != nil {
log.Fatalf("Unable to create connection pool: %v", err) logrus.Fatalf("Unable to create connection pool: %v", err)
} }
if err := createTasksTable(db, ctx); err != nil { if err := createTasksTable(db, ctx); err != nil {
log.Fatalf("Unexpected error: %v", err) logrus.Fatalf("Unexpected error: %v", err)
} else { } else {
fmt.Println("Database setup completed succesfully") logrus.Info("Database setup completed succesfully")
} }
defer db.Close() defer db.Close()