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.
- ipulse_shared_core_ftredge/models/base_api_response.py +4 -0
- ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py +67 -5
- {ipulse_shared_core_ftredge-27.3.0.dist-info → ipulse_shared_core_ftredge-27.4.0.dist-info}/METADATA +1 -1
- {ipulse_shared_core_ftredge-27.3.0.dist-info → ipulse_shared_core_ftredge-27.4.0.dist-info}/RECORD +7 -8
- ipulse_shared_core_ftredge/utils/authz_credit_extraction.py +0 -0
- {ipulse_shared_core_ftredge-27.3.0.dist-info → ipulse_shared_core_ftredge-27.4.0.dist-info}/WHEEL +0 -0
- {ipulse_shared_core_ftredge-27.3.0.dist-info → ipulse_shared_core_ftredge-27.4.0.dist-info}/licenses/LICENCE +0 -0
- {ipulse_shared_core_ftredge-27.3.0.dist-info → ipulse_shared_core_ftredge-27.4.0.dist-info}/top_level.txt +0 -0
|
@@ -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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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."""
|
{ipulse_shared_core_ftredge-27.3.0.dist-info → ipulse_shared_core_ftredge-27.4.0.dist-info}/METADATA
RENAMED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: ipulse_shared_core_ftredge
|
|
3
|
-
Version: 27.
|
|
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
|
{ipulse_shared_core_ftredge-27.3.0.dist-info → ipulse_shared_core_ftredge-27.4.0.dist-info}/RECORD
RENAMED
|
@@ -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=
|
|
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=
|
|
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.
|
|
54
|
-
ipulse_shared_core_ftredge-27.
|
|
55
|
-
ipulse_shared_core_ftredge-27.
|
|
56
|
-
ipulse_shared_core_ftredge-27.
|
|
57
|
-
ipulse_shared_core_ftredge-27.
|
|
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,,
|
|
File without changes
|
{ipulse_shared_core_ftredge-27.3.0.dist-info → ipulse_shared_core_ftredge-27.4.0.dist-info}/WHEEL
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|