mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-09-09 10:04:10 +02:00
Output binary columns as base64 in JSON, closes #125
This commit is contained in:
parent
bc8409941f
commit
20e543e9a4
3 changed files with 46 additions and 1 deletions
13
docs/cli.rst
13
docs/cli.rst
|
|
@ -55,6 +55,19 @@ If you want to pretty-print the output further, you can pipe it through ``python
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
|
Binary strings are not valid JSON, so BLOB columns containing binary data will be returned as a JSON object containing base64 encoded data, that looks like this::
|
||||||
|
|
||||||
|
$ sqlite-utils dogs.db "select name, content from images" | python -mjson.tool
|
||||||
|
[
|
||||||
|
{
|
||||||
|
"name": "smile.gif",
|
||||||
|
"content": {
|
||||||
|
"$base64": true,
|
||||||
|
"encoded": "eJzt0c1x..."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
If you execute an ``UPDATE``, ``INSERT`` or ``DELETE`` query the comand will return the number of affected rows::
|
If you execute an ``UPDATE``, ``INSERT`` or ``DELETE`` query the comand will return the number of affected rows::
|
||||||
|
|
||||||
$ sqlite-utils dogs.db "update dogs set age = 5 where name = 'Cleo'"
|
$ sqlite-utils dogs.db "update dogs set age = 5 where name = 'Cleo'"
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import base64
|
||||||
import click
|
import click
|
||||||
from click_default_group import DefaultGroup
|
from click_default_group import DefaultGroup
|
||||||
import sqlite_utils
|
import sqlite_utils
|
||||||
|
|
@ -748,7 +749,7 @@ def output_rows(iterator, headers, nl, arrays, json_cols):
|
||||||
data = dict(zip(headers, data))
|
data = dict(zip(headers, data))
|
||||||
line = "{firstchar}{serialized}{maybecomma}{lastchar}".format(
|
line = "{firstchar}{serialized}{maybecomma}{lastchar}".format(
|
||||||
firstchar=("[" if first else " ") if not nl else "",
|
firstchar=("[" if first else " ") if not nl else "",
|
||||||
serialized=json.dumps(data),
|
serialized=json.dumps(data, default=json_binary),
|
||||||
maybecomma="," if (not nl and not is_last) else "",
|
maybecomma="," if (not nl and not is_last) else "",
|
||||||
lastchar="]" if (is_last and not nl) else "",
|
lastchar="]" if (is_last and not nl) else "",
|
||||||
)
|
)
|
||||||
|
|
@ -766,3 +767,10 @@ def maybe_json(value):
|
||||||
return json.loads(stripped)
|
return json.loads(stripped)
|
||||||
except ValueError:
|
except ValueError:
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
|
def json_binary(value):
|
||||||
|
if isinstance(value, bytes):
|
||||||
|
return {"$base64": True, "encoded": base64.b64encode(value).decode("latin-1")}
|
||||||
|
else:
|
||||||
|
raise TypeError
|
||||||
|
|
|
||||||
|
|
@ -765,6 +765,30 @@ def test_query_json(db_path, sql, args, expected):
|
||||||
assert expected == result.output.strip()
|
assert expected == result.output.strip()
|
||||||
|
|
||||||
|
|
||||||
|
LOREM_IPSUM_COMPRESSED = b"x\x9c\xed\xd1\xcdq\x03!\x0c\x05\xe0\xbb\xabP\x01\x1eW\x91\xdc|M\x01\n\xc8\x8ef\xf83H\x1e\x97\x1f\x91M\x8e\xe9\xe0\xdd\x96\x05\x84\xf4\xbek\x9fRI\xc7\xf2J\xb9\x97>i\xa9\x11W\xb13\xa5\xde\x96$\x13\xf3I\x9cu\xe8J\xda\xee$EcsI\x8e\x0b$\xea\xab\xf6L&u\xc4emI\xb3foFnT\xf83\xca\x93\xd8QZ\xa8\xf2\xbd1q\xd1\x87\xf3\x85>\x8c\xa4i\x8d\xdaTu\x7f<c\xc9\xf5L\x0f\xd7E\xad/\x9b\x9eI^2\x93\x1a\x9b\xf6F^\n\xd7\xd4\x8f\xca\xfb\x90.\xdd/\xfd\x94\xd4\x11\x87I8\x1a\xaf\xd1S?\x06\x88\xa7\xecBo\xbb$\xbb\t\xe9\xf4\xe8\xe4\x98U\x1bM\x19S\xbe\xa4e\x991x\xfcx\xf6\xe2#\x9e\x93h'&%YK(i)\x7f\t\xc5@N7\xbf+\x1b\xb5\xdd\x10\r\x9e\xb1\xf0y\xa1\xf7W\x92a\xe2;\xc6\xc8\xa0\xa7\xc4\x92\xe2\\\xf2\xa1\x99m\xdf\x88)\xc6\xec\x9a\xa5\xed\x14wR\xf1h\xf22x\xcfM\xfdv\xd3\xa4LY\x96\xcc\xbd[{\xd9m\xf0\x0eH#\x8e\xf5\x9b\xab\xd7\xcb\xe9t\x05\x1f\xf8\xc0\x07>\xf0\x81\x0f|\xe0\x03\x1f\xf8\xc0\x07>\xf0\x81\x0f|\xe0\x03\x1f\xf8\xc0\x07>\xf0\x81\x0f|\xe0\x03\x1f\xf8\xc0\x07>\xf0\x81\x0f|\xe0\x03\x1f\xf8\xc0\x07>\xf0\x81\x0f|\xe0\x03\x1f\xf8\xc0\x07>\xf0\x81\x0f|\xe0\x03\x1f\xf8\xc0\x07>\xf0\x81\x0f|\xe0\x03\x1f\xf8\xc0\x07>\xf0\x81\x0f|\xe0\xfb\x8f\xef\x1b\x9b\x06\x83}"
|
||||||
|
|
||||||
|
|
||||||
|
def test_query_json_binary(db_path):
|
||||||
|
db = Database(db_path)
|
||||||
|
with db.conn:
|
||||||
|
db["files"].insert(
|
||||||
|
{"name": "lorem.txt", "sz": 16984, "data": LOREM_IPSUM_COMPRESSED,},
|
||||||
|
pk="name",
|
||||||
|
)
|
||||||
|
result = CliRunner().invoke(cli.cli, [db_path, "select name, sz, data from files"])
|
||||||
|
assert result.exit_code == 0, str(result)
|
||||||
|
assert json.loads(result.output.strip()) == [
|
||||||
|
{
|
||||||
|
"name": "lorem.txt",
|
||||||
|
"sz": 16984,
|
||||||
|
"data": {
|
||||||
|
"$base64": True,
|
||||||
|
"encoded": "eJzt0c1xAyEMBeC7q1ABHleR3HxNAQrIjmb4M0gelx+RTY7p4N2WBYT0vmufUknH8kq5lz5pqRFXsTOl3pYkE/NJnHXoStruJEVjc0mOCyTqq/ZMJnXEZW1Js2ZvRm5U+DPKk9hRWqjyvTFx0YfzhT6MpGmN2lR1fzxjyfVMD9dFrS+bnkleMpMam/ZGXgrX1I/K+5Au3S/9lNQRh0k4Gq/RUz8GiKfsQm+7JLsJ6fTo5JhVG00ZU76kZZkxePx49uIjnpNoJyYlWUsoaSl/CcVATje/Kxu13RANnrHweaH3V5Jh4jvGyKCnxJLiXPKhmW3fiCnG7Jql7RR3UvFo8jJ4z039dtOkTFmWzL1be9lt8A5II471m6vXy+l0BR/4wAc+8IEPfOADH/jABz7wgQ984AMf+MAHPvCBD3zgAx/4wAc+8IEPfOADH/jABz7wgQ984AMf+MAHPvCBD3zgAx/4wAc+8IEPfOADH/jABz7wgQ984PuP7xubBoN9",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
def test_query_json_with_json_cols(db_path):
|
def test_query_json_with_json_cols(db_path):
|
||||||
db = Database(db_path)
|
db = Database(db_path)
|
||||||
with db.conn:
|
with db.conn:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue