fix: use ::text::jsonb to store methodology overrides correctly
All checks were successful
Build & Deploy / build-and-deploy (push) Successful in 8s

asyncpg cannot encode a Python list as JSONB directly (expects str).
Passing str with ::jsonb causes double-encoding (stored as JSONB string).
Solution: json.dumps() the value → pass as text → PostgreSQL parses
with ::text::jsonb cast, storing it as the correct JSONB array/object.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-10 18:38:02 +00:00
parent d983cfdd3b
commit 932cc7191c

View File

@@ -3095,14 +3095,15 @@ async def api_update_methodology(category: str, key: str, req: MethodologyUpdate
raise HTTPException(422, "content_checklists value must be a non-empty string") raise HTTPException(422, "content_checklists value must be a non-empty string")
pool = await db.get_pool() pool = await db.get_pool()
# Pass req.value directly — asyncpg serializes Python list/dict to JSONB. # json.dumps → text, then PostgreSQL casts text→jsonb.
# json.dumps() caused double-encoding: string passed to ::jsonb became a JSONB string, # Passing a Python list directly causes "expected str, got list" in asyncpg;
# not a JSONB array, making the frontend spread it as individual chars. # passing a str with ::jsonb causes double-encoding (stored as JSONB string).
# ::text::jsonb bypasses asyncpg's codec and lets PostgreSQL parse the JSON.
await pool.execute( await pool.execute(
"INSERT INTO appeal_type_rules (id, appeal_type, rule_category, rule_key, rule_value) " "INSERT INTO appeal_type_rules (id, appeal_type, rule_category, rule_key, rule_value) "
"VALUES (gen_random_uuid(), '_global', $1, $2, $3::jsonb) " "VALUES (gen_random_uuid(), '_global', $1, $2, $3::text::jsonb) "
"ON CONFLICT (appeal_type, rule_category, rule_key) DO UPDATE SET rule_value = $3::jsonb", "ON CONFLICT (appeal_type, rule_category, rule_key) DO UPDATE SET rule_value = $3::text::jsonb",
category, key, req.value, category, key, json.dumps(req.value, ensure_ascii=False),
) )
return {"key": key, "value": req.value, "is_override": True} return {"key": key, "value": req.value, "is_override": True}