3838from pymongo .change_stream import DatabaseChangeStream
3939from pymongo .collection import Collection
4040from pymongo .command_cursor import CommandCursor
41+ from pymongo .common import _ecc_coll_name , _ecoc_coll_name , _esc_coll_name
4142from pymongo .errors import CollectionInvalid , InvalidName
4243from pymongo .read_preferences import ReadPreference , _ServerMode
4344from pymongo .typings import _CollationIn , _DocumentType , _Pipeline
@@ -290,6 +291,7 @@ def create_collection(
290291 write_concern : Optional ["WriteConcern" ] = None ,
291292 read_concern : Optional ["ReadConcern" ] = None ,
292293 session : Optional ["ClientSession" ] = None ,
294+ encrypted_fields : Optional [Mapping [str , Any ]] = None ,
293295 ** kwargs : Any ,
294296 ) -> Collection [_DocumentType ]:
295297 """Create a new :class:`~pymongo.collection.Collection` in this
@@ -321,6 +323,29 @@ def create_collection(
321323 :class:`~pymongo.collation.Collation`.
322324 - `session` (optional): a
323325 :class:`~pymongo.client_session.ClientSession`.
326+ - `encrypted_fields`: Document that describes the encrypted fields for Queryable
327+ Encryption.
328+ For example::
329+
330+ {
331+ "escCollection": "enxcol_.encryptedCollection.esc",
332+ "eccCollection": "enxcol_.encryptedCollection.ecc",
333+ "ecocCollection": "enxcol_.encryptedCollection.ecoc",
334+ "fields": [
335+ {
336+ "path": "firstName",
337+ "keyId": Binary.from_uuid(UUID('00000000-0000-0000-0000-000000000000')),
338+ "bsonType": "string",
339+ "queries": {"queryType": "equality"}
340+ },
341+ {
342+ "path": "ssn",
343+ "keyId": Binary.from_uuid(UUID('04104104-1041-0410-4104-104104104104')),
344+ "bsonType": "string"
345+ }
346+ ]
347+
348+ } }
324349 - `**kwargs` (optional): additional keyword arguments will
325350 be passed as options for the `create collection command`_
326351
@@ -369,14 +394,24 @@ def create_collection(
369394 .. _create collection command:
370395 https://mongodb.com/docs/manual/reference/command/create
371396 """
397+ if (
398+ not encrypted_fields
399+ and self .client .options .auto_encryption_opts
400+ and self .client .options .auto_encryption_opts ._encrypted_fields_map
401+ ):
402+ encrypted_fields = self .client .options .auto_encryption_opts ._encrypted_fields_map .get (
403+ "%s.%s" % (self .name , name )
404+ )
405+ if encrypted_fields :
406+ common .validate_is_mapping ("encrypted_fields" , encrypted_fields )
407+
372408 with self .__client ._tmp_session (session ) as s :
373409 # Skip this check in a transaction where listCollections is not
374410 # supported.
375411 if (not s or not s .in_transaction ) and name in self .list_collection_names (
376412 filter = {"name" : name }, session = s
377413 ):
378414 raise CollectionInvalid ("collection %s already exists" % name )
379-
380415 return Collection (
381416 self ,
382417 name ,
@@ -386,6 +421,7 @@ def create_collection(
386421 write_concern ,
387422 read_concern ,
388423 session = s ,
424+ encrypted_fields = encrypted_fields ,
389425 ** kwargs ,
390426 )
391427
@@ -874,11 +910,27 @@ def list_collection_names(
874910
875911 return [result ["name" ] for result in self .list_collections (session = session , ** kwargs )]
876912
913+ def _drop_helper (self , name , session = None , comment = None ):
914+ command = SON ([("drop" , name )])
915+ if comment is not None :
916+ command ["comment" ] = comment
917+
918+ with self .__client ._socket_for_writes (session ) as sock_info :
919+ return self ._command (
920+ sock_info ,
921+ command ,
922+ allowable_errors = ["ns not found" , 26 ],
923+ write_concern = self ._write_concern_for (session ),
924+ parse_write_concern_error = True ,
925+ session = session ,
926+ )
927+
877928 def drop_collection (
878929 self ,
879930 name_or_collection : Union [str , Collection ],
880931 session : Optional ["ClientSession" ] = None ,
881932 comment : Optional [Any ] = None ,
933+ encrypted_fields : Optional [Mapping [str , Any ]] = None ,
882934 ) -> Dict [str , Any ]:
883935 """Drop a collection.
884936
@@ -889,6 +941,29 @@ def drop_collection(
889941 :class:`~pymongo.client_session.ClientSession`.
890942 - `comment` (optional): A user-provided comment to attach to this
891943 command.
944+ - `encrypted_fields`: Document that describes the encrypted fields for Queryable
945+ Encryption.
946+ For example::
947+
948+ {
949+ "escCollection": "enxcol_.encryptedCollection.esc",
950+ "eccCollection": "enxcol_.encryptedCollection.ecc",
951+ "ecocCollection": "enxcol_.encryptedCollection.ecoc",
952+ "fields": [
953+ {
954+ "path": "firstName",
955+ "keyId": Binary.from_uuid(UUID('00000000-0000-0000-0000-000000000000')),
956+ "bsonType": "string",
957+ "queries": {"queryType": "equality"}
958+ },
959+ {
960+ "path": "ssn",
961+ "keyId": Binary.from_uuid(UUID('04104104-1041-0410-4104-104104104104')),
962+ "bsonType": "string"
963+ }
964+ ]
965+
966+ }
892967
893968
894969 .. note:: The :attr:`~pymongo.database.Database.write_concern` of
@@ -911,20 +986,34 @@ def drop_collection(
911986
912987 if not isinstance (name , str ):
913988 raise TypeError ("name_or_collection must be an instance of str" )
914-
915- command = SON ([("drop" , name )])
916- if comment is not None :
917- command ["comment" ] = comment
918-
919- with self .__client ._socket_for_writes (session ) as sock_info :
920- return self ._command (
921- sock_info ,
922- command ,
923- allowable_errors = ["ns not found" , 26 ],
924- write_concern = self ._write_concern_for (session ),
925- parse_write_concern_error = True ,
926- session = session ,
989+ full_name = "%s.%s" % (self .name , name )
990+ if (
991+ not encrypted_fields
992+ and self .client .options .auto_encryption_opts
993+ and self .client .options .auto_encryption_opts ._encrypted_fields_map
994+ ):
995+ encrypted_fields = self .client .options .auto_encryption_opts ._encrypted_fields_map .get (
996+ full_name
997+ )
998+ if not encrypted_fields and self .client .options .auto_encryption_opts :
999+ colls = list (
1000+ self .list_collections (filter = {"name" : name }, session = session , comment = comment )
9271001 )
1002+ if colls and colls [0 ]["options" ].get ("encryptedFields" ):
1003+ encrypted_fields = colls [0 ]["options" ]["encryptedFields" ]
1004+ if encrypted_fields :
1005+ common .validate_is_mapping ("encrypted_fields" , encrypted_fields )
1006+ self ._drop_helper (
1007+ _esc_coll_name (encrypted_fields , name ), session = session , comment = comment
1008+ )
1009+ self ._drop_helper (
1010+ _ecc_coll_name (encrypted_fields , name ), session = session , comment = comment
1011+ )
1012+ self ._drop_helper (
1013+ _ecoc_coll_name (encrypted_fields , name ), session = session , comment = comment
1014+ )
1015+
1016+ return self ._drop_helper (name , session , comment )
9281017
9291018 def validate_collection (
9301019 self ,
0 commit comments