postgresdb3 0.3.5__tar.gz → 0.4.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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: postgresdb3
3
- Version: 0.3.5
3
+ Version: 0.4.0
4
4
  Summary: Python uchun oddiy PostgreSQL wrapper
5
5
  Author: Abdulbosit Alijonov
6
6
  Project-URL: Source Code, https://github.com/AlijonovUz/PostgresDB
@@ -65,18 +65,62 @@ db.insert_many(
65
65
  users = db.select("users")
66
66
  print(users)
67
67
 
68
+ # Faqat kerakli ustunlarni olish
69
+ users = db.select("users", columns=["id", "name"])
70
+ print(users)
71
+
68
72
  # Bitta qatorni olish
69
- user = db.select("users", where=("name=%s", ["Ali"]), fetchone=True)
73
+ user = db.select("users", where={"name": "Ali"}, fetchone=True)
70
74
  print(user)
71
75
 
72
76
  # Shart bilan ma'lumot olish
73
- adults = db.select("users", where=("age > %s", [18]))
77
+ adults = db.select("users", where={"age__gt": 18})
74
78
  print(adults)
75
79
 
76
80
  # Bir nechta shart bilan
77
- specific_users = db.select("users", where=("age > %s AND name = %s", [18, "Ali"]))
81
+ specific_users = db.select(
82
+ "users",
83
+ where={
84
+ "age__gt": 18,
85
+ "name": "Ali"
86
+ }
87
+ )
78
88
  print(specific_users)
79
89
 
90
+ # LIKE bilan qidirish
91
+ users_like = db.select("users", where={"name__like": "%Ali%"})
92
+ print(users_like)
93
+
94
+ # ILIKE bilan qidirish
95
+ users_ilike = db.select("users", where={"name__ilike": "%ali%"})
96
+ print(users_ilike)
97
+
98
+ # IN bilan qidirish
99
+ selected_users = db.select("users", where={"id__in": [1, 2, 3]})
100
+ print(selected_users)
101
+
102
+ # NULL bilan ishlash
103
+ users_with_null = db.select("users", where={"name__isnull": False})
104
+ print(users_with_null)
105
+
106
+ # Tartiblash va limit
107
+ ordered_users = db.select(
108
+ "users",
109
+ where={"age__gt": 18},
110
+ order_by="age DESC",
111
+ limit=2
112
+ )
113
+ print(ordered_users)
114
+
115
+ # Pagination
116
+ paged_users = db.select(
117
+ "users",
118
+ order_by="id ASC",
119
+ limit=2,
120
+ offset=2
121
+ )
122
+ print(paged_users)
123
+
80
124
  # Faqat 2 ta qatorni olish
81
125
  users = db.select("users", fetchmany=2)
82
126
  print(users)
@@ -130,18 +174,62 @@ async def main():
130
174
  users = await db.select("users")
131
175
  print("Barcha foydalanuvchilar:", users)
132
176
 
177
+ # Faqat kerakli ustunlarni olish
178
+ users = await db.select("users", columns=["id", "name"])
179
+ print("Faqat id va name:", users)
180
+
133
181
  # Bitta qatorni olish
134
- user = await db.select("users", where=("name=$1", ["Ali"]), fetchone=True)
182
+ user = await db.select("users", where={"name": "Ali"}, fetchone=True)
135
183
  print("Foydalanuvchi Ali:", user)
136
184
 
137
185
  # Shart bilan ma'lumot olish
138
- adults = await db.select("users", where=("age > $1", [18]))
186
+ adults = await db.select("users", where={"age__gt": 18})
139
187
  print("Kattalar:", adults)
140
188
 
141
189
  # Bir nechta shart bilan
142
- specific_users = await db.select("users", where=("age > $1 AND name = $2", [18, "Ali"]))
190
+ specific_users = await db.select(
191
+ "users",
192
+ where={
193
+ "age__gt": 18,
194
+ "name": "Ali"
195
+ }
196
+ )
143
197
  print("Maxsus foydalanuvchi:", specific_users)
144
-
198
+
199
+ # LIKE bilan qidirish
200
+ users_like = await db.select("users", where={"name__like": "%Ali%"})
201
+ print("LIKE bo'yicha qidiruv:", users_like)
202
+
203
+ # ILIKE bilan qidirish
204
+ users_ilike = await db.select("users", where={"name__ilike": "%ali%"})
205
+ print("ILIKE bo'yicha qidiruv:", users_ilike)
206
+
207
+ # IN bilan qidirish
208
+ selected_users = await db.select("users", where={"id__in": [1, 2, 3]})
209
+ print("Tanlangan foydalanuvchilar:", selected_users)
210
+
211
+ # NULL bilan ishlash
212
+ users_with_not_null_name = await db.select("users", where={"name__isnull": False})
213
+ print("Name NULL bo'lmaganlar:", users_with_not_null_name)
214
+
215
+ # Tartiblash va limit
216
+ ordered_users = await db.select(
217
+ "users",
218
+ where={"age__gt": 18},
219
+ order_by="age DESC",
220
+ limit=2
221
+ )
222
+ print("Tartiblangan foydalanuvchilar:", ordered_users)
223
+
224
+ # Pagination
225
+ paged_users = await db.select(
226
+ "users",
227
+ order_by="id ASC",
228
+ limit=2,
229
+ offset=1
230
+ )
231
+ print("Pagination natijasi:", paged_users)
232
+
145
233
  # Jadvaldagi ma'lumotni yangilash
146
234
  await db.update("users", "age", 26, "name", "Ali")
147
235
 
@@ -43,18 +43,62 @@ db.insert_many(
43
43
  users = db.select("users")
44
44
  print(users)
45
45
 
46
+ # Faqat kerakli ustunlarni olish
47
+ users = db.select("users", columns=["id", "name"])
48
+ print(users)
49
+
46
50
  # Bitta qatorni olish
47
- user = db.select("users", where=("name=%s", ["Ali"]), fetchone=True)
51
+ user = db.select("users", where={"name": "Ali"}, fetchone=True)
48
52
  print(user)
49
53
 
50
54
  # Shart bilan ma'lumot olish
51
- adults = db.select("users", where=("age > %s", [18]))
55
+ adults = db.select("users", where={"age__gt": 18})
52
56
  print(adults)
53
57
 
54
58
  # Bir nechta shart bilan
55
- specific_users = db.select("users", where=("age > %s AND name = %s", [18, "Ali"]))
59
+ specific_users = db.select(
60
+ "users",
61
+ where={
62
+ "age__gt": 18,
63
+ "name": "Ali"
64
+ }
65
+ )
56
66
  print(specific_users)
57
67
 
68
+ # LIKE bilan qidirish
69
+ users_like = db.select("users", where={"name__like": "%Ali%"})
70
+ print(users_like)
71
+
72
+ # ILIKE bilan qidirish
73
+ users_ilike = db.select("users", where={"name__ilike": "%ali%"})
74
+ print(users_ilike)
75
+
76
+ # IN bilan qidirish
77
+ selected_users = db.select("users", where={"id__in": [1, 2, 3]})
78
+ print(selected_users)
79
+
80
+ # NULL bilan ishlash
81
+ users_with_null = db.select("users", where={"name__isnull": False})
82
+ print(users_with_null)
83
+
84
+ # Tartiblash va limit
85
+ ordered_users = db.select(
86
+ "users",
87
+ where={"age__gt": 18},
88
+ order_by="age DESC",
89
+ limit=2
90
+ )
91
+ print(ordered_users)
92
+
93
+ # Pagination
94
+ paged_users = db.select(
95
+ "users",
96
+ order_by="id ASC",
97
+ limit=2,
98
+ offset=2
99
+ )
100
+ print(paged_users)
101
+
58
102
  # Faqat 2 ta qatorni olish
59
103
  users = db.select("users", fetchmany=2)
60
104
  print(users)
@@ -108,18 +152,62 @@ async def main():
108
152
  users = await db.select("users")
109
153
  print("Barcha foydalanuvchilar:", users)
110
154
 
155
+ # Faqat kerakli ustunlarni olish
156
+ users = await db.select("users", columns=["id", "name"])
157
+ print("Faqat id va name:", users)
158
+
111
159
  # Bitta qatorni olish
112
- user = await db.select("users", where=("name=$1", ["Ali"]), fetchone=True)
160
+ user = await db.select("users", where={"name": "Ali"}, fetchone=True)
113
161
  print("Foydalanuvchi Ali:", user)
114
162
 
115
163
  # Shart bilan ma'lumot olish
116
- adults = await db.select("users", where=("age > $1", [18]))
164
+ adults = await db.select("users", where={"age__gt": 18})
117
165
  print("Kattalar:", adults)
118
166
 
119
167
  # Bir nechta shart bilan
120
- specific_users = await db.select("users", where=("age > $1 AND name = $2", [18, "Ali"]))
168
+ specific_users = await db.select(
169
+ "users",
170
+ where={
171
+ "age__gt": 18,
172
+ "name": "Ali"
173
+ }
174
+ )
121
175
  print("Maxsus foydalanuvchi:", specific_users)
122
-
176
+
177
+ # LIKE bilan qidirish
178
+ users_like = await db.select("users", where={"name__like": "%Ali%"})
179
+ print("LIKE bo'yicha qidiruv:", users_like)
180
+
181
+ # ILIKE bilan qidirish
182
+ users_ilike = await db.select("users", where={"name__ilike": "%ali%"})
183
+ print("ILIKE bo'yicha qidiruv:", users_ilike)
184
+
185
+ # IN bilan qidirish
186
+ selected_users = await db.select("users", where={"id__in": [1, 2, 3]})
187
+ print("Tanlangan foydalanuvchilar:", selected_users)
188
+
189
+ # NULL bilan ishlash
190
+ users_with_not_null_name = await db.select("users", where={"name__isnull": False})
191
+ print("Name NULL bo'lmaganlar:", users_with_not_null_name)
192
+
193
+ # Tartiblash va limit
194
+ ordered_users = await db.select(
195
+ "users",
196
+ where={"age__gt": 18},
197
+ order_by="age DESC",
198
+ limit=2
199
+ )
200
+ print("Tartiblangan foydalanuvchilar:", ordered_users)
201
+
202
+ # Pagination
203
+ paged_users = await db.select(
204
+ "users",
205
+ order_by="id ASC",
206
+ limit=2,
207
+ offset=1
208
+ )
209
+ print("Pagination natijasi:", paged_users)
210
+
123
211
  # Jadvaldagi ma'lumotni yangilash
124
212
  await db.update("users", "age", 26, "name", "Ali")
125
213
 
@@ -95,11 +95,171 @@ class AsyncPostgresDB:
95
95
 
96
96
  await self._manager(sql, commit=True)
97
97
 
98
+ def _validate_identifier(self, value: str, name: str = "identifier") -> str:
99
+ """
100
+ Jadval yoki ustun nomi uchun minimal tekshiruv.
101
+ Faqat harf, raqam, underscore va nuqtaga ruxsat beradi.
102
+ """
103
+ if not isinstance(value, str) or not value.strip():
104
+ raise ValueError(f"{name} bo'sh bo'lmasligi kerak")
105
+
106
+ cleaned = value.replace("_", "").replace(".", "")
107
+ if not cleaned.isalnum():
108
+ raise ValueError(f"Invalid {name}: {value}")
109
+
110
+ return value
111
+
112
+ def _normalize_columns(self, columns: str | list[str]) -> str:
113
+ """
114
+ columns list bo'lsa stringga aylantiradi.
115
+ list bo'lsa har bir column validate qilinadi.
116
+ str bo'lsa SQL expression bo'lishi mumkinligi uchun o'z holicha qaytariladi.
117
+ """
118
+ if isinstance(columns, list):
119
+ if not columns:
120
+ raise ValueError("columns bo'sh list bo'lmasligi kerak")
121
+
122
+ validated_columns = [self._validate_identifier(col, "column") for col in columns]
123
+ return ", ".join(validated_columns)
124
+
125
+ if not isinstance(columns, str) or not columns.strip():
126
+ raise ValueError("columns noto'g'ri bo'lishi mumkin emas")
127
+
128
+ return columns
129
+
130
+ def _build_where(self, where: Any, start_index: int = 1) -> tuple[str, list]:
131
+ """
132
+ Qo'llab-quvvatlanadi:
133
+
134
+ 1) tuple:
135
+ ("age > $1", [18])
136
+
137
+ 2) dict:
138
+ {
139
+ "age__gt": 18,
140
+ "name__ilike": "%ali%",
141
+ "status": "active",
142
+ "id__in": [1, 2, 3],
143
+ "deleted_at__isnull": True
144
+ }
145
+
146
+ 3) list[tuple]:
147
+ [
148
+ ("age", ">", 18),
149
+ ("name", "ILIKE", "%ali%"),
150
+ ("status", "=", "active")
151
+ ]
152
+ """
153
+ if where is None:
154
+ return "", []
155
+
156
+ if isinstance(where, tuple) and len(where) == 2:
157
+ condition, values = where
158
+ return condition, list(values)
159
+
160
+ if isinstance(where, dict):
161
+ clauses = []
162
+ params = []
163
+ index = start_index
164
+
165
+ operator_map = {
166
+ "eq": "=",
167
+ "ne": "!=",
168
+ "gt": ">",
169
+ "gte": ">=",
170
+ "lt": "<",
171
+ "lte": "<=",
172
+ "like": "LIKE",
173
+ "ilike": "ILIKE",
174
+ }
175
+
176
+ for key, value in where.items():
177
+ if "__" in key:
178
+ field, op = key.rsplit("__", 1)
179
+ else:
180
+ field, op = key, "eq"
181
+
182
+ self._validate_identifier(field, "where field")
183
+
184
+ if op in operator_map:
185
+ clauses.append(f"{field} {operator_map[op]} ${index}")
186
+ params.append(value)
187
+ index += 1
188
+
189
+ elif op == "in":
190
+ if not isinstance(value, (list, tuple)) or not value:
191
+ raise ValueError(f"{field}__in uchun bo'sh bo'lmagan list/tuple kerak")
192
+
193
+ placeholders = ", ".join(f"${i}" for i in range(index, index + len(value)))
194
+ clauses.append(f"{field} IN ({placeholders})")
195
+ params.extend(value)
196
+ index += len(value)
197
+
198
+ elif op == "not_in":
199
+ if not isinstance(value, (list, tuple)) or not value:
200
+ raise ValueError(f"{field}__not_in uchun bo'sh bo'lmagan list/tuple kerak")
201
+
202
+ placeholders = ", ".join(f"${i}" for i in range(index, index + len(value)))
203
+ clauses.append(f"{field} NOT IN ({placeholders})")
204
+ params.extend(value)
205
+ index += len(value)
206
+
207
+ elif op == "isnull":
208
+ if value:
209
+ clauses.append(f"{field} IS NULL")
210
+ else:
211
+ clauses.append(f"{field} IS NOT NULL")
212
+
213
+ else:
214
+ raise ValueError(f"Noma'lum operator: {op}")
215
+
216
+ return " AND ".join(clauses), params
217
+
218
+ if isinstance(where, list):
219
+ clauses = []
220
+ params = []
221
+ index = start_index
222
+
223
+ for item in where:
224
+ if len(item) != 3:
225
+ raise ValueError("List formatidagi where elementlari (field, operator, value) bo'lishi kerak")
226
+
227
+ field, operator, value = item
228
+ self._validate_identifier(field, "where field")
229
+ op = operator.upper()
230
+
231
+ if op in {"=", "!=", ">", ">=", "<", "<=", "LIKE", "ILIKE"}:
232
+ clauses.append(f"{field} {op} ${index}")
233
+ params.append(value)
234
+ index += 1
235
+
236
+ elif op in {"IN", "NOT IN"}:
237
+ if not isinstance(value, (list, tuple)) or not value:
238
+ raise ValueError(f"{field} {op} uchun bo'sh bo'lmagan list/tuple kerak")
239
+
240
+ placeholders = ", ".join(f"${i}" for i in range(index, index + len(value)))
241
+ clauses.append(f"{field} {op} ({placeholders})")
242
+ params.extend(value)
243
+ index += len(value)
244
+
245
+ elif op == "IS NULL":
246
+ clauses.append(f"{field} IS NULL")
247
+
248
+ elif op == "IS NOT NULL":
249
+ clauses.append(f"{field} IS NOT NULL")
250
+
251
+ else:
252
+ raise ValueError(f"Noma'lum operator: {operator}")
253
+
254
+ return " AND ".join(clauses), params
255
+
256
+ raise TypeError("where tuple, dict yoki list bo'lishi kerak")
257
+
98
258
  async def select(
99
259
  self,
100
260
  table: str,
101
- columns: str = "*",
102
- where: Optional[List[Any]] = None,
261
+ columns: str | list[str] = "*",
262
+ where: tuple | dict | list | None = None,
103
263
  join: Optional[List[tuple]] = None,
104
264
  group_by: Optional[str] = None,
105
265
  order_by: Optional[str] = None,
@@ -112,8 +272,11 @@ class AsyncPostgresDB:
112
272
 
113
273
  Args:
114
274
  table (str): Asosiy jadval nomi.
115
- columns (str): Tanlanadigan ustunlar (default: "*").
116
- where (Optional[List[Any]]): ("shart", [qiymatlar])
275
+ columns (str | list[str]): Tanlanadigan ustunlar.
276
+ where:
277
+ tuple — ("age > $1", [18])
278
+ dict — {"age__gt": 18, "name__ilike": "%ali%"}
279
+ list — [("age", ">", 18), ("name", "ILIKE", "%ali%")]
117
280
  join (Optional[List[tuple]]): [("INNER JOIN", "orders", "users.id = orders.user_id")]
118
281
  group_by (Optional[str]): GROUP BY ustuni.
119
282
  order_by (Optional[str]): ORDER BY qoidasi.
@@ -124,17 +287,22 @@ class AsyncPostgresDB:
124
287
  Returns:
125
288
  asyncpg.Record yoki list[asyncpg.Record]
126
289
  """
290
+ table = self._validate_identifier(table, "table")
291
+ columns = self._normalize_columns(columns)
292
+
127
293
  sql = f"SELECT {columns} FROM {table}"
128
294
  params: List[Any] = []
129
295
 
130
296
  if join:
131
297
  for join_type, join_table, on_condition in join:
298
+ join_table = self._validate_identifier(join_table, "join table")
132
299
  sql += f" {join_type} {join_table} ON {on_condition}"
133
300
 
134
301
  if where:
135
- condition, values = where
136
- sql += f" WHERE {condition}"
137
- params.extend(values)
302
+ condition, values = self._build_where(where, start_index=1)
303
+ if condition:
304
+ sql += f" WHERE {condition}"
305
+ params.extend(values)
138
306
 
139
307
  if group_by:
140
308
  sql += f" GROUP BY {group_by}"
@@ -143,11 +311,11 @@ class AsyncPostgresDB:
143
311
  sql += f" ORDER BY {order_by}"
144
312
 
145
313
  if limit is not None:
146
- sql += f" LIMIT $%d" % (len(params) + 1)
314
+ sql += f" LIMIT ${len(params) + 1}"
147
315
  params.append(limit)
148
316
 
149
317
  if offset is not None:
150
- sql += " OFFSET $%d" % (len(params) + 1)
318
+ sql += f" OFFSET ${len(params) + 1}"
151
319
  params.append(offset)
152
320
 
153
321
  return await self._manager(sql, *params, fetchone=fetchone, fetchall=not fetchone)
@@ -204,11 +204,158 @@ class PostgresDB:
204
204
  sql += " CASCADE"
205
205
  self._manager(sql, commit=True)
206
206
 
207
+ def _build_where(self, where: Any) -> tuple[str, list]:
208
+ """
209
+ Qo'llab-quvvatlanadi:
210
+
211
+ 1) tuple:
212
+ ("age > %s", [18])
213
+
214
+ 2) dict:
215
+ {
216
+ "age__gt": 18,
217
+ "name__ilike": "%ali%",
218
+ "status": "active",
219
+ "id__in": [1, 2, 3],
220
+ "deleted_at__isnull": True
221
+ }
222
+
223
+ 3) list[tuple]:
224
+ [
225
+ ("age", ">", 18),
226
+ ("name", "ILIKE", "%ali%"),
227
+ ("status", "=", "active")
228
+ ]
229
+ """
230
+ if where is None:
231
+ return "", []
232
+
233
+ if isinstance(where, tuple) and len(where) == 2:
234
+ condition, values = where
235
+ return condition, list(values)
236
+
237
+ if isinstance(where, dict):
238
+ clauses = []
239
+ params = []
240
+
241
+ operator_map = {
242
+ "eq": "=",
243
+ "ne": "!=",
244
+ "gt": ">",
245
+ "gte": ">=",
246
+ "lt": "<",
247
+ "lte": "<=",
248
+ "like": "LIKE",
249
+ "ilike": "ILIKE",
250
+ }
251
+
252
+ for key, value in where.items():
253
+ if "__" in key:
254
+ field, op = key.rsplit("__", 1)
255
+ else:
256
+ field, op = key, "eq"
257
+
258
+ if op in operator_map:
259
+ clauses.append(f"{field} {operator_map[op]} %s")
260
+ params.append(value)
261
+
262
+ elif op == "in":
263
+ if not isinstance(value, (list, tuple)) or not value:
264
+ raise ValueError(f"{field}__in uchun bo'sh bo'lmagan list/tuple kerak")
265
+ placeholders = ", ".join(["%s"] * len(value))
266
+ clauses.append(f"{field} IN ({placeholders})")
267
+ params.extend(value)
268
+
269
+ elif op == "not_in":
270
+ if not isinstance(value, (list, tuple)) or not value:
271
+ raise ValueError(f"{field}__not_in uchun bo'sh bo'lmagan list/tuple kerak")
272
+ placeholders = ", ".join(["%s"] * len(value))
273
+ clauses.append(f"{field} NOT IN ({placeholders})")
274
+ params.extend(value)
275
+
276
+ elif op == "isnull":
277
+ if value:
278
+ clauses.append(f"{field} IS NULL")
279
+ else:
280
+ clauses.append(f"{field} IS NOT NULL")
281
+
282
+ else:
283
+ raise ValueError(f"Noma'lum operator: {op}")
284
+
285
+ return " AND ".join(clauses), params
286
+
287
+ if isinstance(where, list):
288
+ clauses = []
289
+ params = []
290
+
291
+ for item in where:
292
+ if len(item) != 3:
293
+ raise ValueError("List formatidagi where elementlari (field, operator, value) bo'lishi kerak")
294
+
295
+ field, operator, value = item
296
+ op = operator.upper()
297
+
298
+ if op in {"=", "!=", ">", ">=", "<", "<=", "LIKE", "ILIKE"}:
299
+ clauses.append(f"{field} {op} %s")
300
+ params.append(value)
301
+
302
+ elif op in {"IN", "NOT IN"}:
303
+ if not isinstance(value, (list, tuple)) or not value:
304
+ raise ValueError(f"{field} {op} uchun bo'sh bo'lmagan list/tuple kerak")
305
+ placeholders = ", ".join(["%s"] * len(value))
306
+ clauses.append(f"{field} {op} ({placeholders})")
307
+ params.extend(value)
308
+
309
+ elif op == "IS NULL":
310
+ clauses.append(f"{field} IS NULL")
311
+
312
+ elif op == "IS NOT NULL":
313
+ clauses.append(f"{field} IS NOT NULL")
314
+
315
+ else:
316
+ raise ValueError(f"Noma'lum operator: {operator}")
317
+
318
+ return " AND ".join(clauses), params
319
+
320
+ raise TypeError("where tuple, dict yoki list bo'lishi kerak")
321
+
322
+ def _validate_identifier(self, value: str, name: str = "identifier") -> str:
323
+ """
324
+ Jadval yoki ustun nomi uchun minimal tekshiruv.
325
+ Faqat harf, raqam, underscore va nuqtaga ruxsat beradi.
326
+ """
327
+ if not isinstance(value, str) or not value.strip():
328
+ raise ValueError(f"{name} bo'sh bo'lmasligi kerak")
329
+
330
+ cleaned = value.replace("_", "").replace(".", "")
331
+ if not cleaned.isalnum():
332
+ raise ValueError(f"Invalid {name}: {value}")
333
+
334
+ return value
335
+
336
+ def _normalize_columns(self, columns: str | list[str]) -> str:
337
+ """
338
+ columns list bo'lsa stringga aylantiradi.
339
+ list bo'lsa har bir column validate qilinadi.
340
+ str bo'lsa SQL expression bo'lishi mumkinligi uchun o'z holicha qaytariladi.
341
+ """
342
+ if isinstance(columns, list):
343
+ if not columns:
344
+ raise ValueError("columns bo'sh list bo'lmasligi kerak")
345
+
346
+ validated_columns = [self._validate_identifier(col, "column") for col in columns]
347
+ return ", ".join(validated_columns)
348
+
349
+ if not isinstance(columns, str) or not columns.strip():
350
+ raise ValueError("columns noto'g'ri bo'lishi mumkin emas")
351
+
352
+ return columns
353
+
207
354
  def select(
208
355
  self,
209
356
  table: str,
210
- columns: str = "*",
211
- where: tuple | None = None,
357
+ columns: str | list[str] = "*",
358
+ where: tuple | dict | list | None = None,
212
359
  join: list[tuple] | None = None,
213
360
  group_by: str | None = None,
214
361
  order_by: str | None = None,
@@ -219,8 +366,13 @@ class PostgresDB:
219
366
  ) -> Any:
220
367
  """
221
368
  table: str — asosiy jadval
222
- columns: str — tanlanadigan ustunlar ("id, name")
223
- where: tuple | None ("age > %s", [18])
369
+ columns:
370
+ str — "id, name"
371
+ list[str] — ["id", "name"]
372
+ where:
373
+ tuple — ("age > %s", [18])
374
+ dict — {"age__gt": 18, "name__ilike": "%ali%"}
375
+ list — [("age", ">", 18), ("name", "ILIKE", "%ali%")]
224
376
  join: list | None — [("INNER JOIN", "orders", "users.id = orders.user_id")]
225
377
  group_by: str | None — "age"
226
378
  order_by: str | None — "age DESC"
@@ -230,17 +382,22 @@ class PostgresDB:
230
382
  fetchmany: int | None
231
383
  """
232
384
 
385
+ table = self._validate_identifier(table, "table")
386
+ columns = self._normalize_columns(columns)
387
+
233
388
  sql = f"SELECT {columns} FROM {table}"
234
389
  params = []
235
390
 
236
391
  if join:
237
392
  for join_type, join_table, on_condition in join:
393
+ join_table = self._validate_identifier(join_table, "join table")
238
394
  sql += f" {join_type} {join_table} ON {on_condition}"
239
395
 
240
396
  if where:
241
- condition, values = where
242
- sql += f" WHERE {condition}"
243
- params.extend(values)
397
+ condition, values = self._build_where(where)
398
+ if condition:
399
+ sql += f" WHERE {condition}"
400
+ params.extend(values)
244
401
 
245
402
  if group_by:
246
403
  sql += f" GROUP BY {group_by}"
@@ -249,7 +406,7 @@ class PostgresDB:
249
406
  sql += f" ORDER BY {order_by}"
250
407
 
251
408
  if limit is not None:
252
- sql += f" LIMIT %s"
409
+ sql += " LIMIT %s"
253
410
  params.append(limit)
254
411
 
255
412
  if offset is not None:
@@ -337,7 +494,7 @@ class PostgresDB:
337
494
  SELECT table_name
338
495
  FROM information_schema.tables
339
496
  WHERE table_schema = %s
340
- ORDER BY table_name;
497
+ ORDER BY table_name; \
341
498
  """
342
499
  return self._manager(sql, (schema,), fetchall=True)
343
500
 
@@ -353,7 +510,7 @@ class PostgresDB:
353
510
  FROM information_schema.columns
354
511
  WHERE table_schema = %s
355
512
  AND table_name = %s
356
- ORDER BY ordinal_position;
513
+ ORDER BY ordinal_position; \
357
514
  """
358
515
  return self._manager(sql, (schema, table), fetchall=True)
359
516
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: postgresdb3
3
- Version: 0.3.5
3
+ Version: 0.4.0
4
4
  Summary: Python uchun oddiy PostgreSQL wrapper
5
5
  Author: Abdulbosit Alijonov
6
6
  Project-URL: Source Code, https://github.com/AlijonovUz/PostgresDB
@@ -65,18 +65,62 @@ db.insert_many(
65
65
  users = db.select("users")
66
66
  print(users)
67
67
 
68
+ # Faqat kerakli ustunlarni olish
69
+ users = db.select("users", columns=["id", "name"])
70
+ print(users)
71
+
68
72
  # Bitta qatorni olish
69
- user = db.select("users", where=("name=%s", ["Ali"]), fetchone=True)
73
+ user = db.select("users", where={"name": "Ali"}, fetchone=True)
70
74
  print(user)
71
75
 
72
76
  # Shart bilan ma'lumot olish
73
- adults = db.select("users", where=("age > %s", [18]))
77
+ adults = db.select("users", where={"age__gt": 18})
74
78
  print(adults)
75
79
 
76
80
  # Bir nechta shart bilan
77
- specific_users = db.select("users", where=("age > %s AND name = %s", [18, "Ali"]))
81
+ specific_users = db.select(
82
+ "users",
83
+ where={
84
+ "age__gt": 18,
85
+ "name": "Ali"
86
+ }
87
+ )
78
88
  print(specific_users)
79
89
 
90
+ # LIKE bilan qidirish
91
+ users_like = db.select("users", where={"name__like": "%Ali%"})
92
+ print(users_like)
93
+
94
+ # ILIKE bilan qidirish
95
+ users_ilike = db.select("users", where={"name__ilike": "%ali%"})
96
+ print(users_ilike)
97
+
98
+ # IN bilan qidirish
99
+ selected_users = db.select("users", where={"id__in": [1, 2, 3]})
100
+ print(selected_users)
101
+
102
+ # NULL bilan ishlash
103
+ users_with_null = db.select("users", where={"name__isnull": False})
104
+ print(users_with_null)
105
+
106
+ # Tartiblash va limit
107
+ ordered_users = db.select(
108
+ "users",
109
+ where={"age__gt": 18},
110
+ order_by="age DESC",
111
+ limit=2
112
+ )
113
+ print(ordered_users)
114
+
115
+ # Pagination
116
+ paged_users = db.select(
117
+ "users",
118
+ order_by="id ASC",
119
+ limit=2,
120
+ offset=2
121
+ )
122
+ print(paged_users)
123
+
80
124
  # Faqat 2 ta qatorni olish
81
125
  users = db.select("users", fetchmany=2)
82
126
  print(users)
@@ -130,18 +174,62 @@ async def main():
130
174
  users = await db.select("users")
131
175
  print("Barcha foydalanuvchilar:", users)
132
176
 
177
+ # Faqat kerakli ustunlarni olish
178
+ users = await db.select("users", columns=["id", "name"])
179
+ print("Faqat id va name:", users)
180
+
133
181
  # Bitta qatorni olish
134
- user = await db.select("users", where=("name=$1", ["Ali"]), fetchone=True)
182
+ user = await db.select("users", where={"name": "Ali"}, fetchone=True)
135
183
  print("Foydalanuvchi Ali:", user)
136
184
 
137
185
  # Shart bilan ma'lumot olish
138
- adults = await db.select("users", where=("age > $1", [18]))
186
+ adults = await db.select("users", where={"age__gt": 18})
139
187
  print("Kattalar:", adults)
140
188
 
141
189
  # Bir nechta shart bilan
142
- specific_users = await db.select("users", where=("age > $1 AND name = $2", [18, "Ali"]))
190
+ specific_users = await db.select(
191
+ "users",
192
+ where={
193
+ "age__gt": 18,
194
+ "name": "Ali"
195
+ }
196
+ )
143
197
  print("Maxsus foydalanuvchi:", specific_users)
144
-
198
+
199
+ # LIKE bilan qidirish
200
+ users_like = await db.select("users", where={"name__like": "%Ali%"})
201
+ print("LIKE bo'yicha qidiruv:", users_like)
202
+
203
+ # ILIKE bilan qidirish
204
+ users_ilike = await db.select("users", where={"name__ilike": "%ali%"})
205
+ print("ILIKE bo'yicha qidiruv:", users_ilike)
206
+
207
+ # IN bilan qidirish
208
+ selected_users = await db.select("users", where={"id__in": [1, 2, 3]})
209
+ print("Tanlangan foydalanuvchilar:", selected_users)
210
+
211
+ # NULL bilan ishlash
212
+ users_with_not_null_name = await db.select("users", where={"name__isnull": False})
213
+ print("Name NULL bo'lmaganlar:", users_with_not_null_name)
214
+
215
+ # Tartiblash va limit
216
+ ordered_users = await db.select(
217
+ "users",
218
+ where={"age__gt": 18},
219
+ order_by="age DESC",
220
+ limit=2
221
+ )
222
+ print("Tartiblangan foydalanuvchilar:", ordered_users)
223
+
224
+ # Pagination
225
+ paged_users = await db.select(
226
+ "users",
227
+ order_by="id ASC",
228
+ limit=2,
229
+ offset=1
230
+ )
231
+ print("Pagination natijasi:", paged_users)
232
+
145
233
  # Jadvaldagi ma'lumotni yangilash
146
234
  await db.update("users", "age", 26, "name", "Ali")
147
235
 
@@ -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="0.3.5",
8
+ version="0.4.0",
9
9
  packages=find_packages(),
10
10
  install_requires=[
11
11
  "psycopg2>=2.9",
File without changes
File without changes