feat: connect to db and sample query

This commit is contained in:
ysandler 2025-03-17 17:55:17 -05:00
parent 815a3b2856
commit 83545fb854
9 changed files with 83 additions and 46 deletions

View File

@ -0,0 +1,13 @@
-- I DO NOT KNOW IF THIS WORKS --
-- I AM PLAYING ARROUND WITH START UP SCRIPTS FOR THE CONTAINER --
-- Drop existing roles/users if they exist
DROP ROLE IF EXISTS admin;
DROP USER IF EXISTS admin;
-- Create admin user with strong password using bcrypt
CREATE USER admin WITH PASSWORD 'password';
-- Grant all privileges
ALTER ROLE admin SUPERUSER;
GRANT ALL PRIVILEGES TO admin;

3
.env
View File

@ -4,5 +4,6 @@ DB_NAME=worklog
DB_HOST=localhost DB_HOST=localhost
DB_PORT=5432 DB_PORT=5432
DB_EXPOSED_PORT=6767 DB_EXPOSED_PORT=6767
DB_TZ=America/Chicago
VOLUME_ROOT="./container_volume" VOLUME_ROOT="./.container_volume"

View File

@ -2,8 +2,10 @@ package db
import ( import (
"fmt" "fmt"
"log"
"os" "os"
"github.com/joho/godotenv"
"gorm.io/driver/postgres" "gorm.io/driver/postgres"
"gorm.io/gorm" "gorm.io/gorm"
) )
@ -11,37 +13,48 @@ import (
var DB *gorm.DB var DB *gorm.DB
func getEnv(key string) string { func getEnv(key string) string {
if value, ok := os.LookupEnv(key); ok { log.Printf("Loading environment variables...")
err := godotenv.Load()
if err != nil {
log.Fatal(fmt.Sprintf("Error loading .env file: %v", err))
}
value := os.Getenv(key)
if value != "" {
return value return value
} }
panic(fmt.Sprintf("Missing environment variable: %s", key)) panic(fmt.Sprintf("Missing environment variable: %s", key))
} }
func Init() *gorm.DB { func Init() (*gorm.DB, error) {
if DB != nil { if DB != nil {
return DB return DB, nil
} }
connectionString := fmt.Sprintf("host=%s user=%s password=%s dbname=%s host=%s port=%s TimeZone=%s", log.Println("Initializing database connection...")
getEnv("DB_HOST"), connectionString := fmt.Sprintf("user=%s password=%s dbname=%s host=%s port=%s TimeZone=%s",
getEnv("DB_USER"), getEnv("DB_USER"),
getEnv("DB_PASSWORD"), getEnv("DB_PASSWORD"),
getEnv("DB_NAME"), getEnv("DB_NAME"),
getEnv("DB_HOST"), getEnv("DB_HOST"),
getEnv("DB_PORT"), getEnv("DB_EXPOSED_PORT"),
getEnv("DB_TZ")) getEnv("DB_TZ"))
log.Printf("Database connection string: %s", connectionString)
db, err := gorm.Open(postgres.Open(connectionString), &gorm.Config{}) db, err := gorm.Open(postgres.Open(connectionString), &gorm.Config{})
if err != nil { if err != nil {
panic(fmt.Errorf("failed to connect to database: %v", err)) return nil, err
} }
sqlDB, err := db.DB() sqlDB, err := db.DB()
if err != nil { if err != nil {
panic(err) return nil, err
} }
sqlDB.SetMaxOpenConns(10) sqlDB.SetMaxOpenConns(10)
sqlDB.SetMaxIdleConns(5) sqlDB.SetMaxIdleConns(5)
DB = db log.Println("Database connection established successfully")
return DB return db, nil
} }

View File

@ -1,4 +1,3 @@
version: '3'
services: services:
postgresdb: postgresdb:
image: postgres:latest image: postgres:latest
@ -6,15 +5,14 @@ services:
ports: ports:
- "${DB_EXPOSED_PORT}:${DB_PORT}" - "${DB_EXPOSED_PORT}:${DB_PORT}"
environment: environment:
POSTGRES_DB: ${POSTGRES_DB} POSTGRES_DB: worklog
POSTGRES_USER: ${POSTGRES_USER} POSTGRES_USER: admin
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_PASSWORD: password
volumes: volumes:
- "${VOLUME_ROOT}/db:/var/lib/postgresql/data" - "${VOLUME_ROOT}/db:/var/lib/postgresql/data"
- "${VOLUME_ROOT}/scripts:/docker-entrypoint-initdb.d/"
env_file: env_file:
- ./.env - ./.env
depends_on:
- postgresdb
networks: networks:
postgres-network: postgres-network:

View File

@ -9,12 +9,12 @@ import (
type User struct { type User struct {
gorm.Model gorm.Model
ID uuid.UUID `gorm:"type:uuid;primaryKey;default:uuid_generate_v4()"` ID uuid.UUID `gorm:"type:uuid;primaryKey;default:uuid_generate_v4()"`
FirstName string FirstName string `gorm:"size:255"`
LastName string LastName string `gorm:"size:255"`
Email string Email string `gorm:"unique;not null;size:255"`
PhoneNumber string PhoneNumber string `gorm:"size:255"`
CreatedAt time.Time CreatedAt time.Time `gorm:"default:now()"`
UpdatedAt time.Time UpdatedAt time.Time `gorm:"default:now()"`
} }
type DevUser struct { type DevUser struct {
@ -30,21 +30,21 @@ type ClientUser struct {
type ClientUser_Project_Join struct { type ClientUser_Project_Join struct {
gorm.Model gorm.Model
ID uuid.UUID `gorm:"type:uuid;primaryKey;default:uuid_generate_v4()"` ID uuid.UUID `gorm:"type:uuid;primaryKey;default:uuid_generate_v4()"`
ClientId uuid.UUID ClientId uuid.UUID `gorm:"foreignKey:ClientId;index:clientIdProjectIndex" `
ProjectId uuid.UUID ProjectId uuid.UUID `gorm:"foreignKey:ProjectId;index:projectIdClientIndex"`
CreatedAt time.Time CreatedAt time.Time `gorm:"default:now()"`
UpdatedAt time.Time UpdatedAt time.Time `gorm:"default:now()"`
IsStakeholder bool IsStakeholder bool `gorm:"size:1"`
Notes string Notes string `gorm:"type:text"`
} }
type DevUser_Project_Join struct { type DevUser_Project_Join struct {
gorm.Model gorm.Model
ID uuid.UUID `gorm:"type:uuid;primaryKey;default:uuid_generate_v4()"` ID uuid.UUID `gorm:"type:uuid;primaryKey;default:uuid_generate_v4()"`
ClientId uuid.UUID ClientId uuid.UUID `gorm:"foreignKey:ClientId;index:clientIdDevIndex" `
ProjectId uuid.UUID ProjectId uuid.UUID `gorm:"foreignKey:ProjectId;index:projectIdDevIndex"`
CreatedAt time.Time CreatedAt time.Time `gorm:"default:now()"`
UpdatedAt time.Time UpdatedAt time.Time `gorm:"default:now()"`
IsLead bool IsLead bool `gorm:"size:1"`
Notes string Notes string `gorm:"type:text"`
} }

4
go.mod
View File

@ -5,6 +5,8 @@ go 1.23.2
require ( require (
github.com/gofiber/fiber/v3 v3.0.0-beta.4 github.com/gofiber/fiber/v3 v3.0.0-beta.4
github.com/google/uuid v1.6.0 github.com/google/uuid v1.6.0
github.com/joho/godotenv v1.5.1
gorm.io/driver/postgres v1.5.11
gorm.io/gorm v1.25.12 gorm.io/gorm v1.25.12
) )
@ -20,7 +22,6 @@ require (
github.com/jinzhu/inflection v1.0.0 // indirect github.com/jinzhu/inflection v1.0.0 // indirect
github.com/jinzhu/now v1.1.5 // indirect github.com/jinzhu/now v1.1.5 // indirect
github.com/klauspost/compress v1.18.0 // indirect github.com/klauspost/compress v1.18.0 // indirect
github.com/lib/pq v1.10.9 // indirect
github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-colorable v0.1.14 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-isatty v0.0.20 // indirect
github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect github.com/philhofer/fwd v1.1.3-0.20240916144458-20a13a1f6b7c // indirect
@ -33,5 +34,4 @@ require (
golang.org/x/sync v0.12.0 // indirect golang.org/x/sync v0.12.0 // indirect
golang.org/x/sys v0.31.0 // indirect golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect golang.org/x/text v0.23.0 // indirect
gorm.io/driver/postgres v1.5.11 // indirect
) )

4
go.sum
View File

@ -25,10 +25,10 @@ github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ= github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo= github.com/klauspost/compress v1.18.0 h1:c/Cqfb0r+Yi+JtIEq73FWXVkRonBlf0CRNYc8Zttxdo=
github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ= github.com/klauspost/compress v1.18.0/go.mod h1:2Pp+KzxcywXVXMr50+X0Q/Lsb43OQHYWRCY2AiWywWQ=
github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw=
github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE=
github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8=
github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY=

16
main.go
View File

@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"log" "log"
"github.com/gofiber/fiber/v3" "github.com/gofiber/fiber/v3"
@ -9,11 +10,22 @@ import (
) )
func main() { func main() {
if err := db.Init(); err != nil { DB, err := db.Init()
if err != nil {
log.Fatal(err) log.Fatal(err)
} }
repo := repository.GetUserRepo(db.DB) repo := repository.GetUserRepo(DB)
ctx := context.Background()
users, totalUserCount, err := repo.List(ctx, 0, 10)
if err != nil {
log.Println(err)
}
log.Printf("Fetched %d users", len(users))
log.Printf("%d total users", totalUserCount)
app := fiber.New() app := fiber.New()

View File

@ -55,13 +55,13 @@ func (r *UserRepository) Delete(ctx context.Context, id uuid.UUID) error {
return r.db.WithContext(ctx).Delete(&user).Error return r.db.WithContext(ctx).Delete(&user).Error
} }
func (r *UserRepository) List(ctx context.Context, offset int, limit int) ([]entities.User, int64) { func (r *UserRepository) List(ctx context.Context, offset int, limit int) ([]entities.User, int64, error) {
var users []entities.User var users []entities.User
var totalUserCount int64 var totalUserCount int64
query := r.db.WithContext(ctx).Model(&users).Where("1 = 1") // All Users if err := r.db.WithContext(ctx).Where("1 = 1").Count(&totalUserCount).Offset(offset).Limit(limit); err != nil {
query.Count(&totalUserCount) // Count of All Users return nil, 0, err.Error
query.Offset(offset).Limit(limit).Find(&users) // Filtered Users }
return users, totalUserCount return users, totalUserCount, nil
} }