The branch stored scopejson, desiredstate and params as sa.JSON, the only JSON columns in the product. MySQL 5.6 has no JSON type - it arrived in 5.7 - and the migration failed there with a bare syntax error near the word JSON. They are TEXT now, through a JSONText type decorator, so the seventeen call sites still assign and read dicts. The convention elsewhere is already TEXT: guides.blocksjson, geenforce.manifestjson. Spec regenerated: 331 paths, 477 operations across 22 surfaces.
45 lines
1.7 KiB
Python
45 lines
1.7 KiB
Python
"""JSON stored in a TEXT column.
|
|
|
|
MySQL 5.6 has no JSON type - it arrived in 5.7 - and a site is still running
|
|
5.6, where `sa.JSON()` fails at migration time with a bare syntax error near the
|
|
word JSON. Every other JSON-bearing column in this product is already TEXT for
|
|
that reason: guides' `blocksjson`, GE-Enforce's `manifestjson`.
|
|
|
|
This keeps the Python side identical. A model attribute still holds a dict or a
|
|
list, still assigns and reads like one; only the storage changes. The
|
|
alternative - json.dumps and json.loads at seventeen call sites - is the same
|
|
thing written out seventeen times, with seventeen chances to forget one.
|
|
|
|
Note the SQLite behaviour is deliberately the same as MySQL's. Tests run on
|
|
SQLite and production does not, so a type that behaved differently across the
|
|
two would hide exactly the failure this exists to prevent.
|
|
"""
|
|
|
|
import json
|
|
|
|
from sqlalchemy import Text
|
|
from sqlalchemy.types import TypeDecorator
|
|
|
|
|
|
class JSONText(TypeDecorator):
|
|
"""A dict or list on the Python side, TEXT in the database."""
|
|
|
|
impl = Text
|
|
cache_ok = True
|
|
|
|
def process_bind_param(self, value, dialect):
|
|
if value is None:
|
|
return None
|
|
return json.dumps(value, separators=(',', ':'))
|
|
|
|
def process_result_value(self, value, dialect):
|
|
if value is None or value == '':
|
|
return None
|
|
try:
|
|
return json.loads(value)
|
|
except (TypeError, ValueError):
|
|
# A row written before this column was JSON, or hand-edited. Hand
|
|
# back the raw text rather than raising: a policy that cannot be
|
|
# parsed should be visible and fixable, not an exception on read.
|
|
return value
|