Skip to content

Commit 6e0a8a4

Browse files
committed
fix: Update simulations table and PATCH endpoint to contain output structures present in report_outputs
1 parent 7801d45 commit 6e0a8a4

File tree

6 files changed

+55
-32
lines changed

6 files changed

+55
-32
lines changed

changelog_entry.yaml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- bump: patch
2+
changes:
3+
changed:
4+
- Updated simulation table and PATCH endpoint to contain output structures present in report_outputs.

policyengine_api/data/initialise.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,9 +112,9 @@ CREATE TABLE IF NOT EXISTS simulations (
112112
population_id VARCHAR(255) NOT NULL,
113113
population_type VARCHAR(50) NOT NULL,
114114
policy_id INT NOT NULL,
115-
-- output_json stores calculation results for household simulations only
116-
-- For geography simulations, outputs are stored in report_outputs table
117-
output_json JSON DEFAULT NULL
115+
status VARCHAR(32) NOT NULL DEFAULT 'pending',
116+
output JSON DEFAULT NULL,
117+
error_message TEXT DEFAULT NULL
118118
);
119119

120120
CREATE TABLE IF NOT EXISTS report_outputs (

policyengine_api/data/initialise_local.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,9 @@ CREATE TABLE IF NOT EXISTS simulations (
121121
population_id VARCHAR(255) NOT NULL,
122122
population_type VARCHAR(50) NOT NULL,
123123
policy_id INT NOT NULL,
124-
-- output_json stores calculation results for household simulations only
125-
-- For geography simulations, outputs are stored in report_outputs table
126-
output_json JSON DEFAULT NULL
124+
status VARCHAR(32) NOT NULL DEFAULT 'pending',
125+
output JSON DEFAULT NULL,
126+
error_message TEXT DEFAULT NULL
127127
);
128128

129129
CREATE TABLE IF NOT EXISTS report_outputs (

policyengine_api/routes/simulation_routes.py

Lines changed: 19 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -139,34 +139,37 @@ def get_simulation(country_id: str, simulation_id: int) -> Response:
139139
@validate_country
140140
def update_simulation(country_id: str) -> Response:
141141
"""
142-
Update a simulation record with calculation output.
142+
Update a simulation record with results or error.
143143
144144
Args:
145145
country_id (str): The country ID.
146146
147147
Request body can contain:
148148
- id (int): The simulation ID.
149-
- output_json (str): The calculation output as JSON string (for household simulations)
149+
- status (str): The new status ('complete' or 'error')
150+
- output (dict): The result output (for complete status)
151+
- api_version (str): The API version of the simulation
152+
- error_message (str): The error message (for error status)
150153
"""
151154

152155
payload = request.json
153156
if payload is None:
154157
raise BadRequest("Payload missing from request")
155158

156-
# Extract fields
159+
# Extract optional fields
160+
status = payload.get("status")
157161
simulation_id = payload.get("id")
158-
output_json = payload.get("output_json")
162+
output = payload.get("output")
163+
error_message = payload.get("error_message")
159164
print(f"Updating simulation #{simulation_id} for country {country_id}")
160165

161-
# Validate that id is provided
162-
if simulation_id is None:
163-
raise BadRequest("id is required")
164-
if not isinstance(simulation_id, int):
165-
raise BadRequest("id must be an integer")
166+
# Validate status if provided
167+
if status is not None and status not in ["pending", "complete", "error"]:
168+
raise BadRequest("status must be 'pending', 'complete', or 'error'")
166169

167-
# Validate that at least one field is being updated
168-
if output_json is None:
169-
raise BadRequest("output_json must be provided for update")
170+
# Validate that complete status has output
171+
if status == "complete" and output is None:
172+
raise BadRequest("output is required when status is 'complete'")
170173

171174
try:
172175
# First check if the simulation exists
@@ -177,10 +180,12 @@ def update_simulation(country_id: str) -> Response:
177180
raise NotFound(f"Simulation #{simulation_id} not found.")
178181

179182
# Update the simulation
180-
success = simulation_service.update_simulation_output(
183+
success = simulation_service.update_simulation(
181184
country_id=country_id,
182185
simulation_id=simulation_id,
183-
output_json=output_json,
186+
status=status,
187+
output=output,
188+
error_message=error_message,
184189
)
185190

186191
if not success:

policyengine_api/services/simulation_service.py

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def create_simulation(
5656
policy_id: int,
5757
) -> dict:
5858
"""
59-
Create a new simulation record.
59+
Create a new simulation record with pending status.
6060
6161
Args:
6262
country_id (str): The country ID.
@@ -72,13 +72,14 @@ def create_simulation(
7272

7373
try:
7474
database.query(
75-
"INSERT INTO simulations (country_id, api_version, population_id, population_type, policy_id) VALUES (?, ?, ?, ?, ?)",
75+
"INSERT INTO simulations (country_id, api_version, population_id, population_type, policy_id, status) VALUES (?, ?, ?, ?, ?, ?)",
7676
(
7777
country_id,
7878
api_version,
7979
population_id,
8080
population_type,
8181
policy_id,
82+
"pending",
8283
),
8384
)
8485

@@ -135,24 +136,28 @@ def get_simulation(
135136
)
136137
raise e
137138

138-
def update_simulation_output(
139+
def update_simulation(
139140
self,
140141
country_id: str,
141142
simulation_id: int,
142-
output_json: str | None = None,
143+
status: str | None = None,
144+
output: str | None = None,
145+
error_message: str | None = None,
143146
) -> bool:
144147
"""
145-
Update a simulation record with calculation output.
148+
Update a simulation record with results or error.
146149
147150
Args:
148151
country_id (str): The country ID.
149152
simulation_id (int): The simulation ID.
150-
output_json (str | None): The output as JSON string (for household simulations).
153+
status (str | None): The new status ('complete' or 'error').
154+
output (str | None): The result output as JSON string (for complete status).
155+
error_message (str | None): The error message (for error status).
151156
152157
Returns:
153158
bool: True if update was successful.
154159
"""
155-
print(f"Updating simulation {simulation_id} with output")
160+
print(f"Updating simulation {simulation_id}")
156161
# Automatically update api_version on every update to latest
157162
api_version: str = COUNTRY_PACKAGE_VERSIONS.get(country_id)
158163

@@ -161,10 +166,18 @@ def update_simulation_output(
161166
update_fields = []
162167
update_values = []
163168

164-
if output_json is not None:
165-
update_fields.append("output_json = ?")
169+
if status is not None:
170+
update_fields.append("status = ?")
171+
update_values.append(status)
172+
173+
if output is not None:
174+
update_fields.append("output = ?")
166175
# Output is already a JSON string from frontend
167-
update_values.append(output_json)
176+
update_values.append(output)
177+
178+
if error_message is not None:
179+
update_fields.append("error_message = ?")
180+
update_values.append(error_message)
168181

169182
# Always update API version
170183
update_fields.append("api_version = ?")

tests/fixtures/services/simulation_fixtures.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,15 @@ def existing_simulation_record(test_db):
2222
"""Insert an existing simulation record into the database."""
2323
test_db.query(
2424
"""INSERT INTO simulations
25-
(country_id, api_version, population_id, population_type, policy_id)
26-
VALUES (?, ?, ?, ?, ?)""",
25+
(country_id, api_version, population_id, population_type, policy_id, status)
26+
VALUES (?, ?, ?, ?, ?, ?)""",
2727
(
2828
valid_simulation_data["country_id"],
2929
valid_simulation_data["api_version"],
3030
valid_simulation_data["population_id"],
3131
valid_simulation_data["population_type"],
3232
valid_simulation_data["policy_id"],
33+
"pending",
3334
),
3435
)
3536

0 commit comments

Comments
 (0)