ipulse-shared-core-ftredge 27.3.0__py3-none-any.whl → 27.4.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 ipulse-shared-core-ftredge might be problematic. Click here for more details.

@@ -16,6 +16,10 @@ class BaseAPIResponse(BaseModel, Generic[T]):
16
16
  message: Optional[str] = None
17
17
  error: Optional[str] = None
18
18
 
19
+ # Optional fields for specific use cases
20
+ cache_hit: Optional[bool] = None # Whether data came from cache
21
+ charged: Optional[bool] = None # Whether credits were charged for this request
22
+
19
23
  metadata: Dict[str, Any] = {
20
24
  "timestamp": dt.datetime.now(dt.timezone.utc).isoformat()
21
25
  }
@@ -1,13 +1,14 @@
1
1
  """Cache-aware Firestore service base class."""
2
2
  import time
3
- from typing import TypeVar, Generic, Dict, Any, List, Optional, Union, Type
3
+ from typing import TypeVar, Generic, Dict, Any, List, Optional, Union, Type, Tuple
4
4
  from google.cloud import firestore
5
5
  from . import BaseFirestoreService
6
6
  from ...exceptions import ResourceNotFoundError, ServiceError
7
7
  from ...cache.shared_cache import SharedCache
8
8
  from ...models import BaseDataModel
9
9
 
10
- T = TypeVar('T', bound=BaseDataModel)
10
+ T = TypeVar('T', bound=BaseDataModel)0
11
+ 0
11
12
 
12
13
  class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
13
14
  """
@@ -58,7 +59,9 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
58
59
  cache_check_time = (time.time() - start_time) * 1000
59
60
 
60
61
  if cached_doc is not None:
61
- self.logger.debug(f"Cache HIT for document {doc_id} in {cache_check_time:.2f}ms")
62
+ # SharedCache.get() already logs cache hit, only log timing if significant
63
+ if cache_check_time > 5.0: # Only log if cache check took >5ms
64
+ self.logger.debug(f"Cache HIT for document {doc_id} in {cache_check_time:.2f}ms")
62
65
  if convert_to_model and self.model_class:
63
66
  return self._convert_to_model(cached_doc, doc_id)
64
67
  else:
@@ -68,7 +71,66 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
68
71
  self.logger.debug(f"Cache MISS for document {doc_id} - checking Firestore")
69
72
 
70
73
  # Fetch from Firestore using parent method
71
- return await super().get_document(doc_id, convert_to_model)
74
+ result = await super().get_document(doc_id, convert_to_model)
75
+
76
+ # Cache the result if we have a cache and got valid data
77
+ if self.document_cache and result is not None:
78
+ if convert_to_model and isinstance(result, BaseDataModel):
79
+ # Cache the model's dict representation
80
+ self._cache_document_data(doc_id, result.model_dump())
81
+ elif isinstance(result, dict):
82
+ # Cache the dict directly
83
+ self._cache_document_data(doc_id, result)
84
+
85
+ return result
86
+
87
+ async def get_document_with_cache_info(self, doc_id: str, convert_to_model: bool = True) -> Tuple[Union[T, Dict[str, Any], None], bool]:
88
+ """
89
+ Get a document with cache hit information.
90
+
91
+ Args:
92
+ doc_id: Document ID to fetch
93
+ convert_to_model: Whether to convert to Pydantic model
94
+
95
+ Returns:
96
+ Tuple of (document, cache_hit) where cache_hit indicates if from cache
97
+
98
+ Raises:
99
+ ResourceNotFoundError: If document doesn't exist
100
+ """
101
+ cache_hit = False
102
+
103
+ # Check cache first
104
+ if self.document_cache:
105
+ cached_doc = self.document_cache.get(doc_id)
106
+ if cached_doc is not None:
107
+ cache_hit = True
108
+ # Note: SharedCache.get() already logs cache hit at DEBUG level
109
+ if convert_to_model and self.model_class:
110
+ return self._convert_to_model(cached_doc, doc_id), cache_hit
111
+ else:
112
+ cached_doc['id'] = doc_id
113
+ return cached_doc, cache_hit
114
+
115
+ # Cache miss - fetch from Firestore
116
+ self.logger.debug(f"Cache MISS for document {doc_id} - checking Firestore")
117
+
118
+ try:
119
+ result = await super().get_document(doc_id, convert_to_model)
120
+
121
+ # Cache the result if we have a cache and got valid data
122
+ if self.document_cache and result is not None:
123
+ if convert_to_model and isinstance(result, BaseDataModel):
124
+ # Cache the model's dict representation
125
+ self._cache_document_data(doc_id, result.model_dump())
126
+ elif isinstance(result, dict):
127
+ # Cache the dict directly
128
+ self._cache_document_data(doc_id, result)
129
+
130
+ return result, cache_hit
131
+
132
+ except ResourceNotFoundError:
133
+ return None, cache_hit
72
134
 
73
135
  async def get_all_documents(self, cache_key: Optional[str] = None, as_models: bool = True) -> Union[List[T], List[Dict[str, Any]]]:
74
136
  """
@@ -151,7 +213,7 @@ class CacheAwareFirestoreService(BaseFirestoreService[T], Generic[T]):
151
213
  """Helper to cache document data if document_cache is available."""
152
214
  if self.document_cache:
153
215
  self.document_cache.set(doc_id, data)
154
- self.logger.debug(f"Cached item {doc_id} in {self.document_cache.name}")
216
+ # Note: SharedCache.set() already logs at DEBUG level
155
217
 
156
218
  async def create_document(self, doc_id: str, data: Union[T, Dict[str, Any]], creator_uid: str, merge: bool = False) -> Dict[str, Any]:
157
219
  """Create document and invalidate cache."""
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 27.3.0
3
+ Version: 27.4.0
4
4
  Summary: Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.
5
5
  Home-page: https://github.com/TheFutureEdge/ipulse_shared_core
6
6
  Author: Russlan Ramdowar
@@ -11,7 +11,7 @@ ipulse_shared_core_ftredge/exceptions/__init__.py,sha256=Cb_RsIie4DbT_NLwFVwjw4r
11
11
  ipulse_shared_core_ftredge/exceptions/base_exceptions.py,sha256=117YsiCbYLLBu_D0IffYFVSX2yh-pisALMtoSMwj6xI,5338
12
12
  ipulse_shared_core_ftredge/exceptions/user_exceptions.py,sha256=I-nm21MKrUYEoybpRODeYNzc184HfgHvRZQm_xux4VY,6824
13
13
  ipulse_shared_core_ftredge/models/__init__.py,sha256=jhaVbOzJiFUf24saV1-a4GeKUaPif3jqAnIr4wgiUVs,455
14
- ipulse_shared_core_ftredge/models/base_api_response.py,sha256=g7f1jH3VkEyMuW-d_j3ex2zk8LO2EMlkYRJQqYic_KU,792
14
+ ipulse_shared_core_ftredge/models/base_api_response.py,sha256=vEcy5BDXcuJFldWq8FgadSAiq0kbVFA8BYVIpY3n9aE,993
15
15
  ipulse_shared_core_ftredge/models/base_data_model.py,sha256=GZ7KTT5FanHTgvmaHHTxawzAJtuixkbyb-SuL-mjWys,2193
16
16
  ipulse_shared_core_ftredge/models/credit_api_response.py,sha256=gavsJeuIsQJmY1t8DPzRZP5da68DT6IknE_oAeoapTc,797
17
17
  ipulse_shared_core_ftredge/models/custom_json_response.py,sha256=5WCqpb6YEzZQitXE9DdnPv3x-me_0iV_qmd6laeiPWA,1396
@@ -32,7 +32,7 @@ ipulse_shared_core_ftredge/services/charging_processors.py,sha256=Ynt8nQZprdsny9
32
32
  ipulse_shared_core_ftredge/services/user_charging_service.py,sha256=WNVGn77Rcy_Al3M9wF0VZPYQVWL__E2baVRDQeA37I4,14609
33
33
  ipulse_shared_core_ftredge/services/base/__init__.py,sha256=hP2x_F07nycNj6_WCIQE7-8o84cIRj-tZlGwrA1yIcI,491
34
34
  ipulse_shared_core_ftredge/services/base/base_firestore_service.py,sha256=leZFwxb1ruheypqudpKnuNtRQXtO4KNeoJk6ZACozHc,19512
35
- ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py,sha256=ya5Asff9BQodYnJVAw6M_Pm8WtVRPpEK7izFlZ2MyjA,10016
35
+ ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py,sha256=cMqXKat956BJR7qzPHLhAOvgFsjin9-GdQgVut1f3XI,12563
36
36
  ipulse_shared_core_ftredge/services/base/multi_collection_cache_aware_firestore_service.py,sha256=Z-L20YkGhArTlwabPsqRXew-o87oL_9B5WOEh5zF0A4,10739
37
37
  ipulse_shared_core_ftredge/services/catalog/__init__.py,sha256=ctc2nDGwsW_Ji4lk9pys3oyNwR_V-gHSbSHawym5fKQ,385
38
38
  ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py,sha256=X5xAi9sOk_F1ky0ECwPVlwIPPsN2PrZC6bN_pASGDjQ,9702
@@ -47,11 +47,10 @@ ipulse_shared_core_ftredge/services/user/userauth_operations.py,sha256=QY_ueDei4
47
47
  ipulse_shared_core_ftredge/services/user/userprofile_operations.py,sha256=_qyIEAQYCTV-subgP-5naMs_26apCpauomE6qmCCVWs,7333
48
48
  ipulse_shared_core_ftredge/services/user/userstatus_operations.py,sha256=Om9d94cM4uOdTmCNXECU0hFtsUZ-o-OLMEiLAG74YUQ,22730
49
49
  ipulse_shared_core_ftredge/utils/__init__.py,sha256=JnxUb8I2MRjJC7rBPXSrpwBIQDEOku5O9JsiTi3oun8,56
50
- ipulse_shared_core_ftredge/utils/authz_credit_extraction.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
51
50
  ipulse_shared_core_ftredge/utils/custom_json_encoder.py,sha256=DblQLD0KOSNDyQ58wQRogBrShIXzPIZUw_oGOBATnJY,1366
52
51
  ipulse_shared_core_ftredge/utils/json_encoder.py,sha256=QkcaFneVv3-q-s__Dz4OiUWYnM6jgHDJrDMdPv09RCA,2093
53
- ipulse_shared_core_ftredge-27.3.0.dist-info/licenses/LICENCE,sha256=YBtYAXNqCCOo9Mr2hfkbSPAM9CeAr2j1VZBSwQTrNwE,1060
54
- ipulse_shared_core_ftredge-27.3.0.dist-info/METADATA,sha256=9kTpPalCVGts8D7cxf5LFMCzSpcP-C_nVlfZRZeZWu0,782
55
- ipulse_shared_core_ftredge-27.3.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
56
- ipulse_shared_core_ftredge-27.3.0.dist-info/top_level.txt,sha256=8sgYrptpexkA_6_HyGvho26cVFH9kmtGvaK8tHbsGHk,27
57
- ipulse_shared_core_ftredge-27.3.0.dist-info/RECORD,,
52
+ ipulse_shared_core_ftredge-27.4.0.dist-info/licenses/LICENCE,sha256=YBtYAXNqCCOo9Mr2hfkbSPAM9CeAr2j1VZBSwQTrNwE,1060
53
+ ipulse_shared_core_ftredge-27.4.0.dist-info/METADATA,sha256=8oj6rngXz42Rf_-m4Qj5LL-aBTTW5MxsOnlGn6vaEhI,782
54
+ ipulse_shared_core_ftredge-27.4.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
55
+ ipulse_shared_core_ftredge-27.4.0.dist-info/top_level.txt,sha256=8sgYrptpexkA_6_HyGvho26cVFH9kmtGvaK8tHbsGHk,27
56
+ ipulse_shared_core_ftredge-27.4.0.dist-info/RECORD,,