diff --git a/qdrant_client/async_qdrant_client.py b/qdrant_client/async_qdrant_client.py index 6258d6f6..32188586 100644 --- a/qdrant_client/async_qdrant_client.py +++ b/qdrant_client/async_qdrant_client.py @@ -1574,6 +1574,7 @@ async def create_collection( timeout: int | None = None, strict_mode_config: types.StrictModeConfig | None = None, metadata: types.Payload | None = None, + if_not_exists: bool = False, **kwargs: Any, ) -> bool: """Create empty collection with given parameters @@ -1620,11 +1621,18 @@ async def create_collection( If timeout is reached - request will return with service error. strict_mode_config: Configure limitations for the collection, such as max size, rate limits, etc. metadata: Arbitrary JSON-like metadata for the collection + if_not_exists: + If True, collection will only be created if it doesn't already exist. + If False (default), will attempt to create regardless of existence. Returns: Operation result """ assert len(kwargs) == 0, f"Unknown arguments: {list(kwargs.keys())}" + + if if_not_exists and await self.collection_exists(collection_name): + return True + return await self._client.create_collection( collection_name=collection_name, vectors_config=vectors_config, diff --git a/qdrant_client/qdrant_client.py b/qdrant_client/qdrant_client.py index 3dff8cf6..77dc064a 100644 --- a/qdrant_client/qdrant_client.py +++ b/qdrant_client/qdrant_client.py @@ -1639,6 +1639,7 @@ def create_collection( timeout: int | None = None, strict_mode_config: types.StrictModeConfig | None = None, metadata: types.Payload | None = None, + if_not_exists: bool = False, **kwargs: Any, ) -> bool: """Create empty collection with given parameters @@ -1685,12 +1686,18 @@ def create_collection( If timeout is reached - request will return with service error. strict_mode_config: Configure limitations for the collection, such as max size, rate limits, etc. metadata: Arbitrary JSON-like metadata for the collection + if_not_exists: + If True, collection will only be created if it doesn't already exist. + If False (default), will attempt to create regardless of existence. Returns: Operation result """ assert len(kwargs) == 0, f"Unknown arguments: {list(kwargs.keys())}" + if if_not_exists and self.collection_exists(collection_name): + return True + return self._client.create_collection( collection_name=collection_name, vectors_config=vectors_config, diff --git a/tests/test_create_collection_if_not_exists.py b/tests/test_create_collection_if_not_exists.py new file mode 100644 index 00000000..e8f6bc26 --- /dev/null +++ b/tests/test_create_collection_if_not_exists.py @@ -0,0 +1,124 @@ +import pytest +from qdrant_client import QdrantClient, models +from qdrant_client.async_qdrant_client import AsyncQdrantClient + + +@pytest.fixture +def sync_client(): + client = QdrantClient(":memory:") + yield client + client.close() + + +@pytest.fixture +async def async_client(): + client = AsyncQdrantClient(":memory:") + yield client + await client.close() + + +def test_create_collection_if_not_exists_sync(sync_client): + """Test that create_collection with if_not_exists parameter works correctly for sync client""" + collection_name = "test_collection_if_not_exists" + + # Create collection with if_not_exists=True (collection doesn't exist yet) + result = sync_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + if_not_exists=True, + ) + assert result is True + assert sync_client.collection_exists(collection_name) + + # Try to create again with if_not_exists=True (should not fail, return True) + result = sync_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + if_not_exists=True, + ) + assert result is True + + +def test_create_collection_if_not_exists_false_sync(sync_client): + """Test that create_collection with if_not_exists=False still creates collection""" + collection_name = "test_collection_if_not_exists_false" + + # Create collection with explicit if_not_exists=False + result = sync_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + if_not_exists=False, + ) + assert result is True + assert sync_client.collection_exists(collection_name) + + +@pytest.mark.asyncio +async def test_create_collection_if_not_exists_async(async_client): + """Test that create_collection with if_not_exists parameter works correctly for async client""" + collection_name = "test_collection_if_not_exists_async" + + # Create collection with if_not_exists=True (collection doesn't exist yet) + result = await async_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + if_not_exists=True, + ) + assert result is True + assert await async_client.collection_exists(collection_name) + + # Try to create again with if_not_exists=True (should not fail, return True) + result = await async_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + if_not_exists=True, + ) + assert result is True + + +@pytest.mark.asyncio +async def test_create_collection_if_not_exists_false_async(async_client): + """Test that create_collection with if_not_exists=False still creates collection""" + collection_name = "test_collection_if_not_exists_false_async" + + # Create collection with explicit if_not_exists=False + result = await async_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + if_not_exists=False, + ) + assert result is True + assert await async_client.collection_exists(collection_name) + + +def test_create_collection_without_if_not_exists_raises_on_duplicate_sync(sync_client): + """Test that creating an existing collection without if_not_exists=True raises an error.""" + collection_name = "test_duplicate_error" + + sync_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + ) + + with pytest.raises(ValueError, match="already exists"): + sync_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + ) + + +@pytest.mark.asyncio +async def test_create_collection_without_if_not_exists_raises_on_duplicate_async(async_client): + """Test that creating an existing collection without if_not_exists=True raises an error (async).""" + collection_name = "test_duplicate_error_async" + + await async_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + ) + + with pytest.raises(ValueError, match="already exists"): + await async_client.create_collection( + collection_name=collection_name, + vectors_config=models.VectorParams(size=10, distance=models.Distance.COSINE), + )