Repository navigation
Conversation
The JSON/CSV branch used 'fn(doc) or doc', so any falsy result was
discarded and the unconverted row inserted. Exit code 0, no warning:
$ echo '[{"id": 1, "name": "Cleo"}]' | sqlite-utils insert d.db t - --convert '{}'
$ sqlite-utils 'select * from d.db' # -> the original row, not {}
The realistic shape of this is a filter:
--convert 'row if row["ok"] else {}' # meant to drop the bad rows
# every row inserted, including the ones meant to be dropped
'--lines' runs a different expression twelve lines up and has no such
fallback, so the same --convert code is rejected there and silently
accepted here:
--convert 0 JSON input -> exit 0, rows inserted
--convert 0 --lines -> exit 1, Rows must all be dictionaries, got: 0
test_insert_convert_error_messages already asserts that a non-dict
return is rejected (--convert 1); 0, False, [] and "" were the outliers,
purely because they are falsy.
None is the one falsy result that has to keep meaning 'modify doc in
place' - a --convert that is a bare statement returns it, which
test_insert_convert_row_modifying_in_place covers - so the fallback is
now keyed on 'is None' rather than truthiness.
Tests: 7 new cases in tests/test_cli_insert.py, all failing on 6bc1d33.
Suite 1505 passed, 16 skipped. black, flake8, mypy clean. pyright
reports one error and ty two diagnostics, both identical on unmodified
main (tests/test_constructor.py:74 and two unused-type-ignore comments
in db.py/utils.py) and none in the files this touches.
|
Hi @simonw — three of mine across your repos have been open since 26–28 September, all green, so this is one message rather than three pings. sqlite-utils #889 — sqlite-utils #888 — datasette #2968 — an empty-string keyset pagination cursor is dropped by The question I would most like settled is on #889, because it is the one with two defensible answers: right now a conversion that returns a falsy value is kept, which means a filter that wants to drop a row has no way to say so ( |
The JSON/CSV branch of
--convertusedfn(doc) or doc, so any falsy result was thrown away and the unconverted row inserted instead — exit code 0, no warning.The realistic shape of this is a filter:
Every row is inserted, including the ones the filter was written to drop, and nothing says so.
--linesalready rejects the same inputTwelve lines earlier the
--linesbranch has no such fallback, so the identical--convertbehaves differently depending only on the input format:Only
Noneshould fall backtest_insert_convert_error_messagesalready asserts that a non-dict return is rejected —--convert 1errors.0,False,[]and""were the outliers, and only because they are falsy.Noneis the one falsy result that has to keep meaning "modifydocin place": a--convertthat is a bare statement returns it, which is whattest_insert_convert_row_modifying_in_placecovers with--convert 'row["is_chicken"] = True'. So the fallback is keyed onis Nonerather than truthiness:What changes for existing users
A
--convertthat returned a truthy dict, or that mutated in place, is unaffected. A--convertthat returned{},0,"",[]orFalsepreviously inserted the input row unchanged and will now either insert what you returned or fail with the same error--convert 1already produced. That is a behaviour change for anyone who relied on the silent fallback — I cannot think of a case where relying on it was intended, but it is a change and worth stating.One thing this does not solve: there is no way to drop a row.
--convert 'row if row["ok"] else {}'inserts a row of nulls rather than skipping it, both before and after. I have left that alone as it is a separate design question.Testing
Testing
Seven cases in
tests/test_cli_insert.py, all failing on6bc1d33:test_insert_convert_falsy_result_is_rejected—0,"",[],Falsetest_insert_convert_returning_none_still_inserts_the_row— pins the in-place signaltest_insert_convert_returning_empty_dict_does_not_insert_the_originaltest_lines_and_json_convert_reject_the_same_falsy_result— the two formats agreeSuite: 1505 passed, 16 skipped.
black --check,flake8andmypyclean.pyrightreports one error andtytwo diagnostics, but all three are identical on unmodifiedmain(tests/test_constructor.py:74, and two unused-type: ignorecomments indb.py/utils.py) and none are in the files this touches.📚 Documentation preview 📚: https://sqlite-utils--889.org.readthedocs.build/en/889/