healthdatalayer 1.0.1__py3-none-any.whl → 1.2.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of healthdatalayer might be problematic. Click here for more details.

Files changed (96) hide show
  1. healthdatalayer/config/__init__.py +0 -0
  2. healthdatalayer/models/bridge_area_floor_branch/__init__.py +0 -0
  3. healthdatalayer/models/bridge_area_floor_branch/area.py +8 -0
  4. healthdatalayer/models/bridge_area_floor_branch/branch.py +16 -0
  5. healthdatalayer/models/bridge_area_floor_branch/bridge_area_floor_branch.py +27 -0
  6. healthdatalayer/models/bridge_area_floor_branch/floor.py +8 -0
  7. healthdatalayer/models/bridge_area_floor_branch/room.py +8 -0
  8. healthdatalayer/models/bridge_area_floor_branch/system.py +8 -0
  9. healthdatalayer/models/client/__init__.py +0 -0
  10. healthdatalayer/models/client/address.py +13 -0
  11. healthdatalayer/models/client/client.py +25 -0
  12. healthdatalayer/models/client/client_type.py +9 -0
  13. healthdatalayer/models/client/education.py +9 -0
  14. healthdatalayer/models/client/emergency_contact.py +17 -0
  15. healthdatalayer/models/client/gender.py +9 -0
  16. healthdatalayer/models/client/marriage_status.py +9 -0
  17. healthdatalayer/models/client/nationality.py +10 -0
  18. healthdatalayer/models/client/pathological_history.py +29 -0
  19. healthdatalayer/models/client/pet.py +16 -0
  20. healthdatalayer/models/client/profession.py +9 -0
  21. healthdatalayer/models/client/px.py +28 -0
  22. healthdatalayer/models/collaborator/__init__.py +0 -0
  23. healthdatalayer/models/collaborator/collaborator.py +33 -0
  24. healthdatalayer/models/collaborator/collaborator_speciality.py +8 -0
  25. healthdatalayer/models/collaborator/collaborator_type.py +9 -0
  26. healthdatalayer/models/collaborator/speciality.py +23 -0
  27. healthdatalayer/models/lab/__init__.py +0 -0
  28. healthdatalayer/models/lab/client_lab.py +13 -0
  29. healthdatalayer/models/lab/measure_lab.py +11 -0
  30. healthdatalayer/models/lab/medical_lab.py +17 -0
  31. healthdatalayer/models/medical_visit/__init__.py +0 -0
  32. healthdatalayer/models/medical_visit/medical_diagnosis.py +12 -0
  33. healthdatalayer/models/medical_visit/medical_diagnosis_visit.py +25 -0
  34. healthdatalayer/models/medical_visit/medical_drug.py +27 -0
  35. healthdatalayer/models/medical_visit/medical_drug_recipe.py +18 -0
  36. healthdatalayer/models/medical_visit/medical_recipe_visit.py +28 -0
  37. healthdatalayer/models/medical_visit/medical_visit.py +51 -0
  38. healthdatalayer/models/medical_visit/organ_system_review.py +28 -0
  39. healthdatalayer/models/medical_visit/physical_exam.py +45 -0
  40. healthdatalayer/models/medical_visit/visit_triage.py +28 -0
  41. healthdatalayer/models/user/__init__.py +0 -0
  42. healthdatalayer/models/user/permission.py +27 -0
  43. healthdatalayer/models/user/permission_user.py +8 -0
  44. healthdatalayer/models/user/role.py +27 -0
  45. healthdatalayer/models/user/role_permission.py +8 -0
  46. healthdatalayer/models/user/role_user.py +8 -0
  47. healthdatalayer/models/user/user.py +30 -0
  48. healthdatalayer/repositories/client_repositories/__init__.py +0 -0
  49. healthdatalayer/repositories/client_repositories/address_repository.py +64 -0
  50. healthdatalayer/repositories/client_repositories/client_type_repository.py +69 -0
  51. healthdatalayer/repositories/client_repositories/education_repository.py +70 -0
  52. healthdatalayer/repositories/client_repositories/gender_repository.py +70 -0
  53. healthdatalayer/repositories/client_repositories/marriage_status_repository.py +70 -0
  54. healthdatalayer/repositories/client_repositories/pet_repository.py +126 -0
  55. healthdatalayer/repositories/client_repositories/profession_repository.py +70 -0
  56. healthdatalayer/repositories/client_repositories/px_repository.py +210 -0
  57. healthdatalayer/repositories/collaborator_repositories/__init__.py +0 -0
  58. healthdatalayer/repositories/collaborator_repositories/collaborator_repository.py +150 -0
  59. healthdatalayer/repositories/collaborator_repositories/collaborator_type_repository.py +69 -0
  60. healthdatalayer/repositories/collaborator_repositories/speciality_repository.py +75 -0
  61. healthdatalayer/repositories/infraestructure_repositories/__init__.py +0 -0
  62. healthdatalayer/repositories/infraestructure_repositories/area_repository.py +69 -0
  63. healthdatalayer/repositories/infraestructure_repositories/branch_repository.py +69 -0
  64. healthdatalayer/repositories/infraestructure_repositories/bridge_repository.py +80 -0
  65. healthdatalayer/repositories/infraestructure_repositories/floor_repository.py +69 -0
  66. healthdatalayer/repositories/infraestructure_repositories/room_repository.py +69 -0
  67. healthdatalayer/repositories/infraestructure_repositories/system_repository.py +69 -0
  68. healthdatalayer/repositories/lab_repositories/__init__.py +0 -0
  69. healthdatalayer/repositories/lab_repositories/measure_lab_repository.py +80 -0
  70. healthdatalayer/repositories/lab_repositories/medical_lab_repository.py +254 -0
  71. healthdatalayer/repositories/medical_visit_repositories/__init__.py +0 -0
  72. healthdatalayer/repositories/medical_visit_repositories/medical_diagnosis_repository.py +63 -0
  73. healthdatalayer/repositories/medical_visit_repositories/medical_diagnosis_visit_repository.py +92 -0
  74. healthdatalayer/repositories/medical_visit_repositories/medical_drug_recipe_repository.py +70 -0
  75. healthdatalayer/repositories/medical_visit_repositories/medical_drug_repository.py +63 -0
  76. healthdatalayer/repositories/medical_visit_repositories/medical_recipe_visit_repository.py +93 -0
  77. healthdatalayer/repositories/medical_visit_repositories/medical_visit_repository.py +110 -0
  78. healthdatalayer/repositories/medical_visit_repositories/organ_system_review_repository.py +89 -0
  79. healthdatalayer/repositories/medical_visit_repositories/physical_exam_repository.py +89 -0
  80. healthdatalayer/repositories/medical_visit_repositories/visit_triage_repository.py +89 -0
  81. healthdatalayer/repositories/user_repositories/__init__.py +0 -0
  82. healthdatalayer/repositories/user_repositories/permission_repository.py +238 -0
  83. healthdatalayer/repositories/user_repositories/role_repository.py +174 -0
  84. healthdatalayer/repositories/user_repositories/user_repository.py +251 -0
  85. {healthdatalayer-1.0.1.dist-info → healthdatalayer-1.2.0.dist-info}/METADATA +2 -2
  86. healthdatalayer-1.2.0.dist-info/RECORD +94 -0
  87. healthdatalayer-1.2.0.dist-info/top_level.txt +1 -0
  88. healthdatalayer-1.0.1.dist-info/RECORD +0 -10
  89. healthdatalayer-1.0.1.dist-info/top_level.txt +0 -3
  90. {config → healthdatalayer}/__init__.py +0 -0
  91. {config → healthdatalayer/config}/config.py +0 -0
  92. {config → healthdatalayer/config}/db.py +0 -0
  93. {config → healthdatalayer/config}/vault.py +0 -0
  94. {models → healthdatalayer/models}/__init__.py +0 -0
  95. {repositories → healthdatalayer/repositories}/__init__.py +0 -0
  96. {healthdatalayer-1.0.1.dist-info → healthdatalayer-1.2.0.dist-info}/WHEEL +0 -0
@@ -0,0 +1,89 @@
1
+ from typing import Optional, List
2
+ from uuid import UUID
3
+ from sqlmodel import select, or_
4
+ from sqlalchemy.orm import selectinload,joinedload
5
+ from models import VisitTriage
6
+ from models import MedicalVisit
7
+ from config.db import engines, get_session
8
+
9
+ class VisitTriageRepository:
10
+ def __init__(self, tenant: str):
11
+ self.tenant = tenant
12
+ if tenant not in engines:
13
+ raise ValueError(f"Tenant {tenant} is not configured")
14
+
15
+ def create_command(self, visit_triage: VisitTriage) -> VisitTriage:
16
+ with get_session(self.tenant) as session:
17
+ session.add(visit_triage)
18
+ session.commit()
19
+ session.refresh(visit_triage)
20
+ return visit_triage
21
+
22
+ def get_by_id_command(self, visit_triage_id: UUID, load_relations: bool = False) -> Optional[VisitTriage]:
23
+ with get_session(self.tenant) as session:
24
+
25
+ if load_relations:
26
+ statement = select(VisitTriage).where(VisitTriage.visit_triage_id == visit_triage_id).options(
27
+ joinedload(VisitTriage.medical_visit)
28
+ )
29
+ visit_triage = session.exec(statement).first()
30
+
31
+ return visit_triage
32
+ else:
33
+ return session.get(VisitTriage, visit_triage_id)
34
+
35
+ def get_by_medical_visit_id_command(self, medical_visit_id: UUID, load_relations: bool = False) ->Optional[VisitTriage]:
36
+ with get_session(self.tenant) as session:
37
+
38
+ statement = select(VisitTriage).where(VisitTriage.medical_visit_id == medical_visit_id)
39
+ if load_relations:
40
+ statement = statement.options(
41
+ joinedload(VisitTriage.medical_visit)
42
+ )
43
+ visit_triage = session.exec(statement).first()
44
+
45
+ return visit_triage
46
+
47
+ def get_all_command(self, active_only: bool = True,load_related: bool = False) -> List[VisitTriage]:
48
+ with get_session(self.tenant) as session:
49
+
50
+ statement = select(VisitTriage)
51
+
52
+ if load_related:
53
+ statement = select(VisitTriage).options(
54
+ selectinload(VisitTriage.medical_visit)
55
+ )
56
+
57
+ if active_only:
58
+ statement = statement.where(VisitTriage.is_active == True)
59
+ visit_triage = session.exec(statement).all()
60
+
61
+ return visit_triage
62
+
63
+ def update_command(self, visit_triage: VisitTriage) -> VisitTriage:
64
+ with get_session(self.tenant) as session:
65
+ existing_visit_triage = session.get(VisitTriage, visit_triage.visit_triage_id)
66
+ if not existing_visit_triage:
67
+ raise ValueError(f"triage with id {visit_triage.visit_triage_id} does not exist")
68
+
69
+ for key, value in visit_triage.dict(exclude_unset=True).items():
70
+ setattr(existing_visit_triage, key, value)
71
+
72
+ bd_visit_triage = session.merge(existing_visit_triage)
73
+ session.commit()
74
+ session.refresh(bd_visit_triage)
75
+ return bd_visit_triage
76
+
77
+ def delete_command(self, visit_triage_id: UUID, soft_delete: bool = False)->None:
78
+ with get_session(self.tenant) as session:
79
+ existing_visit_triage = session.get(MedicalVisit, visit_triage_id)
80
+ if not existing_visit_triage:
81
+ raise ValueError(f"MedicalVisit with id {visit_triage_id} does not exist")
82
+
83
+ if soft_delete:
84
+ existing_visit_triage.is_active = False
85
+ session.add(existing_visit_triage)
86
+ else:
87
+ session.delete(existing_visit_triage)
88
+
89
+ session.commit()
@@ -0,0 +1,238 @@
1
+ from typing import Optional, List
2
+ from uuid import UUID
3
+ from sqlmodel import select
4
+ from sqlalchemy.orm import selectinload
5
+
6
+ from models import Permission
7
+ from models import Role
8
+ from models import User
9
+ from config.db import engines, get_session
10
+
11
+ class PermissionRepository:
12
+ def __init__(self, tenant: str):
13
+ self.tenant = tenant
14
+ if tenant not in engines:
15
+ raise ValueError(f"Tenant {tenant} is not configured")
16
+
17
+ def create_command(self, permission: Permission) -> Permission:
18
+ with get_session(self.tenant) as session:
19
+ session.add(permission)
20
+ session.commit()
21
+ session.refresh(permission)
22
+ return permission
23
+
24
+ def get_by_id_command(self, permission_id: UUID, load_relations: bool = False) -> Optional[Permission]:
25
+ with get_session(self.tenant) as session:
26
+ if load_relations:
27
+ statement = select(Permission).where(Permission.permission_id == permission_id).options(
28
+ selectinload(Permission.roles),
29
+ selectinload(Permission.users)
30
+ )
31
+ return session.exec(statement).first()
32
+ else:
33
+ return session.get(Permission, permission_id)
34
+
35
+ def get_by_name_command(self, name: str, load_relations: bool = False) -> Optional[Permission]:
36
+ with get_session(self.tenant) as session:
37
+ statement = select(Permission).where(Permission.name == name)
38
+
39
+ if load_relations:
40
+ statement = statement.options(
41
+ selectinload(Permission.roles),
42
+ selectinload(Permission.users)
43
+ )
44
+
45
+ return session.exec(statement).first()
46
+
47
+ def search_by_name_command(self, name: str, load_relations: bool = False) -> List[Permission]:
48
+ with get_session(self.tenant) as session:
49
+ statement = select(Permission).where(Permission.name.ilike(f"%{name}%"))
50
+
51
+ if load_relations:
52
+ statement = statement.options(
53
+ selectinload(Permission.roles),
54
+ selectinload(Permission.users)
55
+ )
56
+
57
+ results = session.exec(statement)
58
+ return results.all()
59
+
60
+ def list_all_command(self, active_only: bool = True, load_relations: bool = False) -> List[Permission]:
61
+ with get_session(self.tenant) as session:
62
+ statement = select(Permission)
63
+
64
+ if active_only:
65
+ statement = statement.where(Permission.is_active == True)
66
+
67
+ if load_relations:
68
+ statement = statement.options(
69
+ selectinload(Permission.roles),
70
+ selectinload(Permission.users)
71
+ )
72
+
73
+ results = session.exec(statement)
74
+ return results.all()
75
+
76
+ def update_command(self, permission: Permission) -> Permission:
77
+ with get_session(self.tenant) as session:
78
+ db_permission = session.merge(permission)
79
+ session.commit()
80
+ session.refresh(db_permission)
81
+ return db_permission
82
+
83
+ def delete_command(self, permission_id: UUID, soft_delete: bool = True) -> bool:
84
+ with get_session(self.tenant) as session:
85
+ db_permission = session.get(Permission, permission_id)
86
+ if not db_permission:
87
+ return False
88
+
89
+ if soft_delete:
90
+ db_permission.is_active = False
91
+ session.add(db_permission)
92
+ else:
93
+ session.delete(db_permission)
94
+
95
+ session.commit()
96
+ return True
97
+
98
+ def count_command(self, active_only: bool = True) -> int:
99
+ with get_session(self.tenant) as session:
100
+ statement = select(Permission)
101
+ if active_only:
102
+ statement = statement.where(Permission.is_active == True)
103
+ results = session.exec(statement)
104
+ return len(results.all())
105
+
106
+ def exists_by_name_command(self, name: str) -> bool:
107
+ with get_session(self.tenant) as session:
108
+ statement = select(Permission).where(Permission.name == name)
109
+ result = session.exec(statement).first()
110
+ return result is not None
111
+
112
+ # ROLE COMMANDS
113
+
114
+ def get_permission_roles_command(self, permission_id: UUID) -> List[Role]:
115
+ with get_session(self.tenant) as session:
116
+ statement = select(Permission).options(selectinload(Permission.roles)).where(
117
+ Permission.permission_id == permission_id
118
+ )
119
+ permission = session.exec(statement).first()
120
+ if not permission:
121
+ return []
122
+ return permission.roles
123
+
124
+ def assign_to_role_command(self, permission_id: UUID, role_id: UUID) -> Optional[Permission]:
125
+ with get_session(self.tenant) as session:
126
+ permission_statement = select(Permission).options(selectinload(Permission.roles)).where(
127
+ Permission.permission_id == permission_id
128
+ )
129
+ permission = session.exec(permission_statement).first()
130
+ if not permission:
131
+ return None
132
+
133
+ role = session.get(Role, role_id)
134
+ if not role:
135
+ return None
136
+
137
+ if role not in permission.roles:
138
+ permission.roles.append(role)
139
+ session.add(permission)
140
+ session.commit()
141
+ session.refresh(permission)
142
+
143
+ return permission
144
+
145
+ def remove_from_role_command(self, permission_id: UUID, role_id: UUID) -> Optional[Permission]:
146
+ with get_session(self.tenant) as session:
147
+ permission_statement = select(Permission).options(selectinload(Permission.roles)).where(
148
+ Permission.permission_id == permission_id
149
+ )
150
+ permission = session.exec(permission_statement).first()
151
+ if not permission:
152
+ return None
153
+
154
+ role = session.get(Role, role_id)
155
+ if not role:
156
+ return None
157
+
158
+ if role in permission.roles:
159
+ permission.roles.remove(role)
160
+ session.add(permission)
161
+ session.commit()
162
+ session.refresh(permission)
163
+
164
+ return permission
165
+
166
+ def is_assigned_to_role_command(self, permission_id: UUID, role_id: UUID) -> bool:
167
+ with get_session(self.tenant) as session:
168
+ statement = select(Permission).options(selectinload(Permission.roles)).where(
169
+ Permission.permission_id == permission_id
170
+ )
171
+ permission = session.exec(statement).first()
172
+ if not permission:
173
+ return False
174
+ return any(role.role_id == role_id for role in permission.roles)
175
+
176
+ # USER COMMANDS
177
+
178
+ def get_permission_users_command(self, permission_id: UUID) -> List[User]:
179
+ with get_session(self.tenant) as session:
180
+ statement = select(Permission).options(selectinload(Permission.users)).where(
181
+ Permission.permission_id == permission_id
182
+ )
183
+ permission = session.exec(statement).first()
184
+ if not permission:
185
+ return []
186
+ return permission.users
187
+
188
+ def assign_to_user_command(self, permission_id: UUID, user_id: UUID) -> Optional[Permission]:
189
+ with get_session(self.tenant) as session:
190
+ permission_statement = select(Permission).options(selectinload(Permission.users)).where(
191
+ Permission.permission_id == permission_id
192
+ )
193
+ permission = session.exec(permission_statement).first()
194
+ if not permission:
195
+ return None
196
+
197
+ user = session.get(User, user_id)
198
+ if not user:
199
+ return None
200
+
201
+ if user not in permission.users:
202
+ permission.users.append(user)
203
+ session.add(permission)
204
+ session.commit()
205
+ session.refresh(permission)
206
+
207
+ return permission
208
+
209
+ def remove_from_user_command(self, permission_id: UUID, user_id: UUID) -> Optional[Permission]:
210
+ with get_session(self.tenant) as session:
211
+ permission_statement = select(Permission).options(selectinload(Permission.users)).where(
212
+ Permission.permission_id == permission_id
213
+ )
214
+ permission = session.exec(permission_statement).first()
215
+ if not permission:
216
+ return None
217
+
218
+ user = session.get(User, user_id)
219
+ if not user:
220
+ return None
221
+
222
+ if user in permission.users:
223
+ permission.users.remove(user)
224
+ session.add(permission)
225
+ session.commit()
226
+ session.refresh(permission)
227
+
228
+ return permission
229
+
230
+ def is_assigned_to_user_command(self, permission_id: UUID, user_id: UUID) -> bool:
231
+ with get_session(self.tenant) as session:
232
+ statement = select(Permission).options(selectinload(Permission.users)).where(
233
+ Permission.permission_id == permission_id
234
+ )
235
+ permission = session.exec(statement).first()
236
+ if not permission:
237
+ return False
238
+ return any(user.user_id == user_id for user in permission.users)
@@ -0,0 +1,174 @@
1
+ from typing import Optional, List
2
+ from uuid import UUID
3
+ from sqlmodel import select
4
+ from sqlalchemy.orm import selectinload
5
+
6
+ from models import Role
7
+ from models import Permission
8
+ from models import User
9
+ from config.db import engines, get_session
10
+
11
+ class RoleRepository:
12
+ def __init__(self, tenant: str):
13
+ self.tenant = tenant
14
+ if tenant not in engines:
15
+ raise ValueError(f"Tenant {tenant} is not configured")
16
+
17
+ def create_command(self, role: Role) -> Role:
18
+ with get_session(self.tenant) as session:
19
+ session.add(role)
20
+ session.commit()
21
+ session.refresh(role)
22
+ return role
23
+
24
+ def get_by_id_command(self, role_id: UUID, load_relations: bool = False) -> Optional[Role]:
25
+ with get_session(self.tenant) as session:
26
+ if load_relations:
27
+ statement = select(Role).where(Role.role_id == role_id).options(
28
+ selectinload(Role.permissions),
29
+ selectinload(Role.users)
30
+ )
31
+ return session.exec(statement).first()
32
+ else:
33
+ return session.get(Role, role_id)
34
+
35
+ def get_by_name_command(self, name: str, load_relations: bool = False) -> Optional[Role]:
36
+ with get_session(self.tenant) as session:
37
+ statement = select(Role).where(Role.name == name)
38
+
39
+ if load_relations:
40
+ statement = statement.options(
41
+ selectinload(Role.permissions),
42
+ selectinload(Role.users)
43
+ )
44
+
45
+ return session.exec(statement).first()
46
+
47
+ def search_by_name_command(self, name: str, load_relations: bool = False) -> List[Role]:
48
+ with get_session(self.tenant) as session:
49
+ statement = select(Role).where(Role.name.ilike(f"%{name}%"))
50
+
51
+ if load_relations:
52
+ statement = statement.options(
53
+ selectinload(Role.permissions),
54
+ selectinload(Role.users)
55
+ )
56
+
57
+ results = session.exec(statement)
58
+ return results.all()
59
+
60
+ def list_all_command(self, active_only: bool = True, load_relations: bool = False) -> List[Role]:
61
+ with get_session(self.tenant) as session:
62
+ statement = select(Role)
63
+
64
+ if active_only:
65
+ statement = statement.where(Role.is_active == True)
66
+
67
+ if load_relations:
68
+ statement = statement.options(
69
+ selectinload(Role.permissions),
70
+ selectinload(Role.users)
71
+ )
72
+
73
+ results = session.exec(statement)
74
+ return results.all()
75
+
76
+ def update_command(self, role: Role) -> Role:
77
+ with get_session(self.tenant) as session:
78
+ db_role = session.merge(role)
79
+ session.commit()
80
+ session.refresh(db_role)
81
+ return db_role
82
+
83
+ def delete_command(self, role_id: UUID, soft_delete: bool = True) -> bool:
84
+ with get_session(self.tenant) as session:
85
+ db_role = session.get(Role, role_id)
86
+ if not db_role:
87
+ return False
88
+
89
+ if soft_delete:
90
+ db_role.is_active = False
91
+ session.add(db_role)
92
+ else:
93
+ session.delete(db_role)
94
+
95
+ session.commit()
96
+ return True
97
+
98
+ def count_command(self, active_only: bool = True) -> int:
99
+ with get_session(self.tenant) as session:
100
+ statement = select(Role)
101
+ if active_only:
102
+ statement = statement.where(Role.is_active == True)
103
+ results = session.exec(statement)
104
+ return len(results.all())
105
+
106
+ def exists_by_name_command(self, name: str) -> bool:
107
+ with get_session(self.tenant) as session:
108
+ statement = select(Role).where(Role.name == name)
109
+ result = session.exec(statement).first()
110
+ return result is not None
111
+
112
+ # RELATIONS COMMANDS
113
+
114
+ def get_role_permissions_command(self, role_id: UUID) -> List[Permission]:
115
+ with get_session(self.tenant) as session:
116
+ statement = select(Role).options(selectinload(Role.permissions)).where(Role.role_id == role_id)
117
+ role = session.exec(statement).first()
118
+ if not role:
119
+ return []
120
+ return role.permissions
121
+
122
+ def get_role_users_command(self, role_id: UUID) -> List[User]:
123
+ with get_session(self.tenant) as session:
124
+ statement = select(Role).options(selectinload(Role.users)).where(Role.role_id == role_id)
125
+ role = session.exec(statement).first()
126
+ if not role:
127
+ return []
128
+ return role.users
129
+
130
+ def assign_permission_command(self, role_id: UUID, permission_id: UUID) -> Optional[Role]:
131
+ with get_session(self.tenant) as session:
132
+ role_statement = select(Role).options(selectinload(Role.permissions)).where(Role.role_id == role_id)
133
+ role = session.exec(role_statement).first()
134
+ if not role:
135
+ return None
136
+
137
+ permission = session.get(Permission, permission_id)
138
+ if not permission:
139
+ return None
140
+
141
+ if permission not in role.permissions:
142
+ role.permissions.append(permission)
143
+ session.add(role)
144
+ session.commit()
145
+ session.refresh(role)
146
+
147
+ return role
148
+
149
+ def remove_permission_command(self, role_id: UUID, permission_id: UUID) -> Optional[Role]:
150
+ with get_session(self.tenant) as session:
151
+ role_statement = select(Role).options(selectinload(Role.permissions)).where(Role.role_id == role_id)
152
+ role = session.exec(role_statement).first()
153
+ if not role:
154
+ return None
155
+
156
+ permission = session.get(Permission, permission_id)
157
+ if not permission:
158
+ return None
159
+
160
+ if permission in role.permissions:
161
+ role.permissions.remove(permission)
162
+ session.add(role)
163
+ session.commit()
164
+ session.refresh(role)
165
+
166
+ return role
167
+
168
+ def has_permission_command(self, role_id: UUID, permission_name: str) -> bool:
169
+ with get_session(self.tenant) as session:
170
+ statement = select(Role).options(selectinload(Role.permissions)).where(Role.role_id == role_id)
171
+ role = session.exec(statement).first()
172
+ if not role:
173
+ return False
174
+ return any(perm.name == permission_name for perm in role.permissions)