ipulse-shared-core-ftredge 27.1.1__tar.gz → 27.3.0__tar.gz

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.

Files changed (64) hide show
  1. {ipulse_shared_core_ftredge-27.1.1/src/ipulse_shared_core_ftredge.egg-info → ipulse_shared_core_ftredge-27.3.0}/PKG-INFO +2 -2
  2. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/setup.py +2 -2
  3. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py +2 -2
  4. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/catalog/usertype.py +2 -2
  5. ipulse_shared_core_ftredge-27.3.0/src/ipulse_shared_core_ftredge/models/time_series_packaged_dataset_model.py +45 -0
  6. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/user/user_subscription.py +2 -2
  7. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/user/userprofile.py +2 -2
  8. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/user/userstatus.py +2 -2
  9. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/__init__.py +1 -1
  10. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/base/__init__.py +1 -0
  11. ipulse_shared_core_ftredge-27.3.0/src/ipulse_shared_core_ftredge/services/base/multi_collection_cache_aware_firestore_service.py +244 -0
  12. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0/src/ipulse_shared_core_ftredge.egg-info}/PKG-INFO +2 -2
  13. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge.egg-info/SOURCES.txt +2 -0
  14. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge.egg-info/requires.txt +1 -1
  15. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/LICENCE +0 -0
  16. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/README.md +0 -0
  17. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/pyproject.toml +0 -0
  18. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/setup.cfg +0 -0
  19. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/__init__.py +0 -0
  20. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/cache/__init__.py +0 -0
  21. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/cache/shared_cache.py +0 -0
  22. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/dependencies/__init__.py +0 -0
  23. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/dependencies/auth_firebase_token_validation.py +0 -0
  24. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/dependencies/auth_protected_router.py +0 -0
  25. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/dependencies/authz_credit_extraction.py +0 -0
  26. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/dependencies/authz_for_apis.py +0 -0
  27. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/dependencies/firestore_client.py +0 -0
  28. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/exceptions/__init__.py +0 -0
  29. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/exceptions/base_exceptions.py +0 -0
  30. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/exceptions/user_exceptions.py +0 -0
  31. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/__init__.py +0 -0
  32. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/base_api_response.py +0 -0
  33. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/base_data_model.py +0 -0
  34. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/catalog/__init__.py +0 -0
  35. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/credit_api_response.py +0 -0
  36. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/custom_json_response.py +0 -0
  37. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/user/__init__.py +0 -0
  38. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/user/user_permissions.py +0 -0
  39. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/models/user/userauth.py +0 -0
  40. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/monitoring/__init__.py +0 -0
  41. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/monitoring/tracemon.py +0 -0
  42. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/base/base_firestore_service.py +0 -0
  43. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py +0 -0
  44. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/catalog/__init__.py +0 -0
  45. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py +0 -0
  46. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py +0 -0
  47. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/charging_processors.py +0 -0
  48. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/__init__.py +0 -0
  49. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/user_charging_operations.py +0 -0
  50. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/user_core_service.py +0 -0
  51. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/user_multistep_operations.py +0 -0
  52. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/user_permissions_operations.py +0 -0
  53. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/user_subscription_operations.py +0 -0
  54. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/userauth_operations.py +0 -0
  55. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/userprofile_operations.py +0 -0
  56. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user/userstatus_operations.py +0 -0
  57. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/services/user_charging_service.py +0 -0
  58. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/utils/__init__.py +0 -0
  59. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/utils/authz_credit_extraction.py +0 -0
  60. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/utils/custom_json_encoder.py +0 -0
  61. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge/utils/json_encoder.py +0 -0
  62. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge.egg-info/dependency_links.txt +0 -0
  63. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/src/ipulse_shared_core_ftredge.egg-info/top_level.txt +0 -0
  64. {ipulse_shared_core_ftredge-27.1.1 → ipulse_shared_core_ftredge-27.3.0}/tests/test_shared_cache.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 27.1.1
3
+ Version: 27.3.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
@@ -12,7 +12,7 @@ License-File: LICENCE
12
12
  Requires-Dist: pydantic[email]~=2.5
13
13
  Requires-Dist: python-dateutil~=2.8
14
14
  Requires-Dist: fastapi~=0.115.8
15
- Requires-Dist: ipulse_shared_base_ftredge==11.1.1
15
+ Requires-Dist: ipulse_shared_base_ftredge~=12.2.0
16
16
  Dynamic: author
17
17
  Dynamic: classifier
18
18
  Dynamic: home-page
@@ -3,7 +3,7 @@ from setuptools import setup, find_packages
3
3
 
4
4
  setup(
5
5
  name='ipulse_shared_core_ftredge',
6
- version='27.1.1',
6
+ version='27.3.0',
7
7
  package_dir={'': 'src'}, # Specify the source directory
8
8
  packages=find_packages(where='src'), # Look for packages in 'src'
9
9
  install_requires=[
@@ -11,7 +11,7 @@ setup(
11
11
  'pydantic[email]~=2.5',
12
12
  'python-dateutil~=2.8',
13
13
  'fastapi~=0.115.8',
14
- 'ipulse_shared_base_ftredge==11.1.1',
14
+ 'ipulse_shared_base_ftredge~=12.2.0',
15
15
  ],
16
16
  author='Russlan Ramdowar',
17
17
  description='Shared Core models and Logger util for the Pulse platform project. Using AI for financial advisory and investment management.',
@@ -10,7 +10,7 @@ from enum import StrEnum
10
10
  from datetime import datetime, timezone, timedelta
11
11
  from pydantic import Field, ConfigDict, field_validator,model_validator, BaseModel
12
12
  from ipulse_shared_base_ftredge import (Layer, Module, list_enums_as_lower_strings,
13
- Subject, SubscriptionPlanName,ObjectOverallStatus,
13
+ SystemSubject, SubscriptionPlanName,ObjectOverallStatus,
14
14
  SubscriptionStatus, TimeUnit)
15
15
  from ..base_data_model import BaseDataModel
16
16
  from ..user.user_permissions import UserPermission
@@ -60,7 +60,7 @@ class SubscriptionPlan(BaseDataModel):
60
60
  model_config = ConfigDict(extra="forbid")
61
61
 
62
62
  VERSION: ClassVar[float] = 1.0
63
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, Subject.CATALOG))
63
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.CATALOG))
64
64
  OBJ_REF: ClassVar[str] = "subscriptionplan"
65
65
 
66
66
  # System-managed fields
@@ -9,7 +9,7 @@ based on their user type (superadmin, admin, internal, authenticated, anonymous)
9
9
  from typing import Dict, Any, Optional, ClassVar, List
10
10
  from datetime import datetime
11
11
  from pydantic import Field, ConfigDict, field_validator, model_validator
12
- from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, Subject, ObjectOverallStatus
12
+ from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, ObjectOverallStatus
13
13
  from ipulse_shared_base_ftredge.enums.enums_iam import IAMUserType
14
14
  from ipulse_shared_core_ftredge.models.base_data_model import BaseDataModel
15
15
  from ipulse_shared_core_ftredge.models.user.user_permissions import UserPermission
@@ -28,7 +28,7 @@ class UserType(BaseDataModel):
28
28
  model_config = ConfigDict(extra="forbid")
29
29
 
30
30
  VERSION: ClassVar[float] = 1.0
31
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE.name, Subject.CATALOG.name))
31
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE.name, SystemSubject.CATALOG.name))
32
32
  OBJ_REF: ClassVar[str] = "usertype"
33
33
 
34
34
  # System-managed fields
@@ -0,0 +1,45 @@
1
+ # pylint: disable=missing-module-docstring, missing-class-docstring
2
+ from typing import List, Optional, TypeVar, Generic
3
+ from datetime import datetime
4
+ from pydantic import Field, BaseModel
5
+ from ipulse_shared_core_ftredge.models.base_data_model import BaseDataModel
6
+
7
+ # Generic type for the records within the dataset
8
+ RecordsSamplingType = TypeVar('RecordsSamplingType', bound=BaseModel)
9
+
10
+ class TimeSeriesPackagedDatasetModel(BaseDataModel, Generic[RecordsSamplingType]):
11
+ """
12
+ An intermediary model for time series datasets that holds aggregated records.
13
+ It provides a generic way to handle different types of time series records.
14
+ """
15
+ # Subject identification fields
16
+ subject_id: str = Field(default="", description="The unique identifier for the subject.")
17
+ pulse_sector_category: str = Field(default="", description="The sector category for the subject.")
18
+
19
+ # Schema identification fields
20
+ schema_id: str = Field(default="", description="The unique identifier for the schema.")
21
+ schema_name: str = Field(default="", description="The name of the schema.")
22
+ schema_version: int = Field(default=1, description="The version of the schema.")
23
+
24
+ # Generic lists for different temporal buckets of records
25
+ max_bulk_records: List[RecordsSamplingType] = Field(default_factory=list)
26
+ latest_bulk_records: Optional[List[RecordsSamplingType]] = Field(default_factory=list)
27
+ latest_intraday_records: Optional[List[RecordsSamplingType]] = Field(default_factory=list)
28
+
29
+ # Metadata fields
30
+ max_bulk_updated_at: Optional[datetime] = None
31
+ max_bulk_updated_by: Optional[str] = None
32
+ max_bulk_recent_date_id: Optional[datetime] = None
33
+ max_bulk_oldest_date_id: Optional[datetime] = None
34
+ latest_bulk_recent_date_id: Optional[datetime] = None
35
+ latest_bulk_oldest_date_id: Optional[datetime] = None
36
+ latest_record_updated_at: Optional[datetime] = None
37
+ latest_record_updated_by: Optional[str] = None
38
+ latest_record_change_id: Optional[str] = None
39
+ latest_intraday_bulk_updated_at: Optional[datetime] = None
40
+ latest_intraday_bulk_updated_by: Optional[str] = None
41
+
42
+ @property
43
+ def id(self) -> str:
44
+ """Return subject_id for backward compatibility and consistency."""
45
+ return self.subject_id
@@ -3,7 +3,7 @@ from dateutil.relativedelta import relativedelta
3
3
  import uuid
4
4
  from typing import Optional, ClassVar, Dict, Any, List
5
5
  from pydantic import Field, ConfigDict, model_validator
6
- from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, Subject, SubscriptionPlanName, SubscriptionStatus, TimeUnit
6
+ from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, SubscriptionPlanName, SubscriptionStatus, TimeUnit
7
7
  from ..base_data_model import BaseDataModel
8
8
  from .user_permissions import UserPermission
9
9
  # ORIGINAL AUTHOR ="russlan.ramdowar;russlan@ftredge.com"
@@ -22,7 +22,7 @@ class UserSubscription(BaseDataModel):
22
22
  model_config = ConfigDict(frozen=True, extra="forbid")
23
23
 
24
24
  VERSION: ClassVar[float] = 3.0 # Incremented version for direct fields instead of computed
25
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, Subject.SUBSCRIPTION))
25
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.SUBSCRIPTION))
26
26
  OBJ_REF: ClassVar[str] = "subscription"
27
27
 
28
28
  # System-managed fields (read-only)
@@ -3,7 +3,7 @@ from datetime import date, datetime
3
3
  import re # Add re import
4
4
  from typing import Set, Optional, ClassVar, Dict, Any, List
5
5
  from pydantic import EmailStr, Field, ConfigDict, model_validator, field_validator
6
- from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, Subject, IAMUserType
6
+ from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, IAMUserType
7
7
  from ..base_data_model import BaseDataModel
8
8
  # ORIGINAL AUTHOR ="Russlan Ramdowar;russlan@ftredge.com"
9
9
  # CLASS_ORGIN_DATE=datetime(2024, 2, 12, 20, 5)
@@ -17,7 +17,7 @@ class UserProfile(BaseDataModel):
17
17
 
18
18
  # Class constants
19
19
  VERSION: ClassVar[float] = 5.0 # Incremented version for primary_usertype addition
20
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, Subject.USER))
20
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.USER))
21
21
  OBJ_REF: ClassVar[str] = "userprofile"
22
22
 
23
23
  schema_version: float = Field(
@@ -2,7 +2,7 @@
2
2
  from datetime import datetime, timezone, timedelta
3
3
  from typing import Set, Optional, Dict, List, ClassVar, Any
4
4
  from pydantic import Field, ConfigDict, model_validator, field_validator
5
- from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, Subject, TimeUnit
5
+ from ipulse_shared_base_ftredge import Layer, Module, list_enums_as_lower_strings, SystemSubject, TimeUnit
6
6
  from ipulse_shared_base_ftredge.enums.enums_iam import IAMUnit
7
7
  from .user_subscription import UserSubscription
8
8
  from ..base_data_model import BaseDataModel
@@ -20,7 +20,7 @@ class UserStatus(BaseDataModel):
20
20
 
21
21
  # Class constants
22
22
  VERSION: ClassVar[float] = 7.0 # Major version bump for flattened IAM permissions structure
23
- DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, Subject.USER))
23
+ DOMAIN: ClassVar[str] = "_".join(list_enums_as_lower_strings(Layer.PULSE_APP, Module.CORE, SystemSubject.USER))
24
24
  OBJ_REF: ClassVar[str] = "userstatus"
25
25
 
26
26
  # Centralized collection name and document ID prefix
@@ -2,7 +2,7 @@
2
2
 
3
3
 
4
4
  # Import from base services
5
- from .base import BaseFirestoreService, CacheAwareFirestoreService
5
+ from .base import BaseFirestoreService, CacheAwareFirestoreService, MultiCollectionCacheAwareFirestoreService
6
6
 
7
7
  from .charging_processors import ChargingProcessor
8
8
  from .user_charging_service import UserChargingService
@@ -7,6 +7,7 @@ preventing circular import dependencies.
7
7
 
8
8
  from .base_firestore_service import BaseFirestoreService
9
9
  from .cache_aware_firestore_service import CacheAwareFirestoreService
10
+ from .multi_collection_cache_aware_firestore_service import MultiCollectionCacheAwareFirestoreService
10
11
 
11
12
  __all__ = [
12
13
  'BaseFirestoreService',
@@ -0,0 +1,244 @@
1
+ """
2
+ Generic multi-collection cache-aware Firestore service.
3
+
4
+ This service extends CacheAwareFirestoreService to support dynamic collection operations
5
+ while maintaining all proven infrastructure patterns. It's designed to be generic and
6
+ reusable across different model types.
7
+ """
8
+ from typing import Dict, Any, List, Optional, Union, Type, TypeVar, Generic
9
+ from google.cloud import firestore
10
+ from .cache_aware_firestore_service import CacheAwareFirestoreService
11
+ from ...exceptions import ServiceError, ValidationError, ResourceNotFoundError
12
+ from ...cache.shared_cache import SharedCache
13
+ from ...models import BaseDataModel
14
+ import logging
15
+
16
+ # Generic type for BaseDataModel subclasses
17
+ T = TypeVar('T', bound=BaseDataModel)
18
+
19
+
20
+ class MultiCollectionCacheAwareFirestoreService(CacheAwareFirestoreService[T], Generic[T]):
21
+ """
22
+ Generic multi-collection extension of CacheAwareFirestoreService.
23
+
24
+ This service extends the proven CacheAwareFirestoreService infrastructure to support
25
+ dynamic collection operations based on storage_location_path while maintaining
26
+ all caching, error handling, and CRUD capabilities.
27
+
28
+ This is a generic base class that can be extended for specific model types.
29
+ """
30
+
31
+ def __init__(self,
32
+ db: firestore.Client,
33
+ logger: logging.Logger,
34
+ model_class: Type[T],
35
+ resource_type: str,
36
+ base_collection_name: str,
37
+ timeout: float = 30.0):
38
+
39
+ # Initialize the parent CacheAwareFirestoreService with a base collection
40
+ # We'll override the collection_name dynamically per operation
41
+ super().__init__(
42
+ db=db,
43
+ collection_name=base_collection_name, # Base collection name
44
+ resource_type=resource_type,
45
+ model_class=model_class,
46
+ logger=logger,
47
+ document_cache=None, # We'll manage caches per collection
48
+ collection_cache=None, # We'll manage caches per collection
49
+ timeout=timeout
50
+ )
51
+
52
+ # Cache for per-collection cache instances
53
+ self._collection_caches: Dict[str, Dict[str, SharedCache]] = {}
54
+
55
+ self.logger.info(f"MultiCollectionCacheAwareFirestoreService initialized for {resource_type}")
56
+
57
+ def _get_collection_caches(self, storage_location_path: str) -> Dict[str, SharedCache]:
58
+ """Get or create cache instances for a specific storage location."""
59
+ if storage_location_path not in self._collection_caches:
60
+ # Create collection-specific cache instances
61
+ # No need for safe_name transformation - dots are fine in strings
62
+
63
+ document_cache = SharedCache(
64
+ name=f"MultiColDoc_{storage_location_path}",
65
+ ttl=600.0, # 10 minutes
66
+ enabled=True,
67
+ logger=self.logger
68
+ )
69
+
70
+ collection_cache = SharedCache(
71
+ name=f"MultiColCollection_{storage_location_path}",
72
+ ttl=600.0, # 10 minutes
73
+ enabled=True,
74
+ logger=self.logger
75
+ )
76
+
77
+ self._collection_caches[storage_location_path] = {
78
+ 'document': document_cache,
79
+ 'collection': collection_cache
80
+ }
81
+
82
+ self.logger.info(f"Created cache instances for collection: {storage_location_path}")
83
+
84
+ return self._collection_caches[storage_location_path]
85
+
86
+ def _set_collection_context(self, storage_location_path: str):
87
+ """Set the collection context for the current operation."""
88
+ # Update the collection name for this operation
89
+ self.collection_name = storage_location_path
90
+
91
+ # Update the cache references for this collection
92
+ caches = self._get_collection_caches(storage_location_path)
93
+ self.document_cache = caches['document']
94
+ self.collection_cache = caches['collection']
95
+
96
+ async def get_document_from_collection(self,
97
+ storage_location_path: str,
98
+ doc_id: str,
99
+ convert_to_model: bool = True) -> Union[T, Dict[str, Any], None]:
100
+ """
101
+ Get a document from a specific collection using the cache-aware infrastructure.
102
+ """
103
+ try:
104
+ # Set collection context
105
+ self._set_collection_context(storage_location_path)
106
+
107
+ # Use the parent's cache-aware get_document method
108
+ return await super().get_document(doc_id, convert_to_model)
109
+
110
+ except ResourceNotFoundError:
111
+ self.logger.info(f"Document {doc_id} not found in {storage_location_path}")
112
+ return None
113
+ except Exception as e:
114
+ self.logger.error(f"Error getting document {doc_id} from {storage_location_path}: {str(e)}", exc_info=True)
115
+ raise ServiceError(
116
+ operation=f"getting document from {storage_location_path}",
117
+ error=e,
118
+ resource_type=self.resource_type,
119
+ resource_id=doc_id
120
+ ) from e
121
+
122
+ async def get_all_documents_from_collection(self,
123
+ storage_location_path: str,
124
+ cache_key: Optional[str] = None) -> List[T]:
125
+ """
126
+ Get all documents from a specific collection using cache-aware infrastructure.
127
+ """
128
+ try:
129
+ # Set collection context
130
+ self._set_collection_context(storage_location_path)
131
+
132
+ # Use cache key if not provided
133
+ if not cache_key:
134
+ cache_key = f"all_documents_{storage_location_path}"
135
+
136
+ # Use the parent's cache-aware get_all_documents method
137
+ results = await super().get_all_documents(cache_key=cache_key, as_models=True)
138
+
139
+ # Ensure we return model instances
140
+ model_results: List[T] = []
141
+ for item in results:
142
+ if isinstance(item, BaseDataModel) and self.model_class and isinstance(item, self.model_class):
143
+ model_results.append(item) # type: ignore
144
+ elif isinstance(item, dict) and self.model_class:
145
+ try:
146
+ model_results.append(self.model_class.model_validate(item))
147
+ except Exception as e:
148
+ self.logger.warning(f"Failed to convert dict to model: {e}")
149
+
150
+ return model_results
151
+
152
+ except Exception as e:
153
+ self.logger.error(f"Error getting all documents from {storage_location_path}: {str(e)}", exc_info=True)
154
+ raise ServiceError(
155
+ operation=f"getting all documents from {storage_location_path}",
156
+ error=e,
157
+ resource_type=self.resource_type
158
+ ) from e
159
+
160
+ async def create_document_in_collection(self,
161
+ storage_location_path: str,
162
+ doc_id: str,
163
+ data: Union[T, Dict[str, Any]],
164
+ creator_uid: str,
165
+ merge: bool = False) -> Dict[str, Any]:
166
+ """
167
+ Create a document in a specific collection using cache-aware infrastructure.
168
+ Automatically handles cache invalidation.
169
+ """
170
+ try:
171
+ # Set collection context
172
+ self._set_collection_context(storage_location_path)
173
+
174
+ # Use the parent's cache-aware create_document method
175
+ return await super().create_document(doc_id, data, creator_uid, merge)
176
+
177
+ except Exception as e:
178
+ self.logger.error(f"Error creating document {doc_id} in {storage_location_path}: {str(e)}", exc_info=True)
179
+ raise ServiceError(
180
+ operation=f"creating document in {storage_location_path}",
181
+ error=e,
182
+ resource_type=self.resource_type,
183
+ resource_id=doc_id
184
+ ) from e
185
+
186
+ async def update_document_in_collection(self,
187
+ storage_location_path: str,
188
+ doc_id: str,
189
+ update_data: Dict[str, Any],
190
+ updater_uid: str,
191
+ require_exists: bool = True) -> Dict[str, Any]:
192
+ """
193
+ Update a document in a specific collection using cache-aware infrastructure.
194
+ Automatically handles cache invalidation.
195
+ """
196
+ try:
197
+ # Set collection context
198
+ self._set_collection_context(storage_location_path)
199
+
200
+ # Use the parent's cache-aware update_document method
201
+ return await super().update_document(doc_id, update_data, updater_uid, require_exists)
202
+
203
+ except Exception as e:
204
+ self.logger.error(f"Error updating document {doc_id} in {storage_location_path}: {str(e)}", exc_info=True)
205
+ raise ServiceError(
206
+ operation=f"updating document in {storage_location_path}",
207
+ error=e,
208
+ resource_type=self.resource_type,
209
+ resource_id=doc_id
210
+ ) from e
211
+
212
+ async def delete_document_from_collection(self,
213
+ storage_location_path: str,
214
+ doc_id: str,
215
+ require_exists: bool = True) -> bool:
216
+ """
217
+ Delete a document from a specific collection using cache-aware infrastructure.
218
+ Automatically handles cache invalidation.
219
+ """
220
+ try:
221
+ # Set collection context
222
+ self._set_collection_context(storage_location_path)
223
+
224
+ # Use the parent's cache-aware delete_document method
225
+ return await super().delete_document(doc_id, require_exists)
226
+
227
+ except Exception as e:
228
+ self.logger.error(f"Error deleting document {doc_id} from {storage_location_path}: {str(e)}", exc_info=True)
229
+ raise ServiceError(
230
+ operation=f"deleting document from {storage_location_path}",
231
+ error=e,
232
+ resource_type=self.resource_type,
233
+ resource_id=doc_id
234
+ ) from e
235
+
236
+ def get_cache_stats(self) -> Dict[str, Any]:
237
+ """Get cache statistics for all collections managed by this service."""
238
+ stats = {}
239
+ for storage_path, caches in self._collection_caches.items():
240
+ stats[storage_path] = {
241
+ 'document_cache': caches['document'].get_stats(),
242
+ 'collection_cache': caches['collection'].get_stats()
243
+ }
244
+ return stats
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipulse_shared_core_ftredge
3
- Version: 27.1.1
3
+ Version: 27.3.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
@@ -12,7 +12,7 @@ License-File: LICENCE
12
12
  Requires-Dist: pydantic[email]~=2.5
13
13
  Requires-Dist: python-dateutil~=2.8
14
14
  Requires-Dist: fastapi~=0.115.8
15
- Requires-Dist: ipulse_shared_base_ftredge==11.1.1
15
+ Requires-Dist: ipulse_shared_base_ftredge~=12.2.0
16
16
  Dynamic: author
17
17
  Dynamic: classifier
18
18
  Dynamic: home-page
@@ -24,6 +24,7 @@ src/ipulse_shared_core_ftredge/models/base_api_response.py
24
24
  src/ipulse_shared_core_ftredge/models/base_data_model.py
25
25
  src/ipulse_shared_core_ftredge/models/credit_api_response.py
26
26
  src/ipulse_shared_core_ftredge/models/custom_json_response.py
27
+ src/ipulse_shared_core_ftredge/models/time_series_packaged_dataset_model.py
27
28
  src/ipulse_shared_core_ftredge/models/catalog/__init__.py
28
29
  src/ipulse_shared_core_ftredge/models/catalog/subscriptionplan.py
29
30
  src/ipulse_shared_core_ftredge/models/catalog/usertype.py
@@ -41,6 +42,7 @@ src/ipulse_shared_core_ftredge/services/user_charging_service.py
41
42
  src/ipulse_shared_core_ftredge/services/base/__init__.py
42
43
  src/ipulse_shared_core_ftredge/services/base/base_firestore_service.py
43
44
  src/ipulse_shared_core_ftredge/services/base/cache_aware_firestore_service.py
45
+ src/ipulse_shared_core_ftredge/services/base/multi_collection_cache_aware_firestore_service.py
44
46
  src/ipulse_shared_core_ftredge/services/catalog/__init__.py
45
47
  src/ipulse_shared_core_ftredge/services/catalog/catalog_subscriptionplan_service.py
46
48
  src/ipulse_shared_core_ftredge/services/catalog/catalog_usertype_service.py
@@ -1,4 +1,4 @@
1
1
  pydantic[email]~=2.5
2
2
  python-dateutil~=2.8
3
3
  fastapi~=0.115.8
4
- ipulse_shared_base_ftredge==11.1.1
4
+ ipulse_shared_base_ftredge~=12.2.0