diff --git a/src/basic_memory/cli/commands/__init__.py b/src/basic_memory/cli/commands/__init__.py index 40e0d1b9..881d14d6 100644 --- a/src/basic_memory/cli/commands/__init__.py +++ b/src/basic_memory/cli/commands/__init__.py @@ -1,5 +1,5 @@ """Command module exports.""" -from . import init, status, sync, import_memory_json +from . import status, sync, import_memory_json -__all__ = ["init", "status", "sync", "import_memory_json.py"] +__all__ = [ "status", "sync", "import_memory_json.py"] diff --git a/src/basic_memory/cli/commands/init.py b/src/basic_memory/cli/commands/init.py deleted file mode 100644 index e8c5cc8a..00000000 --- a/src/basic_memory/cli/commands/init.py +++ /dev/null @@ -1,38 +0,0 @@ -"""Initialize command for basic-memory CLI.""" - -import asyncio -from pathlib import Path - -import typer -from loguru import logger - -from basic_memory.cli.app import app -from basic_memory.db import engine_session_factory, DatabaseType -from basic_memory.config import config - - -async def _init(force: bool = False): - """Initialize the database.""" - db_path = config.database_path - - if db_path.exists() and not force: - typer.echo(f"Database already exists at {db_path}. Use --force to reinitialize.") - raise typer.Exit(1) - - # Create data directory if needed - db_path.parent.mkdir(parents=True, exist_ok=True) - - try: - async with engine_session_factory(db_path, db_type=DatabaseType.FILESYSTEM, init=True): - typer.echo(f"Initialized database at {db_path}") - except Exception as e: - logger.error(f"Error initializing database: {e}") - typer.echo(f"Error initializing database: {e}") - raise typer.Exit(1) - -@app.command() -def init( - force: bool = typer.Option(False, "--force", "-f", help="Force reinitialization if database exists") -): - """Initialize a new basic-memory database.""" - asyncio.run(_init(force)) diff --git a/src/basic_memory/cli/main.py b/src/basic_memory/cli/main.py index 9f0356e3..de11ebd2 100644 --- a/src/basic_memory/cli/main.py +++ b/src/basic_memory/cli/main.py @@ -5,11 +5,10 @@ import typer from loguru import logger from basic_memory.cli.app import app -from basic_memory.cli.commands.init import init # Register commands -from basic_memory.cli.commands import init, status, sync -__all__ = ["init", "status", "sync"] +from basic_memory.cli.commands import status, sync +__all__ = ["status", "sync"] from basic_memory.config import config diff --git a/src/basic_memory/db.py b/src/basic_memory/db.py index 4385a835..10f80a83 100644 --- a/src/basic_memory/db.py +++ b/src/basic_memory/db.py @@ -15,6 +15,8 @@ from sqlalchemy.ext.asyncio import ( ) from basic_memory.models import Base, SCHEMA_VERSION +from basic_memory.models.search import CREATE_SEARCH_INDEX +from basic_memory.repository.search_repository import SearchRepository # Module level state _engine: Optional[AsyncEngine] = None @@ -77,7 +79,10 @@ async def init_db() -> None: await session.execute(text("PRAGMA foreign_keys=ON")) conn = await session.connection() await conn.run_sync(Base.metadata.create_all) - + + # recreate search index + await session.execute(CREATE_SEARCH_INDEX) + await session.commit() async def drop_db(): diff --git a/src/basic_memory/repository/search_repository.py b/src/basic_memory/repository/search_repository.py index d06c3942..1f1a09e2 100644 --- a/src/basic_memory/repository/search_repository.py +++ b/src/basic_memory/repository/search_repository.py @@ -70,6 +70,8 @@ class SearchRepository: async def init_search_index(self): """Create or recreate the search index.""" + + logger.info("Initializing search index") async with db.scoped_session(self.session_maker) as session: await session.execute(CREATE_SEARCH_INDEX) await session.commit() diff --git a/src/basic_memory/services/database_service.py b/src/basic_memory/services/database_service.py index 8749a797..08f00ccb 100644 --- a/src/basic_memory/services/database_service.py +++ b/src/basic_memory/services/database_service.py @@ -13,6 +13,7 @@ from sqlalchemy.ext.asyncio import AsyncSession from basic_memory import db from basic_memory.config import ProjectConfig from basic_memory.models import Base +from basic_memory.repository.search_repository import SearchRepository async def check_schema_matches_models(session: AsyncSession) -> Tuple[bool, List[str]]: @@ -127,7 +128,7 @@ class DatabaseService: for diff in differences: logger.warning(f" {diff}") logger.info("Rebuilding database to match current models...") - await self.initialize_db() + await self.initialize_db() return True logger.info("Database schema matches models") diff --git a/src/basic_memory/sync/sync_service.py b/src/basic_memory/sync/sync_service.py index 209a308a..9026cd8d 100644 --- a/src/basic_memory/sync/sync_service.py +++ b/src/basic_memory/sync/sync_service.py @@ -4,6 +4,7 @@ from pathlib import Path from typing import Dict from loguru import logger +from sqlalchemy.exc import IntegrityError from basic_memory import file_utils from basic_memory.markdown import EntityParser, EntityMarkdown @@ -153,10 +154,14 @@ class SyncService: # check we found a link that is not the source if target_entity and target_entity.id != relation.from_id: logger.debug(f"Resolved forward reference: {relation.to_name} -> {target_entity.permalink}") - await self.relation_repository.update(relation.id, { - "to_id": target_entity.id, - "to_name": target_entity.title # Update to actual title - }) + + try: + await self.relation_repository.update(relation.id, { + "to_id": target_entity.id, + "to_name": target_entity.title # Update to actual title + }) + except IntegrityError as e: + logger.info(f"Ignoring duplicate relation {relation}") # update search index await self.search_service.index_entity(target_entity)