Ajuste nas migrations
This commit is contained in:
parent
1b25f0baa4
commit
4253f49cbf
3 changed files with 88 additions and 56 deletions
|
|
@ -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)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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)';
|
||||
|
|
|
|||
|
|
@ -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';
|
||||
|
|
|
|||
Loading…
Reference in a new issue