HumboldtJoker commited on
Commit
0aed7dc
·
verified ·
1 Parent(s): b5eecdb

Clean up nested duplicate: v2/v2/tools/schema_tools.py

Browse files
Files changed (1) hide show
  1. v2/v2/tools/schema_tools.py +0 -119
v2/v2/tools/schema_tools.py DELETED
@@ -1,119 +0,0 @@
1
- """Schema inspection for the campus PostgreSQL database.
2
-
3
- Two modes, in preference order:
4
-
5
- live pg_dump --schema-only against the configured DSN (read-only
6
- operation) plus migration status from the migrations table
7
- snapshot a schema_snapshot.sql on disk in the context dir
8
-
9
- Rivet never runs DDL. This module *inspects* only — the argv allowlist
10
- in tools.guard has no path to a writing psql invocation because every
11
- psql call here is built with a fixed read-only query.
12
- """
13
-
14
- import re
15
- from dataclasses import dataclass
16
- from pathlib import Path
17
-
18
- from tools.guard import run_checked
19
-
20
-
21
- @dataclass
22
- class SchemaInfo:
23
- source: str # live | snapshot | none
24
- table_count: int = 0
25
- tables: list = None
26
- migration_status: str = ""
27
- raw_available: bool = False
28
- error: str = ""
29
-
30
-
31
- class SchemaTools:
32
- def __init__(self, context_dir: Path, dsn: str = "",
33
- migrations_dir: str = ""):
34
- self.context_dir = Path(context_dir)
35
- self.dsn = dsn
36
- self.migrations_dir = migrations_dir
37
- self.snapshot_path = self.context_dir / "schema_snapshot.sql"
38
-
39
- # ------------------------------------------------------------------
40
-
41
- def inspect(self) -> SchemaInfo:
42
- if self.dsn:
43
- info = self._inspect_live()
44
- if not info.error:
45
- return info
46
- return self._inspect_snapshot()
47
-
48
- def refresh_snapshot(self) -> SchemaInfo:
49
- """Pull a fresh schema-only dump to the context dir (live mode)."""
50
- if not self.dsn:
51
- return SchemaInfo(source="none", error="no DSN configured")
52
- result = run_checked(
53
- ["pg_dump", "--schema-only", "--no-owner", "--no-privileges",
54
- self.dsn],
55
- timeout=120,
56
- )
57
- if not result.ok:
58
- return SchemaInfo(source="none",
59
- error=result.stderr or result.blocked_reason)
60
- self.snapshot_path.write_text(result.stdout)
61
- return self._inspect_snapshot()
62
-
63
- def table_definition(self, table: str) -> str:
64
- """Extract one table's definition from the snapshot."""
65
- if not self.snapshot_path.exists():
66
- return ""
67
- text = self.snapshot_path.read_text()
68
- pattern = (r"CREATE TABLE[^;]*?\b" + re.escape(table) + r"\b[^;]*?;")
69
- m = re.search(pattern, text, re.IGNORECASE | re.DOTALL)
70
- return m.group(0) if m else ""
71
-
72
- # ------------------------------------------------------------------
73
-
74
- def _inspect_live(self) -> SchemaInfo:
75
- result = run_checked(
76
- ["psql", self.dsn, "-tAc",
77
- "SELECT tablename FROM pg_tables WHERE schemaname='public' "
78
- "ORDER BY tablename"],
79
- timeout=30,
80
- )
81
- if not result.ok:
82
- return SchemaInfo(source="live",
83
- error=result.stderr or result.blocked_reason)
84
- tables = [t for t in result.stdout.splitlines() if t.strip()]
85
- return SchemaInfo(
86
- source="live", table_count=len(tables), tables=tables,
87
- migration_status=self._migration_status_live(),
88
- raw_available=self.snapshot_path.exists(),
89
- )
90
-
91
- def _migration_status_live(self) -> str:
92
- applied = run_checked(
93
- ["psql", self.dsn, "-tAc",
94
- "SELECT count(*) FROM migrations"],
95
- timeout=15,
96
- )
97
- applied_count = applied.stdout.strip() if applied.ok else "?"
98
- on_disk = "?"
99
- if self.migrations_dir and Path(self.migrations_dir).is_dir():
100
- on_disk = str(len(list(Path(self.migrations_dir).glob("*.sql"))))
101
- return f"applied={applied_count} on_disk={on_disk}"
102
-
103
- def _inspect_snapshot(self) -> SchemaInfo:
104
- if not self.snapshot_path.exists():
105
- return SchemaInfo(
106
- source="none",
107
- error=("no live DSN and no schema snapshot — schema claims "
108
- "will be LOW confidence"),
109
- )
110
- text = self.snapshot_path.read_text()
111
- tables = re.findall(
112
- r"CREATE TABLE(?:\s+IF NOT EXISTS)?\s+(?:public\.)?([\w\"]+)",
113
- text, re.IGNORECASE,
114
- )
115
- tables = [t.strip('"') for t in tables]
116
- return SchemaInfo(
117
- source="snapshot", table_count=len(tables),
118
- tables=sorted(set(tables)), raw_available=True,
119
- )