88from typing import IO , Any , Callable , Dict , List , Mapping , Optional , Tuple , Union
99
1010from pydantic import Field , ValidationError , root_validator , validator
11- from requests .structures import CaseInsensitiveDict as RequestsCaseInsensitiveDict
1211from simple_salesforce import Salesforce
1312from typing_extensions import Literal
1413
1514from cumulusci .core .enums import StrEnum
1615from cumulusci .core .exceptions import BulkDataException
1716from cumulusci .tasks .bulkdata .dates import iso_to_date
18- from cumulusci .tasks .bulkdata .select_utils import SelectStrategy
17+ from cumulusci .tasks .bulkdata .select_utils import SelectOptions , SelectStrategy
1918from cumulusci .tasks .bulkdata .step import DataApi , DataOperationType
19+ from cumulusci .tasks .bulkdata .utils import CaseInsensitiveDict
2020from cumulusci .utils import convert_to_snake_case
2121from cumulusci .utils .yaml .model_parser import CCIDictModel
2222
2323logger = getLogger (__name__ )
2424
2525
26- class CaseInsensitiveDict (RequestsCaseInsensitiveDict ):
27- def __init__ (self , * args , ** kwargs ):
28- self ._canonical_keys = {}
29- super ().__init__ (* args , ** kwargs )
30-
31- def canonical_key (self , name ):
32- return self ._canonical_keys [name .lower ()]
33-
34- def __setitem__ (self , key , value ):
35- super ().__setitem__ (key , value )
36- self ._canonical_keys [key .lower ()] = key
37-
38-
3926class MappingLookup (CCIDictModel ):
4027 "Lookup relationship between two tables."
4128 table : Union [str , List [str ]] # Support for polymorphic lookups
@@ -85,7 +72,7 @@ class BulkMode(StrEnum):
8572
8673ENUM_VALUES = {
8774 v .value .lower (): v .value
88- for enum in [BulkMode , DataApi , DataOperationType , SelectStrategy ]
75+ for enum in [BulkMode , DataApi , DataOperationType ]
8976 for v in enum .__members__ .values ()
9077}
9178
@@ -108,13 +95,12 @@ class MappingStep(CCIDictModel):
10895 )
10996 anchor_date : Optional [Union [str , date ]] = None
11097 soql_filter : Optional [str ] = None # soql_filter property
111- selection_strategy : SelectStrategy = SelectStrategy .STANDARD # selection strategy
112- selection_filter : Optional [str ] = (
113- None # filter to be added at the end of select query
98+ select_options : Optional [SelectOptions ] = Field (
99+ default_factory = lambda : SelectOptions (strategy = SelectStrategy .STANDARD )
114100 )
115101 update_key : T .Union [str , T .Tuple [str , ...]] = () # only for upserts
116102
117- @validator ("bulk_mode" , "api" , "action" , "selection_strategy" , pre = True )
103+ @validator ("bulk_mode" , "api" , "action" , pre = True )
118104 def case_normalize (cls , val ):
119105 if isinstance (val , Enum ):
120106 return val
@@ -134,6 +120,24 @@ def split_update_key(cls, val):
134120 ), "`update_key` should be a field name or list of field names."
135121 assert False , "Should be unreachable" # pragma: no cover
136122
123+ @root_validator
124+ def validate_priority_fields (cls , values ):
125+ select_options = values .get ("select_options" )
126+ fields_ = values .get ("fields_" , {})
127+
128+ if select_options and select_options .priority_fields :
129+ priority_field_names = set (select_options .priority_fields .keys ())
130+ field_names = set (fields_ .keys ())
131+
132+ # Check if all priority fields are present in the fields
133+ missing_fields = priority_field_names - field_names
134+ if missing_fields :
135+ raise ValueError (
136+ f"Priority fields { missing_fields } are not present in 'fields'"
137+ )
138+
139+ return values
140+
137141 def get_oid_as_pk (self ):
138142 """Returns True if using Salesforce Ids as primary keys."""
139143 return "Id" in self .fields
0 commit comments