//go:build ignore // Command drop_public_tables removes every table in krowdb's `public` schema. // // DESTRUCTIVE AND IRREVERSIBLE. Authorised by the database admin on 2026-08-24 // to clear an unrelated delivery-platform schema (132 tables, 222 MB) so the // Krow backend can take over this database. // // `hdb_catalog` — Hasura's own 8 metadata tables — is deliberately NOT touched. // // A structure-only snapshot of what this removes was taken beforehand: // /Users/tenext/Documents/Krow/krowdb_public_snapshot_2026-08-24.sql // It carries DDL, not rows. Row data is NOT recoverable after this runs. // // Everything happens in ONE transaction: it either clears the schema completely // or leaves it exactly as it was. // // Run: // cd go-api && go run ../scripts/drop_public_tables.go // // It reads DATABASE_* from the environment (the Makefile exports .env), and // requires CONFIRM_DROP=yes so it cannot fire by accident. package main import ( "context" "fmt" "net/url" "os" "time" "github.com/jackc/pgx/v5" ) func env(k, def string) string { if v := os.Getenv(k); v != "" { return v } return def } func main() { if os.Getenv("CONFIRM_DROP") != "yes" { fmt.Println("refusing: set CONFIRM_DROP=yes to run this.") fmt.Println("this drops EVERY table in the target database's public schema.") os.Exit(1) } dsn := fmt.Sprintf("postgres://%s:%s@%s:%s/%s?sslmode=%s&connect_timeout=15", url.QueryEscape(env("DATABASE_USER", "admin")), url.QueryEscape(env("DATABASE_PASSWORD", "")), env("DATABASE_HOST", "127.0.0.1"), env("DATABASE_PORT", "5432"), url.QueryEscape(env("DATABASE_NAME", "krowdb")), env("DATABASE_SSLMODE", "disable"), ) ctx, cancel := context.WithTimeout(context.Background(), 10*time.Minute) defer cancel() conn, err := pgx.Connect(ctx, dsn) if err != nil { fmt.Println("connect failed:", err) os.Exit(1) } defer conn.Close(ctx) var dbname string _ = conn.QueryRow(ctx, `SELECT current_database()`).Scan(&dbname) fmt.Println("connected to:", dbname) tx, err := conn.Begin(ctx) if err != nil { fmt.Println("begin failed:", err) os.Exit(1) } defer tx.Rollback(ctx) names, err := collect(ctx, tx, ` SELECT c.relname FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = 'public' AND c.relkind = 'r' ORDER BY 1`) if err != nil { fmt.Println("listing tables failed:", err) os.Exit(1) } views, _ := collect(ctx, tx, ` SELECT c.relname FROM pg_class c JOIN pg_namespace n ON n.oid = c.relnamespace WHERE n.nspname = 'public' AND c.relkind = 'v'`) seqs, _ := collect(ctx, tx, ` SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = 'public'`) fmt.Printf("dropping %d tables, %d views, %d sequences from public\n", len(names), len(views), len(seqs)) fmt.Println("hdb_catalog (Hasura) is NOT touched.") // CASCADE because the schema carries foreign keys between these tables; // dropping in dependency order would otherwise be required. for _, t := range names { if _, err := tx.Exec(ctx, fmt.Sprintf(`DROP TABLE IF EXISTS public.%q CASCADE`, t)); err != nil { fmt.Printf(" failed on %s: %v\n", t, err) fmt.Println("rolling back — nothing was dropped.") os.Exit(1) } } for _, v := range views { if _, err := tx.Exec(ctx, fmt.Sprintf(`DROP VIEW IF EXISTS public.%q CASCADE`, v)); err != nil { fmt.Printf(" failed on view %s: %v\n", v, err) os.Exit(1) } } for _, s := range seqs { if _, err := tx.Exec(ctx, fmt.Sprintf(`DROP SEQUENCE IF EXISTS public.%q CASCADE`, s)); err != nil { fmt.Printf(" failed on sequence %s: %v\n", s, err) os.Exit(1) } } if err := tx.Commit(ctx); err != nil { fmt.Println("commit failed:", err) os.Exit(1) } fmt.Println("committed.") var pub, hdb int _ = conn.QueryRow(ctx, `SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='public' AND c.relkind='r'`).Scan(&pub) _ = conn.QueryRow(ctx, `SELECT count(*) FROM pg_class c JOIN pg_namespace n ON n.oid=c.relnamespace WHERE n.nspname='hdb_catalog' AND c.relkind='r'`).Scan(&hdb) fmt.Println("\nafter:") fmt.Println(" public tables :", pub) fmt.Println(" hdb_catalog tables :", hdb, "(preserved)") } func collect(ctx context.Context, tx pgx.Tx, q string) ([]string, error) { rows, err := tx.Query(ctx, q) if err != nil { return nil, err } defer rows.Close() var out []string for rows.Next() { var s string if err := rows.Scan(&s); err != nil { return nil, err } out = append(out, s) } return out, rows.Err() }