Skip to content

Commit 7fae06e

Browse files
Functionality to prioritize user specified fields
1 parent f86f94d commit 7fae06e

6 files changed

Lines changed: 180 additions & 60 deletions

File tree

cumulusci/tasks/bulkdata/load.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ def configure_step(self, mapping):
360360
num_records_in_target = sobject_map.get(mapping.sf_object, None)
361361

362362
# Check for similarity selection strategy and modify fields accordingly
363-
if mapping.selection_strategy == "similarity":
363+
if mapping.select_options.strategy == "similarity":
364364
# Describe the object to determine polymorphic lookups
365365
describe_result = self.sf.restful(
366366
f"sobjects/{mapping.sf_object}/describe"
@@ -469,8 +469,9 @@ def configure_step(self, mapping):
469469
fields=fields,
470470
api=mapping.api,
471471
volume=volume,
472-
selection_strategy=mapping.selection_strategy,
473-
selection_filter=mapping.selection_filter,
472+
selection_strategy=mapping.select_options.strategy,
473+
selection_filter=mapping.select_options.filter,
474+
selection_priority_fields=mapping.select_options.priority_fields,
474475
content_type=content_type,
475476
)
476477
return step, query
@@ -577,7 +578,7 @@ def _query_db(self, mapping):
577578
transformers = []
578579
if (
579580
mapping.action == DataOperationType.SELECT
580-
and mapping.selection_strategy == "similarity"
581+
and mapping.select_options.strategy == "similarity"
581582
):
582583
transformers.append(
583584
DynamicLookupQueryExtender(

cumulusci/tasks/bulkdata/mapping_parser.py

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,34 +8,21 @@
88
from typing import IO, Any, Callable, Dict, List, Mapping, Optional, Tuple, Union
99

1010
from pydantic import Field, ValidationError, root_validator, validator
11-
from requests.structures import CaseInsensitiveDict as RequestsCaseInsensitiveDict
1211
from simple_salesforce import Salesforce
1312
from typing_extensions import Literal
1413

1514
from cumulusci.core.enums import StrEnum
1615
from cumulusci.core.exceptions import BulkDataException
1716
from 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
1918
from cumulusci.tasks.bulkdata.step import DataApi, DataOperationType
19+
from cumulusci.tasks.bulkdata.utils import CaseInsensitiveDict
2020
from cumulusci.utils import convert_to_snake_case
2121
from cumulusci.utils.yaml.model_parser import CCIDictModel
2222

2323
logger = 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-
3926
class 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

8673
ENUM_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

cumulusci/tasks/bulkdata/query_transformers.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,11 @@ def columns_to_add(self):
123123
load_fields = lookup_mapping_step.get_load_field_list()
124124
for field in load_fields:
125125
matching_column = next(
126-
(col for col in aliased_table.columns if col.name == field)
126+
(
127+
col
128+
for col in aliased_table.columns
129+
if col.name == lookup_mapping_step.fields[field]
130+
)
127131
)
128132
columns.append(
129133
matching_column.label(f"{aliased_table.name}_{field}")

0 commit comments

Comments
 (0)