diff --git a/src/basic_memory/repository/project_repository.py b/src/basic_memory/repository/project_repository.py index 7bd6b0280..e5d64dbb3 100644 --- a/src/basic_memory/repository/project_repository.py +++ b/src/basic_memory/repository/project_repository.py @@ -168,19 +168,24 @@ async def set_as_default(self, session: AsyncSession, project_id: int) -> Option Returns: The updated project if found, None otherwise """ - # First, clear the default flag for all projects using direct SQL + target_project = await self.select_by_id(session, project_id) + if not target_project: + return None # pragma: no cover + + # Preserve the target row while clearing previous defaults. Clearing an already-default + # target through bulk SQL leaves its ORM identity-map value at True, so assigning True + # again emits no UPDATE and otherwise persists a database with no default project. await session.execute( - text("UPDATE project SET is_default = NULL WHERE is_default IS NOT NULL") + text( + "UPDATE project SET is_default = NULL " + "WHERE id != :project_id AND is_default IS NOT NULL" + ), + {"project_id": project_id}, ) - await session.flush() - # Set the new default project - target_project = await self.select_by_id(session, project_id) - if target_project: - target_project.is_default = True - await session.flush() - return target_project - return None # pragma: no cover + target_project.is_default = True + await session.flush() + return target_project @override async def delete(self, session: AsyncSession, entity_id: int) -> bool: diff --git a/tests/repository/test_project_repository.py b/tests/repository/test_project_repository.py index 9fa48b02c..531c37095 100644 --- a/tests/repository/test_project_repository.py +++ b/tests/repository/test_project_repository.py @@ -272,6 +272,27 @@ async def test_set_as_default( assert project2_updated.is_default is True +@pytest.mark.asyncio +async def test_set_as_default_keeps_existing_default( + project_repository: ProjectRepository, test_project: Project, session_maker +): + """Setting the existing default again must leave it persisted as the default.""" + async with db.scoped_session(session_maker) as session: + existing_default = await project_repository.find_by_id(session, test_project.id) + assert existing_default is not None + assert existing_default.is_default is True + + updated_default = await project_repository.set_as_default(session, existing_default.id) + assert updated_default is not None + assert updated_default.is_default is True + + # Verify from a new identity map so the assertion reflects persisted database state. + async with db.scoped_session(session_maker) as session: + persisted_default = await project_repository.get_default_project(session) + assert persisted_default is not None + assert persisted_default.id == test_project.id + + @pytest.mark.asyncio async def test_update_project( project_repository: ProjectRepository, sample_project: Project, session_maker