altcodepro-polydb-python 2.2.6__tar.gz → 2.2.8__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.
Files changed (82) hide show
  1. {altcodepro_polydb_python-2.2.6/src/altcodepro_polydb_python.egg-info → altcodepro_polydb_python-2.2.8}/PKG-INFO +1 -1
  2. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/pyproject.toml +1 -1
  3. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8/src/altcodepro_polydb_python.egg-info}/PKG-INFO +1 -1
  4. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/cache.py +113 -70
  5. altcodepro_polydb_python-2.2.8/src/polydb/databaseFactory.py +957 -0
  6. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/registry.py +11 -0
  7. altcodepro_polydb_python-2.2.6/src/polydb/databaseFactory.py +0 -1299
  8. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/LICENSE +0 -0
  9. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/MANIFEST.in +0 -0
  10. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/README.md +0 -0
  11. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/example_usage.py +0 -0
  12. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/requirements-aws.txt +0 -0
  13. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/requirements-azure.txt +0 -0
  14. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/requirements-dev.txt +0 -0
  15. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/requirements-gcp.txt +0 -0
  16. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/requirements-generic.txt +0 -0
  17. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/requirements.txt +0 -0
  18. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/setup.cfg +0 -0
  19. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/setup.py +0 -0
  20. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/altcodepro_polydb_python.egg-info/SOURCES.txt +0 -0
  21. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/altcodepro_polydb_python.egg-info/dependency_links.txt +0 -0
  22. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/altcodepro_polydb_python.egg-info/requires.txt +0 -0
  23. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/altcodepro_polydb_python.egg-info/top_level.txt +0 -0
  24. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/PolyDB.py +0 -0
  25. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/__init__.py +0 -0
  26. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/AzureBlobStorageAdapter.py +0 -0
  27. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/AzureFileStorageAdapter.py +0 -0
  28. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/AzureQueueAdapter.py +0 -0
  29. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/AzureTableStorageAdapter.py +0 -0
  30. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/BlockchainBlobAdapter.py +0 -0
  31. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/BlockchainKVAdapter.py +0 -0
  32. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/BlockchainQueueAdapter.py +0 -0
  33. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/DynamoDBAdapter.py +0 -0
  34. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/EFSAdapter.py +0 -0
  35. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/FirestoreAdapter.py +0 -0
  36. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/GCPPubSubAdapter.py +0 -0
  37. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/GCPStorageAdapter.py +0 -0
  38. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/MongoDBAdapter.py +0 -0
  39. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/PostgreSQLAdapter.py +0 -0
  40. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/S3Adapter.py +0 -0
  41. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/S3CompatibleAdapter.py +0 -0
  42. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/SQSAdapter.py +0 -0
  43. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/VercelBlobAdapter.py +0 -0
  44. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/VercelKVAdapter.py +0 -0
  45. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/VercelQueueAdapter.py +0 -0
  46. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/adapters/__init__.py +0 -0
  47. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/advanced_query.py +0 -0
  48. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/audit/AuditStorage.py +0 -0
  49. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/audit/__init__.py +0 -0
  50. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/audit/context.py +0 -0
  51. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/audit/manager.py +0 -0
  52. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/audit/models.py +0 -0
  53. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/base/NoSQLKVAdapter.py +0 -0
  54. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/base/ObjectStorageAdapter.py +0 -0
  55. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/base/QueueAdapter.py +0 -0
  56. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/base/SharedFilesAdapter.py +0 -0
  57. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/base/__init__.py +0 -0
  58. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/batch.py +0 -0
  59. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/cloudDatabaseFactory.py +0 -0
  60. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/decorators.py +0 -0
  61. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/errors.py +0 -0
  62. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/json_safe.py +0 -0
  63. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/models.py +0 -0
  64. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/monitoring.py +0 -0
  65. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/multitenancy.py +0 -0
  66. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/py.typed +0 -0
  67. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/query.py +0 -0
  68. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/retry.py +0 -0
  69. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/schema.py +0 -0
  70. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/security.py +0 -0
  71. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/types.py +0 -0
  72. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/utils.py +0 -0
  73. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/src/polydb/validation.py +0 -0
  74. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_aws.py +0 -0
  75. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_azure.py +0 -0
  76. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_blockchain.py +0 -0
  77. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_cloud_factory.py +0 -0
  78. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_gcp.py +0 -0
  79. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_mongodb.py +0 -0
  80. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_multi_engine.py +0 -0
  81. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_postgresql.py +0 -0
  82. {altcodepro_polydb_python-2.2.6 → altcodepro_polydb_python-2.2.8}/tests/test_vercel.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: altcodepro-polydb-python
3
- Version: 2.2.6
3
+ Version: 2.2.8
4
4
  Summary: Production-ready multi-cloud database abstraction layer with connection pooling, retry logic, and thread safety
5
5
  Author: AltCodePro
6
6
  Project-URL: Homepage, https://github.com/altcodepro/polydb-python
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "altcodepro-polydb-python"
7
- version = "2.2.6"
7
+ version = "2.2.8"
8
8
  description = "Production-ready multi-cloud database abstraction layer with connection pooling, retry logic, and thread safety"
9
9
  readme = { file = "README.md", content-type = "text/markdown" }
10
10
  requires-python = ">=3.8"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: altcodepro-polydb-python
3
- Version: 2.2.6
3
+ Version: 2.2.8
4
4
  Summary: Production-ready multi-cloud database abstraction layer with connection pooling, retry logic, and thread safety
5
5
  Author: AltCodePro
6
6
  Project-URL: Homepage, https://github.com/altcodepro/polydb-python
@@ -10,8 +10,10 @@ from enum import Enum
10
10
  import redis
11
11
  from .json_safe import json_safe
12
12
 
13
+
13
14
  class CacheStrategy(Enum):
14
15
  """Cache invalidation strategies"""
16
+
15
17
  LRU = "lru" # Least Recently Used
16
18
  LFU = "lfu" # Least Frequently Used
17
19
  TTL = "ttl" # Time To Live
@@ -21,12 +23,9 @@ class CacheStrategy(Enum):
21
23
 
22
24
  class RedisCacheEngine:
23
25
  """Redis-based distributed cache"""
24
-
26
+
25
27
  def __init__(
26
- self,
27
- redis_url: Optional[str] = None,
28
- prefix: str = "polydb:",
29
- default_ttl: int = 3600
28
+ self, redis_url: Optional[str] = None, prefix: str = "polydb:", default_ttl: int = 3600
30
29
  ):
31
30
  self.prefix = prefix
32
31
  self.default_ttl = default_ttl
@@ -34,7 +33,7 @@ class RedisCacheEngine:
34
33
  self._lock = threading.Lock()
35
34
  self.redis_url = redis_url
36
35
  self._initialize()
37
-
36
+
38
37
  def _initialize(self):
39
38
  """Initialize Redis connection"""
40
39
  try:
@@ -44,32 +43,30 @@ class RedisCacheEngine:
44
43
  self._client = redis.from_url(self.redis_url)
45
44
  else:
46
45
  import os
47
- redis_host = os.getenv('REDIS_HOST', 'localhost')
48
- redis_port = int(os.getenv('REDIS_PORT', '6379'))
49
- redis_db = int(os.getenv('REDIS_DB', '0'))
50
-
46
+
47
+ redis_host = os.getenv("REDIS_HOST", "localhost")
48
+ redis_port = int(os.getenv("REDIS_PORT", "6379"))
49
+ redis_db = int(os.getenv("REDIS_DB", "0"))
50
+
51
51
  self._client = redis.Redis(
52
- host=redis_host,
53
- port=redis_port,
54
- db=redis_db,
55
- decode_responses=True
52
+ host=redis_host, port=redis_port, db=redis_db, decode_responses=True
56
53
  )
57
54
  except ImportError:
58
55
  raise ImportError("Redis not installed. Install with: pip install redis")
59
-
56
+
60
57
  def _make_key(self, model: str, query: Dict[str, Any]) -> str:
61
58
  """Generate cache key"""
62
- query_str = json.dumps(query, sort_keys=True,default=json_safe)
59
+ query_str = json.dumps(query, sort_keys=True, default=json_safe)
63
60
  query_hash = hashlib.md5(query_str.encode()).hexdigest()
64
61
  return f"{self.prefix}{model}:{query_hash}"
65
-
62
+
66
63
  def get(self, model: str, query: Dict[str, Any]) -> Optional[Any]:
67
64
  """Get from cache"""
68
65
  if not self._client:
69
66
  return None
70
-
67
+
71
68
  key = self._make_key(model, query)
72
-
69
+
73
70
  try:
74
71
  data = self._client.get(key)
75
72
  if data:
@@ -79,39 +76,29 @@ class RedisCacheEngine:
79
76
  return None
80
77
  except Exception:
81
78
  return None
82
-
83
- def set(
84
- self,
85
- model: str,
86
- query: Dict[str, Any],
87
- value: Any,
88
- ttl: Optional[int] = None
89
- ):
79
+
80
+ def set(self, model: str, query: Dict[str, Any], value: Any, ttl: Optional[int] = None):
90
81
  """Set cache with TTL"""
91
82
  if not self._client:
92
83
  return
93
-
84
+
94
85
  key = self._make_key(model, query)
95
86
  ttl = ttl or self.default_ttl
96
-
87
+
97
88
  try:
98
- data = json.dumps(value,default=json_safe)
89
+ data = json.dumps(value, default=json_safe)
99
90
  self._client.setex(key, ttl, data)
100
-
91
+
101
92
  # Initialize access count
102
93
  self._client.set(f"{key}:access_count", 0, ex=ttl)
103
94
  except Exception:
104
95
  pass
105
-
106
- def invalidate(
107
- self,
108
- model: str,
109
- query: Optional[Dict[str, Any]] = None
110
- ):
96
+
97
+ def invalidate(self, model: str, query: Optional[Dict[str, Any]] = None):
111
98
  """Invalidate cache"""
112
99
  if not self._client:
113
100
  return
114
-
101
+
115
102
  if query:
116
103
  key = self._make_key(model, query)
117
104
  self._client.delete(key, f"{key}:access_count")
@@ -121,66 +108,122 @@ class RedisCacheEngine:
121
108
  keys = self._client.keys(pattern)
122
109
  if keys:
123
110
  self._client.delete(*keys)
124
-
111
+
125
112
  def clear(self):
126
113
  """Clear entire cache"""
127
114
  if not self._client:
128
115
  return
129
-
116
+
130
117
  pattern = f"{self.prefix}*"
131
118
  keys = self._client.keys(pattern)
132
119
  if keys:
133
120
  self._client.delete(*keys)
134
-
121
+
135
122
  def get_stats(self) -> Dict[str, Any]:
136
123
  """Get cache statistics"""
137
124
  if not self._client:
138
125
  return {}
139
-
126
+
140
127
  try:
141
- info = self._client.info('stats')
128
+ info = self._client.info("stats")
142
129
  return {
143
- 'hits': info.get('keyspace_hits', 0),
144
- 'misses': info.get('keyspace_misses', 0),
145
- 'hit_rate': info.get('keyspace_hits', 0) /
146
- max(info.get('keyspace_hits', 0) + info.get('keyspace_misses', 0), 1)
130
+ "hits": info.get("keyspace_hits", 0),
131
+ "misses": info.get("keyspace_misses", 0),
132
+ "hit_rate": info.get("keyspace_hits", 0)
133
+ / max(info.get("keyspace_hits", 0) + info.get("keyspace_misses", 0), 1),
147
134
  }
148
135
  except Exception:
149
136
  return {}
150
137
 
138
+ # ---------------------------------------------------------
139
+ # ZSET (Sorted Set) Operations — for rate limiting, ranking
140
+ # ---------------------------------------------------------
141
+
142
+ def _make_raw_key(self, model: str, key: str) -> str:
143
+ """Direct key (no hashing) for structured use cases like rate limiting"""
144
+ return f"{self.prefix}{model}:{key}"
145
+
146
+ def zadd(self, model: str, key: str, mapping: Dict[str, float]) -> None:
147
+ if not self._client:
148
+ return
149
+
150
+ redis_key = self._make_raw_key(model, key)
151
+
152
+ try:
153
+ self._client.zadd(redis_key, mapping)
154
+ except Exception:
155
+ pass
156
+
157
+ def zcard(self, model: str, key: str) -> int:
158
+ if not self._client:
159
+ return 0
160
+
161
+ redis_key = self._make_raw_key(model, key)
162
+
163
+ try:
164
+ return int(self._client.zcard(redis_key))
165
+ except Exception:
166
+ return 0
167
+
168
+ def zremrangebyscore(
169
+ self,
170
+ model: str,
171
+ key: str,
172
+ min_score: float,
173
+ max_score: float,
174
+ ) -> None:
175
+ if not self._client:
176
+ return
177
+
178
+ redis_key = self._make_raw_key(model, key)
179
+
180
+ try:
181
+ self._client.zremrangebyscore(redis_key, min_score, max_score)
182
+ except Exception:
183
+ pass
184
+
185
+ def expire_key(self, model: str, key: str, ttl: int) -> None:
186
+ if not self._client:
187
+ return
188
+
189
+ redis_key = self._make_raw_key(model, key)
190
+
191
+ try:
192
+ self._client.expire(redis_key, ttl)
193
+ except Exception:
194
+ pass
195
+
196
+ def delete_key(self, model: str, key: str) -> None:
197
+ if not self._client:
198
+ return
199
+
200
+ redis_key = self._make_raw_key(model, key)
201
+
202
+ try:
203
+ self._client.delete(redis_key)
204
+ except Exception:
205
+ pass
206
+
151
207
 
152
208
  class CacheWarmer:
153
209
  """Pre-populate cache with frequently accessed data"""
154
-
210
+
155
211
  def __init__(self, factory, cache_engine):
156
212
  self.factory = factory
157
213
  self.cache = cache_engine
158
-
159
- def warm_model(
160
- self,
161
- model,
162
- queries: List[Dict[str, Any]],
163
- ttl: Optional[int] = None
164
- ):
214
+
215
+ def warm_model(self, model, queries: List[Dict[str, Any]], ttl: Optional[int] = None):
165
216
  """Warm cache for specific queries"""
166
217
  for query in queries:
167
218
  try:
168
219
  results = self.factory.read(model, query=query)
169
220
  self.cache.set(
170
- model.__name__ if isinstance(model, type) else model,
171
- query,
172
- results,
173
- ttl
221
+ model.__name__ if isinstance(model, type) else model, query, results, ttl
174
222
  )
175
223
  except Exception:
176
224
  pass
177
-
178
- def warm_popular_queries(
179
- self,
180
- model,
181
- limit: int = 10,
182
- ttl: Optional[int] = None
183
- ):
225
+
226
+ def warm_popular_queries(self, model, limit: int = 10, ttl: Optional[int] = None):
184
227
  """Warm cache with most popular queries"""
185
228
  # This would need query log analysis
186
229
  # Placeholder implementation
@@ -189,17 +232,17 @@ class CacheWarmer:
189
232
 
190
233
  class CacheInvalidationStrategy:
191
234
  """Manages cache invalidation strategies"""
192
-
235
+
193
236
  def __init__(self, cache_engine, strategy: CacheStrategy = CacheStrategy.TTL):
194
237
  self.cache = cache_engine
195
238
  self.strategy = strategy
196
-
239
+
197
240
  def invalidate_on_write(self, model: str, data: Dict[str, Any]):
198
241
  """Invalidate cache on write operations"""
199
242
  if self.strategy in [CacheStrategy.WRITE_THROUGH, CacheStrategy.WRITE_BACK]:
200
243
  self.cache.invalidate(model)
201
-
244
+
202
245
  def invalidate_related(self, model: str, relationships: List[str]):
203
246
  """Invalidate related models"""
204
247
  for related in relationships:
205
- self.cache.invalidate(related)
248
+ self.cache.invalidate(related)