Skip to content

Commit 831c9e8

Browse files
authored
Merge pull request #3421 from PolicyEngine/feat/report-output-run-stage-1
Add report output run stage-1 schema scaffolding
2 parents 4b35a63 + 3bd5d4f commit 831c9e8

4 files changed

Lines changed: 222 additions & 5 deletions

File tree

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add additive report and simulation run schema scaffolding for the report-output run migration.

policyengine_api/data/initialise.sql

Lines changed: 66 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,11 @@ CREATE TABLE IF NOT EXISTS simulations (
114114
policy_id INT NOT NULL,
115115
status VARCHAR(32) NOT NULL DEFAULT 'pending',
116116
output JSON DEFAULT NULL,
117-
error_message TEXT DEFAULT NULL
117+
error_message TEXT DEFAULT NULL,
118+
simulation_spec_json JSON DEFAULT NULL,
119+
simulation_spec_schema_version INT DEFAULT NULL,
120+
active_run_id CHAR(36) DEFAULT NULL,
121+
latest_successful_run_id CHAR(36) DEFAULT NULL
118122
);
119123

120124
CREATE TABLE IF NOT EXISTS report_outputs (
@@ -126,5 +130,64 @@ CREATE TABLE IF NOT EXISTS report_outputs (
126130
status VARCHAR(32) NOT NULL DEFAULT 'pending',
127131
output JSON DEFAULT NULL,
128132
error_message TEXT DEFAULT NULL,
129-
year VARCHAR(255) DEFAULT '2025'
130-
);
133+
year VARCHAR(255) DEFAULT '2025',
134+
report_kind VARCHAR(64) DEFAULT NULL,
135+
report_spec_json JSON DEFAULT NULL,
136+
report_spec_schema_version INT DEFAULT NULL,
137+
report_spec_status VARCHAR(32) DEFAULT NULL,
138+
active_run_id CHAR(36) DEFAULT NULL,
139+
latest_successful_run_id CHAR(36) DEFAULT NULL
140+
);
141+
142+
CREATE TABLE IF NOT EXISTS report_output_runs (
143+
id CHAR(36) PRIMARY KEY,
144+
report_output_id INT NOT NULL,
145+
run_sequence INT NOT NULL,
146+
status VARCHAR(32) NOT NULL,
147+
output JSON DEFAULT NULL,
148+
error_message TEXT DEFAULT NULL,
149+
trigger_type VARCHAR(32) NOT NULL,
150+
requested_at DATETIME DEFAULT NULL,
151+
started_at DATETIME DEFAULT NULL,
152+
finished_at DATETIME DEFAULT NULL,
153+
source_run_id CHAR(36) DEFAULT NULL,
154+
report_spec_snapshot_json JSON DEFAULT NULL,
155+
country_package_version VARCHAR(255) DEFAULT NULL,
156+
policyengine_version VARCHAR(255) DEFAULT NULL,
157+
data_version VARCHAR(255) DEFAULT NULL,
158+
runtime_app_name VARCHAR(255) DEFAULT NULL,
159+
report_cache_version VARCHAR(255) DEFAULT NULL,
160+
simulation_cache_version VARCHAR(255) DEFAULT NULL,
161+
requested_version_override VARCHAR(255) DEFAULT NULL,
162+
resolved_dataset VARCHAR(255) DEFAULT NULL,
163+
resolved_options_hash VARCHAR(255) DEFAULT NULL,
164+
UNIQUE KEY report_output_run_sequence_idx (report_output_id, run_sequence)
165+
);
166+
167+
CREATE TABLE IF NOT EXISTS simulation_runs (
168+
id CHAR(36) PRIMARY KEY,
169+
simulation_id INT NOT NULL,
170+
report_output_run_id CHAR(36) DEFAULT NULL,
171+
input_position TINYINT DEFAULT NULL,
172+
run_sequence INT NOT NULL,
173+
status VARCHAR(32) NOT NULL,
174+
output JSON DEFAULT NULL,
175+
error_message TEXT DEFAULT NULL,
176+
trigger_type VARCHAR(32) NOT NULL,
177+
requested_at DATETIME DEFAULT NULL,
178+
started_at DATETIME DEFAULT NULL,
179+
finished_at DATETIME DEFAULT NULL,
180+
source_run_id CHAR(36) DEFAULT NULL,
181+
simulation_spec_snapshot_json JSON DEFAULT NULL,
182+
country_package_version VARCHAR(255) DEFAULT NULL,
183+
policyengine_version VARCHAR(255) DEFAULT NULL,
184+
data_version VARCHAR(255) DEFAULT NULL,
185+
runtime_app_name VARCHAR(255) DEFAULT NULL,
186+
simulation_cache_version VARCHAR(255) DEFAULT NULL,
187+
UNIQUE KEY simulation_run_sequence_idx (simulation_id, run_sequence)
188+
);
189+
190+
CREATE TABLE IF NOT EXISTS legacy_report_output_aliases (
191+
legacy_report_output_id INT PRIMARY KEY,
192+
canonical_report_output_id INT NOT NULL
193+
);

policyengine_api/data/initialise_local.sql

Lines changed: 67 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ DROP TABLE IF EXISTS reform_impact;
66
DROP TABLE IF EXISTS analysis;
77
DROP TABLE IF EXISTS user_policies;
88
DROP TABLE IF EXISTS tracers;
9+
DROP TABLE IF EXISTS report_output_runs;
10+
DROP TABLE IF EXISTS simulation_runs;
11+
DROP TABLE IF EXISTS legacy_report_output_aliases;
912

1013
CREATE TABLE IF NOT EXISTS household (
1114
id INTEGER PRIMARY KEY,
@@ -123,7 +126,11 @@ CREATE TABLE IF NOT EXISTS simulations (
123126
policy_id INT NOT NULL,
124127
status VARCHAR(32) NOT NULL DEFAULT 'pending',
125128
output JSON DEFAULT NULL,
126-
error_message TEXT DEFAULT NULL
129+
error_message TEXT DEFAULT NULL,
130+
simulation_spec_json JSON DEFAULT NULL,
131+
simulation_spec_schema_version INT DEFAULT NULL,
132+
active_run_id CHAR(36) DEFAULT NULL,
133+
latest_successful_run_id CHAR(36) DEFAULT NULL
127134
);
128135

129136
CREATE TABLE IF NOT EXISTS report_outputs (
@@ -135,6 +142,64 @@ CREATE TABLE IF NOT EXISTS report_outputs (
135142
status VARCHAR(32) NOT NULL DEFAULT 'pending',
136143
output JSON DEFAULT NULL,
137144
error_message TEXT DEFAULT NULL,
138-
year VARCHAR(255) DEFAULT '2025'
145+
year VARCHAR(255) DEFAULT '2025',
146+
report_kind VARCHAR(64) DEFAULT NULL,
147+
report_spec_json JSON DEFAULT NULL,
148+
report_spec_schema_version INT DEFAULT NULL,
149+
report_spec_status VARCHAR(32) DEFAULT NULL,
150+
active_run_id CHAR(36) DEFAULT NULL,
151+
latest_successful_run_id CHAR(36) DEFAULT NULL
152+
);
153+
154+
CREATE TABLE IF NOT EXISTS report_output_runs (
155+
id CHAR(36) PRIMARY KEY,
156+
report_output_id INT NOT NULL,
157+
run_sequence INT NOT NULL,
158+
status VARCHAR(32) NOT NULL,
159+
output JSON DEFAULT NULL,
160+
error_message TEXT DEFAULT NULL,
161+
trigger_type VARCHAR(32) NOT NULL,
162+
requested_at DATETIME DEFAULT NULL,
163+
started_at DATETIME DEFAULT NULL,
164+
finished_at DATETIME DEFAULT NULL,
165+
source_run_id CHAR(36) DEFAULT NULL,
166+
report_spec_snapshot_json JSON DEFAULT NULL,
167+
country_package_version VARCHAR(255) DEFAULT NULL,
168+
policyengine_version VARCHAR(255) DEFAULT NULL,
169+
data_version VARCHAR(255) DEFAULT NULL,
170+
runtime_app_name VARCHAR(255) DEFAULT NULL,
171+
report_cache_version VARCHAR(255) DEFAULT NULL,
172+
simulation_cache_version VARCHAR(255) DEFAULT NULL,
173+
requested_version_override VARCHAR(255) DEFAULT NULL,
174+
resolved_dataset VARCHAR(255) DEFAULT NULL,
175+
resolved_options_hash VARCHAR(255) DEFAULT NULL,
176+
UNIQUE (report_output_id, run_sequence)
139177
);
140178

179+
CREATE TABLE IF NOT EXISTS simulation_runs (
180+
id CHAR(36) PRIMARY KEY,
181+
simulation_id INT NOT NULL,
182+
report_output_run_id CHAR(36) DEFAULT NULL,
183+
input_position TINYINT DEFAULT NULL,
184+
run_sequence INT NOT NULL,
185+
status VARCHAR(32) NOT NULL,
186+
output JSON DEFAULT NULL,
187+
error_message TEXT DEFAULT NULL,
188+
trigger_type VARCHAR(32) NOT NULL,
189+
requested_at DATETIME DEFAULT NULL,
190+
started_at DATETIME DEFAULT NULL,
191+
finished_at DATETIME DEFAULT NULL,
192+
source_run_id CHAR(36) DEFAULT NULL,
193+
simulation_spec_snapshot_json JSON DEFAULT NULL,
194+
country_package_version VARCHAR(255) DEFAULT NULL,
195+
policyengine_version VARCHAR(255) DEFAULT NULL,
196+
data_version VARCHAR(255) DEFAULT NULL,
197+
runtime_app_name VARCHAR(255) DEFAULT NULL,
198+
simulation_cache_version VARCHAR(255) DEFAULT NULL,
199+
UNIQUE (simulation_id, run_sequence)
200+
);
201+
202+
CREATE TABLE IF NOT EXISTS legacy_report_output_aliases (
203+
legacy_report_output_id INT PRIMARY KEY,
204+
canonical_report_output_id INT NOT NULL
205+
);

tests/unit/data/test_run_schema.py

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
from pathlib import Path
2+
3+
from policyengine_api.constants import REPO
4+
5+
6+
def _column_names(test_db, table_name: str) -> set[str]:
7+
rows = test_db.query(f"PRAGMA table_info({table_name})").fetchall()
8+
return {row["name"] for row in rows}
9+
10+
11+
def test_stage_one_run_schema_is_initialized_in_local_test_db(test_db):
12+
report_output_columns = _column_names(test_db, "report_outputs")
13+
assert {
14+
"report_kind",
15+
"report_spec_json",
16+
"report_spec_schema_version",
17+
"report_spec_status",
18+
"active_run_id",
19+
"latest_successful_run_id",
20+
}.issubset(report_output_columns)
21+
22+
simulation_columns = _column_names(test_db, "simulations")
23+
assert {
24+
"simulation_spec_json",
25+
"simulation_spec_schema_version",
26+
"active_run_id",
27+
"latest_successful_run_id",
28+
}.issubset(simulation_columns)
29+
30+
report_run_columns = _column_names(test_db, "report_output_runs")
31+
assert {
32+
"id",
33+
"report_output_id",
34+
"run_sequence",
35+
"trigger_type",
36+
"report_spec_snapshot_json",
37+
"country_package_version",
38+
"policyengine_version",
39+
"data_version",
40+
"runtime_app_name",
41+
"report_cache_version",
42+
"simulation_cache_version",
43+
"requested_version_override",
44+
"resolved_dataset",
45+
"resolved_options_hash",
46+
}.issubset(report_run_columns)
47+
48+
simulation_run_columns = _column_names(test_db, "simulation_runs")
49+
assert {
50+
"id",
51+
"simulation_id",
52+
"report_output_run_id",
53+
"input_position",
54+
"run_sequence",
55+
"trigger_type",
56+
"simulation_spec_snapshot_json",
57+
"country_package_version",
58+
"policyengine_version",
59+
"data_version",
60+
"runtime_app_name",
61+
"simulation_cache_version",
62+
}.issubset(simulation_run_columns)
63+
64+
alias_columns = _column_names(test_db, "legacy_report_output_aliases")
65+
assert {"legacy_report_output_id", "canonical_report_output_id"} == alias_columns
66+
67+
68+
def test_stage_one_schema_is_defined_in_both_sql_initializers():
69+
sql_paths = [
70+
REPO / "policyengine_api" / "data" / "initialise.sql",
71+
REPO / "policyengine_api" / "data" / "initialise_local.sql",
72+
]
73+
74+
required_snippets = [
75+
"CREATE TABLE IF NOT EXISTS report_output_runs",
76+
"CREATE TABLE IF NOT EXISTS simulation_runs",
77+
"CREATE TABLE IF NOT EXISTS legacy_report_output_aliases",
78+
"report_spec_json",
79+
"report_spec_status",
80+
"simulation_spec_json",
81+
"active_run_id",
82+
"latest_successful_run_id",
83+
]
84+
85+
for sql_path in sql_paths:
86+
sql_text = Path(sql_path).read_text()
87+
for snippet in required_snippets:
88+
assert snippet in sql_text, f"{snippet} missing from {sql_path.name}"

0 commit comments

Comments
 (0)