PYTHON-4037 Avoid Appending Write/Read Concern in Atlas Search Index Helper Commands (#1570)
This commit is contained in:
parent
44e47304ff
commit
c154c6b67b
@ -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
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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"
|
||||
|
||||
@ -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"
|
||||
|
||||
252
test/index_management/searchIndexIgnoresReadWriteConcern.json
Normal file
252
test/index_management/searchIndexIgnoresReadWriteConcern.json
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@ -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."""
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user