PYTHON-4037 Avoid Appending Write/Read Concern in Atlas Search Index Helper Commands (#1570)

This commit is contained in:
Steven Silvester 2024-04-03 06:17:51 -05:00 committed by GitHub
parent 44e47304ff
commit c154c6b67b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 297 additions and 141 deletions

View File

@ -41,6 +41,8 @@ PyMongo 4.7 brings a number of improvements including:
:attr:`pymongo.monitoring.ConnectionReadyEvent.duration` properties.
- Added the ``type`` and ``kwargs`` arguments to :class:`~pymongo.operations.SearchIndexModel` to enable
creating vector search indexes in MongoDB Atlas.
- Fixed a bug where ``read_concern`` and ``write_concern`` were improperly added to
:meth:`~pymongo.collection.Collection.list_search_indexes` queries.
Unavoidable breaking changes

View File

@ -72,6 +72,7 @@ from pymongo.operations import (
_IndexList,
_Op,
)
from pymongo.read_concern import DEFAULT_READ_CONCERN, ReadConcern
from pymongo.read_preferences import ReadPreference, _ServerMode
from pymongo.results import (
BulkWriteResult,
@ -81,7 +82,7 @@ from pymongo.results import (
UpdateResult,
)
from pymongo.typings import _CollationIn, _DocumentType, _DocumentTypeArg, _Pipeline
from pymongo.write_concern import WriteConcern, validate_boolean
from pymongo.write_concern import DEFAULT_WRITE_CONCERN, WriteConcern, validate_boolean
T = TypeVar("T")
@ -119,7 +120,6 @@ if TYPE_CHECKING:
from pymongo.collation import Collation
from pymongo.database import Database
from pymongo.pool import Connection
from pymongo.read_concern import ReadConcern
from pymongo.server import Server
@ -2364,7 +2364,10 @@ class Collection(common.BaseObject, Generic[_DocumentType]):
pipeline = [{"$listSearchIndexes": {"name": name}}]
coll = self.with_options(
codec_options=DEFAULT_CODEC_OPTIONS, read_preference=ReadPreference.PRIMARY
codec_options=DEFAULT_CODEC_OPTIONS,
read_preference=ReadPreference.PRIMARY,
write_concern=DEFAULT_WRITE_CONCERN,
read_concern=DEFAULT_READ_CONCERN,
)
cmd = _CollectionAggregationCommand(
coll,

View File

@ -50,8 +50,7 @@
"mappings": {
"dynamic": true
}
},
"type": "search"
}
}
},
"expectError": {
@ -74,8 +73,7 @@
"mappings": {
"dynamic": true
}
},
"type": "search"
}
}
],
"$db": "database0"
@ -99,8 +97,7 @@
"dynamic": true
}
},
"name": "test index",
"type": "search"
"name": "test index"
}
},
"expectError": {
@ -124,68 +121,7 @@
"dynamic": true
}
},
"name": "test index",
"type": "search"
}
],
"$db": "database0"
}
}
}
]
}
]
},
{
"description": "create a vector search index",
"operations": [
{
"name": "createSearchIndex",
"object": "collection0",
"arguments": {
"model": {
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
}
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"createSearchIndexes": "collection0",
"indexes": [
{
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
"name": "test index"
}
],
"$db": "database0"

View File

@ -83,8 +83,7 @@
"mappings": {
"dynamic": true
}
},
"type": "search"
}
}
]
},
@ -108,8 +107,7 @@
"mappings": {
"dynamic": true
}
},
"type": "search"
}
}
],
"$db": "database0"
@ -134,8 +132,7 @@
"dynamic": true
}
},
"name": "test index",
"type": "search"
"name": "test index"
}
]
},
@ -160,70 +157,7 @@
"dynamic": true
}
},
"name": "test index",
"type": "search"
}
],
"$db": "database0"
}
}
}
]
}
]
},
{
"description": "create a vector search index",
"operations": [
{
"name": "createSearchIndexes",
"object": "collection0",
"arguments": {
"models": [
{
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
}
]
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"createSearchIndexes": "collection0",
"indexes": [
{
"definition": {
"fields": [
{
"type": "vector",
"path": "plot_embedding",
"numDimensions": 1536,
"similarity": "euclidean"
}
]
},
"name": "test index",
"type": "vectorSearch"
"name": "test index"
}
],
"$db": "database0"

View File

@ -0,0 +1,252 @@
{
"description": "search index operations ignore read and write concern",
"schemaVersion": "1.4",
"createEntities": [
{
"client": {
"id": "client0",
"useMultipleMongoses": false,
"uriOptions": {
"readConcernLevel": "local",
"w": 1
},
"observeEvents": [
"commandStartedEvent"
]
}
},
{
"database": {
"id": "database0",
"client": "client0",
"databaseName": "database0"
}
},
{
"collection": {
"id": "collection0",
"database": "database0",
"collectionName": "collection0"
}
}
],
"runOnRequirements": [
{
"minServerVersion": "7.0.0",
"topologies": [
"replicaset",
"load-balanced",
"sharded"
],
"serverless": "forbid"
}
],
"tests": [
{
"description": "createSearchIndex ignores read and write concern",
"operations": [
{
"name": "createSearchIndex",
"object": "collection0",
"arguments": {
"model": {
"definition": {
"mappings": {
"dynamic": true
}
}
}
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"createSearchIndexes": "collection0",
"indexes": [
{
"definition": {
"mappings": {
"dynamic": true
}
}
}
],
"$db": "database0",
"writeConcern": {
"$$exists": false
},
"readConcern": {
"$$exists": false
}
}
}
}
]
}
]
},
{
"description": "createSearchIndexes ignores read and write concern",
"operations": [
{
"name": "createSearchIndexes",
"object": "collection0",
"arguments": {
"models": []
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"createSearchIndexes": "collection0",
"indexes": [],
"$db": "database0",
"writeConcern": {
"$$exists": false
},
"readConcern": {
"$$exists": false
}
}
}
}
]
}
]
},
{
"description": "dropSearchIndex ignores read and write concern",
"operations": [
{
"name": "dropSearchIndex",
"object": "collection0",
"arguments": {
"name": "test index"
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"dropSearchIndex": "collection0",
"name": "test index",
"$db": "database0",
"writeConcern": {
"$$exists": false
},
"readConcern": {
"$$exists": false
}
}
}
}
]
}
]
},
{
"description": "listSearchIndexes ignores read and write concern",
"operations": [
{
"name": "listSearchIndexes",
"object": "collection0",
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"aggregate": "collection0",
"pipeline": [
{
"$listSearchIndexes": {}
}
],
"writeConcern": {
"$$exists": false
},
"readConcern": {
"$$exists": false
}
}
}
}
]
}
]
},
{
"description": "updateSearchIndex ignores the read and write concern",
"operations": [
{
"name": "updateSearchIndex",
"object": "collection0",
"arguments": {
"name": "test index",
"definition": {}
},
"expectError": {
"isError": true,
"errorContains": "Atlas"
}
}
],
"expectEvents": [
{
"client": "client0",
"events": [
{
"commandStartedEvent": {
"command": {
"updateSearchIndex": "collection0",
"name": "test index",
"definition": {},
"$db": "database0",
"writeConcern": {
"$$exists": false
},
"readConcern": {
"$$exists": false
}
}
}
}
]
}
]
}
]
}

View File

@ -30,6 +30,8 @@ from test.utils import AllowListEventListener, EventListener
from pymongo import MongoClient
from pymongo.errors import OperationFailure
from pymongo.operations import SearchIndexModel
from pymongo.read_concern import ReadConcern
from pymongo.write_concern import WriteConcern
_TEST_PATH = os.path.join(os.path.dirname(os.path.realpath(__file__)), "index_management")
@ -257,6 +259,33 @@ class TestSearchIndexProse(SearchIndexIntegrationBase):
# Run a ``dropSearchIndex`` command and assert that no error is thrown.
coll0.drop_search_index("foo")
def test_case_6(self):
"""Driver can successfully create and list search indexes with non-default readConcern and writeConcern."""
# Create a collection with the "create" command using a randomly generated name (referred to as ``coll0``).
coll0 = self.db[f"col{uuid.uuid4()}"]
coll0.insert_one({})
# Apply a write concern ``WriteConcern(w=1)`` and a read concern with ``ReadConcern(level="majority")`` to ``coll0``.
coll0 = coll0.with_options(
write_concern=WriteConcern(w="1"), read_concern=ReadConcern(level="majority")
)
# Create a new search index on ``coll0`` with the ``createSearchIndex`` helper.
name = "test-search-index-case6"
model = {"name": name, "definition": {"mappings": {"dynamic": False}}}
resp = coll0.create_search_index(model)
# Assert that the command returns the name of the index: ``"test-search-index-case6"``.
self.assertEqual(resp, name)
# Run ``coll0.listSearchIndexes()`` repeatedly every 5 seconds until the following condition is satisfied and store the value in a variable ``index``:
# - An index with the ``name`` of ``test-search-index-case6`` is present and the index has a field ``queryable`` with a value of ``true``.
index = self.wait_for_ready(coll0, name)
# Assert that ``index`` has a property ``latestDefinition`` whose value is ``{ 'mappings': { 'dynamic': false } }``
self.assertIn("latestDefinition", index)
self.assertEqual(index["latestDefinition"], model["definition"])
def test_case_7(self):
"""Driver handles index types."""