38
38
from pymongo .change_stream import DatabaseChangeStream
39
39
from pymongo .collection import Collection
40
40
from pymongo .command_cursor import CommandCursor
41
+ from pymongo .common import _ecc_coll_name , _ecoc_coll_name , _esc_coll_name
41
42
from pymongo .errors import CollectionInvalid , InvalidName
42
43
from pymongo .read_preferences import ReadPreference , _ServerMode
43
44
from pymongo .typings import _CollationIn , _DocumentType , _Pipeline
@@ -290,6 +291,7 @@ def create_collection(
290
291
write_concern : Optional ["WriteConcern" ] = None ,
291
292
read_concern : Optional ["ReadConcern" ] = None ,
292
293
session : Optional ["ClientSession" ] = None ,
294
+ encrypted_fields : Optional [Mapping [str , Any ]] = None ,
293
295
** kwargs : Any ,
294
296
) -> Collection [_DocumentType ]:
295
297
"""Create a new :class:`~pymongo.collection.Collection` in this
@@ -321,6 +323,29 @@ def create_collection(
321
323
:class:`~pymongo.collation.Collation`.
322
324
- `session` (optional): a
323
325
: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
+ } }
324
349
- `**kwargs` (optional): additional keyword arguments will
325
350
be passed as options for the `create collection command`_
326
351
@@ -369,14 +394,24 @@ def create_collection(
369
394
.. _create collection command:
370
395
https://mongodb.com/docs/manual/reference/command/create
371
396
"""
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
+
372
408
with self .__client ._tmp_session (session ) as s :
373
409
# Skip this check in a transaction where listCollections is not
374
410
# supported.
375
411
if (not s or not s .in_transaction ) and name in self .list_collection_names (
376
412
filter = {"name" : name }, session = s
377
413
):
378
414
raise CollectionInvalid ("collection %s already exists" % name )
379
-
380
415
return Collection (
381
416
self ,
382
417
name ,
@@ -386,6 +421,7 @@ def create_collection(
386
421
write_concern ,
387
422
read_concern ,
388
423
session = s ,
424
+ encrypted_fields = encrypted_fields ,
389
425
** kwargs ,
390
426
)
391
427
@@ -874,11 +910,27 @@ def list_collection_names(
874
910
875
911
return [result ["name" ] for result in self .list_collections (session = session , ** kwargs )]
876
912
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
+
877
928
def drop_collection (
878
929
self ,
879
930
name_or_collection : Union [str , Collection ],
880
931
session : Optional ["ClientSession" ] = None ,
881
932
comment : Optional [Any ] = None ,
933
+ encrypted_fields : Optional [Mapping [str , Any ]] = None ,
882
934
) -> Dict [str , Any ]:
883
935
"""Drop a collection.
884
936
@@ -889,6 +941,29 @@ def drop_collection(
889
941
:class:`~pymongo.client_session.ClientSession`.
890
942
- `comment` (optional): A user-provided comment to attach to this
891
943
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
+ }
892
967
893
968
894
969
.. note:: The :attr:`~pymongo.database.Database.write_concern` of
@@ -911,20 +986,34 @@ def drop_collection(
911
986
912
987
if not isinstance (name , str ):
913
988
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 )
927
1001
)
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 )
928
1017
929
1018
def validate_collection (
930
1019
self ,
0 commit comments