Skip to content

Commit d30d69b

Browse files
fix(platform): support entity resource overwrites with folder resolution
1 parent d0fdafd commit d30d69b

File tree

7 files changed

+278
-189
lines changed

7 files changed

+278
-189
lines changed

packages/uipath-platform/pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "uipath-platform"
3-
version = "0.1.21"
3+
version = "0.1.22"
44
description = "HTTP client library for programmatic access to UiPath Platform"
55
readme = { file = "README.md", content-type = "text/markdown" }
66
requires-python = ">=3.11"

packages/uipath-platform/src/uipath/platform/entities/_entities_service.py

Lines changed: 9 additions & 176 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,18 @@
88
from uipath.core.tracing import traced
99

1010
from ..common._base_service import BaseService
11-
from ..common._bindings import EntityResourceOverwrite, _resource_overwrites
11+
from ..common._bindings import _resource_overwrites
1212
from ..common._config import UiPathApiConfig
1313
from ..common._execution_context import UiPathExecutionContext
1414
from ..common._models import Endpoint, RequestSpec
1515
from ..common.constants import HEADER_FOLDER_KEY
1616
from ..orchestrator._folder_service import FolderService
1717
from ._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
)
@@ -27,7 +28,6 @@
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

Comments
 (0)