diff --git a/graphiti_core/driver/falkordb_driver.py b/graphiti_core/driver/falkordb_driver.py index 2268b3dd43..dde8b0c5b5 100644 --- a/graphiti_core/driver/falkordb_driver.py +++ b/graphiti_core/driver/falkordb_driver.py @@ -230,8 +230,8 @@ def graph_ops(self) -> GraphMaintenanceOperations: return self._graph_ops def _get_graph(self, graph_name: str | None) -> FalkorGraph: - # FalkorDB requires a non-None database name for multi-tenant graphs; the default is "default_db" - if graph_name is None: + # FalkorDB requires a non-empty database name for multi-tenant graphs; the default is "default_db" + if not graph_name: graph_name = self._database return self.client.select_graph(graph_name) @@ -325,6 +325,13 @@ def clone(self, database: str) -> 'GraphDriver': Returns a shallow copy of this driver with a different default database. Reuses the same connection (e.g. FalkorDB, Neo4j). """ + # An empty group_id must not become an empty graph name: falkordb-py's + # select_graph('') raises a misleading TypeError ("Expected a string + # parameter, but received "). Fall back to the current + # database instead. See #1650. + if not database: + database = self._database + if database == self._database: cloned = self elif database == self.default_group_id: diff --git a/tests/driver/test_falkordb_driver.py b/tests/driver/test_falkordb_driver.py index 6905e4a3c9..b1e7614645 100644 --- a/tests/driver/test_falkordb_driver.py +++ b/tests/driver/test_falkordb_driver.py @@ -92,6 +92,17 @@ def test_get_graph_with_none_defaults_to_default_database(self): self.mock_client.select_graph.assert_called_once_with('default_db') assert result is mock_graph + @unittest.skipIf(not HAS_FALKORDB, 'FalkorDB is not installed') + def test_get_graph_with_empty_name_defaults_to_default_database(self): + """Test _get_graph with an empty name defaults to default_db.""" + mock_graph = MagicMock() + self.mock_client.select_graph.return_value = mock_graph + + result = self.driver._get_graph('') + + self.mock_client.select_graph.assert_called_once_with('default_db') + assert result is mock_graph + @pytest.mark.asyncio @unittest.skipIf(not HAS_FALKORDB, 'FalkorDB is not installed') async def test_execute_query_success(self): @@ -236,6 +247,50 @@ async def test_delete_all_indexes(self): mock_execute.assert_called_once_with('CALL db.indexes()') + @unittest.skipIf(not HAS_FALKORDB, 'FalkorDB is not installed') + def test_clone_with_empty_database_falls_back_to_current_database(self): + """Test clone with an empty database falls back to the current database.""" + cloned = self.driver.clone('') + + assert cloned is self.driver + assert cloned._database == self.driver._database + + @pytest.mark.asyncio + @unittest.skipIf(not HAS_FALKORDB, 'FalkorDB is not installed') + async def test_clone_with_empty_database_never_selects_empty_graph(self): + """Test that a query on a clone('') driver never calls select_graph('').""" + mock_graph = MagicMock() + mock_result = MagicMock() + mock_result.header = [] + mock_result.result_set = [] + mock_graph.query = AsyncMock(return_value=mock_result) + self.mock_client.select_graph.return_value = mock_graph + + cloned = self.driver.clone('') + await cloned.execute_query('MATCH (n) RETURN n') + + self.mock_client.select_graph.assert_called_once_with('default_db') + + @unittest.skipIf(not HAS_FALKORDB, 'FalkorDB is not installed') + def test_clone_with_database_creates_new_driver(self): + """Test clone with a specific database creates a new driver on that database.""" + cloned = self.driver.clone('group') + + assert cloned is not self.driver + assert isinstance(cloned, FalkorDriver) + assert cloned.client is self.mock_client + assert cloned._database == 'group' + + @unittest.skipIf(not HAS_FALKORDB, 'FalkorDB is not installed') + def test_clone_with_default_group_id_uses_default_database(self): + """Test clone with the default group id creates a new driver on the default database.""" + cloned = self.driver.clone(self.driver.default_group_id) + + assert cloned is not self.driver + assert isinstance(cloned, FalkorDriver) + assert cloned.client is self.mock_client + assert cloned._database == 'default_db' + class TestFalkorDriverSession: """Test FalkorDB driver session functionality."""