From 924fb0e82c44953b6976cc912cd9097bed6193ed Mon Sep 17 00:00:00 2001 From: Kylesoda <249518290+kylesoda@users.noreply.github.com> Date: Sun, 22 Mar 2026 16:59:24 -0500 Subject: [PATCH] Add tasks fixture script and remove users fixture script --- scripts/fixtures/create-tasks.fixture.go | 148 +++++++++++++ scripts/fixtures/create_users_fixture.go | 261 ----------------------- 2 files changed, 148 insertions(+), 261 deletions(-) create mode 100644 scripts/fixtures/create-tasks.fixture.go delete mode 100644 scripts/fixtures/create_users_fixture.go diff --git a/scripts/fixtures/create-tasks.fixture.go b/scripts/fixtures/create-tasks.fixture.go new file mode 100644 index 0000000..ecb24ac --- /dev/null +++ b/scripts/fixtures/create-tasks.fixture.go @@ -0,0 +1,148 @@ +package main + +import ( + "context" + "fmt" + "log" + "math/rand" + "os" + "strings" + "time" + + "github.com/jackc/pgx/v5/pgxpool" + "github.com/joho/godotenv" +) + +func createTasksTable(db *pgxpool.Pool, ctx context.Context) error { + createTableSQL := ` +CREATE TABLE IF NOT EXISTS tasks ( + id SERIAL PRIMARY KEY, + text TEXT NOT NULL, + completed BOOLEAN NOT NULL DEFAULT FALSE, + created_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW(), + updated_at TIMESTAMP WITH TIME ZONE NOT NULL DEFAULT NOW() +);` + + _, err := db.Exec(ctx, createTableSQL) + if err != nil { + return fmt.Errorf("error creating tasks table: %w", err) + } + + return nil +} + +func truncateTasksTable(db *pgxpool.Pool, ctx context.Context) error { + truncateSQL := `TRUNCATE TABLE tasks RESTART IDENTITY CASCADE;` + _, err := db.Exec(ctx, truncateSQL) + if err != nil { + return fmt.Errorf("error truncating tasks table: %w", err) + } + return nil +} + +type Task struct { + Id int64 + Text string + Completed bool + Created_at time.Time + Updated_at time.Time +} + +func generateTasks(count int) []Task { + tasks := make([]Task, count) + + for i := 1; i <= count; i++ { + tasks[i-1] = Task{ + Text: fmt.Sprintf("random task Nº %v", i), + Completed: rand.Float64() > 0.5, + } + } + + return tasks +} + +func bulkInsertTasks(db *pgxpool.Pool, ctx context.Context, tasks []Task) error { + if len(tasks) == 0 { + return nil + } + + var sb strings.Builder + sb.WriteString(`INSERT INTO tasks (text, completed) VALUES `) + + args := make([]any, 0, len(tasks)*2) + + for i, task := range tasks { + if i > 0 { + sb.WriteString(`, `) + } + + fmt.Fprintf(&sb, `($%d, $%d)`, i*2+1, i*2+2) + args = append(args, task.Text, task.Completed) + } + + sb.WriteString(`;`) + + _, err := db.Exec(ctx, sb.String(), args...) + + if err != nil { + return fmt.Errorf("error bulk inserting tasks: %w", err) + } + + return nil +} + +func main() { + err := godotenv.Load() + if err != nil { + log.Println("Warning: could not load .env file") + } + + dbURL := os.Getenv("PG_FROM_DB_URL") + if dbURL == "" { + log.Fatal("PG_FROM_DB_URL environment variable not set") + } + + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + + db, err := pgxpool.New(ctx, dbURL) + if err != nil { + log.Fatalf("Unable to create connection pool: %v", err) + } + defer db.Close() + + fmt.Println("Creating tasks table...") + err = createTasksTable(db, ctx) + if err != nil { + log.Fatalf("Failed to create table: %v", err) + } + fmt.Println("✓ Tasks table created/already exists") + + fmt.Println("Clearing existing data...") + err = truncateTasksTable(db, ctx) + if err != nil { + log.Fatalf("Failed to truncate table: %v", err) + } + fmt.Println("✓ Table cleared") + + fmt.Println("Generating 1000 tasks records...") + tasks := generateTasks(1000) + fmt.Println("✓ Tasks generated") + + fmt.Println("Performing bulk insert...") + err = bulkInsertTasks(db, ctx, tasks) + if err != nil { + log.Fatalf("Failed to bulk insert tasks: %v", err) + } + fmt.Println("✓ All 1000 task records inserted successfully") + + var count int + err = db.QueryRow(ctx, "SELECT COUNT(*) FROM tasks;").Scan(&count) + if err != nil { + log.Printf("Warning: could not verify record count: %v", err) + } else { + fmt.Printf("✓ Final task count: %d\n", count) + } + + fmt.Println("\nFixture creation completed successfully!") +} diff --git a/scripts/fixtures/create_users_fixture.go b/scripts/fixtures/create_users_fixture.go deleted file mode 100644 index c175e00..0000000 --- a/scripts/fixtures/create_users_fixture.go +++ /dev/null @@ -1,261 +0,0 @@ -package main - -import ( - "context" - "fmt" - "log" - "math" - "math/rand" - "os" - "time" - - "github.com/jackc/pgx/v5/pgxpool" - "github.com/joho/godotenv" -) - -var ( - firstNames = []string{ - "Juan", "María", "Carlos", "Ana", "Miguel", "Rosa", "Pedro", "Isabel", - "Luis", "Carmen", "José", "Antonia", "Fernando", "Dolores", "Diego", "Margarita", - "Alejandro", "Francisca", "Antonio", "Juana", "Francisco", "Pilar", "Andrés", "Elena", - "Rafael", "Teresa", "Enrique", "Ángeles", "Jorge", "Soledad", "Ramón", "Asunción", - } - lastNames = []string{ - "García", "Rodríguez", "González", "López", "Martínez", "Sánchez", "Peña", "Castellanos", - "Moreno", "Jiménez", "Hernández", "Díaz", "Ramírez", "Cruz", "Velasco", "Campos", - "Medina", "Ruiz", "Domínguez", "Delgado", "Flores", "Silver", "Torres", "Rivera", - "Vargas", "Castro", "Vega", "Rojas", "Parra", "Salazar", "Guzmán", "Ochoa", - } - domainNames = []string{ - "gmail.com", "yahoo.com", "hotmail.com", "outlook.com", "empresa.com", - "mail.com", "correo.es", "example.com", "test.io", "domain.dev", - } -) - -func init() { - rand.Seed(time.Now().UnixNano()) -} - -func randomFirstName() string { - return firstNames[rand.Intn(len(firstNames))] -} - -func randomLastName() string { - return lastNames[rand.Intn(len(lastNames))] -} - -func randomEmail() string { - firstName := randomFirstName() - lastName := randomLastName() - domain := domainNames[rand.Intn(len(domainNames))] - return fmt.Sprintf("%s.%s@%s", firstName, lastName, domain) -} - -func randomAge() int { - return rand.Intn(70) + 18 -} - -func randomSalary() float64 { - return math.Round((rand.Float64()*100000 + 25000)) / 100 -} - -func randomBirthDate() time.Time { - years := rand.Intn(70) + 18 - days := rand.Intn(365) - return time.Now().AddDate(-years, 0, -days) -} - -func randomPhoneNumber() string { - return fmt.Sprintf("+34 6%d %d%d%d%d%d%d%d", - rand.Intn(10), - rand.Intn(10), rand.Intn(10), rand.Intn(10), rand.Intn(10), - rand.Intn(10), rand.Intn(10), rand.Intn(10), - ) -} - -func randomCity() string { - cities := []string{ - "Madrid", "Barcelona", "Valencia", "Sevilla", "Bilbao", - "Zaragoza", "Málaga", "Murcia", "Palma", "Las Palmas", - "Córdoba", "Valladolid", "Vigo", "Gijón", "Hospitalet", - } - return cities[rand.Intn(len(cities))] -} - -func randomHobbies() []string { - allHobbies := []string{ - "lectura", "viajes", "cine", "música", "deportes", - "cocina", "fotografía", "gaming", "yoga", "senderismo", - "natación", "tenis", "ajedrez", "pintura", "jardinería", - } - - numHobbies := rand.Intn(4) + 1 - selected := make([]string, 0, numHobbies) - used := make(map[int]bool) - - for len(selected) < numHobbies { - idx := rand.Intn(len(allHobbies)) - if !used[idx] { - used[idx] = true - selected = append(selected, allHobbies[idx]) - } - } - return selected -} - -func createUsersTable(db *pgxpool.Pool, ctx context.Context) error { - createTableSQL := ` - CREATE TABLE IF NOT EXISTS users ( - id SERIAL PRIMARY KEY, - first_name VARCHAR(100) NOT NULL, - last_name VARCHAR(100) NOT NULL, - email VARCHAR(255) UNIQUE NOT NULL, - age INTEGER NOT NULL CHECK (age >= 18), - birth_date DATE NOT NULL, - salary NUMERIC(12, 2), - phone_number VARCHAR(20), - is_active BOOLEAN DEFAULT true, - is_verified BOOLEAN DEFAULT false, - city VARCHAR(100), - hobbies TEXT[], - created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, - metadata JSONB - ); - ` - - _, err := db.Exec(ctx, createTableSQL) - if err != nil { - return fmt.Errorf("error creating users table: %w", err) - } - - return nil -} - -func truncateUsersTable(db *pgxpool.Pool, ctx context.Context) error { - truncateSQL := `TRUNCATE TABLE users RESTART IDENTITY CASCADE;` - _, err := db.Exec(ctx, truncateSQL) - if err != nil { - return fmt.Errorf("error truncating users table: %w", err) - } - return nil -} - -func insertUserRecord(db *pgxpool.Pool, ctx context.Context, userNum int) error { - firstName := randomFirstName() - lastName := randomLastName() - email := randomEmail() - age := randomAge() - birthDate := randomBirthDate() - salary := randomSalary() - phoneNumber := randomPhoneNumber() - isActive := rand.Intn(2) == 1 - isVerified := rand.Intn(2) == 1 - city := randomCity() - hobbies := randomHobbies() - - metadata := fmt.Sprintf( - `{"user_number": %d, "registration_source": "%s", "tags": [%d, %d, %d]}`, - userNum, - []string{"web", "mobile", "api"}[rand.Intn(3)], - rand.Intn(100), - rand.Intn(100), - rand.Intn(100), - ) - - insertSQL := ` - INSERT INTO users ( - first_name, last_name, email, age, birth_date, salary, - phone_number, is_active, is_verified, city, hobbies, metadata - ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12) - ON CONFLICT (email) DO NOTHING; - ` - - _, err := db.Exec( - ctx, - insertSQL, - firstName, - lastName, - email, - age, - birthDate, - salary, - phoneNumber, - isActive, - isVerified, - city, - hobbies, - metadata, - ) - - if err != nil { - return fmt.Errorf("error inserting user %d: %w", userNum, err) - } - - return nil -} - -func main() { - err := godotenv.Load() - if err != nil { - log.Println("Warning: could not load .env file") - } - - dbURL := os.Getenv("PG_FROM_DB_URL") - if dbURL == "" { - log.Fatal("PG_FROM_DB_URL environment variable not set") - } - - ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) - defer cancel() - - db, err := pgxpool.New(ctx, dbURL) - if err != nil { - log.Fatalf("Unable to create connection pool: %v", err) - } - defer db.Close() - - err = db.Ping(ctx) - if err != nil { - log.Fatalf("Unable to ping database: %v", err) - } - fmt.Println("✓ Connected to database successfully") - - fmt.Println("Creating users table...") - err = createUsersTable(db, ctx) - if err != nil { - log.Fatalf("Failed to create table: %v", err) - } - fmt.Println("✓ Users table created/already exists") - - fmt.Println("Clearing existing data...") - err = truncateUsersTable(db, ctx) - if err != nil { - log.Fatalf("Failed to truncate table: %v", err) - } - fmt.Println("✓ Table cleared") - - fmt.Println("Inserting 1000 user records...") - for i := 1; i <= 1000; i++ { - err := insertUserRecord(db, ctx, i) - if err != nil { - log.Printf("Warning: failed to insert user %d: %v", i, err) - } - - if i%100 == 0 { - fmt.Printf(" Progress: %d/1000 records inserted\n", i) - } - } - - fmt.Println("✓ All 1000 user records inserted successfully") - - var count int - err = db.QueryRow(ctx, "SELECT COUNT(*) FROM users;").Scan(&count) - if err != nil { - log.Printf("Warning: could not verify record count: %v", err) - } else { - fmt.Printf("✓ Final user count: %d\n", count) - } - - fmt.Println("\n✅ Fixture creation completed successfully!") -}