altcodepro-polydb-python 2.3.1__tar.gz → 2.3.3__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 (81) hide show
  1. {altcodepro_polydb_python-2.3.1/src/altcodepro_polydb_python.egg-info → altcodepro_polydb_python-2.3.3}/PKG-INFO +1 -1
  2. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/pyproject.toml +1 -1
  3. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3/src/altcodepro_polydb_python.egg-info}/PKG-INFO +1 -1
  4. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/AzureTableStorageAdapter.py +82 -12
  5. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/LICENSE +0 -0
  6. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/MANIFEST.in +0 -0
  7. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/README.md +0 -0
  8. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/example_usage.py +0 -0
  9. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/requirements-aws.txt +0 -0
  10. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/requirements-azure.txt +0 -0
  11. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/requirements-dev.txt +0 -0
  12. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/requirements-gcp.txt +0 -0
  13. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/requirements-generic.txt +0 -0
  14. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/requirements.txt +0 -0
  15. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/setup.cfg +0 -0
  16. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/setup.py +0 -0
  17. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/altcodepro_polydb_python.egg-info/SOURCES.txt +0 -0
  18. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/altcodepro_polydb_python.egg-info/dependency_links.txt +0 -0
  19. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/altcodepro_polydb_python.egg-info/requires.txt +0 -0
  20. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/altcodepro_polydb_python.egg-info/top_level.txt +0 -0
  21. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/PolyDB.py +0 -0
  22. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/__init__.py +0 -0
  23. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/AzureBlobStorageAdapter.py +0 -0
  24. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/AzureFileStorageAdapter.py +0 -0
  25. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/AzureQueueAdapter.py +0 -0
  26. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/BlockchainBlobAdapter.py +0 -0
  27. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/BlockchainKVAdapter.py +0 -0
  28. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/BlockchainQueueAdapter.py +0 -0
  29. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/DynamoDBAdapter.py +0 -0
  30. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/EFSAdapter.py +0 -0
  31. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/FirestoreAdapter.py +0 -0
  32. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/GCPPubSubAdapter.py +0 -0
  33. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/GCPStorageAdapter.py +0 -0
  34. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/MongoDBAdapter.py +0 -0
  35. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/PostgreSQLAdapter.py +0 -0
  36. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/S3Adapter.py +0 -0
  37. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/S3CompatibleAdapter.py +0 -0
  38. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/SQSAdapter.py +0 -0
  39. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/VercelBlobAdapter.py +0 -0
  40. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/VercelKVAdapter.py +0 -0
  41. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/VercelQueueAdapter.py +0 -0
  42. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/adapters/__init__.py +0 -0
  43. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/advanced_query.py +0 -0
  44. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/audit/AuditStorage.py +0 -0
  45. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/audit/__init__.py +0 -0
  46. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/audit/context.py +0 -0
  47. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/audit/manager.py +0 -0
  48. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/audit/models.py +0 -0
  49. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/base/NoSQLKVAdapter.py +0 -0
  50. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/base/ObjectStorageAdapter.py +0 -0
  51. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/base/QueueAdapter.py +0 -0
  52. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/base/SharedFilesAdapter.py +0 -0
  53. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/base/__init__.py +0 -0
  54. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/batch.py +0 -0
  55. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/cache.py +0 -0
  56. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/cloudDatabaseFactory.py +0 -0
  57. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/databaseFactory.py +0 -0
  58. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/decorators.py +0 -0
  59. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/errors.py +0 -0
  60. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/json_safe.py +0 -0
  61. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/models.py +0 -0
  62. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/monitoring.py +0 -0
  63. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/multitenancy.py +0 -0
  64. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/py.typed +0 -0
  65. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/query.py +0 -0
  66. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/registry.py +0 -0
  67. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/retry.py +0 -0
  68. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/schema.py +0 -0
  69. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/security.py +0 -0
  70. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/types.py +0 -0
  71. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/utils.py +0 -0
  72. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/src/polydb/validation.py +0 -0
  73. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/tests/test_aws.py +0 -0
  74. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/tests/test_azure.py +0 -0
  75. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/tests/test_blockchain.py +0 -0
  76. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/tests/test_cloud_factory.py +0 -0
  77. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/tests/test_gcp.py +0 -0
  78. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/tests/test_mongodb.py +0 -0
  79. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/tests/test_multi_engine.py +0 -0
  80. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/tests/test_postgresql.py +0 -0
  81. {altcodepro_polydb_python-2.3.1 → altcodepro_polydb_python-2.3.3}/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.1
3
+ Version: 2.3.3
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.3.1"
7
+ version = "2.3.3"
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"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: altcodepro-polydb-python
3
- Version: 2.3.1
3
+ Version: 2.3.3
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
@@ -19,7 +19,9 @@ from ..errors import NoSQLError, ConnectionError
19
19
  from ..retry import retry
20
20
  from ..types import JsonDict
21
21
  from ..models import PartitionConfig
22
+ import logging
22
23
 
24
+ logger = logging.getLogger(__name__)
23
25
 
24
26
  _BYTES_PREFIX = "@@polydb_bytes@@:"
25
27
  _JSON_PREFIX = "@@polydb_json@@:"
@@ -281,11 +283,22 @@ class AzureTableStorageAdapter(NoSQLKVAdapter):
281
283
 
282
284
  return out
283
285
 
286
+ def _sanitize_blob_part(self, value: str) -> str:
287
+ # Blob-safe: lowercase, alphanumeric + dash only
288
+ s = str(value).lower()
289
+ s = re.sub(r"[^a-z0-9\-]", "-", s)
290
+ s = re.sub(r"-+", "-", s)
291
+ return s.strip("-")[:100]
292
+
284
293
  def _entity_size_bytes(self, entity: JsonDict) -> int:
285
294
  return len(json.dumps(entity, default=json_safe).encode("utf-8"))
286
295
 
287
296
  def _blob_key(self, pk: str, rk: str, checksum: str) -> str:
288
- return f"{pk}/{rk}/{checksum}.json"
297
+ safe_pk = self._sanitize_blob_part(pk)
298
+ safe_rk = self._sanitize_blob_part(rk)
299
+
300
+ # Flat structure (avoid deep paths)
301
+ return f"{safe_pk}-{safe_rk}-{checksum}.json"
289
302
 
290
303
  def _blob_upload(self, blob_key: str, data_bytes: bytes):
291
304
  if not self._blob_service:
@@ -323,14 +336,53 @@ class AzureTableStorageAdapter(NoSQLKVAdapter):
323
336
 
324
337
  entity = self._pack_entity(model, safe_pk, safe_rk, data)
325
338
 
326
- size = self._entity_size_bytes(entity)
327
- if size > self.AZURE_TABLE_MAX_SIZE:
328
- full_payload_bytes = json.dumps(entity, default=json_safe).encode("utf-8")
339
+ # ---------------------------------------------------
340
+ # SIZE ESTIMATION (Azure uses UTF-16 for strings)
341
+ # ---------------------------------------------------
342
+ MAX_PROPERTY_CHARS = 30 * 1024 # ~30K chars safe under 32K limit
343
+ MAX_ENTITY_SIZE = 40 * 1024 # conservative total entity threshold
344
+
345
+ def _is_large_string(val: Any) -> bool:
346
+ return isinstance(val, str) and len(val) > MAX_PROPERTY_CHARS
347
+
348
+ # Check if any property exceeds safe char limit
349
+ has_large_property = False
350
+ large_key = None
351
+
352
+ for key, value in entity.items():
353
+ if _is_large_string(value):
354
+ has_large_property = True
355
+ large_key = key
356
+ logger.warning(
357
+ f"LARGE PROPERTY DETECTED: {key} length={len(value)} chars → forcing blob overflow"
358
+ )
359
+ break
360
+
361
+ # Check full entity size
362
+ entity_json = json.dumps(entity, default=json_safe)
363
+ entity_size = len(entity_json.encode("utf-8"))
364
+
365
+ force_blob = has_large_property or entity_size > MAX_ENTITY_SIZE
366
+
367
+ if force_blob:
368
+ logger.info(
369
+ f"Entity exceeds safe limits → using blob storage "
370
+ f"(size={entity_size//1024} KB, large_key={large_key})"
371
+ )
372
+
373
+ # ---------------------------------------------------
374
+ # STORE FULL ENTITY IN BLOB
375
+ # ---------------------------------------------------
376
+ full_payload_bytes = entity_json.encode("utf-8")
329
377
  checksum = hashlib.md5(full_payload_bytes).hexdigest()
330
378
  blob_key = self._blob_key(safe_pk, safe_rk, checksum)
379
+
331
380
  self._blob_upload(blob_key, full_payload_bytes)
332
381
 
333
- reference_entity: JsonDict = {
382
+ # ---------------------------------------------------
383
+ # STORE REFERENCE IN TABLE
384
+ # ---------------------------------------------------
385
+ reference_entity = {
334
386
  "PartitionKey": safe_pk,
335
387
  "RowKey": safe_rk,
336
388
  _MODEL_FIELD: model.__qualname__,
@@ -341,31 +393,49 @@ class AzureTableStorageAdapter(NoSQLKVAdapter):
341
393
  "__keymap__": entity.get("__keymap__", "{}"),
342
394
  }
343
395
 
344
- # keep a small index of scalars for basic filtering
345
- kept = 0
396
+ # Keep only small searchable fields
346
397
  for k, v in entity.items():
347
398
  if k in ("PartitionKey", "RowKey", "__keymap__", _MODEL_FIELD):
348
399
  continue
349
400
  if k.startswith("_"):
350
401
  continue
351
- if v is None or isinstance(v, (str, bool, int, float, datetime)):
402
+
403
+ if isinstance(v, (str, bool, int, float)):
404
+ if isinstance(v, str) and len(v) > 2000:
405
+ continue
406
+ reference_entity[k] = v
407
+
408
+ elif isinstance(v, datetime):
352
409
  reference_entity[k] = v
353
- kept += 1
354
- if kept >= 50:
355
- break
356
410
 
357
411
  self._table_client.upsert_entity(reference_entity)
412
+
413
+ logger.info(f"Stored in blob: {blob_key} ({len(full_payload_bytes)//1024} KB)")
414
+
358
415
  return {
359
416
  "PartitionKey": safe_pk,
360
417
  "RowKey": safe_rk,
361
418
  "_overflow": True,
419
+ "_blob_key": blob_key,
362
420
  "id": safe_rk,
363
421
  }
364
422
 
423
+ # ---------------------------------------------------
424
+ # NORMAL TABLE STORAGE
425
+ # ---------------------------------------------------
365
426
  self._table_client.upsert_entity(entity)
366
- return {"PartitionKey": safe_pk, "RowKey": safe_rk, "id": safe_rk}
427
+
428
+ return {
429
+ "PartitionKey": safe_pk,
430
+ "RowKey": safe_rk,
431
+ "id": safe_rk,
432
+ }
367
433
 
368
434
  except Exception as e:
435
+ # Do NOT retry deterministic size errors
436
+ if "PropertyValueTooLarge" in str(e):
437
+ raise NoSQLError("Azure Table limit exceeded → must use blob overflow") from e
438
+
369
439
  raise NoSQLError(f"Azure Table put failed: {str(e)}")
370
440
 
371
441
  @retry(max_attempts=3, delay=1.0, exceptions=(NoSQLError,))