diff --git a/README.md b/README.md index 338abd0b..e667679f 100644 --- a/README.md +++ b/README.md @@ -384,18 +384,19 @@ poetry run black --check tests && poetry run ruff tests && poetry run mypy tests ### Testing -Ensure you provide all required environment variables (you can do so by editing `tests/.env` after `tests/.env.template`): +Ensure you provide all required environment variables (you can start from `tests/.env.template`): ```bash export ASTRA_DB_APPLICATION_TOKEN="..." export ASTRA_DB_API_ENDPOINT="..." export ASTRA_DB_KEYSPACE="..." # Optional +export ASTRA_DB_SECONDARY_KEYSPACE="..." # Optional, enables cross-ns testing export ASTRA_DB_ID="..." # For the Ops testing only export ASTRA_DB_OPS_APPLICATION_TOKEN="..." # Ops-only, falls back to the other token ``` -then you can run: +then you can source the `.env` you created and finally run: ```bash poetry run pytest diff --git a/astrapy/idiomatic/collection.py b/astrapy/idiomatic/collection.py index 5c7319e2..3f3da2dd 100644 --- a/astrapy/idiomatic/collection.py +++ b/astrapy/idiomatic/collection.py @@ -15,15 +15,15 @@ from __future__ import annotations import json -from typing import Any, Dict, Iterable, List, Optional +from typing import Any, Dict, Iterable, List, Optional, Union from astrapy.db import AstraDBCollection, AsyncAstraDBCollection from astrapy.idiomatic.types import DocumentType, ProjectionType -from astrapy.idiomatic.utils import raise_unsupported_parameter, unsupported from astrapy.idiomatic.database import AsyncDatabase, Database from astrapy.idiomatic.results import DeleteResult, InsertManyResult, InsertOneResult from astrapy.idiomatic.cursors import AsyncCursor, Cursor + INSERT_MANY_CONCURRENCY = 20 @@ -115,15 +115,7 @@ def set_caller( def insert_one( self, document: DocumentType, - *, - bypass_document_validation: Optional[bool] = None, ) -> InsertOneResult: - if bypass_document_validation: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="insert_one", - parameter_name="bypass_document_validation", - ) io_response = self._astra_db_collection.insert_one(document) if "insertedIds" in io_response.get("status", {}): if io_response["status"]["insertedIds"]: @@ -147,14 +139,7 @@ def insert_many( documents: Iterable[DocumentType], *, ordered: bool = True, - bypass_document_validation: Optional[bool] = None, ) -> InsertManyResult: - if bypass_document_validation: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="insert_many", - parameter_name="bypass_document_validation", - ) if ordered: cim_responses = self._astra_db_collection.chunked_insert_many( documents=list(documents), @@ -210,6 +195,28 @@ def find( .sort(sort) ) + def find_one( + self, + filter: Optional[Dict[str, Any]] = None, + *, + projection: Optional[ProjectionType] = None, + skip: Optional[int] = None, + limit: Optional[int] = None, + sort: Optional[Dict[str, Any]] = None, + ) -> Union[DocumentType, None]: + fo_cursor = self.find( + filter=filter, + projection=projection, + skip=skip, + limit=limit, + sort=sort, + ) + try: + document = fo_cursor.__next__() + return document + except StopIteration: + return None + def distinct( self, key: str, @@ -223,22 +230,7 @@ def distinct( def count_documents( self, filter: Dict[str, Any], - *, - skip: Optional[int] = None, - limit: Optional[int] = None, ) -> int: - if skip: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="count_documents", - parameter_name="skip", - ) - if limit: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="count_documents", - parameter_name="limit", - ) cd_response = self._astra_db_collection.count_documents(filter=filter) if "count" in cd_response.get("status", {}): return cd_response["status"]["count"] # type: ignore[no-any-return] @@ -251,15 +243,7 @@ def count_documents( def delete_one( self, filter: Dict[str, Any], - *, - let: Optional[int] = None, ) -> DeleteResult: - if let: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="delete_one", - parameter_name="let", - ) do_response = self._astra_db_collection.delete_one_by_predicate(filter=filter) if "deletedCount" in do_response.get("status", {}): deleted_count = do_response["status"]["deletedCount"] @@ -283,15 +267,7 @@ def delete_one( def delete_many( self, filter: Dict[str, Any], - *, - let: Optional[int] = None, ) -> DeleteResult: - if let: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="delete_many", - parameter_name="let", - ) dm_response = self._astra_db_collection.delete_many(filter=filter) if "deletedCount" in dm_response.get("status", {}): deleted_count = dm_response["status"]["deletedCount"] @@ -312,54 +288,6 @@ def delete_many( f"(gotten '${json.dumps(dm_response)}')" ) - @unsupported - def find_raw_batches(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def aggregate(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def aggregate_raw_batches(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def watch(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def rename(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def create_index(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def create_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def drop_index(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def drop_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def list_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def index_information(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def create_search_index(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def create_search_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def drop_search_index(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def list_search_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def update_search_index(*pargs: Any, **kwargs: Any) -> Any: ... - class AsyncCollection: def __init__( @@ -449,15 +377,7 @@ def set_caller( async def insert_one( self, document: DocumentType, - *, - bypass_document_validation: Optional[bool] = None, ) -> InsertOneResult: - if bypass_document_validation: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="insert_one", - parameter_name="bypass_document_validation", - ) io_response = await self._astra_db_collection.insert_one(document) if "insertedIds" in io_response.get("status", {}): if io_response["status"]["insertedIds"]: @@ -481,14 +401,7 @@ async def insert_many( documents: Iterable[DocumentType], *, ordered: bool = True, - bypass_document_validation: Optional[bool] = None, ) -> InsertManyResult: - if bypass_document_validation: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="insert_many", - parameter_name="bypass_document_validation", - ) if ordered: cim_responses = await self._astra_db_collection.chunked_insert_many( documents=list(documents), @@ -544,6 +457,28 @@ def find( .sort(sort) ) + async def find_one( + self, + filter: Optional[Dict[str, Any]] = None, + *, + projection: Optional[ProjectionType] = None, + skip: Optional[int] = None, + limit: Optional[int] = None, + sort: Optional[Dict[str, Any]] = None, + ) -> Union[DocumentType, None]: + fo_cursor = self.find( + filter=filter, + projection=projection, + skip=skip, + limit=limit, + sort=sort, + ) + try: + document = await fo_cursor.__anext__() + return document + except StopAsyncIteration: + return None + async def distinct( self, key: str, @@ -558,22 +493,7 @@ async def distinct( async def count_documents( self, filter: Dict[str, Any], - *, - skip: Optional[int] = None, - limit: Optional[int] = None, ) -> int: - if skip: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="count_documents", - parameter_name="skip", - ) - if limit: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="count_documents", - parameter_name="limit", - ) cd_response = await self._astra_db_collection.count_documents(filter=filter) if "count" in cd_response.get("status", {}): return cd_response["status"]["count"] # type: ignore[no-any-return] @@ -586,15 +506,7 @@ async def count_documents( async def delete_one( self, filter: Dict[str, Any], - *, - let: Optional[int] = None, ) -> DeleteResult: - if let: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="delete_one", - parameter_name="let", - ) do_response = await self._astra_db_collection.delete_one_by_predicate( filter=filter ) @@ -623,12 +535,6 @@ async def delete_many( *, let: Optional[int] = None, ) -> DeleteResult: - if let: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="delete_many", - parameter_name="let", - ) dm_response = await self._astra_db_collection.delete_many(filter=filter) if "deletedCount" in dm_response.get("status", {}): deleted_count = dm_response["status"]["deletedCount"] @@ -648,51 +554,3 @@ async def delete_many( "Could not complete a delete_many operation. " f"(gotten '${json.dumps(dm_response)}')" ) - - @unsupported - async def find_raw_batches(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def aggregate(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def aggregate_raw_batches(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def watch(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def rename(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def create_index(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def create_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def drop_index(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def drop_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def list_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def index_information(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def create_search_index(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def create_search_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def drop_search_index(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def list_search_indexes(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def update_search_index(*pargs: Any, **kwargs: Any) -> Any: ... diff --git a/astrapy/idiomatic/database.py b/astrapy/idiomatic/database.py index c8afb531..148f44ed 100644 --- a/astrapy/idiomatic/database.py +++ b/astrapy/idiomatic/database.py @@ -19,7 +19,7 @@ from typing import Any, Dict, List, Optional, Type, Union, TYPE_CHECKING from astrapy.db import AstraDB, AsyncAstraDB -from astrapy.idiomatic.utils import raise_unsupported_parameter, unsupported + if TYPE_CHECKING: from astrapy.idiomatic.collection import AsyncCollection, Collection @@ -245,14 +245,7 @@ def list_collections( self, *, namespace: Optional[str] = None, - filter: Optional[Dict[str, Any]] = None, ) -> List[Dict[str, Any]]: - if filter: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="list_collections", - parameter_name="filter", - ) if namespace: _client = self._astra_db.copy(namespace=namespace) else: @@ -274,14 +267,7 @@ def list_collection_names( self, *, namespace: Optional[str] = None, - filter: Optional[Dict[str, Any]] = None, ) -> List[str]: - if filter: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="list_collection_names", - parameter_name="filter", - ) if namespace: _client = self._astra_db.copy(namespace=namespace) else: @@ -296,21 +282,6 @@ def list_collection_names( # we know this is a list of strings return gc_response["status"]["collections"] # type: ignore[no-any-return] - @unsupported - def aggregate(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def cursor_command(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def dereference(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def watch(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - def validate_collection(*pargs: Any, **kwargs: Any) -> Any: ... - class AsyncDatabase: def __init__( @@ -500,14 +471,7 @@ async def list_collections( self, *, namespace: Optional[str] = None, - filter: Optional[Dict[str, Any]] = None, ) -> List[Dict[str, Any]]: - if filter: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="list_collections", - parameter_name="filter", - ) _client: AsyncAstraDB if namespace: _client = self._astra_db.copy(namespace=namespace) @@ -530,14 +494,7 @@ async def list_collection_names( self, *, namespace: Optional[str] = None, - filter: Optional[Dict[str, Any]] = None, ) -> List[str]: - if filter: - raise_unsupported_parameter( - class_name=self.__class__.__name__, - method_name="list_collection_names", - parameter_name="filter", - ) gc_response = await self._astra_db.copy(namespace=namespace).get_collections() if "collections" not in gc_response.get("status", {}): raise ValueError( @@ -547,18 +504,3 @@ async def list_collection_names( else: # we know this is a list of strings return gc_response["status"]["collections"] # type: ignore[no-any-return] - - @unsupported - async def aggregate(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def cursor_command(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def dereference(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def watch(*pargs: Any, **kwargs: Any) -> Any: ... - - @unsupported - async def validate_collection(*pargs: Any, **kwargs: Any) -> Any: ... diff --git a/astrapy/idiomatic/utils.py b/astrapy/idiomatic/utils.py deleted file mode 100644 index f8ac2532..00000000 --- a/astrapy/idiomatic/utils.py +++ /dev/null @@ -1,42 +0,0 @@ -# Copyright DataStax, Inc. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. - -from __future__ import annotations -from functools import wraps -from typing import Any, Callable - -DEFAULT_NOT_SUPPORTED_MESSAGE = "Operation not supported." -DEFAULT_NOT_SUPPORTED_PARAMETER_MESSAGE_TEMPLATE = "Parameter `{parameter_name}` not supported for method `{method_name}` of class `{class_name}`." - - -def unsupported(func: Callable[..., Any]) -> Callable[..., Any]: - @wraps(func) - def unsupported_func(*args: Any, **kwargs: Any) -> Any: - raise TypeError(DEFAULT_NOT_SUPPORTED_MESSAGE) - - return unsupported_func - - -def raise_unsupported_parameter( - *, - class_name: str, - method_name: str, - parameter_name: str, -) -> None: - message = DEFAULT_NOT_SUPPORTED_PARAMETER_MESSAGE_TEMPLATE.format( - class_name=class_name, - method_name=method_name, - parameter_name=parameter_name, - ) - raise TypeError(message) diff --git a/tests/.env.template b/tests/.env.template index 3d1482ae..01e53557 100644 --- a/tests/.env.template +++ b/tests/.env.template @@ -8,7 +8,7 @@ export ASTRA_DB_API_ENDPOINT="https://-.apps.astra.datastax.co # # OPTIONAL: # export ASTRA_DB_KEYSPACE="..." - +# export ASTRA_DB_SECONDARY_KEYSPACE="..." ################### # FOR THE OPS TEST: diff --git a/tests/idiomatic/integration/test_ddl_async.py b/tests/idiomatic/integration/test_ddl_async.py index 56626776..fa058b57 100644 --- a/tests/idiomatic/integration/test_ddl_async.py +++ b/tests/idiomatic/integration/test_ddl_async.py @@ -107,15 +107,6 @@ async def test_database_list_collections_async( ) -> None: assert TEST_COLLECTION_NAME in await async_database.list_collection_names() - @pytest.mark.describe("test of Database list_collections unsupported filter, async") - async def test_database_list_collections_filter_async( - self, - async_database: AsyncDatabase, - async_collection: AsyncCollection, - ) -> None: - with pytest.raises(TypeError): - await async_database.list_collection_names(filter={"k": "v"}) - @pytest.mark.skipif( ASTRA_DB_SECONDARY_KEYSPACE is None, reason="No secondary keyspace provided" ) diff --git a/tests/idiomatic/integration/test_ddl_sync.py b/tests/idiomatic/integration/test_ddl_sync.py index b1c83e5e..38cc77cc 100644 --- a/tests/idiomatic/integration/test_ddl_sync.py +++ b/tests/idiomatic/integration/test_ddl_sync.py @@ -107,15 +107,6 @@ def test_database_list_collections_sync( ) -> None: assert TEST_COLLECTION_NAME in sync_database.list_collection_names() - @pytest.mark.describe("test of Database list_collections unsupported filter, sync") - def test_database_list_collections_filter_sync( - self, - sync_database: Database, - sync_collection: Collection, - ) -> None: - with pytest.raises(TypeError): - sync_database.list_collection_names(filter={"k": "v"}) - @pytest.mark.skipif( ASTRA_DB_SECONDARY_KEYSPACE is None, reason="No secondary keyspace provided" ) diff --git a/tests/idiomatic/integration/test_dml_async.py b/tests/idiomatic/integration/test_dml_async.py index 1b5e1ca6..dc15bb0d 100644 --- a/tests/idiomatic/integration/test_dml_async.py +++ b/tests/idiomatic/integration/test_dml_async.py @@ -362,3 +362,105 @@ async def test_collection_insert_many_async( ordered=False, ) assert {doc["_id"] for doc in col.find()} == {"a", "b", "c", "d", "e"} + + @pytest.mark.describe("test of collection find_one, async") + async def test_collection_find_one_async( + self, + async_empty_collection: AsyncCollection, + ) -> None: + col = async_empty_collection + await col.insert_many( + [ + {"_id": "?", "seq": 0, "kind": "punctuation"}, + {"_id": "a", "seq": 1, "kind": "letter"}, + {"_id": "b", "seq": 2, "kind": "letter"}, + ] + ) + + fo1 = await col.find_one({"kind": "frog"}) + assert fo1 is None + + Nski = 1 + Nlim = 10 + Nsor = {"seq": 1} + Nfil = {"kind": "letter"} + + # case 0000 of find-pattern matrix + doc0000 = await col.find_one(skip=None, limit=None, sort=None, filter=None) + assert doc0000 is not None + assert doc0000["seq"] in {0, 1, 2} + + # case 0001 + doc0001 = await col.find_one(skip=None, limit=None, sort=None, filter=Nfil) + assert doc0001 is not None + assert doc0001["seq"] in {1, 2} + + # case 0010 + doc0010 = await col.find_one(skip=None, limit=None, sort=Nsor, filter=None) + assert doc0010 is not None + assert doc0010["seq"] == 0 + + # case 0011 + doc0011 = await col.find_one(skip=None, limit=None, sort=Nsor, filter=Nfil) + assert doc0011 is not None + assert doc0011["seq"] == 1 + + # case 0100 + doc0100 = await col.find_one(skip=None, limit=Nlim, sort=None, filter=None) + assert doc0100 is not None + assert doc0100["seq"] in {0, 1, 2} + + # case 0101 + doc0101 = await col.find_one(skip=None, limit=Nlim, sort=None, filter=Nfil) + assert doc0101 is not None + assert doc0101["seq"] in {1, 2} + + # case 0110 + doc0110 = await col.find_one(skip=None, limit=Nlim, sort=Nsor, filter=None) + assert doc0110 is not None + assert doc0110["seq"] == 0 + + # case 0111 + doc0111 = await col.find_one(skip=None, limit=Nlim, sort=Nsor, filter=Nfil) + assert doc0111 is not None + assert doc0111["seq"] == 1 + + # case 1000 + # col.find_one(skip=Nski, limit=None, sort=None, filter=None) ... + + # case 1001 + # col.find_one(skip=Nski, limit=None, sort=None, filter=Nfil) ... + + # case 1010 + doc1010 = await col.find_one(skip=Nski, limit=None, sort=Nsor, filter=None) + assert doc1010 is not None + assert doc1010["seq"] == 1 + + # case 1011 + doc1011 = await col.find_one(skip=Nski, limit=None, sort=Nsor, filter=Nfil) + assert doc1011 is not None + assert doc1011["seq"] == 2 + + # case 1100 + # col.find_one(skip=Nski, limit=Nlim, sort=None, filter=None) ... + + # case 1101 + # col.find_one(skip=Nski, limit=Nlim, sort=None, filter=Nfil) ... + + # case 1110 + doc1110 = await col.find_one(skip=Nski, limit=Nlim, sort=Nsor, filter=None) + assert doc1110 is not None + assert doc1110["seq"] == 1 + + # case 1111 + doc1111 = await col.find_one(skip=Nski, limit=Nlim, sort=Nsor, filter=Nfil) + assert doc1111 is not None + assert doc1111["seq"] == 2 + + # projection + doc_full = await col.find_one(skip=Nski, limit=Nlim, sort=Nsor, filter=Nfil) + doc_proj = await col.find_one( + skip=Nski, limit=Nlim, sort=Nsor, filter=Nfil, projection={"kind": True} + ) + assert doc_proj == {"_id": "b", "kind": "letter"} + assert doc_full == {"_id": "b", "seq": 2, "kind": "letter"} diff --git a/tests/idiomatic/integration/test_dml_sync.py b/tests/idiomatic/integration/test_dml_sync.py index 1933f5af..6fa709b4 100644 --- a/tests/idiomatic/integration/test_dml_sync.py +++ b/tests/idiomatic/integration/test_dml_sync.py @@ -351,3 +351,105 @@ def test_collection_insert_many_sync( ordered=False, ) assert {doc["_id"] for doc in col.find()} == {"a", "b", "c", "d", "e"} + + @pytest.mark.describe("test of collection find_one, sync") + def test_collection_find_one_sync( + self, + sync_empty_collection: Collection, + ) -> None: + col = sync_empty_collection + col.insert_many( + [ + {"_id": "?", "seq": 0, "kind": "punctuation"}, + {"_id": "a", "seq": 1, "kind": "letter"}, + {"_id": "b", "seq": 2, "kind": "letter"}, + ] + ) + + fo1 = col.find_one({"kind": "frog"}) + assert fo1 is None + + Nski = 1 + Nlim = 10 + Nsor = {"seq": 1} + Nfil = {"kind": "letter"} + + # case 0000 of find-pattern matrix + doc0000 = col.find_one(skip=None, limit=None, sort=None, filter=None) + assert doc0000 is not None + assert doc0000["seq"] in {0, 1, 2} + + # case 0001 + doc0001 = col.find_one(skip=None, limit=None, sort=None, filter=Nfil) + assert doc0001 is not None + assert doc0001["seq"] in {1, 2} + + # case 0010 + doc0010 = col.find_one(skip=None, limit=None, sort=Nsor, filter=None) + assert doc0010 is not None + assert doc0010["seq"] == 0 + + # case 0011 + doc0011 = col.find_one(skip=None, limit=None, sort=Nsor, filter=Nfil) + assert doc0011 is not None + assert doc0011["seq"] == 1 + + # case 0100 + doc0100 = col.find_one(skip=None, limit=Nlim, sort=None, filter=None) + assert doc0100 is not None + assert doc0100["seq"] in {0, 1, 2} + + # case 0101 + doc0101 = col.find_one(skip=None, limit=Nlim, sort=None, filter=Nfil) + assert doc0101 is not None + assert doc0101["seq"] in {1, 2} + + # case 0110 + doc0110 = col.find_one(skip=None, limit=Nlim, sort=Nsor, filter=None) + assert doc0110 is not None + assert doc0110["seq"] == 0 + + # case 0111 + doc0111 = col.find_one(skip=None, limit=Nlim, sort=Nsor, filter=Nfil) + assert doc0111 is not None + assert doc0111["seq"] == 1 + + # case 1000 + # col.find_one(skip=Nski, limit=None, sort=None, filter=None) ... + + # case 1001 + # col.find_one(skip=Nski, limit=None, sort=None, filter=Nfil) ... + + # case 1010 + doc1010 = col.find_one(skip=Nski, limit=None, sort=Nsor, filter=None) + assert doc1010 is not None + assert doc1010["seq"] == 1 + + # case 1011 + doc1011 = col.find_one(skip=Nski, limit=None, sort=Nsor, filter=Nfil) + assert doc1011 is not None + assert doc1011["seq"] == 2 + + # case 1100 + # col.find_one(skip=Nski, limit=Nlim, sort=None, filter=None) ... + + # case 1101 + # col.find_one(skip=Nski, limit=Nlim, sort=None, filter=Nfil) ... + + # case 1110 + doc1110 = col.find_one(skip=Nski, limit=Nlim, sort=Nsor, filter=None) + assert doc1110 is not None + assert doc1110["seq"] == 1 + + # case 1111 + doc1111 = col.find_one(skip=Nski, limit=Nlim, sort=Nsor, filter=Nfil) + assert doc1111 is not None + assert doc1111["seq"] == 2 + + # projection + doc_full = col.find_one(skip=Nski, limit=Nlim, sort=Nsor, filter=Nfil) + doc_proj = col.find_one( + skip=Nski, limit=Nlim, sort=Nsor, filter=Nfil, projection={"kind": True} + ) + assert doc_proj == {"_id": "b", "kind": "letter"} + assert doc_full == {"_id": "b", "seq": 2, "kind": "letter"} diff --git a/tests/idiomatic/unit/test_collections_async.py b/tests/idiomatic/unit/test_collections_async.py index c6019915..b65032ae 100644 --- a/tests/idiomatic/unit/test_collections_async.py +++ b/tests/idiomatic/unit/test_collections_async.py @@ -173,44 +173,6 @@ async def test_collection_set_caller_async( ) assert col1 == col2 - @pytest.mark.describe("test errors for unsupported Collection methods, async") - async def test_collection_unsupported_methods_async( - self, - async_collection_instance: AsyncCollection, - ) -> None: - with pytest.raises(TypeError): - await async_collection_instance.find_raw_batches(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.aggregate(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.aggregate_raw_batches(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.watch(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.rename(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.create_index(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.create_indexes(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.drop_index(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.drop_indexes(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.list_indexes(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.index_information(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.create_search_index(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.create_search_indexes(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.drop_search_index(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.list_search_indexes(1, "x") - with pytest.raises(TypeError): - await async_collection_instance.update_search_index(1, "x") - @pytest.mark.describe("test collection conversions with caller mutableness, async") async def test_collection_conversions_caller_mutableness_async( self, diff --git a/tests/idiomatic/unit/test_collections_sync.py b/tests/idiomatic/unit/test_collections_sync.py index fe8069fb..d23fee71 100644 --- a/tests/idiomatic/unit/test_collections_sync.py +++ b/tests/idiomatic/unit/test_collections_sync.py @@ -173,44 +173,6 @@ def test_collection_set_caller_sync( ) assert col1 == col2 - @pytest.mark.describe("test errors for unsupported Collection methods, sync") - def test_collection_unsupported_methods_sync( - self, - sync_collection_instance: Collection, - ) -> None: - with pytest.raises(TypeError): - sync_collection_instance.find_raw_batches(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.aggregate(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.aggregate_raw_batches(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.watch(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.rename(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.create_index(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.create_indexes(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.drop_index(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.drop_indexes(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.list_indexes(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.index_information(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.create_search_index(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.create_search_indexes(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.drop_search_index(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.list_search_indexes(1, "x") - with pytest.raises(TypeError): - sync_collection_instance.update_search_index(1, "x") - @pytest.mark.describe("test collection conversions with caller mutableness, sync") def test_collection_conversions_caller_mutableness_sync( self, diff --git a/tests/idiomatic/unit/test_databases_async.py b/tests/idiomatic/unit/test_databases_async.py index 3d9ac708..48c7f1d7 100644 --- a/tests/idiomatic/unit/test_databases_async.py +++ b/tests/idiomatic/unit/test_databases_async.py @@ -165,22 +165,6 @@ async def test_database_set_caller_async( ) assert db1 == db2 - @pytest.mark.describe("test errors for unsupported Database methods, async") - async def test_database_unsupported_methods_async( - self, - async_database: AsyncDatabase, - ) -> None: - with pytest.raises(TypeError): - await async_database.aggregate(1, "x") - with pytest.raises(TypeError): - await async_database.cursor_command(1, "x") - with pytest.raises(TypeError): - await async_database.dereference(1, "x") - with pytest.raises(TypeError): - await async_database.watch(1, "x") - with pytest.raises(TypeError): - await async_database.validate_collection(1, "x") - @pytest.mark.describe("test get_collection method, async") async def test_database_get_collection_async( self, diff --git a/tests/idiomatic/unit/test_databases_sync.py b/tests/idiomatic/unit/test_databases_sync.py index d94f6e3e..d82241e3 100644 --- a/tests/idiomatic/unit/test_databases_sync.py +++ b/tests/idiomatic/unit/test_databases_sync.py @@ -165,22 +165,6 @@ def test_database_set_caller_sync( ) assert db1 == db2 - @pytest.mark.describe("test errors for unsupported Database methods, sync") - def test_database_unsupported_methods_sync( - self, - sync_database: Database, - ) -> None: - with pytest.raises(TypeError): - sync_database.aggregate(1, "x") - with pytest.raises(TypeError): - sync_database.cursor_command(1, "x") - with pytest.raises(TypeError): - sync_database.dereference(1, "x") - with pytest.raises(TypeError): - sync_database.watch(1, "x") - with pytest.raises(TypeError): - sync_database.validate_collection(1, "x") - @pytest.mark.describe("test get_collection method, sync") def test_database_get_collection_sync( self,