--crossdb option for joining across databases (#1232)

* Test for cross-database join, refs #283
* Warn if --crossdb used with more than 10 DBs, refs #283
* latest.datasette.io demo of --crossdb joins, refs #283
* Show attached databases on /_memory page, refs #283
* Documentation for cross-database queries, refs #283
This commit is contained in:
Simon Willison 2021-02-18 14:09:12 -08:00 committed by GitHub
commit 6f41c8a2be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 215 additions and 8 deletions

View file

@ -105,6 +105,7 @@ def make_app_client(
static_mounts=None,
template_dir=None,
metadata=None,
crossdb=False,
):
with tempfile.TemporaryDirectory() as tmpdir:
filepath = os.path.join(tmpdir, filename)
@ -149,6 +150,7 @@ def make_app_client(
inspect_data=inspect_data,
static_mounts=static_mounts,
template_dir=template_dir,
crossdb=crossdb,
)
ds.sqlite_functions.append(("sleep", 1, lambda n: time.sleep(float(n))))
yield TestClient(ds)
@ -180,6 +182,15 @@ def app_client_two_attached_databases():
yield client
@pytest.fixture(scope="session")
def app_client_two_attached_databases_crossdb_enabled():
with make_app_client(
extra_databases={"extra database.db": EXTRA_DATABASE_SQL},
crossdb=True,
) as client:
yield client
@pytest.fixture(scope="session")
def app_client_conflicting_database_names():
with make_app_client(
@ -750,7 +761,12 @@ def assert_permissions_checked(datasette, actions):
default=False,
help="Delete and recreate database if it exists",
)
def cli(db_filename, metadata, plugins_path, recreate):
@click.option(
"--extra-db-filename",
type=click.Path(file_okay=True, dir_okay=False),
help="Write out second test DB to this file",
)
def cli(db_filename, metadata, plugins_path, recreate, extra_db_filename):
"""Write out the fixtures database used by Datasette's test suite"""
if metadata and not metadata.endswith(".json"):
raise click.ClickException("Metadata should end with .json")
@ -784,6 +800,17 @@ def cli(db_filename, metadata, plugins_path, recreate):
newpath = path / filepath.name
newpath.write_text(filepath.open().read())
print(f" Wrote plugin: {newpath}")
if extra_db_filename:
if pathlib.Path(extra_db_filename).exists():
if not recreate:
raise click.ClickException(
f"{extra_db_filename} already exists, use --recreate to reset it"
)
else:
pathlib.Path(extra_db_filename).unlink()
conn = sqlite3.connect(extra_db_filename)
conn.executescript(EXTRA_DATABASE_SQL)
print(f"Test tables written to {extra_db_filename}")
if __name__ == "__main__":