diff --git a/datasette/cli.py b/datasette/cli.py index 8d0d9aec..668ee1fd 100644 --- a/datasette/cli.py +++ b/datasette/cli.py @@ -1,3 +1,4 @@ +import asyncio import click from click import formatting from click_default_group import DefaultGroup @@ -60,7 +61,7 @@ def cli(): @cli.command() @click.argument("files", type=click.Path(exists=True), nargs=-1) -@click.option("--inspect-file", default="inspect-data.json") +@click.option("--inspect-file", default="-") @click.option( "sqlite_extensions", "--load-extension", @@ -70,8 +71,31 @@ def cli(): help="Path to a SQLite extension to load", ) def inspect(files, inspect_file, sqlite_extensions): - app = Datasette(files, sqlite_extensions=sqlite_extensions) - open(inspect_file, "w").write(json.dumps(app.inspect(), indent=2)) + app = Datasette([], immutables=files, sqlite_extensions=sqlite_extensions) + if inspect_file == "-": + out = sys.stdout + else: + out = open(inspect_file, "w") + loop = asyncio.get_event_loop() + inspect_data = loop.run_until_complete(inspect_(files, sqlite_extensions)) + out.write(json.dumps(inspect_data, indent=2)) + + +async def inspect_(files, sqlite_extensions): + app = Datasette([], immutables=files, sqlite_extensions=sqlite_extensions) + data = {} + for name, database in app.databases.items(): + counts = await database.table_counts(limit=3600 * 1000) + data[name] = { + "hash": database.hash, + "size": database.size, + "file": database.path, + "tables": { + table_name: {"count": table_count} + for table_name, table_count in counts.items() + }, + } + return data @cli.group() diff --git a/docs/full_text_search.rst b/docs/full_text_search.rst index 08e85c90..97656bb8 100644 --- a/docs/full_text_search.rst +++ b/docs/full_text_search.rst @@ -7,7 +7,7 @@ SQLite includes `a powerful mechanism for enabling full-text search `__ provides a command-line mechanism that can be used to implement the above steps. + .. _full_text_search_table_or_view: Configuring full-text search for a table or view diff --git a/docs/introspection.rst b/docs/introspection.rst index 6aeedc61..9162ac34 100644 --- a/docs/introspection.rst +++ b/docs/introspection.rst @@ -21,40 +21,6 @@ Shows the contents of the ``metadata.json`` file that was passed to ``datasette "databases": {...} } -.. _JsonDataView_inspect: - -/-/inspect ----------- - -Shows the result of running ``datasette inspect`` on the currently loaded databases. This is run automatically when Datasette starts up, or can be run as a separate step and passed to ``datasette serve --inspect-file``. - -This is an internal implementation detail of Datasette and the format should not be considered stable - it is likely to change in undocumented ways between different releases. - -`Inspect example `_:: - - { - "fivethirtyeight": { - "file": "fivethirtyeight.db", - "hash": "5de27e3eceb3f5ba817e0b2e066cea77832592b62d94690b5102a48f385b95fb", - "tables": { - "./index": { - "columns": [ - "dataset_url", - "article_url", - "live" - ], - "count": 125, - "foreign_keys": { - "incoming": [], - "outgoing": [] - }, - "fts_table": null, - "hidden": false, - "name": "./index", - "primary_keys": [] - }, - ... - .. _JsonDataView_versions: /-/versions diff --git a/tests/test_inspect.py b/tests/test_inspect.py index 89b20b1f..da68652b 100644 --- a/tests/test_inspect.py +++ b/tests/test_inspect.py @@ -1,92 +1,28 @@ -from datasette.app import Datasette -from datasette.utils import sqlite3 -import os -import pytest -import tempfile +from .fixtures import app_client +from datasette.cli import cli +from click.testing import CliRunner +import json -TABLES = """ -CREATE TABLE "election_results" ( - "county" INTEGER, - "party" INTEGER, - "office" INTEGER, - "votes" INTEGER, - FOREIGN KEY (county) REFERENCES county(id), - FOREIGN KEY (party) REFERENCES party(id), - FOREIGN KEY (office) REFERENCES office(id) - ); - -CREATE VIRTUAL TABLE "election_results_fts" USING FTS4 ("county", "party"); - -CREATE TABLE "county" ( - "id" INTEGER PRIMARY KEY , - "name" TEXT -); - -CREATE TABLE "party" ( - "id" INTEGER PRIMARY KEY , - "name" TEXT -); - -CREATE TABLE "office" ( - "id" INTEGER PRIMARY KEY , - "name" TEXT -); -""" +def test_inspect_cli(app_client): + runner = CliRunner() + result = runner.invoke(cli, ["inspect", "fixtures.db"]) + data = json.loads(result.output) + assert ["fixtures"] == list(data.keys()) + database = data["fixtures"] + assert "fixtures.db" == database["file"] + assert isinstance(database["hash"], str) + assert 64 == len(database["hash"]) + for table_name, expected_count in { + "Table With Space In Name": 0, + "facetable": 15 + }.items(): + assert expected_count == database["tables"][table_name]["count"] -@pytest.fixture(scope="session") -def ds_instance(): - with tempfile.TemporaryDirectory() as tmpdir: - filepath = os.path.join(tmpdir, "fixtures.db") - conn = sqlite3.connect(filepath) - conn.executescript(TABLES) - yield Datasette([filepath]) - - -def test_inspect_hidden_tables(ds_instance): - info = ds_instance.inspect() - tables = info["fixtures"]["tables"] - expected_hidden = ( - "election_results_fts", - "election_results_fts_content", - "election_results_fts_docsize", - "election_results_fts_segdir", - "election_results_fts_segments", - "election_results_fts_stat", - ) - expected_visible = ("election_results", "county", "party", "office") - assert sorted(expected_hidden) == sorted( - [table for table in tables if tables[table]["hidden"]] - ) - assert sorted(expected_visible) == sorted( - [table for table in tables if not tables[table]["hidden"]] - ) - - -def test_inspect_foreign_keys(ds_instance): - info = ds_instance.inspect() - tables = info["fixtures"]["tables"] - for table_name in ("county", "party", "office"): - assert 0 == tables[table_name]["count"] - foreign_keys = tables[table_name]["foreign_keys"] - assert [] == foreign_keys["outgoing"] - assert [ - { - "column": "id", - "other_column": table_name, - "other_table": "election_results", - } - ] == foreign_keys["incoming"] - - election_results = tables["election_results"] - assert 0 == election_results["count"] - assert sorted( - [ - {"column": "county", "other_column": "id", "other_table": "county"}, - {"column": "party", "other_column": "id", "other_table": "party"}, - {"column": "office", "other_column": "id", "other_table": "office"}, - ], - key=lambda d: d["column"], - ) == sorted(election_results["foreign_keys"]["outgoing"], key=lambda d: d["column"]) - assert [] == election_results["foreign_keys"]["incoming"] +def test_inspect_cli_writes_to_file(app_client): + runner = CliRunner() + result = runner.invoke(cli, ["inspect", "fixtures.db", "--inspect-file", "foo.json"]) + assert 0 == result.exit_code, result.output + data = json.load(open("foo.json")) + assert ["fixtures"] == list(data.keys())