41
41
from pymongo import _csot
42
42
from pymongo .cursor import Cursor
43
43
from pymongo .daemon import _spawn_daemon
44
- from pymongo .encryption_options import AutoEncryptionOpts
44
+ from pymongo .encryption_options import AutoEncryptionOpts , RangeOpts
45
45
from pymongo .errors import (
46
46
ConfigurationError ,
47
47
EncryptionError ,
@@ -416,6 +416,14 @@ class Algorithm(str, enum.Enum):
416
416
417
417
.. versionadded:: 4.2
418
418
"""
419
+ RANGEPREVIEW = "RangePreview"
420
+ """RangePreview.
421
+
422
+ .. note:: Support for Range queries is in beta.
423
+ Backwards-breaking changes may be made before the final release.
424
+
425
+ .. versionadded:: 4.4
426
+ """
419
427
420
428
421
429
class QueryType (str , enum .Enum ):
@@ -430,6 +438,9 @@ class QueryType(str, enum.Enum):
430
438
EQUALITY = "equality"
431
439
"""Used to encrypt a value for an equality query."""
432
440
441
+ RANGEPREVIEW = "rangePreview"
442
+ """Used to encrypt a value for a range query."""
443
+
433
444
434
445
class ClientEncryption (Generic [_DocumentType ]):
435
446
"""Explicit client-side field level encryption."""
@@ -627,6 +638,45 @@ def create_data_key(
627
638
key_material = key_material ,
628
639
)
629
640
641
+ def _encrypt_helper (
642
+ self ,
643
+ value ,
644
+ algorithm ,
645
+ key_id = None ,
646
+ key_alt_name = None ,
647
+ query_type = None ,
648
+ contention_factor = None ,
649
+ range_opts = None ,
650
+ is_expression = False ,
651
+ ):
652
+ self ._check_closed ()
653
+ if key_id is not None and not (
654
+ isinstance (key_id , Binary ) and key_id .subtype == UUID_SUBTYPE
655
+ ):
656
+ raise TypeError ("key_id must be a bson.binary.Binary with subtype 4" )
657
+
658
+ doc = encode (
659
+ {"v" : value },
660
+ codec_options = self ._codec_options ,
661
+ )
662
+ if range_opts :
663
+ range_opts = encode (
664
+ range_opts .document ,
665
+ codec_options = self ._codec_options ,
666
+ )
667
+ with _wrap_encryption_errors ():
668
+ encrypted_doc = self ._encryption .encrypt (
669
+ value = doc ,
670
+ algorithm = algorithm ,
671
+ key_id = key_id ,
672
+ key_alt_name = key_alt_name ,
673
+ query_type = query_type ,
674
+ contention_factor = contention_factor ,
675
+ range_opts = range_opts ,
676
+ is_expression = is_expression ,
677
+ )
678
+ return decode (encrypted_doc )["v" ] # type: ignore[index]
679
+
630
680
def encrypt (
631
681
self ,
632
682
value : Any ,
@@ -635,6 +685,7 @@ def encrypt(
635
685
key_alt_name : Optional [str ] = None ,
636
686
query_type : Optional [str ] = None ,
637
687
contention_factor : Optional [int ] = None ,
688
+ range_opts : Optional [RangeOpts ] = None ,
638
689
) -> Binary :
639
690
"""Encrypt a BSON value with a given key and algorithm.
640
691
@@ -655,10 +706,10 @@ def encrypt(
655
706
when the algorithm is :attr:`Algorithm.INDEXED`. An integer value
656
707
*must* be given when the :attr:`Algorithm.INDEXED` algorithm is
657
708
used.
709
+ - `range_opts`: **(BETA)** An instance of RangeOpts.
658
710
659
- .. note:: `query_type` and `contention_factor` are part of the
660
- Queryable Encryption beta. Backwards-breaking changes may be made before the
661
- final release.
711
+ .. note:: `query_type`, `contention_factor` and `range_opts` are part of the Queryable Encryption beta.
712
+ Backwards-breaking changes may be made before the final release.
662
713
663
714
:Returns:
664
715
The encrypted value, a :class:`~bson.binary.Binary` with subtype 6.
@@ -667,23 +718,66 @@ def encrypt(
667
718
Added the `query_type` and `contention_factor` parameters.
668
719
669
720
"""
670
- self ._check_closed ()
671
- if key_id is not None and not (
672
- isinstance (key_id , Binary ) and key_id .subtype == UUID_SUBTYPE
673
- ):
674
- raise TypeError ("key_id must be a bson.binary.Binary with subtype 4" )
721
+ return self ._encrypt_helper (
722
+ value = value ,
723
+ algorithm = algorithm ,
724
+ key_id = key_id ,
725
+ key_alt_name = key_alt_name ,
726
+ query_type = query_type ,
727
+ contention_factor = contention_factor ,
728
+ range_opts = range_opts ,
729
+ is_expression = False ,
730
+ )
675
731
676
- doc = encode ({"v" : value }, codec_options = self ._codec_options )
677
- with _wrap_encryption_errors ():
678
- encrypted_doc = self ._encryption .encrypt (
679
- doc ,
680
- algorithm ,
681
- key_id = key_id ,
682
- key_alt_name = key_alt_name ,
683
- query_type = query_type ,
684
- contention_factor = contention_factor ,
685
- )
686
- return decode (encrypted_doc )["v" ] # type: ignore[index]
732
+ def encrypt_expression (
733
+ self ,
734
+ expression : Mapping [str , Any ],
735
+ algorithm : str ,
736
+ key_id : Optional [Binary ] = None ,
737
+ key_alt_name : Optional [str ] = None ,
738
+ query_type : Optional [str ] = None ,
739
+ contention_factor : Optional [int ] = None ,
740
+ range_opts : Optional [RangeOpts ] = None ,
741
+ ) -> RawBSONDocument :
742
+ """Encrypt a BSON expression with a given key and algorithm.
743
+
744
+ Note that exactly one of ``key_id`` or ``key_alt_name`` must be
745
+ provided.
746
+
747
+ :Parameters:
748
+ - `expression`: **(BETA)** The BSON aggregate or match expression to encrypt.
749
+ - `algorithm` (string): The encryption algorithm to use. See
750
+ :class:`Algorithm` for some valid options.
751
+ - `key_id`: Identifies a data key by ``_id`` which must be a
752
+ :class:`~bson.binary.Binary` with subtype 4 (
753
+ :attr:`~bson.binary.UUID_SUBTYPE`).
754
+ - `key_alt_name`: Identifies a key vault document by 'keyAltName'.
755
+ - `query_type` (str): **(BETA)** The query type to execute. See
756
+ :class:`QueryType` for valid options.
757
+ - `contention_factor` (int): **(BETA)** The contention factor to use
758
+ when the algorithm is :attr:`Algorithm.INDEXED`. An integer value
759
+ *must* be given when the :attr:`Algorithm.INDEXED` algorithm is
760
+ used.
761
+ - `range_opts`: **(BETA)** An instance of RangeOpts.
762
+
763
+ .. note:: Support for range queries is in beta.
764
+ Backwards-breaking changes may be made before the final release.
765
+
766
+ :Returns:
767
+ The encrypted expression, a :class:`~bson.RawBSONDocument`.
768
+
769
+ .. versionadded:: 4.4
770
+ """
771
+ return self ._encrypt_helper (
772
+ value = expression ,
773
+ algorithm = algorithm ,
774
+ key_id = key_id ,
775
+ key_alt_name = key_alt_name ,
776
+ query_type = query_type ,
777
+ contention_factor = contention_factor ,
778
+ range_opts = range_opts ,
779
+ is_expression = True ,
780
+ )
687
781
688
782
def decrypt (self , value : Binary ) -> Any :
689
783
"""Decrypt an encrypted value.
0 commit comments