88from uipath .core .tracing import traced
99
1010from ..common ._base_service import BaseService
11- from ..common ._bindings import EntityResourceOverwrite , _resource_overwrites
11+ from ..common ._bindings import _resource_overwrites
1212from ..common ._config import UiPathApiConfig
1313from ..common ._execution_context import UiPathExecutionContext
1414from ..common ._models import Endpoint , RequestSpec
1515from ..common .constants import HEADER_FOLDER_KEY
1616from ..orchestrator ._folder_service import FolderService
1717from ._entity_resolution import (
18- build_resolution_routing_context ,
18+ RoutingStrategy ,
1919 build_resolution_service ,
2020 create_resolution_plan ,
2121 create_resolution_plan_async ,
22+ create_routing_strategy ,
2223 fetch_resolved_entities ,
2324 fetch_resolved_entities_async ,
2425)
2728 Entity ,
2829 EntityRecord ,
2930 EntityRecordsBatchResponse ,
30- EntityRouting ,
3131 EntitySetResolution ,
3232 QueryRoutingOverrideContext ,
3333)
@@ -74,32 +74,11 @@ def __init__(
7474 ) -> None :
7575 super ().__init__ (config = config , execution_context = execution_context )
7676 self ._folders_service = folders_service
77- self ._folders_map = folders_map or {}
78- self ._effective_entity_names = entity_name_overrides or {}
79- self ._routing_context = routing_context
80-
81- def with_folders_map (
82- self ,
83- folders_map : Dict [str , str ],
84- entity_name_overrides : Optional [Dict [str , str ]] = None ,
85- ) -> "EntitiesService" :
86- """Return a new EntitiesService configured with the given folders map.
87-
88- The map is used to build a routing context automatically when
89- ``query_entity_records`` is called without an explicit routing context.
90- Folder paths in the map are resolved to folder keys via ``FolderService``.
91-
92- Args:
93- folders_map: Mapping of entity name to folder path.
94- entity_name_overrides: Mapping of original entity name to
95- overridden entity name.
96- """
97- return EntitiesService (
98- config = self ._config ,
99- execution_context = self ._execution_context ,
100- folders_service = self ._folders_service ,
77+ self ._routing_strategy : RoutingStrategy = create_routing_strategy (
10178 folders_map = folders_map ,
102- entity_name_overrides = entity_name_overrides ,
79+ effective_entity_names = entity_name_overrides ,
80+ routing_context = routing_context ,
81+ folders_service = folders_service ,
10382 )
10483
10584 @traced (name = "entity_retrieve" , run_type = "uipath" )
@@ -629,7 +608,7 @@ def _query_entities_for_records(
629608 sql_query : str ,
630609 ) -> List [Dict [str , Any ]]:
631610 self ._validate_sql_query (sql_query )
632- routing_context = self ._build_routing_context_from_map ()
611+ routing_context = self ._routing_strategy . resolve ()
633612 spec = self ._query_entity_records_spec (sql_query , routing_context )
634613 response = self .request (spec .method , spec .endpoint , json = spec .json )
635614 return response .json ().get ("results" , [])
@@ -639,7 +618,7 @@ async def _query_entities_for_records_async(
639618 sql_query : str ,
640619 ) -> List [Dict [str , Any ]]:
641620 self ._validate_sql_query (sql_query )
642- routing_context = await self ._build_routing_context_from_map_async ()
621+ routing_context = await self ._routing_strategy . resolve_async ()
643622 spec = self ._query_entity_records_spec (sql_query , routing_context )
644623 response = await self .request_async (spec .method , spec .endpoint , json = spec .json )
645624 return response .json ().get ("results" , [])
@@ -1158,152 +1137,6 @@ def _query_entity_records_spec(
11581137 json = body ,
11591138 )
11601139
1161- def _build_routing_context_from_map (
1162- self ,
1163- ) -> Optional [QueryRoutingOverrideContext ]:
1164- """Build a routing context from the configured folders_map and context overwrites.
1165-
1166- If a pre-built routing context was provided (e.g. by
1167- ``resolve_entity_set_async``), it is returned directly without
1168- re-resolving folder paths.
1169-
1170- Otherwise, folder paths in the map are resolved to folder keys via
1171- FolderService and entity overwrites from the active
1172- ``ResourceOverwritesContext`` are merged in.
1173-
1174- Returns:
1175- A QueryRoutingOverrideContext if routing entries exist,
1176- None otherwise.
1177- """
1178- if self ._routing_context is not None :
1179- return self ._routing_context
1180- resolved = self ._resolve_folder_paths_to_ids ()
1181- return self ._build_routing_context_from_resolved_map (resolved )
1182-
1183- async def _build_routing_context_from_map_async (
1184- self ,
1185- ) -> Optional [QueryRoutingOverrideContext ]:
1186- """Async version of _build_routing_context_from_map."""
1187- if self ._routing_context is not None :
1188- return self ._routing_context
1189- resolved = await self ._resolve_folder_paths_to_ids_async ()
1190- return self ._build_routing_context_from_resolved_map (resolved )
1191-
1192- def _resolve_folder_paths_to_ids (self ) -> Optional [dict [str , str ]]:
1193- entity_overwrites = self ._get_entity_overwrites_from_context ()
1194- folder_paths = set (self ._folders_map .values ())
1195- for overwrite in entity_overwrites .values ():
1196- if overwrite .folder_path :
1197- folder_paths .add (overwrite .folder_path )
1198-
1199- if not folder_paths :
1200- return None
1201-
1202- resolved : dict [str , str ] = {}
1203- for folder_path in folder_paths :
1204- if self ._folders_service is not None :
1205- folder_key = self ._folders_service .retrieve_folder_key (folder_path )
1206- if folder_key is not None :
1207- resolved [folder_path ] = folder_key
1208- continue
1209- resolved [folder_path ] = folder_path
1210-
1211- return resolved
1212-
1213- async def _resolve_folder_paths_to_ids_async (self ) -> Optional [dict [str , str ]]:
1214- entity_overwrites = self ._get_entity_overwrites_from_context ()
1215- folder_paths = set (self ._folders_map .values ())
1216- for overwrite in entity_overwrites .values ():
1217- if overwrite .folder_path :
1218- folder_paths .add (overwrite .folder_path )
1219-
1220- if not folder_paths :
1221- return None
1222-
1223- resolved : dict [str , str ] = {}
1224- for folder_path in folder_paths :
1225- if self ._folders_service is not None :
1226- folder_key = await self ._folders_service .retrieve_folder_key_async (
1227- folder_path
1228- )
1229- if folder_key is not None :
1230- resolved [folder_path ] = folder_key
1231- continue
1232- resolved [folder_path ] = folder_path
1233-
1234- return resolved
1235-
1236- @staticmethod
1237- def _get_entity_overwrites_from_context () -> Dict [str , EntityResourceOverwrite ]:
1238- """Extract entity overwrites from the active ResourceOverwritesContext.
1239-
1240- Returns:
1241- A dict mapping original entity name to its EntityResourceOverwrite.
1242- """
1243- context_overwrites = _resource_overwrites .get ()
1244- if not context_overwrites :
1245- return {}
1246-
1247- result : Dict [str , EntityResourceOverwrite ] = {}
1248- for key , overwrite in context_overwrites .items ():
1249- if isinstance (overwrite , EntityResourceOverwrite ):
1250- # Key format is "entity.<original_id>"
1251- original_name = key .split ("." , 1 )[1 ] if "." in key else key
1252- result [original_name ] = overwrite
1253- return result
1254-
1255- def _build_routing_context_from_resolved_map (
1256- self ,
1257- resolved : Optional [dict [str , str ]],
1258- ) -> Optional [QueryRoutingOverrideContext ]:
1259- if self ._folders_map :
1260- return build_resolution_routing_context (
1261- {
1262- name : (resolved or {}).get (folder_path , folder_path )
1263- for name , folder_path in self ._folders_map .items ()
1264- },
1265- self ._effective_entity_names ,
1266- )
1267-
1268- routings : List [EntityRouting ] = []
1269- if not self ._folders_map :
1270- # Fallback for direct SDK usage (no folders_map)
1271- entity_overwrites = self ._get_entity_overwrites_from_context ()
1272- for original_name , overwrite in entity_overwrites .items ():
1273- override_name = (
1274- overwrite .resource_identifier
1275- if overwrite .resource_identifier != original_name
1276- else None
1277- )
1278- routings .append (
1279- EntityRouting (
1280- entity_name = original_name ,
1281- folder_id = self ._resolve_overwrite_folder (overwrite , resolved ),
1282- override_entity_name = override_name ,
1283- )
1284- )
1285-
1286- if not routings :
1287- return None
1288-
1289- return QueryRoutingOverrideContext (entity_routings = routings )
1290-
1291- @staticmethod
1292- def _resolve_overwrite_folder (
1293- overwrite : EntityResourceOverwrite ,
1294- resolved : Optional [dict [str , str ]],
1295- ) -> str :
1296- """Return the folder key for an entity overwrite.
1297-
1298- Uses folder_id directly when present (already a key).
1299- Falls back to resolving folder_path through the resolved map.
1300- """
1301- if overwrite .folder_id :
1302- return overwrite .folder_id
1303- if overwrite .folder_path and resolved :
1304- return resolved .get (overwrite .folder_path , overwrite .folder_path )
1305- return overwrite .folder_identifier
1306-
13071140 def _insert_batch_spec (self , entity_key : str , records : List [Any ]) -> RequestSpec :
13081141 return RequestSpec (
13091142 method = "POST" ,
0 commit comments