simonw / simonw/sqlite-utils

Automatic JSON de-serialization

Open
#612 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
Python
Stars
2.2k
Forks
172
Avg merge
9m
Merged PRs (30d)
1

Description

My use case is that I'd like to more easily import and explore JSON documents returned from APIs. Obviously, the automatic type detection and table creation provided by sqlite-utils (SU) adds considerable productivity to that effort.

One of the difficulties I've encountered is that SU will serialize dicts/lists to JSON but doesn't deserialize it when retrieved. It turns out that with a bit of modification, it would not be hard to support this use case. This is what I came up with:

import json
import sqlite3

from sqlite_utils import db


db.COLUMN_TYPE_MAPPING['JSON'] = 'JSONB'


class Database(db.Database):
    def __init__(self, fpath, *args, **kwargs):
        conn = sqlite3.connect(fpath, detect_types=sqlite3.PARSE_DECLTYPES)
        sqlite3.register_converter('jsonb', self.json_loads)

        super().__init__(conn, *args, **kwargs)

    # Keep this on the class so it can be easily customized in a subclass
    def json_loads(self, val: bytes):
        return json.loads(val)


db = Database(':memory:')

db['users'].insert(
    {'id': 1, 'name': 'John Doe', 'preferences': {'theme': 'dark', 'language': 'en'}},
    columns={'preferences': 'JSON'},
    replace=True,
)

row = db['users'].get(1)
assert isinstance(row['preferences'], dict), row

This could all be made mostly automatic if SU:

  1. Column type detection used 'JSON' instead of 'TEXT' when detecting Python objects that will be jsonified
  2. sqlite3 is setup to handle JSON/JSONB conversion

Considerations:

  1. I'd like to see this made the default but until the next major version bump, could be hidden behind Database(..., jsonb_columns=True)
  2. Whether or not JSON or JSONB columns are used would depend on SQLite version.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the sqlite_utils.db.Database class and its COLUMN_TYPE_MAPPING, then trace how Python dicts and lists are detected and serialized during insert and how connections are created. Done should include optional JSON/JSONB column handling and retrieval of stored values as Python objects, while accounting for SQLite version differences and the proposed jsonb_columns option.

Written by the indexing model from the issue text.

Assessment

Tech stack
python, sqlite
Domain
database
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.