|
18 | 18 | from fides.api.service.connectors.query_configs.query_config import (
|
19 | 19 | QueryStringWithoutTuplesOverrideQueryConfig,
|
20 | 20 | )
|
21 |
| -from fides.api.util.collection_util import Row, filter_nonempty_values, unflatten_dict |
| 21 | +from fides.api.util.collection_util import ( |
| 22 | + Row, |
| 23 | + filter_nonempty_values, |
| 24 | + flatten_dict, |
| 25 | + merge_dicts, |
| 26 | + unflatten_dict, |
| 27 | +) |
22 | 28 |
|
23 | 29 |
|
24 | 30 | class BigQueryQueryConfig(QueryStringWithoutTuplesOverrideQueryConfig):
|
@@ -124,44 +130,28 @@ def generate_update(
|
124 | 130 | This implementation handles nested fields by grouping them as JSON objects rather than
|
125 | 131 | individual field updates.
|
126 | 132 | """
|
127 |
| - # Get initial update value map |
| 133 | + # Get initial update value map (already flattened) |
128 | 134 | update_value_map: Dict[str, Any] = self.update_value_map(row, policy, request)
|
129 | 135 |
|
130 |
| - # Convert flattened paths to nested structure using unflatten_dict |
131 |
| - unflattened_update_map = unflatten_dict(update_value_map) |
132 |
| - |
133 |
| - # Prepare final update map, preserving original nested structures |
134 |
| - final_update_map = {} |
135 |
| - for field, value in unflattened_update_map.items(): |
136 |
| - if isinstance(value, dict): |
137 |
| - # For nested fields, preserve original structure and update only changed values |
138 |
| - original_struct = row.get(field, {}) |
139 |
| - if isinstance(original_struct, dict): |
140 |
| - updated_struct = {**original_struct, **value} |
141 |
| - final_update_map[field] = updated_struct |
142 |
| - elif isinstance(value, list): |
143 |
| - # Handle array fields, preserving unmodified values |
144 |
| - original_array = row.get(field, []) |
145 |
| - if isinstance(original_array, list): |
146 |
| - updated_array = [] |
147 |
| - |
148 |
| - # For each item in the original array |
149 |
| - for i, original_item in enumerate(original_array): |
150 |
| - if i < len(value): |
151 |
| - updated_item = value[i] |
152 |
| - # If both are dictionaries, merge them to preserve unmodified fields |
153 |
| - if isinstance(original_item, dict) and isinstance( |
154 |
| - updated_item, dict |
155 |
| - ): |
156 |
| - updated_item = {**original_item, **updated_item} |
157 |
| - updated_array.append(updated_item) |
158 |
| - else: |
159 |
| - updated_array.append(original_item) |
160 |
| - |
161 |
| - final_update_map[field] = updated_array |
162 |
| - else: |
163 |
| - # Keep regular fields |
164 |
| - final_update_map[field] = value |
| 136 | + # 1. Take update_value_map as-is (already flattened) |
| 137 | + |
| 138 | + # 2. Flatten the row |
| 139 | + flattened_row = flatten_dict(row) |
| 140 | + |
| 141 | + # 3. Merge flattened_row with update_value_map (update_value_map takes precedence) |
| 142 | + merged_dict = merge_dicts(flattened_row, update_value_map) |
| 143 | + |
| 144 | + # 4. Unflatten the merged dictionary |
| 145 | + nested_result = unflatten_dict(merged_dict) |
| 146 | + |
| 147 | + # 5. Only keep top-level keys that are in the update_value_map |
| 148 | + # Get unique top-level keys from update_value_map |
| 149 | + top_level_keys = {key.split(".")[0] for key in update_value_map.keys()} |
| 150 | + |
| 151 | + # Filter the nested result to only include those top-level keys |
| 152 | + final_update_map = { |
| 153 | + k: v for k, v in nested_result.items() if k in top_level_keys |
| 154 | + } |
165 | 155 |
|
166 | 156 | # Use existing non-empty reference fields mechanism for WHERE clause
|
167 | 157 | non_empty_reference_field_keys: Dict[str, Field] = filter_nonempty_values(
|
|
0 commit comments