Ajuste nas migrations

This commit is contained in:
Marcus Bohessef 2026-02-07 10:41:16 -03:00
parent 1b25f0baa4
commit 4253f49cbf
3 changed files with 88 additions and 56 deletions

View file

@ -5,6 +5,7 @@ import (
"fmt"
"log"
"os"
"sort"
"strings"
"github.com/joho/godotenv"
@ -44,60 +45,69 @@ func main() {
}
defer db.Close()
// List of migrations to run (in order)
migrations := []string{
"024_create_external_services_credentials.sql",
"025_create_chat_tables.sql",
"026_create_system_settings.sql",
"027_create_email_system.sql",
"028_add_avatar_url_to_users.sql",
// Discover migrations directory from several probable locations
possibleDirs := []string{
"migrations",
"backend/migrations",
"../migrations",
"/home/yamamoto/lab/gohorsejobs/backend/migrations",
}
for _, migFile := range migrations {
log.Printf("Processing migration: %s", migFile)
var migrationsDir string
for _, d := range possibleDirs {
if fi, err := os.Stat(d); err == nil && fi.IsDir() {
migrationsDir = d
break
}
}
// Try multiple paths
paths := []string{
"migrations/" + migFile,
"backend/migrations/" + migFile,
"../migrations/" + migFile,
"/home/yamamoto/lab/gohorsejobs/backend/migrations/" + migFile,
if migrationsDir == "" {
log.Fatal("Could not find migrations directory; looked in common locations")
}
entries, err := os.ReadDir(migrationsDir)
if err != nil {
log.Fatalf("Failed reading migrations dir %s: %v", migrationsDir, err)
}
var files []string
for _, e := range entries {
if e.IsDir() {
continue
}
name := e.Name()
if strings.HasSuffix(name, ".sql") {
files = append(files, name)
}
}
// Sort filenames to ensure chronological order
sort.Strings(files)
for _, migFile := range files {
fullPath := migrationsDir + "/" + migFile
log.Printf("Processing migration: %s (from %s)", migFile, fullPath)
content, err := os.ReadFile(fullPath)
if err != nil {
log.Fatalf("Could not read migration %s: %v", fullPath, err)
}
var content []byte
var readErr error
for _, p := range paths {
content, readErr = os.ReadFile(p)
if readErr == nil {
log.Printf("Found migration at: %s", p)
break
}
}
if content == nil {
log.Fatalf("Could not find migration file %s. Last error: %v", migFile, readErr)
}
statements := strings.Split(string(content), ";")
for _, stmt := range statements {
trimmed := strings.TrimSpace(stmt)
if trimmed == "" {
// Execute the whole file. lib/pq supports multi-statement Exec.
sqlText := string(content)
log.Printf("Executing migration file %s", fullPath)
_, err = db.Exec(sqlText)
if err != nil {
errStr := err.Error()
// Tolerable errors: object already exists, column doesn't exist in some contexts,
// or duplicate key when updates are guarded by intent. Log and continue.
if strings.Contains(errStr, "already exists") || strings.Contains(errStr, "column") && strings.Contains(errStr, "does not exist") || strings.Contains(errStr, "duplicate key value violates unique constraint") {
log.Printf("Warning while applying %s: %v", migFile, err)
continue
}
log.Printf("Executing: %s", trimmed)
_, err = db.Exec(trimmed)
if err != nil {
if strings.Contains(err.Error(), "already exists") {
log.Printf("Warning (ignored): %v", err)
} else {
log.Printf("FAILED executing: %s\nError: %v", trimmed, err)
// Verify if we should stop. For now, continue best effort or fail?
// Use fatal for critical schema errors not "already exists"
log.Fatal(err)
}
}
log.Fatalf("Failed applying migration %s: %v", migFile, err)
}
log.Printf("Migration %s applied successfully", migFile)
}

View file

@ -11,17 +11,29 @@ CREATE TABLE IF NOT EXISTS regions (
CREATE TABLE IF NOT EXISTS cities (
id SERIAL PRIMARY KEY,
region_id INT NOT NULL,
region_id INT,
name VARCHAR(100) NOT NULL,
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
FOREIGN KEY (region_id) REFERENCES regions(id) ON DELETE CASCADE
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
);
-- Indexes
CREATE INDEX idx_regions_country ON regions(country_code);
CREATE INDEX idx_cities_region ON cities(region_id);
-- Ensure column and constraints exist when table already existed without them
ALTER TABLE cities
ADD COLUMN IF NOT EXISTS region_id INT;
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM information_schema.table_constraints tc
JOIN information_schema.key_column_usage kcu ON tc.constraint_name = kcu.constraint_name
WHERE tc.table_name = 'cities' AND tc.constraint_type = 'FOREIGN KEY' AND kcu.column_name = 'region_id'
) THEN
ALTER TABLE cities ADD CONSTRAINT fk_cities_region FOREIGN KEY (region_id) REFERENCES regions(id) ON DELETE CASCADE;
END IF;
END$$;
-- Indexes (safe if table/column already existed)
CREATE INDEX IF NOT EXISTS idx_regions_country ON regions(country_code);
CREATE INDEX IF NOT EXISTS idx_cities_region ON cities(region_id);
-- Comments
COMMENT ON TABLE regions IS 'Global Regions (States, Provinces, Prefectures)';

View file

@ -3,7 +3,7 @@
-- Increase status column length to support 'force_change_password' (21 chars)
ALTER TABLE users ALTER COLUMN status TYPE VARCHAR(50);
-- Update only the intended superadmin identifier to avoid unique constraint conflicts.
UPDATE users
SET
identifier = 'lol',
@ -12,4 +12,14 @@ SET
name = 'Dr. Horse Expert',
status = 'force_change_password',
updated_at = CURRENT_TIMESTAMP
WHERE identifier = 'superadmin' OR email = 'admin@gohorsejobs.com';
WHERE identifier = 'superadmin';
-- If there is a separate user with email 'admin@gohorsejobs.com', update non-identifier fields only
UPDATE users
SET
email = 'lol@gohorsejobs.com',
full_name = 'Dr. Horse Expert',
name = 'Dr. Horse Expert',
status = 'force_change_password',
updated_at = CURRENT_TIMESTAMP
WHERE email = 'admin@gohorsejobs.com' AND identifier <> 'lol';