diff --git a/cmd/user_program_import/main.go b/cmd/user_program_import/main.go index 9bb32af..edede42 100644 --- a/cmd/user_program_import/main.go +++ b/cmd/user_program_import/main.go @@ -10,6 +10,7 @@ import ( "github.com/jackc/pgx/v5" "geoip-rest/internal/importer" + "geoip-rest/internal/userprogram" ) const ( @@ -49,6 +50,10 @@ func main() { log.Fatalf("failed to import updates from %s: %v", updateDir, err) } + if err := userprogram.SeedIPGeoInfoIfMissing(ctx, conn, schema); err != nil { + log.Fatalf("failed to seed ip_geoinfo: %v", err) + } + log.Printf("%s is ready in schema %s using data from %s (updates: %s)", targetTableName, schema, csvPath, updateDir) } diff --git a/internal/userprogram/ip_geoinfo.go b/internal/userprogram/ip_geoinfo.go index 78fcd1c..638586d 100644 --- a/internal/userprogram/ip_geoinfo.go +++ b/internal/userprogram/ip_geoinfo.go @@ -31,6 +31,35 @@ CREATE TABLE IF NOT EXISTS %s.ip_geoinfo ( return err } +const defaultSeedPath = "/initial_data/ip_geoinfo_seed_20251208.sql" + +// SeedIPGeoInfoIfMissing applies the seed SQL when ip_geoinfo is absent. +func SeedIPGeoInfoIfMissing(ctx context.Context, conn *pgx.Conn, schema string) error { + exists, err := ipGeoInfoExists(ctx, conn, schema) + if err != nil { + return err + } + if exists { + return nil + } + if _, err := os.Stat(defaultSeedPath); err == nil { + if err := ExecuteSQLFile(ctx, conn, defaultSeedPath); err != nil { + return fmt.Errorf("execute seed sql: %w", err) + } + } + return EnsureIPGeoInfoTable(ctx, conn, schema) +} + +func ipGeoInfoExists(ctx context.Context, conn *pgx.Conn, schema string) (bool, error) { + var exists bool + err := conn.QueryRow(ctx, ` +SELECT EXISTS ( + SELECT 1 FROM information_schema.tables + WHERE table_schema = $1 AND table_name = 'ip_geoinfo' +);`, schema).Scan(&exists) + return exists, err +} + // ExportPublicIPs writes distinct login_public_ip values to a CSV file with header. func ExportPublicIPs(ctx context.Context, conn *pgx.Conn, schema, path string) error { rows, err := conn.Query(ctx, fmt.Sprintf(` diff --git a/internal/userprogram/sync.go b/internal/userprogram/sync.go index 50d6252..d27dcbd 100644 --- a/internal/userprogram/sync.go +++ b/internal/userprogram/sync.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "log" + "os" "path/filepath" "time" @@ -132,6 +133,21 @@ func verifyCounts(ctx context.Context, cfg SyncConfig, dumper *Dumper, conn *pgx } func ensureIPGeoInfo(ctx context.Context, cfg SyncConfig, conn *pgx.Conn) error { + exists, err := ipGeoInfoExists(ctx, conn, cfg.Schema) + if err != nil { + return err + } + + if !exists { + seedPath := filepath.Join("/initial_data", "ip_geoinfo_seed_20251208.sql") + if _, err := os.Stat(seedPath); err == nil { + if err := ExecuteSQLFile(ctx, conn, seedPath); err != nil { + return fmt.Errorf("execute seed sql: %w", err) + } + exists = true + } + } + if err := EnsureIPGeoInfoTable(ctx, conn, cfg.Schema); err != nil { return err } @@ -159,6 +175,9 @@ func ensureIPGeoInfo(ctx context.Context, cfg SyncConfig, conn *pgx.Conn) error return fmt.Errorf("generate ip_geoinfo sql: %w", err) } if count == 0 { + if !exists { + return fmt.Errorf("seeded ip_geoinfo but no new IPs found for update") + } return nil } if err := ExecuteSQLFile(ctx, conn, sqlPath); err != nil {