Coverage for functions \ flipdare \ manager \ db_manager.py: 72%
268 statements
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
« prev ^ index » next coverage.py v7.13.0, created at 2026-05-08 12:22 +1000
1#!/usr/bin/env python
2# Copyright (c) 2026 Flipdare Pty Ltd. All rights reserved.
3#
4# This file is part of Flipdare's proprietary software and contains
5# confidential and copyrighted material. Unauthorised copying,
6# modification, distribution, or use of this file is strictly
7# prohibited without prior written permission from Flipdare Pty Ltd.
8#
9# This software includes third-party components licensed under MIT,
10# BSD, and Apache 2.0 licences. See THIRD_PARTY_NOTICES for details.
11#
12from typing import Any
14from google.cloud.firestore import Client as FirestoreClient
15from flipdare.app_log import LOG
16from flipdare.app_types import (
17 ChatBridge,
18 ComplianceBridge,
19 ContentBridge,
20 DareBridge,
21 FlagBridge,
22 FriendBridge,
23 GroupBridge,
24 InviteBridge,
25 PledgeBridge,
26 RestrictionBridge,
27 UserBridge,
28)
29from flipdare.core.singleton import Singleton
30from flipdare.firestore._app_db import AppDb
31from flipdare.firestore.backend.app_job_db import AppJobDb
32from flipdare.firestore.backend.app_log_db import AppLogDb
33from flipdare.firestore.backend.app_stat_db import AppStatDb
34from flipdare.firestore.backend.compliance_db import ComplianceDb
35from flipdare.firestore.backend.exchange_rate_db import ExchangeRateDb
36from flipdare.firestore.backend.run_config_group_db import RunConfigGroupDb
37from flipdare.firestore.backend.run_config_job_db import RunConfigJobDb
38from flipdare.firestore.chat_db import ChatDb
39from flipdare.firestore.content_db import ContentDb
40from flipdare.firestore.dare_db import DareDb
41from flipdare.firestore.db_bridge import DbBridge
42from flipdare.firestore.flag_db import FlagDb
43from flipdare.firestore.friend_db import FriendDb
44from flipdare.firestore.group_db import GroupDb
45from flipdare.firestore.invite_db import InviteDb
46from flipdare.firestore.issue_db import IssueDb
47from flipdare.firestore.payment_issue_db import PaymentIssueDb
48from flipdare.firestore.pledge_db import PledgeDb
49from flipdare.firestore.restriction_db import RestrictionDb
50from flipdare.firestore.user_db import UserDb
51from flipdare.firestore.user_summary_db import UserSummaryDb
52from flipdare.generated.shared.firestore_collections import FirestoreCollections
54__all__ = ["DbManager"]
57class DbManager(Singleton):
58 """Class for managing database operations across different collections."""
60 def __init__(self, client: FirestoreClient) -> None:
61 super().__init__()
63 self._client = client
64 self._dare_db: DareDb | None = None
65 self._user_db: UserDb | None = None
66 self._group_db: GroupDb | None = None
67 self._invite_db: InviteDb | None = None
68 self._friend_db: FriendDb | None = None
69 self._flag_db: FlagDb | None = None
70 self._restriction_db: RestrictionDb | None = None
71 self._exchange_rate_db: ExchangeRateDb | None = None
72 self._pledge_db: PledgeDb | None = None
73 self._stat_db: AppStatDb | None = None
74 self._job_db: AppJobDb | None = None
75 self._log_db: AppLogDb | None = None
76 self._content_db: ContentDb | None = None
77 self._summary_db: UserSummaryDb | None = None
78 self._chat_db: ChatDb | None = None
79 self._issue_db: IssueDb | None = None
80 self._payment_issue_db: PaymentIssueDb | None = None
81 self._compliance_db: ComplianceDb | None = None
82 self._runtime_group_db: RunConfigGroupDb | None = None
83 self._runtime_job_db: RunConfigJobDb | None = None
85 self._user_bridge: UserBridge | None = None
86 self._friend_bridge: FriendBridge | None = None
87 self._group_bridge: GroupBridge | None = None
88 self._invite_bridge: InviteBridge | None = None
89 self._dare_bridge: DareBridge | None = None
90 self._pledge_bridge: PledgeBridge | None = None
91 self._flag_bridge: FlagBridge | None = None
92 self._content_bridge: ContentBridge | None = None
93 self._chat_bridge: ChatBridge | None = None
94 self._compliance_bridge: ComplianceBridge | None = None
95 self._restriction_bridge: RestrictionBridge | None = None
97 @property
98 def database_client(self) -> FirestoreClient:
99 return self._client
101 # -------------------------------------------------------------------------
102 # Databases
103 # -------------------------------------------------------------------------
105 @property
106 def dare_db(self) -> DareDb:
107 if self._dare_db is None:
108 self._dare_db = DareDb(self.database_client)
110 return self._dare_db
112 @dare_db.setter
113 def dare_db(self, db: DareDb) -> None:
114 self._dare_db = db
116 @property
117 def user_db(self) -> UserDb:
118 if self._user_db is None:
119 self._user_db = UserDb(self.database_client)
121 return self._user_db
123 @property
124 def group_db(self) -> GroupDb:
125 if self._group_db is None:
126 self._group_db = GroupDb(self.database_client)
127 return self._group_db
129 @property
130 def invite_db(self) -> InviteDb:
131 if self._invite_db is None:
132 self._invite_db = InviteDb(self.database_client)
133 return self._invite_db
135 @property
136 def friend_db(self) -> FriendDb:
137 if self._friend_db is None:
138 self._friend_db = FriendDb(self.database_client)
139 return self._friend_db
141 @property
142 def flag_db(self) -> FlagDb:
143 if self._flag_db is None:
144 self._flag_db = FlagDb(self.database_client)
145 return self._flag_db
147 @property
148 def issue_db(self) -> IssueDb:
149 if self._issue_db is None:
150 self._issue_db = IssueDb(self.database_client)
151 return self._issue_db
153 @property
154 def payment_issue_db(self) -> PaymentIssueDb:
155 if self._payment_issue_db is None:
156 self._payment_issue_db = PaymentIssueDb(self.database_client)
157 return self._payment_issue_db
159 @property
160 def restriction_db(self) -> RestrictionDb:
161 if self._restriction_db is None:
162 self._restriction_db = RestrictionDb(self.database_client)
163 return self._restriction_db
165 @property
166 def pledge_db(self) -> PledgeDb:
167 if self._pledge_db is None:
168 self._pledge_db = PledgeDb(self.database_client)
169 return self._pledge_db
171 @property
172 def content_db(self) -> ContentDb:
173 if self._content_db is None:
174 self._content_db = ContentDb(self.database_client)
175 return self._content_db
177 @property
178 def chat_db(self) -> ChatDb:
179 if self._chat_db is None:
180 self._chat_db = ChatDb(self.database_client)
181 return self._chat_db
183 # internal/admin
184 @property
185 def stat_db(self) -> AppStatDb:
186 if self._stat_db is None:
187 self._stat_db = AppStatDb(self.database_client)
188 return self._stat_db
190 @property
191 def exchange_rate_db(self) -> ExchangeRateDb:
192 if self._exchange_rate_db is None:
193 self._exchange_rate_db = ExchangeRateDb(self.database_client)
194 return self._exchange_rate_db
196 @property
197 def job_db(self) -> AppJobDb:
198 if self._job_db is None:
199 self._job_db = AppJobDb(self.database_client)
200 return self._job_db
202 @property
203 def log_db(self) -> AppLogDb:
204 if self._log_db is None:
205 self._log_db = AppLogDb(self.database_client)
206 return self._log_db
208 @property
209 def summary_db(self) -> UserSummaryDb:
210 if self._summary_db is None:
211 self._summary_db = UserSummaryDb(self.database_client)
212 return self._summary_db
214 @property
215 def run_group_db(self) -> RunConfigGroupDb:
216 if self._runtime_group_db is None:
217 self._runtime_group_db = RunConfigGroupDb(self.database_client)
218 return self._runtime_group_db
220 @property
221 def run_job_db(self) -> RunConfigJobDb:
222 if self._runtime_job_db is None:
223 self._runtime_job_db = RunConfigJobDb(self.database_client)
224 return self._runtime_job_db
226 @property
227 def compliance_db(self) -> ComplianceDb:
228 if self._compliance_db is None:
229 self._compliance_db = ComplianceDb(self.database_client)
230 return self._compliance_db
232 # -------------------------------------------------------------------------
233 # Bridges
234 # -------------------------------------------------------------------------
236 @property
237 def user_bridge(self) -> UserBridge:
238 if self._user_bridge is None:
239 self._user_bridge = DbBridge(self.user_db, "User")
240 return self._user_bridge
242 @property
243 def friend_bridge(self) -> FriendBridge:
244 if self._friend_bridge is None:
245 self._friend_bridge = DbBridge(self.friend_db, "Friend")
246 return self._friend_bridge
248 @property
249 def group_bridge(self) -> GroupBridge:
250 if self._group_bridge is None:
251 self._group_bridge = DbBridge(self.group_db, "Group")
252 return self._group_bridge
254 @property
255 def invite_bridge(self) -> InviteBridge:
256 if self._invite_bridge is None:
257 self._invite_bridge = DbBridge(self.invite_db, "Invite")
258 return self._invite_bridge
260 @property
261 def dare_bridge(self) -> DareBridge:
262 if self._dare_bridge is None:
263 self._dare_bridge = DbBridge(self.dare_db, "Dare")
264 return self._dare_bridge
266 @property
267 def pledge_bridge(self) -> PledgeBridge:
268 if self._pledge_bridge is None:
269 self._pledge_bridge = DbBridge(self.pledge_db, "Pledge")
270 return self._pledge_bridge
272 @property
273 def flag_bridge(self) -> FlagBridge:
274 if self._flag_bridge is None:
275 self._flag_bridge = DbBridge(self.flag_db, "Flag")
276 return self._flag_bridge
278 @property
279 def content_bridge(self) -> ContentBridge:
280 if self._content_bridge is None:
281 self._content_bridge = DbBridge(self.content_db, "Content")
282 return self._content_bridge
284 @property
285 def chat_bridge(self) -> ChatBridge:
286 if self._chat_bridge is None:
287 self._chat_bridge = DbBridge(self.chat_db, "Chat")
288 return self._chat_bridge
290 @property
291 def compliance_bridge(self) -> ComplianceBridge:
292 if self._compliance_bridge is None:
293 self._compliance_bridge = DbBridge(self.compliance_db, "Compliance")
294 return self._compliance_bridge
296 @property
297 def restriction_bridge(self) -> RestrictionBridge:
298 if self._restriction_bridge is None:
299 self._restriction_bridge = DbBridge(self.restriction_db, "Restriction")
300 return self._restriction_bridge
302 # -------------------------------------------------------------------------
303 # Misc
304 # -------------------------------------------------------------------------
306 def get_db_for_collection( # noqa: PLR0912
307 self,
308 collection: FirestoreCollections,
309 ) -> AppDb[Any, Any] | None:
310 match collection:
311 case FirestoreCollections.DARE:
312 return self.dare_db
313 case FirestoreCollections.USER:
314 return self.user_db
315 case FirestoreCollections.GROUP:
316 return self.group_db
317 case FirestoreCollections.INVITE:
318 return self.invite_db
319 case FirestoreCollections.FRIEND:
320 return self.friend_db
321 case FirestoreCollections.FLAG:
322 return self.flag_db
323 case FirestoreCollections.RESTRICTION:
324 return self.restriction_db
325 case FirestoreCollections.EXCHANGE_RATE:
326 return self.exchange_rate_db
327 case FirestoreCollections.PLEDGE:
328 return self.pledge_db
329 case FirestoreCollections.APP_JOB:
330 return self.job_db
331 case FirestoreCollections.APP_LOG:
332 return self.log_db
333 case FirestoreCollections.CONTENT:
334 return self.content_db
335 case FirestoreCollections.USER_SUMMARY:
336 return self.summary_db
337 case FirestoreCollections.CHAT:
338 return self.chat_db
339 case FirestoreCollections.ISSUE:
340 return self.issue_db
341 case FirestoreCollections.COMPLIANCE:
342 return self.compliance_db
343 case FirestoreCollections.RUNTIME_GROUP:
344 return self.run_group_db
345 case FirestoreCollections.RUNTIME_JOB:
346 return self.run_job_db
347 case FirestoreCollections.APP_STAT | FirestoreCollections.APP_STAT_METRIC:
348 return self.stat_db
349 case _:
350 # this should only occur for sub collections ..
351 LOG().warning(f"No AppDb found for collection {collection.value}")
352 return None