postgresdb3 1.0.3__tar.gz → 1.1.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.
Files changed (31) hide show
  1. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/PKG-INFO +7 -6
  2. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/README.md +6 -5
  3. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/core/async_db.py +4 -0
  4. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/models.py +8 -4
  5. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/query.py +43 -20
  6. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3.egg-info/PKG-INFO +7 -6
  7. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/setup.py +1 -1
  8. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/__init__.py +0 -0
  9. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/cli.py +0 -0
  10. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/core/__init__.py +0 -0
  11. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/core/sync_db.py +0 -0
  12. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/migrations/__init__.py +0 -0
  13. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/migrations/engine.py +0 -0
  14. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/__init__.py +0 -0
  15. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/base.py +0 -0
  16. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/expressions.py +0 -0
  17. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/fields/__init__.py +0 -0
  18. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/fields/base.py +0 -0
  19. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/fields/datetime.py +0 -0
  20. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/fields/foreign.py +0 -0
  21. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/fields/misc.py +0 -0
  22. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/fields/numeric.py +0 -0
  23. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/fields/text.py +0 -0
  24. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/meta.py +0 -0
  25. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3/orm/relations.py +0 -0
  26. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3.egg-info/SOURCES.txt +0 -0
  27. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3.egg-info/dependency_links.txt +0 -0
  28. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3.egg-info/requires.txt +0 -0
  29. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/postgresdb3.egg-info/top_level.txt +0 -0
  30. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/pyproject.toml +0 -0
  31. {postgresdb3-1.0.3 → postgresdb3-1.1.0}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: postgresdb3
3
- Version: 1.0.3
3
+ Version: 1.1.0
4
4
  Summary: High-Performance Sync and Async PostgreSQL ORM for Python
5
5
  Author: Abdulbosit Alijonov
6
6
  Project-URL: Source Code, https://github.com/AlijonovUz/PostgresDB
@@ -132,7 +132,7 @@ users = User.raw_sql("SELECT * FROM users WHERE age > %s", 20)
132
132
  print(users[0].name) # Bu Model Obyekti!
133
133
 
134
134
  # Asinxron
135
- users = await AsyncUser.raw_sql("SELECT * FROM asyncusers WHERE age > $1", 20)
135
+ users = await AsyncUser.raw_sql("SELECT * FROM asyncusers WHERE age > %s", 20)
136
136
  ```
137
137
 
138
138
  ---
@@ -244,15 +244,16 @@ for u in users:
244
244
  u.age += 1
245
245
  User.bulk_update(users, fields=["age"])
246
246
  ```
247
+ *(Eslatma: Ommaviy amallar to'liq atomar tranzaksiyaga o'ralgan, xatolik chiqsa 100% orqaga qaytadi!)*
247
248
 
248
249
  **Sahifalash (Pagination):**
249
250
  Foydalanuvchiga ma'lumotlarni qismlab (limit/offset bilan avtomatik) taqdim etish:
250
251
  ```python
251
252
  result = User.query().paginate(page=1, per_page=20)
252
- print(result["total"]) # Jami elementlar soni
253
- print(result["pages"]) # Jami sahifalar soni
254
- print(result["has_next"]) # Keyingi sahifa bormi? (True/False)
255
- print(result["data"]) # Modellar ro'yxati (20 ta)
253
+ print(result.total) # Jami elementlar soni
254
+ print(result.pages) # Jami sahifalar soni
255
+ print(result.has_next) # Keyingi sahifa bormi? (True/False)
256
+ print(result.data) # Modellar ro'yxati (20 ta)
256
257
  ```
257
258
 
258
259
  ---
@@ -110,7 +110,7 @@ users = User.raw_sql("SELECT * FROM users WHERE age > %s", 20)
110
110
  print(users[0].name) # Bu Model Obyekti!
111
111
 
112
112
  # Asinxron
113
- users = await AsyncUser.raw_sql("SELECT * FROM asyncusers WHERE age > $1", 20)
113
+ users = await AsyncUser.raw_sql("SELECT * FROM asyncusers WHERE age > %s", 20)
114
114
  ```
115
115
 
116
116
  ---
@@ -222,15 +222,16 @@ for u in users:
222
222
  u.age += 1
223
223
  User.bulk_update(users, fields=["age"])
224
224
  ```
225
+ *(Eslatma: Ommaviy amallar to'liq atomar tranzaksiyaga o'ralgan, xatolik chiqsa 100% orqaga qaytadi!)*
225
226
 
226
227
  **Sahifalash (Pagination):**
227
228
  Foydalanuvchiga ma'lumotlarni qismlab (limit/offset bilan avtomatik) taqdim etish:
228
229
  ```python
229
230
  result = User.query().paginate(page=1, per_page=20)
230
- print(result["total"]) # Jami elementlar soni
231
- print(result["pages"]) # Jami sahifalar soni
232
- print(result["has_next"]) # Keyingi sahifa bormi? (True/False)
233
- print(result["data"]) # Modellar ro'yxati (20 ta)
231
+ print(result.total) # Jami elementlar soni
232
+ print(result.pages) # Jami sahifalar soni
233
+ print(result.has_next) # Keyingi sahifa bormi? (True/False)
234
+ print(result.data) # Modellar ro'yxati (20 ta)
234
235
  ```
235
236
 
236
237
  ---
@@ -27,6 +27,10 @@ class AsyncPostgresDB:
27
27
  self._async_conn = contextvars.ContextVar(f"async_conn_{id(self)}", default=None)
28
28
 
29
29
  async def _manager(self, sql: str, *params, fetchone=False, fetchall=False, commit=False, many=False) -> Any:
30
+ if "%s" in sql:
31
+ parts = sql.split("%s")
32
+ sql = "".join([part + f"${i+1}" for i, part in enumerate(parts[:-1])]) + parts[-1]
33
+
30
34
  if self.echo:
31
35
  print(f"\033[94m[SQL]: {sql} \n[PARAMS]: {params}\033[0m")
32
36
  if not self.pool:
@@ -131,7 +131,8 @@ class Model(BaseModel, metaclass=ModelMeta):
131
131
  values_list.append(val_tuple)
132
132
 
133
133
  columns_str = ", ".join(columns)
134
- cls.db.insert_many(cls.table, columns_str, values_list)
134
+ with cls.db.transaction():
135
+ cls.db.insert_many(cls.table, columns_str, values_list)
135
136
 
136
137
  @classmethod
137
138
  def bulk_update(cls, instances: list["Model"], fields: list[str]) -> None:
@@ -147,7 +148,8 @@ class Model(BaseModel, metaclass=ModelMeta):
147
148
  val_tuple = tuple(getattr(inst, f, None) for f in fields) + (getattr(inst, pk_name),)
148
149
  values_list.append(val_tuple)
149
150
 
150
- cls.db._manager(sql, values_list, commit=True, many=True)
151
+ with cls.db.transaction():
152
+ cls.db._manager(sql, values_list, commit=True, many=True)
151
153
 
152
154
  def save(self):
153
155
  self.__class__._check_setup()
@@ -345,7 +347,8 @@ class AsyncModel(BaseModel, metaclass=ModelMeta):
345
347
  values_list.append(val_tuple)
346
348
 
347
349
  columns_str = ", ".join(columns)
348
- await cls.db.insert_many(cls.table, columns_str, values_list)
350
+ async with cls.db.transaction():
351
+ await cls.db.insert_many(cls.table, columns_str, values_list)
349
352
 
350
353
  @classmethod
351
354
  async def bulk_update(cls, instances: list["AsyncModel"], fields: list[str]) -> None:
@@ -361,7 +364,8 @@ class AsyncModel(BaseModel, metaclass=ModelMeta):
361
364
  val_tuple = tuple(getattr(inst, f, None) for f in fields) + (getattr(inst, pk_name),)
362
365
  values_list.append(val_tuple)
363
366
 
364
- await cls.db._manager(sql, values_list, commit=True, many=True)
367
+ async with cls.db.transaction():
368
+ await cls.db._manager(sql, values_list, commit=True, many=True)
365
369
 
366
370
  async def save(self):
367
371
  self.__class__._check_setup()
@@ -1,3 +1,18 @@
1
+ from dataclasses import dataclass
2
+ from typing import TypeVar, Generic
3
+
4
+ T = TypeVar('T')
5
+
6
+ @dataclass
7
+ class PaginationResult(Generic[T]):
8
+ total: int
9
+ pages: int
10
+ current_page: int
11
+ per_page: int
12
+ has_next: bool
13
+ has_prev: bool
14
+ data: list[T]
15
+
1
16
  class QuerySet:
2
17
  def __init__(self, model):
3
18
  self.model = model
@@ -80,7 +95,11 @@ class QuerySet:
80
95
  for field_name in fields:
81
96
  field = self.model._fields.get(field_name)
82
97
  if not field or not hasattr(field, "to"):
83
- raise ValueError(f"{field_name} ForeignKey emas yoki topilmadi")
98
+ raise ValueError(f"'{field_name}' xato kiritildi. select_related faqat ForeignKey yoki OneToOneField bilan ishlaydi.")
99
+
100
+ from .fields.foreign import ManyToManyField
101
+ if isinstance(field, ManyToManyField):
102
+ raise TypeError(f"'{field_name}' bu ManyToManyField! Uning uchun select_related() emas, balki prefetch_related() ishlating.")
84
103
 
85
104
  related_table = field.to.table
86
105
  on_condition = f"{self.model.table}.{field_name} = {related_table}.{field.to.get_pk_name()}"
@@ -309,15 +328,15 @@ class QuerySet:
309
328
  total = self.count()
310
329
  pages = (total + per_page - 1) // per_page
311
330
  data = self.limit(per_page).offset((page - 1) * per_page).all()
312
- return {
313
- "total": total,
314
- "pages": pages,
315
- "current_page": page,
316
- "per_page": per_page,
317
- "has_next": page < pages,
318
- "has_prev": page > 1,
319
- "data": data
320
- }
331
+ return PaginationResult(
332
+ total=total,
333
+ pages=pages,
334
+ current_page=page,
335
+ per_page=per_page,
336
+ has_next=page < pages,
337
+ has_prev=page > 1,
338
+ data=data
339
+ )
321
340
 
322
341
  def exists(self):
323
342
  where = self._build_where()
@@ -486,7 +505,11 @@ class AsyncQuerySet:
486
505
  for field_name in fields:
487
506
  field = self.model._fields.get(field_name)
488
507
  if not field or not hasattr(field, "to"):
489
- raise ValueError(f"{field_name} ForeignKey emas yoki topilmadi")
508
+ raise ValueError(f"'{field_name}' xato kiritildi. select_related faqat ForeignKey yoki OneToOneField bilan ishlaydi.")
509
+
510
+ from .fields.foreign import ManyToManyField
511
+ if isinstance(field, ManyToManyField):
512
+ raise TypeError(f"'{field_name}' bu ManyToManyField! Uning uchun select_related() emas, balki prefetch_related() ishlating.")
490
513
 
491
514
  related_table = field.to.table
492
515
  on_condition = f"{self.model.table}.{field_name} = {related_table}.{field.to.get_pk_name()}"
@@ -649,15 +672,15 @@ class AsyncQuerySet:
649
672
  total = await self.count()
650
673
  pages = (total + per_page - 1) // per_page
651
674
  data = await self.limit(per_page).offset((page - 1) * per_page).all()
652
- return {
653
- "total": total,
654
- "pages": pages,
655
- "current_page": page,
656
- "per_page": per_page,
657
- "has_next": page < pages,
658
- "has_prev": page > 1,
659
- "data": data
660
- }
675
+ return PaginationResult(
676
+ total=total,
677
+ pages=pages,
678
+ current_page=page,
679
+ per_page=per_page,
680
+ has_next=page < pages,
681
+ has_prev=page > 1,
682
+ data=data
683
+ )
661
684
 
662
685
  async def exists(self):
663
686
  where = self._build_where()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: postgresdb3
3
- Version: 1.0.3
3
+ Version: 1.1.0
4
4
  Summary: High-Performance Sync and Async PostgreSQL ORM for Python
5
5
  Author: Abdulbosit Alijonov
6
6
  Project-URL: Source Code, https://github.com/AlijonovUz/PostgresDB
@@ -132,7 +132,7 @@ users = User.raw_sql("SELECT * FROM users WHERE age > %s", 20)
132
132
  print(users[0].name) # Bu Model Obyekti!
133
133
 
134
134
  # Asinxron
135
- users = await AsyncUser.raw_sql("SELECT * FROM asyncusers WHERE age > $1", 20)
135
+ users = await AsyncUser.raw_sql("SELECT * FROM asyncusers WHERE age > %s", 20)
136
136
  ```
137
137
 
138
138
  ---
@@ -244,15 +244,16 @@ for u in users:
244
244
  u.age += 1
245
245
  User.bulk_update(users, fields=["age"])
246
246
  ```
247
+ *(Eslatma: Ommaviy amallar to'liq atomar tranzaksiyaga o'ralgan, xatolik chiqsa 100% orqaga qaytadi!)*
247
248
 
248
249
  **Sahifalash (Pagination):**
249
250
  Foydalanuvchiga ma'lumotlarni qismlab (limit/offset bilan avtomatik) taqdim etish:
250
251
  ```python
251
252
  result = User.query().paginate(page=1, per_page=20)
252
- print(result["total"]) # Jami elementlar soni
253
- print(result["pages"]) # Jami sahifalar soni
254
- print(result["has_next"]) # Keyingi sahifa bormi? (True/False)
255
- print(result["data"]) # Modellar ro'yxati (20 ta)
253
+ print(result.total) # Jami elementlar soni
254
+ print(result.pages) # Jami sahifalar soni
255
+ print(result.has_next) # Keyingi sahifa bormi? (True/False)
256
+ print(result.data) # Modellar ro'yxati (20 ta)
256
257
  ```
257
258
 
258
259
  ---
@@ -5,7 +5,7 @@ with open("README.md", "r", encoding="utf-8") as f:
5
5
 
6
6
  setup(
7
7
  name="postgresdb3",
8
- version="1.0.3",
8
+ version="1.1.0",
9
9
  packages=find_packages(),
10
10
  install_requires=[
11
11
  "psycopg2>=2.9",
File without changes
File without changes