11from __future__ import annotations
22
3- from collections import defaultdict
43from collections .abc import Collection
54from dataclasses import dataclass
65from uuid import UUID
@@ -49,7 +48,7 @@ async def _get_related_roles(
4948) -> list [RoleRow ]:
5049 """
5150 Get all roles related to the given entity as object permissions.
52- Loads all object_permissions, permission_groups , and permission_rows for each role .
51+ Loads object_permissions with their scope_associations , and permission_groups with permissions .
5352 """
5453 role_scalars = await db_sess .scalars (
5554 sa .select (RoleRow )
@@ -61,7 +60,9 @@ async def _get_related_roles(
6160 )
6261 )
6362 .options (
64- selectinload (RoleRow .object_permission_rows ),
63+ selectinload (RoleRow .object_permission_rows ).selectinload (
64+ ObjectPermissionRow .scope_association_rows
65+ ),
6566 selectinload (RoleRow .permission_group_rows ).selectinload (
6667 PermissionGroupRow .permission_rows
6768 ),
@@ -70,41 +71,8 @@ async def _get_related_roles(
7071 return role_scalars .unique ().all ()
7172
7273
73- async def _get_entity_scopes (
74- db_sess : SASession ,
75- entities : Collection [ObjectId ],
76- ) -> dict [ObjectId , set [ScopeId ]]:
77- """
78- Get all scopes for a list of entities in a single query.
79-
80- Returns:
81- Mapping of ObjectId -> set of ScopeId
82- """
83- if not entities :
84- return {}
85-
86- entity_tuples = [(e .entity_type , e .entity_id ) for e in entities ]
87- assoc_scalars = await db_sess .scalars (
88- sa .select (AssociationScopesEntitiesRow ).where (
89- sa .tuple_ (
90- AssociationScopesEntitiesRow .entity_type ,
91- AssociationScopesEntitiesRow .entity_id ,
92- ).in_ (entity_tuples )
93- )
94- )
95-
96- result : defaultdict [ObjectId , set [ScopeId ]] = defaultdict (set )
97- assoc_rows : list [AssociationScopesEntitiesRow ] = assoc_scalars .all ()
98- for assoc in assoc_rows :
99- key = assoc .object_id ()
100- scope = assoc .parsed_scope_id ()
101- result [key ].add (scope )
102- return result
103-
104-
10574def _perm_group_ids_to_delete_in_role (
10675 role_row : RoleRow ,
107- entity_scopes : dict [ObjectId , set [ScopeId ]],
10876 entity_to_delete : ObjectId ,
10977) -> list [UUID ]:
11078 """
@@ -118,13 +86,13 @@ def _perm_group_ids_to_delete_in_role(
11886 if not role_row .permission_group_rows :
11987 return perm_group_ids
12088
89+ # Collect scopes from remaining entities (via eagerly loaded scope_association_rows)
12190 remaining_scopes : set [ScopeId ] = set ()
12291 for object_permission_row in role_row .object_permission_rows :
123- object_id = object_permission_row .object_id ()
124- if object_id == entity_to_delete :
92+ if object_permission_row .object_id () == entity_to_delete :
12593 continue
126- scopes = entity_scopes . get ( object_id , set ())
127- remaining_scopes .update ( scopes )
94+ for assoc in object_permission_row . scope_association_rows :
95+ remaining_scopes .add ( assoc . parsed_scope_id () )
12896
12997 for perm_group_row in role_row .permission_group_rows :
13098 # Skip permission groups that have remaining permissions
@@ -138,23 +106,13 @@ def _perm_group_ids_to_delete_in_role(
138106
139107def _perm_group_ids_to_delete (
140108 role_rows : Collection [RoleRow ],
141- entity_scopes : dict [ObjectId , set [ScopeId ]],
142109 entity_to_delete : ObjectId ,
143110) -> list [UUID ]:
144- # all_entites = _all_object_permission_entities_in_roles(role_rows)
145- # if not all_entites:
146- # all_entites.add(entity_to_delete)
147- # entity_scopes = await _get_entity_scopes(db_sess, all_entites)
148-
149111 if not role_rows :
150112 return []
151113 permission_group_ids : list [UUID ] = []
152114 for role_row in role_rows :
153- perm_group_ids = _perm_group_ids_to_delete_in_role (
154- role_row ,
155- entity_scopes ,
156- entity_to_delete ,
157- )
115+ perm_group_ids = _perm_group_ids_to_delete_in_role (role_row , entity_to_delete )
158116 permission_group_ids .extend (perm_group_ids )
159117 return permission_group_ids
160118
@@ -174,17 +132,6 @@ def _object_permission_ids_to_delete(
174132 return object_permission_ids
175133
176134
177- def _all_object_permission_entities_in_roles (
178- role_rows : Collection [RoleRow ],
179- ) -> set [ObjectId ]:
180- object_ids : set [ObjectId ] = set ()
181- for role_row in role_rows :
182- for object_permission_row in role_row .object_permission_rows :
183- object_id = object_permission_row .object_id ()
184- object_ids .add (object_id )
185- return object_ids
186-
187-
188135async def _delete_main_object_row (
189136 db_sess : SASession ,
190137 purger : Purger [TRow ],
@@ -226,16 +173,10 @@ async def _delete_rbac_entity(
226173 db_sess : SASession ,
227174 entity_id : ObjectId ,
228175) -> None :
229- # Get all roles associated with the entity as object permission
176+ # Get all roles with object_permissions and their scope_associations eagerly loaded
230177 role_rows = await _get_related_roles (db_sess , entity_id )
231178 object_permission_ids = _object_permission_ids_to_delete (role_rows , entity_id )
232- all_entites = _all_object_permission_entities_in_roles (role_rows )
233- if not all_entites :
234- all_entites .add (entity_id )
235- entity_scopes = await _get_entity_scopes (db_sess , all_entites )
236-
237- # Determine which object_permissions and permission_groups to delete
238- permission_group_ids = _perm_group_ids_to_delete (role_rows , entity_scopes , entity_id )
179+ permission_group_ids = _perm_group_ids_to_delete (role_rows , entity_id )
239180
240181 # Execute deletions
241182 if object_permission_ids :
0 commit comments