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

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 

13 

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 

53 

54__all__ = ["DbManager"] 

55 

56 

57class DbManager(Singleton): 

58 """Class for managing database operations across different collections.""" 

59 

60 def __init__(self, client: FirestoreClient) -> None: 

61 super().__init__() 

62 

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 

84 

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 

96 

97 @property 

98 def database_client(self) -> FirestoreClient: 

99 return self._client 

100 

101 # ------------------------------------------------------------------------- 

102 # Databases 

103 # ------------------------------------------------------------------------- 

104 

105 @property 

106 def dare_db(self) -> DareDb: 

107 if self._dare_db is None: 

108 self._dare_db = DareDb(self.database_client) 

109 

110 return self._dare_db 

111 

112 @dare_db.setter 

113 def dare_db(self, db: DareDb) -> None: 

114 self._dare_db = db 

115 

116 @property 

117 def user_db(self) -> UserDb: 

118 if self._user_db is None: 

119 self._user_db = UserDb(self.database_client) 

120 

121 return self._user_db 

122 

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 

128 

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 

134 

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 

140 

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 

146 

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 

152 

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 

158 

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 

164 

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 

170 

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 

176 

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 

182 

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 

189 

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 

195 

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 

201 

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 

207 

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 

213 

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 

219 

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 

225 

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 

231 

232 # ------------------------------------------------------------------------- 

233 # Bridges 

234 # ------------------------------------------------------------------------- 

235 

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 

241 

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 

247 

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 

253 

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 

259 

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 

265 

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 

271 

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 

277 

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 

283 

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 

289 

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 

295 

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 

301 

302 # ------------------------------------------------------------------------- 

303 # Misc 

304 # ------------------------------------------------------------------------- 

305 

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