Name what a command calls its database, and whether it exists

`tag_restore` reached into `HaikuRAGApp._display_path` and `_path`, and seven
places spelled out `self._is_local and not self._path.exists()`. `display_path`
and `database_missing` say both, and `database_missing` is False for a database
behind a URI, which has no path to check.

`init` keeps its own check: it asks the opposite question.
This commit is contained in:
Yiorgis Gozadinos 2026-08-28 14:02:56 +03:00
parent 1de1b662ae
commit 81e05cba7a
No known key found for this signature in database
3 changed files with 27 additions and 19 deletions

View file

@ -101,10 +101,18 @@ class HaikuRAGApp:
return self._connection[1] return self._connection[1]
@property @property
def _display_path(self) -> "Path | str": def display_path(self) -> "Path | str":
"""What a one-database command calls the database it opened.""" """What a one-database command calls the database it opened."""
return self._one.db_path or self._one.uri return self._one.db_path or self._one.uri
@property
def database_missing(self) -> bool:
"""Whether the one local database this command resolved to does not exist.
Always False for a database behind a URI, which has no path to check.
"""
return self._is_local and not self._path.exists()
async def init(self): async def init(self):
"""Initialize a new database.""" """Initialize a new database."""
if self._is_local and self._path.exists(): if self._is_local and self._path.exists():
@ -116,7 +124,7 @@ class HaikuRAGApp:
async with HaikuRAG._covering(self.scope, self.config, create=True): async with HaikuRAG._covering(self.scope, self.config, create=True):
pass pass
self.console.print( self.console.print(
f"[bold green]Database initialized at {self._display_path}[/bold green]" f"[bold green]Database initialized at {self.display_path}[/bold green]"
) )
async def info(self): async def info(self):
@ -127,10 +135,10 @@ class HaikuRAGApp:
# Basic: show path/URI # Basic: show path/URI
self.console.print("[bold]haiku.rag database info[/bold]") self.console.print("[bold]haiku.rag database info[/bold]")
self.console.print( self.console.print(
f" [repr.attrib_name]path[/repr.attrib_name]: {self._display_path}" f" [repr.attrib_name]path[/repr.attrib_name]: {self.display_path}"
) )
if self._is_local and not self._path.exists(): if self.database_missing:
self.console.print("[red]Database path does not exist.[/red]") self.console.print("[red]Database path does not exist.[/red]")
return return
@ -258,10 +266,10 @@ class HaikuRAGApp:
self.console.print("[bold]haiku.rag doctor[/bold]") self.console.print("[bold]haiku.rag doctor[/bold]")
self.console.print( self.console.print(
f" [repr.attrib_name]path[/repr.attrib_name]: {self._display_path}" f" [repr.attrib_name]path[/repr.attrib_name]: {self.display_path}"
) )
if self._is_local and not self._path.exists(): if self.database_missing:
self.console.print("[red]Database path does not exist.[/red]") self.console.print("[red]Database path does not exist.[/red]")
return True return True
@ -329,7 +337,7 @@ class HaikuRAGApp:
""" """
from haiku.rag.store.engine import Store from haiku.rag.store.engine import Store
if self._is_local and not self._path.exists(): if self.database_missing:
self.console.print("[red]Database path does not exist.[/red]") self.console.print("[red]Database path does not exist.[/red]")
return return
@ -425,7 +433,7 @@ class HaikuRAGApp:
async def create_tag(self, name: str): async def create_tag(self, name: str):
"""Tag the current version of every table.""" """Tag the current version of every table."""
if self._is_local and not self._path.exists(): if self.database_missing:
raise ValueError(f"Database path does not exist: {self._path}") raise ValueError(f"Database path does not exist: {self._path}")
async with self._tag_write_store() as store: async with self._tag_write_store() as store:
await store.create_tag(name) await store.create_tag(name)
@ -433,7 +441,7 @@ class HaikuRAGApp:
async def list_tags(self): async def list_tags(self):
"""List database tags, flagging partial ones.""" """List database tags, flagging partial ones."""
if self._is_local and not self._path.exists(): if self.database_missing:
raise ValueError(f"Database path does not exist: {self._path}") raise ValueError(f"Database path does not exist: {self._path}")
async with self._tag_read_store() as store: async with self._tag_read_store() as store:
tags = await store.list_tags() tags = await store.list_tags()
@ -454,7 +462,7 @@ class HaikuRAGApp:
async def delete_tag(self, name: str): async def delete_tag(self, name: str):
"""Delete a tag from every table that has it.""" """Delete a tag from every table that has it."""
if self._is_local and not self._path.exists(): if self.database_missing:
raise ValueError(f"Database path does not exist: {self._path}") raise ValueError(f"Database path does not exist: {self._path}")
async with self._tag_write_store() as store: async with self._tag_write_store() as store:
await store.delete_tag(name) await store.delete_tag(name)
@ -469,7 +477,7 @@ class HaikuRAGApp:
Raises: Raises:
ValueError: If the database path does not exist. ValueError: If the database path does not exist.
""" """
if self._is_local and not self._path.exists(): if self.database_missing:
raise ValueError(f"Database path does not exist: {self._path}") raise ValueError(f"Database path does not exist: {self._path}")
async with self._tag_write_store() as store: async with self._tag_write_store() as store:
safety_tag = await store.restore_tag(name) safety_tag = await store.restore_tag(name)
@ -886,7 +894,7 @@ class HaikuRAGApp:
f"[repr.attrib_name]created at[/repr.attrib_name]: {doc.created_at} [repr.attrib_name]updated at[/repr.attrib_name]: {doc.updated_at}" f"[repr.attrib_name]created at[/repr.attrib_name]: {doc.created_at} [repr.attrib_name]updated at[/repr.attrib_name]: {doc.updated_at}"
) )
# `list` does not load content, which is where the docling blobs live, so # `list` does not load content, which is where the docling blobs live, so
# the header would otherwise announce a field the command declined to fetch. # the header prints only for a fetched field.
if doc.content: if doc.content:
self.console.print("[repr.attrib_name]content[/repr.attrib_name]:") self.console.print("[repr.attrib_name]content[/repr.attrib_name]:")
self.console.print(content) self.console.print(content)
@ -932,9 +940,9 @@ class HaikuRAGApp:
The server opens its own client and validates it on startup, so nothing The server opens its own client and validates it on startup, so nothing
is opened here first. is opened here first.
""" """
# The resolved scope, not a derived path and configuration: a path # The resolved scope: a path overrides a configured URI, and a derived
# would override a configured URI, and deriving drops the name results # single-database configuration drops the name results and citations
# and citations carry. # carry.
server = _mcp_server_covering(self.scope, self.config, self.read_only) server = _mcp_server_covering(self.scope, self.config, self.read_only)
try: try:
if transport == "stdio": if transport == "stdio":

View file

@ -756,11 +756,11 @@ def tag_restore(
), ),
): ):
app = create_app(db) app = create_app(db)
if app._is_local and not app._path.exists(): if app.database_missing:
typer.echo(f"Error: Database path does not exist: {app._path}", err=True) typer.echo(f"Error: Database path does not exist: {app.display_path}", err=True)
raise typer.Exit(1) raise typer.Exit(1)
if not yes: if not yes:
typer.echo(f"Database: {app._display_path}") typer.echo(f"Database: {app.display_path}")
typer.echo(f"Tag: {name}") typer.echo(f"Tag: {name}")
typer.echo("This changes the live database state across all tables.") typer.echo("This changes the live database state across all tables.")
typer.echo("Stop all ingestion and other writers before continuing.") typer.echo("Stop all ingestion and other writers before continuing.")

View file

@ -449,7 +449,7 @@ def test_remote_uri_is_the_display_path(tmp_path):
config = AppConfig(lancedb=LanceDBConfig(uri="s3://bucket/path")) config = AppConfig(lancedb=LanceDBConfig(uri="s3://bucket/path"))
app = HaikuRAGApp(scope=for_path(None, config), config=config) app = HaikuRAGApp(scope=for_path(None, config), config=config)
assert app._display_path == "s3://bucket/path" assert app.display_path == "s3://bucket/path"
assert app._is_local is False assert app._is_local is False