altcodepro-polydb-python 2.2.2__py3-none-any.whl → 2.2.4__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.
Files changed (38) hide show
  1. altcodepro_polydb_python-2.2.4.dist-info/METADATA +489 -0
  2. altcodepro_polydb_python-2.2.4.dist-info/RECORD +57 -0
  3. {altcodepro_polydb_python-2.2.2.dist-info → altcodepro_polydb_python-2.2.4.dist-info}/WHEEL +1 -1
  4. polydb/__init__.py +2 -2
  5. polydb/adapters/AzureBlobStorageAdapter.py +146 -41
  6. polydb/adapters/AzureFileStorageAdapter.py +148 -43
  7. polydb/adapters/AzureQueueAdapter.py +96 -34
  8. polydb/adapters/AzureTableStorageAdapter.py +462 -119
  9. polydb/adapters/BlockchainBlobAdapter.py +111 -0
  10. polydb/adapters/BlockchainKVAdapter.py +152 -0
  11. polydb/adapters/BlockchainQueueAdapter.py +116 -0
  12. polydb/adapters/DynamoDBAdapter.py +463 -176
  13. polydb/adapters/FirestoreAdapter.py +320 -148
  14. polydb/adapters/GCPPubSubAdapter.py +217 -0
  15. polydb/adapters/GCPStorageAdapter.py +184 -39
  16. polydb/adapters/MongoDBAdapter.py +159 -39
  17. polydb/adapters/PostgreSQLAdapter.py +285 -83
  18. polydb/adapters/S3Adapter.py +172 -35
  19. polydb/adapters/S3CompatibleAdapter.py +62 -8
  20. polydb/adapters/SQSAdapter.py +121 -44
  21. polydb/adapters/VercelBlobAdapter.py +196 -0
  22. polydb/adapters/VercelKVAdapter.py +275 -283
  23. polydb/adapters/VercelQueueAdapter.py +61 -0
  24. polydb/audit/AuditStorage.py +1 -1
  25. polydb/base/NoSQLKVAdapter.py +113 -101
  26. polydb/base/ObjectStorageAdapter.py +42 -6
  27. polydb/base/QueueAdapter.py +2 -2
  28. polydb/base/SharedFilesAdapter.py +2 -2
  29. polydb/cloudDatabaseFactory.py +200 -0
  30. polydb/databaseFactory.py +434 -101
  31. polydb/models.py +63 -1
  32. polydb/query.py +111 -42
  33. altcodepro_polydb_python-2.2.2.dist-info/METADATA +0 -379
  34. altcodepro_polydb_python-2.2.2.dist-info/RECORD +0 -52
  35. polydb/adapters/PubSubAdapter.py +0 -85
  36. polydb/factory.py +0 -107
  37. {altcodepro_polydb_python-2.2.2.dist-info → altcodepro_polydb_python-2.2.4.dist-info}/licenses/LICENSE +0 -0
  38. {altcodepro_polydb_python-2.2.2.dist-info → altcodepro_polydb_python-2.2.4.dist-info}/top_level.txt +0 -0
polydb/models.py CHANGED
@@ -10,6 +10,7 @@ from enum import Enum
10
10
 
11
11
  class CloudProvider(Enum):
12
12
  """Supported cloud providers"""
13
+
13
14
  AZURE = "azure"
14
15
  AWS = "aws"
15
16
  GCP = "gcp"
@@ -17,11 +18,13 @@ class CloudProvider(Enum):
17
18
  MONGODB = "mongodb"
18
19
  S3_COMPATIBLE = "s3_compatible"
19
20
  POSTGRESQL = "postgresql"
21
+ BLOCKCHAIN = "blockchain"
20
22
 
21
23
 
22
24
  @dataclass
23
25
  class PartitionConfig:
24
26
  """Configuration for partition and row keys"""
27
+
25
28
  partition_key_template: str = "default_{id}"
26
29
  row_key_template: Optional[str] = None
27
30
  composite_keys: Optional[List[str]] = None
@@ -31,9 +34,68 @@ class PartitionConfig:
31
34
  @dataclass
32
35
  class QueryOptions:
33
36
  """LINQ-style query options"""
37
+
34
38
  filter_func: Optional[Callable] = None
35
39
  order_by: Optional[str] = None
36
40
  skip: int = 0
37
41
  take: Optional[int] = None
38
42
  select_fields: Optional[List[str]] = None
39
- count_only: bool = False
43
+ count_only: bool = False
44
+
45
+
46
+ # ============================================================
47
+ # CONFIG CLASSES (TYPED)
48
+ # ============================================================
49
+
50
+
51
+ class StorageConfig:
52
+ def __init__(self, provider: CloudProvider, name: str = "default"):
53
+ self.provider = provider
54
+ self.name = name
55
+
56
+
57
+ class AzureStorageConfig(StorageConfig):
58
+ def __init__(
59
+ self,
60
+ name: str = "default",
61
+ connection_string: Optional[str] = None,
62
+ container: Optional[str] = None,
63
+ ):
64
+ super().__init__(CloudProvider.AZURE, name)
65
+ self.connection_string = connection_string
66
+ self.container = container
67
+
68
+
69
+ class S3StorageConfig(StorageConfig):
70
+ def __init__(
71
+ self,
72
+ name: str = "default",
73
+ endpoint: Optional[str] = None,
74
+ access_key: Optional[str] = None,
75
+ secret_key: Optional[str] = None,
76
+ bucket: Optional[str] = None,
77
+ ):
78
+ super().__init__(CloudProvider.S3_COMPATIBLE, name)
79
+ self.endpoint = endpoint
80
+ self.access_key = access_key
81
+ self.secret_key = secret_key
82
+ self.bucket = bucket
83
+
84
+
85
+ class GCPStorageConfig(StorageConfig):
86
+ def __init__(self, name: str = "default", bucket: Optional[str] = None):
87
+ super().__init__(CloudProvider.GCP, name)
88
+ self.bucket = bucket
89
+
90
+
91
+ class VercelStorageConfig(StorageConfig):
92
+ def __init__(self, name: str = "default", token: Optional[str] = None, timeout: int = 10):
93
+ super().__init__(CloudProvider.VERCEL, name)
94
+ self.token = token
95
+ self.timeout = timeout
96
+
97
+
98
+ class BlockchainStorageConfig(StorageConfig):
99
+ def __init__(self, name: str = "default", ipfs_url: Optional[str] = None):
100
+ super().__init__(CloudProvider.BLOCKCHAIN, name)
101
+ self.ipfs_url = ipfs_url
polydb/query.py CHANGED
@@ -1,8 +1,8 @@
1
1
  # src/polydb/query.py
2
- from __future__ import annotations
3
2
 
3
+ from __future__ import annotations
4
4
  from dataclasses import dataclass, field
5
- from typing import Any, Callable, Dict, List, Optional, Union
5
+ from typing import Any, Dict, List, Optional, Union
6
6
  from enum import Enum
7
7
 
8
8
 
@@ -29,122 +29,191 @@ class QueryFilter:
29
29
 
30
30
  @dataclass
31
31
  class QueryBuilder:
32
- """LINQ-style query builder supporting all SQL clauses"""
33
-
32
+ """LINQ-style query builder supporting SQL and NoSQL"""
33
+
34
34
  filters: List[QueryFilter] = field(default_factory=list)
35
- order_by_fields: List[tuple[str, bool]] = field(default_factory=list) # (field, desc)
35
+ order_by_fields: List[tuple[str, bool]] = field(default_factory=list)
36
+
36
37
  skip_count: int = 0
37
38
  take_count: Optional[int] = None
38
- select_fields: Optional[List[str]] = None
39
+
40
+ selected_fields: Optional[List[str]] = None
39
41
  group_by_fields: Optional[List[str]] = None
40
- distinct: bool = False
42
+
43
+ distinct_flag: bool = False
41
44
  count_only: bool = False
42
-
43
- def where(self, field: str, operator: Union[Operator, str], value: Any) -> QueryBuilder:
44
- """Add filter condition"""
45
- if isinstance(operator, str):
46
- operator = Operator(operator)
47
- self.filters.append(QueryFilter(field, operator, value))
45
+
46
+ # ------------------------------------------------
47
+ # FILTERS
48
+ # ------------------------------------------------
49
+
50
+ def where(
51
+ self, field: str, operator: Union["Operator", str, None], value: Any
52
+ ) -> "QueryBuilder":
53
+ # Allow legacy callers that pass "" meaning equality
54
+ if operator in ("", None):
55
+ op = Operator.EQ
56
+ elif isinstance(operator, Operator):
57
+ op = operator
58
+ else:
59
+ op = Operator(operator)
60
+
61
+ self.filters.append(QueryFilter(field=field, operator=op, value=value))
48
62
  return self
49
-
63
+
64
+ # ------------------------------------------------
65
+ # ORDER
66
+ # ------------------------------------------------
67
+
50
68
  def order_by(self, field: str, descending: bool = False) -> QueryBuilder:
51
- """Add ordering"""
52
69
  self.order_by_fields.append((field, descending))
53
70
  return self
54
-
71
+
72
+ # ------------------------------------------------
73
+ # PAGINATION
74
+ # ------------------------------------------------
75
+
55
76
  def skip(self, count: int) -> QueryBuilder:
56
- """Skip records"""
57
77
  self.skip_count = count
58
78
  return self
59
-
79
+
60
80
  def take(self, count: int) -> QueryBuilder:
61
- """Take records"""
62
81
  self.take_count = count
63
82
  return self
64
-
83
+
84
+ # ------------------------------------------------
85
+ # SELECT
86
+ # ------------------------------------------------
87
+
65
88
  def select(self, *fields: str) -> QueryBuilder:
66
- """Select specific fields"""
67
- self.select_fields = list(fields)
89
+ self.selected_fields = list(fields)
90
+ return self
91
+
92
+ def select_fields(self, fields: List[str]) -> QueryBuilder:
93
+ self.selected_fields = fields
68
94
  return self
69
-
95
+
96
+ # ------------------------------------------------
97
+ # GROUP
98
+ # ------------------------------------------------
99
+
70
100
  def group_by(self, *fields: str) -> QueryBuilder:
71
- """Group by fields"""
72
101
  self.group_by_fields = list(fields)
73
102
  return self
74
-
75
- def distinct_on(self) -> QueryBuilder:
76
- """Return distinct results"""
77
- self.distinct = True
103
+
104
+ # ------------------------------------------------
105
+ # DISTINCT
106
+ # ------------------------------------------------
107
+
108
+ def distinct(self) -> QueryBuilder:
109
+ self.distinct_flag = True
78
110
  return self
79
-
111
+
112
+ # ------------------------------------------------
113
+ # COUNT
114
+ # ------------------------------------------------
115
+
80
116
  def count(self) -> QueryBuilder:
81
- """Return count only"""
82
117
  self.count_only = True
83
118
  return self
84
-
119
+
120
+ # ------------------------------------------------
121
+ # SQL WHERE
122
+ # ------------------------------------------------
123
+
85
124
  def to_sql_where(self) -> tuple[str, List[Any]]:
86
- """Convert to SQL WHERE clause"""
125
+
87
126
  if not self.filters:
88
127
  return "", []
89
-
128
+
90
129
  clauses = []
91
130
  params = []
92
-
131
+
93
132
  for f in self.filters:
133
+
94
134
  if f.operator == Operator.EQ:
95
135
  clauses.append(f"{f.field} = %s")
96
136
  params.append(f.value)
137
+
97
138
  elif f.operator == Operator.NE:
98
139
  clauses.append(f"{f.field} != %s")
99
140
  params.append(f.value)
141
+
100
142
  elif f.operator == Operator.GT:
101
143
  clauses.append(f"{f.field} > %s")
102
144
  params.append(f.value)
145
+
103
146
  elif f.operator == Operator.GTE:
104
147
  clauses.append(f"{f.field} >= %s")
105
148
  params.append(f.value)
149
+
106
150
  elif f.operator == Operator.LT:
107
151
  clauses.append(f"{f.field} < %s")
108
152
  params.append(f.value)
153
+
109
154
  elif f.operator == Operator.LTE:
110
155
  clauses.append(f"{f.field} <= %s")
111
156
  params.append(f.value)
157
+
112
158
  elif f.operator == Operator.IN:
113
- placeholders = ','.join(['%s'] * len(f.value))
114
- clauses.append(f"{f.field} IN ({placeholders})")
115
- params.extend(f.value)
159
+
160
+ if isinstance(f.value, (list, tuple)):
161
+ placeholders = ",".join(["%s"] * len(f.value))
162
+ clauses.append(f"{f.field} IN ({placeholders})")
163
+ params.extend(f.value)
164
+
165
+ else:
166
+ clauses.append(f"{f.field} LIKE %s")
167
+ params.append(f.value)
168
+
116
169
  elif f.operator == Operator.NOT_IN:
117
- placeholders = ','.join(['%s'] * len(f.value))
170
+ placeholders = ",".join(["%s"] * len(f.value))
118
171
  clauses.append(f"{f.field} NOT IN ({placeholders})")
119
172
  params.extend(f.value)
173
+
120
174
  elif f.operator == Operator.CONTAINS:
121
175
  clauses.append(f"{f.field} LIKE %s")
122
176
  params.append(f"%{f.value}%")
177
+
123
178
  elif f.operator == Operator.STARTS_WITH:
124
179
  clauses.append(f"{f.field} LIKE %s")
125
180
  params.append(f"{f.value}%")
181
+
126
182
  elif f.operator == Operator.ENDS_WITH:
127
183
  clauses.append(f"{f.field} LIKE %s")
128
184
  params.append(f"%{f.value}")
129
-
185
+
130
186
  return " AND ".join(clauses), params
131
-
187
+
188
+ # ------------------------------------------------
189
+ # NOSQL FILTER
190
+ # ------------------------------------------------
191
+
132
192
  def to_nosql_filter(self) -> Dict[str, Any]:
133
- """Convert to NoSQL filter dict"""
193
+
134
194
  result = {}
195
+
135
196
  for f in self.filters:
197
+
136
198
  if f.operator == Operator.EQ:
137
199
  result[f.field] = f.value
200
+
138
201
  elif f.operator == Operator.IN:
139
202
  result[f"{f.field}__in"] = f.value
203
+
140
204
  elif f.operator == Operator.GT:
141
205
  result[f"{f.field}__gt"] = f.value
206
+
142
207
  elif f.operator == Operator.GTE:
143
208
  result[f"{f.field}__gte"] = f.value
209
+
144
210
  elif f.operator == Operator.LT:
145
211
  result[f"{f.field}__lt"] = f.value
212
+
146
213
  elif f.operator == Operator.LTE:
147
214
  result[f"{f.field}__lte"] = f.value
215
+
148
216
  elif f.operator == Operator.CONTAINS:
149
217
  result[f"{f.field}__contains"] = f.value
150
- return result
218
+
219
+ return result