Add opt-in Database(deserialize_json=True) to parse JSON strings back into dict/list on read

Values inserted as dict/list are serialized to JSON TEXT columns, but rows
fetched via .rows/.rows_where()/.get()/.search()/.query() previously always
came back as raw strings. This adds an opt-in constructor flag that parses
any string value that looks like a JSON object or array back into a
dict/list, without changing the default (raw string) behavior.

Fixes #612
This commit is contained in:
Parker Gurney 2026-08-05 14:23:56 -07:00
commit 064625da59
3 changed files with 67 additions and 5 deletions

View file

@ -899,6 +899,28 @@ def test_insert_dictionaries_and_lists_as_json(fresh_db, data_structure):
assert data_structure == json.loads(row[1])
def test_deserialize_json(fresh_db):
fresh_db["test"].insert(
{"id": 1, "data": {"foo": "bar"}, "tags": [1, 2, 3], "name": "not json"},
pk="id",
)
# Default behaviour: values come back as the raw JSON strings that were stored
row = fresh_db["test"].get(1)
assert row["data"] == '{"foo": "bar"}'
assert row["tags"] == "[1, 2, 3]"
assert row["name"] == "not json"
# Opt-in: deserialize_json=True parses them back into dict/list
db2 = Database(fresh_db.conn, deserialize_json=True)
row2 = db2["test"].get(1)
assert row2["data"] == {"foo": "bar"}
assert row2["tags"] == [1, 2, 3]
assert row2["name"] == "not json"
# Also applies to .rows, .rows_where() and .query()
assert list(db2["test"].rows)[0]["data"] == {"foo": "bar"}
assert list(db2.query("select data from test"))[0]["data"] == {"foo": "bar"}
def test_insert_list_nested_unicode(fresh_db):
fresh_db["test"].insert(
{"id": 1, "data": {"key1": {"nested": ["cømplex"]}}}, pk="id"