Closed lemon24 closed 1 year ago
I looked a bit into using cattrs for this.
Using only cattrs is somewhat involved, because:
entry.id, entry.title, ..., feed.url, ...
, like in the code below)entry.feed as entry.feed_url
)Arguably, it may be better to use cattrs just for (un)structuring and basic conversions (datetime, tuples, ...), and handle (un)flattening and JSON string conversions separately.
The code below contains a few different ways of manipulating the output of a query to a form that's accepted by cattrs structure(); all of them precompute the list of changes ahead of time to some extent, based on the expected type.
Conclusions (preliminary):
Following some sage advice from @andreivasiliu, I think it's probably best to keep the handmade row–object conversion functions; in his words:
Having your conversions manually laid out like that means that a reader (the fleshy kind) will always know all forms the data passes through. And knowing the shape of data is generally the most important thing in code (it's why typing helps so much). If you know what the input and output looks like, you can easily infer the conversion function. If all you can see is an abstract conversion function, then you have no idea what kinds of inputs it works on, and what kinds of outputs it's supposed to give out.
(...and it's not that many conversions anyway, I got carried away with cattrs for a bit there :)
On a semi-related note, this is probably a good opportunity to get rid of fix_datetime_tzinfo() and require Storage to return timezone-aware datetimes (UTC only); better now before #325.
https://github.com/python/cpython/issues/90016 https://docs.python.org/3.12/library/sqlite3.html#default-adapters-and-converters-deprecated
...but, the converter infra is global, so that can't work for reader (as a library, it should not change global stuff).
One solution that might work is to make custom connection/cursor subclasses that take care of the conversion (we'd need to turn detect_types off). For reference, reader uses TIMESTAMP for dates, which is stored as
2016-11-05 00:00:00
or2023-08-25 03:00:42.262181
.Update: ...except doing it in pure-Python is impossible, because detect_types=PARSE_DECLTYPES uses sqlite3_column_decltype, which is not exposed in the Python sqlite3 API.