altcodepro-polydb-python 2.3.13__tar.gz → 2.3.15__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 (83) hide show
  1. {altcodepro_polydb_python-2.3.13/src/altcodepro_polydb_python.egg-info → altcodepro_polydb_python-2.3.15}/PKG-INFO +3 -1
  2. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/pyproject.toml +3 -1
  3. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15/src/altcodepro_polydb_python.egg-info}/PKG-INFO +3 -1
  4. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/altcodepro_polydb_python.egg-info/requires.txt +2 -0
  5. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/PolyDB.py +35 -35
  6. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/PostgreSQLAdapter.py +54 -5
  7. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/base/ObjectStorageAdapter.py +1 -0
  8. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/LICENSE +0 -0
  9. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/MANIFEST.in +0 -0
  10. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/README.md +0 -0
  11. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/requirements-aws.txt +0 -0
  12. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/requirements-azure.txt +0 -0
  13. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/requirements-dev.txt +0 -0
  14. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/requirements-gcp.txt +0 -0
  15. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/requirements-generic.txt +0 -0
  16. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/requirements.txt +0 -0
  17. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/setup.cfg +0 -0
  18. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/setup.py +0 -0
  19. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/altcodepro_polydb_python.egg-info/SOURCES.txt +0 -0
  20. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/altcodepro_polydb_python.egg-info/dependency_links.txt +0 -0
  21. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/altcodepro_polydb_python.egg-info/top_level.txt +0 -0
  22. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/__init__.py +0 -0
  23. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/AzureBlobStorageAdapter.py +0 -0
  24. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/AzureFileStorageAdapter.py +0 -0
  25. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/AzureQueueAdapter.py +0 -0
  26. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/AzureTableStorageAdapter.py +0 -0
  27. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/BlockchainBlobAdapter.py +0 -0
  28. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/BlockchainFileAdapter.py +0 -0
  29. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/BlockchainKVAdapter.py +0 -0
  30. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/BlockchainQueueAdapter.py +0 -0
  31. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/DynamoDBAdapter.py +0 -0
  32. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/EFSAdapter.py +0 -0
  33. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/FirestoreAdapter.py +0 -0
  34. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/GCPFilestoreAdapter.py +0 -0
  35. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/GCPPubSubAdapter.py +0 -0
  36. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/GCPStorageAdapter.py +0 -0
  37. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/MongoDBAdapter.py +0 -0
  38. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/S3Adapter.py +0 -0
  39. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/S3CompatibleAdapter.py +0 -0
  40. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/SQSAdapter.py +0 -0
  41. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/VercelBlobAdapter.py +0 -0
  42. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/VercelFileAdapter.py +0 -0
  43. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/VercelKVAdapter.py +0 -0
  44. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/VercelQueueAdapter.py +0 -0
  45. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/adapters/__init__.py +0 -0
  46. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/advanced_query.py +0 -0
  47. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/audit/AuditStorage.py +0 -0
  48. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/audit/__init__.py +0 -0
  49. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/audit/context.py +0 -0
  50. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/audit/manager.py +0 -0
  51. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/audit/models.py +0 -0
  52. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/base/NoSQLKVAdapter.py +0 -0
  53. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/base/QueueAdapter.py +0 -0
  54. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/base/SharedFilesAdapter.py +0 -0
  55. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/base/__init__.py +0 -0
  56. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/batch.py +0 -0
  57. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/cache.py +0 -0
  58. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/cloudDatabaseFactory.py +0 -0
  59. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/databaseFactory.py +0 -0
  60. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/decorators.py +0 -0
  61. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/errors.py +0 -0
  62. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/json_safe.py +0 -0
  63. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/models.py +0 -0
  64. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/monitoring.py +0 -0
  65. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/multitenancy.py +0 -0
  66. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/py.typed +0 -0
  67. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/query.py +0 -0
  68. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/registry.py +0 -0
  69. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/retry.py +0 -0
  70. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/schema.py +0 -0
  71. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/security.py +0 -0
  72. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/types.py +0 -0
  73. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/utils.py +0 -0
  74. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/src/polydb/validation.py +0 -0
  75. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/tests/test_aws.py +0 -0
  76. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/tests/test_azure.py +0 -0
  77. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/tests/test_blockchain.py +0 -0
  78. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/tests/test_cloud_factory.py +0 -0
  79. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/tests/test_gcp.py +0 -0
  80. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/tests/test_mongodb.py +0 -0
  81. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/tests/test_multi_engine.py +0 -0
  82. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/tests/test_postgresql.py +0 -0
  83. {altcodepro_polydb_python-2.3.13 → altcodepro_polydb_python-2.3.15}/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.3.13
3
+ Version: 2.3.15
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
@@ -38,6 +38,8 @@ Requires-Dist: web3>=7.16.0
38
38
  Requires-Dist: google-cloud-firestore>=2.27.0
39
39
  Requires-Dist: google-cloud-pubsub>=2.38.0
40
40
  Requires-Dist: pymongo>=4.17.0
41
+ Requires-Dist: build>=1.5.0
42
+ Requires-Dist: twine>=6.2.0
41
43
  Provides-Extra: aws
42
44
  Requires-Dist: boto3>=1.42.47; extra == "aws"
43
45
  Requires-Dist: botocore>=1.42.47; extra == "aws"
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "altcodepro-polydb-python"
7
- version = "2.3.13"
7
+ version = "2.3.15"
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.11"
@@ -57,6 +57,8 @@ dependencies = [
57
57
  "google-cloud-firestore>=2.27.0",
58
58
  "google-cloud-pubsub>=2.38.0",
59
59
  "pymongo>=4.17.0",
60
+ "build>=1.5.0",
61
+ "twine>=6.2.0",
60
62
  ]
61
63
 
62
64
  # Generic/Open-source stack (cheapest option)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: altcodepro-polydb-python
3
- Version: 2.3.13
3
+ Version: 2.3.15
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
@@ -38,6 +38,8 @@ Requires-Dist: web3>=7.16.0
38
38
  Requires-Dist: google-cloud-firestore>=2.27.0
39
39
  Requires-Dist: google-cloud-pubsub>=2.38.0
40
40
  Requires-Dist: pymongo>=4.17.0
41
+ Requires-Dist: build>=1.5.0
42
+ Requires-Dist: twine>=6.2.0
41
43
  Provides-Extra: aws
42
44
  Requires-Dist: boto3>=1.42.47; extra == "aws"
43
45
  Requires-Dist: botocore>=1.42.47; extra == "aws"
@@ -13,6 +13,8 @@ web3>=7.16.0
13
13
  google-cloud-firestore>=2.27.0
14
14
  google-cloud-pubsub>=2.38.0
15
15
  pymongo>=4.17.0
16
+ build>=1.5.0
17
+ twine>=6.2.0
16
18
 
17
19
  [all]
18
20
  boto3>=1.42.47
@@ -1,5 +1,6 @@
1
1
  from __future__ import annotations
2
2
 
3
+ import os
3
4
  from typing import Any, Dict, List, Optional, Tuple, Type, Union
4
5
 
5
6
  from .advanced_query import AdvancedQueryBuilder, QueryHelper
@@ -23,8 +24,6 @@ from .types import JsonDict, Lookup
23
24
  from .utils import setup_logger
24
25
  from .validation import ModelValidator, SchemaValidator
25
26
 
26
- ModelRef = Union[Type, str]
27
-
28
27
 
29
28
  class PolyDB:
30
29
  """
@@ -51,6 +50,7 @@ class PolyDB:
51
50
  storage_configs: Optional[List[StorageConfig]] = None,
52
51
  tenant_registry: Optional[TenantRegistry] = None,
53
52
  partition_config: Optional[PartitionConfig] = None,
53
+ redis_cache_url: Optional[str] = None,
54
54
  enable_retries: bool = True,
55
55
  enable_audit: bool = True,
56
56
  enable_audit_reads: bool = False,
@@ -59,6 +59,7 @@ class PolyDB:
59
59
  enable_monitoring: bool = False,
60
60
  enable_encryption: bool = False,
61
61
  enable_rls: bool = False,
62
+ soft_delete: bool = True,
62
63
  ) -> None:
63
64
  self.logger = setup_logger(self.__class__.__name__)
64
65
 
@@ -71,7 +72,6 @@ class PolyDB:
71
72
  provider=provider,
72
73
  cloud_factory=self.cloud,
73
74
  engines=engines,
74
- tenant_registry=tenant_registry,
75
75
  enable_retries=enable_retries,
76
76
  enable_audit=enable_audit,
77
77
  enable_audit_reads=enable_audit_reads,
@@ -79,7 +79,10 @@ class PolyDB:
79
79
  use_redis_cache=use_redis_cache,
80
80
  enable_monitoring=enable_monitoring,
81
81
  enable_encryption=enable_encryption,
82
- enable_rls=enable_rls,
82
+ soft_delete=soft_delete,
83
+ redis_cache_url=redis_cache_url
84
+ or os.getenv("REDIS_CACHE_URL")
85
+ or os.getenv("REDIS_URL"),
83
86
  )
84
87
 
85
88
  self.partition_config = partition_config
@@ -123,7 +126,7 @@ class PolyDB:
123
126
  return self.cloud.get_object_storage(name)
124
127
 
125
128
  def get_shared_files(self):
126
- return self.cloud.get_shared_files()
129
+ return self.cloud.get_files()
127
130
 
128
131
  def get_queue(self):
129
132
  return self.cloud.get_queue()
@@ -137,7 +140,7 @@ class PolyDB:
137
140
 
138
141
  def create(
139
142
  self,
140
- model: ModelRef,
143
+ model: str,
141
144
  data: JsonDict,
142
145
  *,
143
146
  engine_override: Optional[EngineOverride] = None,
@@ -146,7 +149,7 @@ class PolyDB:
146
149
 
147
150
  def read(
148
151
  self,
149
- model: ModelRef,
152
+ model: str,
150
153
  query: Optional[Lookup] = None,
151
154
  *,
152
155
  limit: Optional[int] = None,
@@ -169,7 +172,7 @@ class PolyDB:
169
172
 
170
173
  def read_one(
171
174
  self,
172
- model: ModelRef,
175
+ model: str,
173
176
  query: Lookup,
174
177
  *,
175
178
  no_cache: bool = False,
@@ -186,7 +189,7 @@ class PolyDB:
186
189
 
187
190
  def get(
188
191
  self,
189
- model: ModelRef,
192
+ model: str,
190
193
  entity_id: Any,
191
194
  *,
192
195
  include_deleted: bool = False,
@@ -203,7 +206,7 @@ class PolyDB:
203
206
 
204
207
  def read_page(
205
208
  self,
206
- model: ModelRef,
209
+ model: str,
207
210
  query: Lookup,
208
211
  *,
209
212
  page_size: int = 100,
@@ -222,7 +225,7 @@ class PolyDB:
222
225
 
223
226
  def update(
224
227
  self,
225
- model: ModelRef,
228
+ model: str,
226
229
  entity_id: Any,
227
230
  data: JsonDict,
228
231
  *,
@@ -241,7 +244,7 @@ class PolyDB:
241
244
 
242
245
  def upsert(
243
246
  self,
244
- model: ModelRef,
247
+ model: str,
245
248
  data: JsonDict,
246
249
  *,
247
250
  replace: bool = False,
@@ -256,7 +259,7 @@ class PolyDB:
256
259
 
257
260
  def delete(
258
261
  self,
259
- model: ModelRef,
262
+ model: str,
260
263
  entity_id: Any,
261
264
  *,
262
265
  etag: Optional[str] = None,
@@ -278,12 +281,12 @@ class PolyDB:
278
281
  def query(self) -> QueryBuilder:
279
282
  return QueryBuilder()
280
283
 
281
- def advanced_query(self) -> AdvancedQueryBuilder:
282
- return AdvancedQueryBuilder()
284
+ def advanced_query(self, table: str) -> AdvancedQueryBuilder:
285
+ return AdvancedQueryBuilder(table)
283
286
 
284
287
  def query_linq(
285
288
  self,
286
- model: ModelRef,
289
+ model: str,
287
290
  builder: QueryBuilder,
288
291
  *,
289
292
  engine_override: Optional[EngineOverride] = None,
@@ -426,7 +429,7 @@ class PolyDB:
426
429
  queue_name: str = "default",
427
430
  delay: Optional[int] = None,
428
431
  ) -> str:
429
- queue = self.get_queue()
432
+ queue: Any = self.get_queue()
430
433
  if hasattr(queue, "publish"):
431
434
  return queue.publish(queue_name=queue_name, message=message, delay=delay)
432
435
  return self.send_queue(message, queue_name=queue_name)
@@ -438,7 +441,7 @@ class PolyDB:
438
441
  max_messages: int = 10,
439
442
  wait_seconds: int = 5,
440
443
  ) -> List[Dict[str, Any]]:
441
- queue = self.get_queue()
444
+ queue: Any = self.get_queue()
442
445
  if hasattr(queue, "consume"):
443
446
  return queue.consume(
444
447
  queue_name=queue_name,
@@ -492,7 +495,7 @@ class PolyDB:
492
495
 
493
496
  def set_cache(
494
497
  self,
495
- model: ModelRef,
498
+ model: str,
496
499
  key: Any,
497
500
  value: Any,
498
501
  *,
@@ -504,7 +507,7 @@ class PolyDB:
504
507
 
505
508
  def get_cache(
506
509
  self,
507
- model: ModelRef,
510
+ model: str,
508
511
  key: Any,
509
512
  ) -> Optional[Any]:
510
513
  if not self.cache:
@@ -513,7 +516,7 @@ class PolyDB:
513
516
 
514
517
  def invalidate_cache(
515
518
  self,
516
- model: ModelRef,
519
+ model: str,
517
520
  key: Optional[Any] = None,
518
521
  ) -> None:
519
522
  if not self.cache:
@@ -530,7 +533,7 @@ class PolyDB:
530
533
 
531
534
  def warm_model_cache(
532
535
  self,
533
- model: ModelRef,
536
+ model: str,
534
537
  queries: List[Any],
535
538
  *,
536
539
  ttl: int = 300,
@@ -541,7 +544,7 @@ class PolyDB:
541
544
 
542
545
  def warm_popular_queries(
543
546
  self,
544
- model: ModelRef,
547
+ model: str,
545
548
  *,
546
549
  limit: int = 20,
547
550
  ttl: int = 300,
@@ -554,27 +557,27 @@ class PolyDB:
554
557
  # BATCH
555
558
  # ============================================================
556
559
 
557
- def bulk_insert(self, model: ModelRef, records: List[JsonDict]) -> BatchResult:
560
+ def bulk_insert(self, model: str, records: List[JsonDict]) -> BatchResult:
558
561
  return self.batch.bulk_insert(model, records)
559
562
 
560
563
  def bulk_update(
561
564
  self,
562
- model: ModelRef,
563
- updates: List[Tuple[Any, JsonDict]],
565
+ model: str,
566
+ updates: List[Dict[str, Any]], # {entity_id, data}
564
567
  ) -> BatchResult:
565
568
  return self.batch.bulk_update(model, updates)
566
569
 
567
- def bulk_delete(self, model: ModelRef, entity_ids: List[Any]) -> BatchResult:
570
+ def bulk_delete(self, model: str, entity_ids: List[Any]) -> BatchResult:
568
571
  return self.batch.bulk_delete(model, entity_ids)
569
572
 
570
573
  # ============================================================
571
574
  # VALIDATION
572
575
  # ============================================================
573
576
 
574
- def validate_model(self, model: ModelRef):
577
+ def validate_model(self, model: Type):
575
578
  return ModelValidator.validate_model(model)
576
579
 
577
- def validate(self, model: ModelRef) -> None:
580
+ def validate(self, model: Type) -> None:
578
581
  ModelValidator.validate_and_raise(model)
579
582
 
580
583
  def validate_data(self, model: Any, data: JsonDict):
@@ -672,11 +675,7 @@ class PolyDB:
672
675
  self.rls.add_policy(model, name, policy_func, apply_to)
673
676
 
674
677
  def set_default_rls_filters(
675
- self,
676
- model: str,
677
- *,
678
- read_filters: Optional[Dict[str, Any]] = None,
679
- write_filters: Optional[Dict[str, Any]] = None,
678
+ self, model: str, *, read_filters: Dict[str, Any], write_filters: Dict[str, Any]
680
679
  ) -> None:
681
680
  if not self.rls:
682
681
  raise RuntimeError("RLS is not enabled on this PolyDB instance.")
@@ -687,7 +686,8 @@ class PolyDB:
687
686
  # ============================================================
688
687
 
689
688
  def with_tenant(self, tenant_id: str) -> "PolyDB":
690
- TenantContext.set_tenant(tenant_id, self.tenant_registry)
689
+ if self.tenant_registry:
690
+ TenantContext.set_tenant(tenant_id, self.tenant_registry)
691
691
  return self
692
692
 
693
693
  def get_tenant(self) -> Optional[TenantConfig]:
@@ -32,25 +32,64 @@ class PostgreSQLAdapter:
32
32
  self._lock = threading.Lock()
33
33
  self._initialize_pool()
34
34
 
35
+ def _ping_connection(self, conn) -> bool:
36
+ """Test if connection is still alive"""
37
+ try:
38
+ with conn.cursor() as cur:
39
+ cur.execute("SELECT 1")
40
+ return True
41
+ except Exception:
42
+ return False
43
+
35
44
  def _initialize_pool(self):
36
45
  try:
37
46
  import psycopg2.pool
47
+ from urllib.parse import urlparse, parse_qs, urlencode, urlunparse
48
+
49
+ # Enhance connection string with better Azure settings
50
+ dsn = self.connection_string
51
+ if "postgresql://" in dsn:
52
+ parsed = urlparse(dsn)
53
+ query = parse_qs(parsed.query)
54
+ query.setdefault("connect_timeout", ["30"])
55
+ query.setdefault("keepalives", ["1"])
56
+ query.setdefault("keepalives_idle", ["30"])
57
+ query.setdefault("keepalives_interval", ["10"])
58
+ query.setdefault("keepalives_count", ["5"])
59
+
60
+ new_query = urlencode(query, doseq=True)
61
+ parsed = parsed._replace(query=new_query)
62
+ dsn = urlunparse(parsed)
38
63
 
39
64
  with self._lock:
40
65
  if not self._pool:
41
66
  self._pool = psycopg2.pool.ThreadedConnectionPool(
42
- minconn=int(os.getenv("POSTGRES_MIN_CONNECTIONS", "2")),
43
- maxconn=int(os.getenv("POSTGRES_MAX_CONNECTIONS", "20")),
44
- dsn=self.connection_string,
67
+ minconn=int(os.getenv("POSTGRES_MIN_CONNECTIONS", "5")),
68
+ maxconn=int(os.getenv("POSTGRES_MAX_CONNECTIONS", "30")),
69
+ dsn=dsn,
45
70
  )
46
- self.logger.info("PostgreSQL pool initialized")
71
+ self.logger.info("PostgreSQL pool initialized with Azure optimizations")
47
72
  except Exception as e:
48
73
  raise ConnectionError(f"Failed to initialize PostgreSQL pool: {str(e)}")
49
74
 
50
75
  def _get_connection(self) -> Any:
51
76
  if not self._pool:
52
77
  self._initialize_pool()
53
- return self._pool.getconn() # type: ignore
78
+
79
+ try:
80
+ conn = self._pool.getconn() # type: ignore
81
+
82
+ # Critical: Validate connection for Azure transient issues
83
+ if not self._ping_connection(conn):
84
+ self.logger.warning("Stale connection detected from pool, closing and retrying")
85
+ self._pool.putconn(conn, close=True) # type: ignore
86
+ conn = self._pool.getconn() # type: ignore # Get fresh connection
87
+
88
+ return conn
89
+
90
+ except Exception as e:
91
+ self.logger.error(f"Failed to acquire connection from pool: {e}")
92
+ raise ConnectionError(f"Could not obtain database connection: {e}") from e
54
93
 
55
94
  def _return_connection(self, conn: Any):
56
95
  if self._pool and conn:
@@ -59,6 +98,16 @@ class PostgreSQLAdapter:
59
98
  # ---------------------------------------------------------------------
60
99
  # TRANSACTIONS
61
100
  # ---------------------------------------------------------------------
101
+ def reset_pool(self):
102
+ """Reset the entire pool (call during startup or after major failures)"""
103
+ with self._lock:
104
+ if self._pool:
105
+ try:
106
+ self._pool.closeall()
107
+ except:
108
+ pass
109
+ self._pool = None
110
+ self._initialize_pool()
62
111
 
63
112
  def begin_transaction(self) -> Any:
64
113
  """Begin a transaction and return the connection handle."""
@@ -18,6 +18,7 @@ class ObjectStorageAdapter(ABC):
18
18
  optimize: bool = True,
19
19
  media_type: Optional[str] = None,
20
20
  metadata: Dict[str, Any] | None = None,
21
+ container_name: Optional[str] = None,
21
22
  ) -> str:
22
23
  """Store object with optional optimization"""
23
24
  if optimize and media_type: