Skip to content

Commit d77782f

Browse files
committed
✨ feat: add order_by/count/all
1 parent 22fc1be commit d77782f

File tree

3 files changed

+92
-30
lines changed

3 files changed

+92
-30
lines changed

pyproject.toml

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,13 @@
11
[tool.poetry]
22
name = "use-mysql"
3-
version = "0.0.1"
3+
version = "0.0.2"
44
description = ""
55
authors = ["miclon <jcnd@163.com>"]
66
readme = "README.md"
7-
packages = [
8-
{ include = 'use_mysql', from = 'src' }
9-
]
7+
packages = [{ include = 'use_mysql', from = 'src' }]
108

119
[tool.poetry.dependencies]
1210
python = "^3.8"
13-
usepy = "^0.2.6"
1411
mysql-connector-python = "^8.1.0"
1512

1613

src/use_mysql/__init__.py

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import logging
22
import time
33
from datetime import date, datetime
4+
from typing import Any, Dict, List, Optional
45

56
from _mysql_connector import MySQLInterfaceError
67
from mysql.connector.cursor import MySQLCursor
@@ -116,15 +117,16 @@ def __exit__(self, exc_type, exc_val, exc_tb):
116117
def execute(self, sql, params=None):
117118
while True:
118119
try:
119-
with self.cursor as cursor:
120-
cursor.execute(sql, params)
121-
self.connection.commit()
122-
return cursor.lastrowid
120+
cursor = self.cursor
121+
cursor.execute(sql, params)
122+
self.connection.commit()
123+
return cursor.lastrowid
123124
except MySQLInterfaceError:
124125
logger.exception(f"MysqlStore execute error<{sql}>")
125126
del self.connection
126127
except Exception as e:
127-
raise e
128+
logger.error(f"Unexpected error during SQL execution: {e}")
129+
raise
128130

129131

130132
class ModelMetaClass(type):
@@ -150,13 +152,16 @@ def __new__(cls, name, bases, attrs):
150152

151153
class Model(metaclass=ModelMetaClass):
152154
def __init__(self):
153-
self._where_conditions = []
154-
self._insert_data = {}
155-
self._update_data = {}
156-
self._delete_flag = False
155+
self._where_conditions: List[str] = []
156+
self._insert_data: Dict[str, Any] = {}
157+
self._update_data: Dict[str, Any] = {}
158+
self._delete_flag: bool = False
159+
self._order_by: Optional[str] = None
160+
self._limit: Optional[int] = None
161+
self._offset: Optional[int] = None
157162

158163
@staticmethod
159-
def _format_value(value):
164+
def _format_value(value: Any) -> str:
160165
if isinstance(value, str):
161166
return f"'{value}'"
162167
elif isinstance(value, date):
@@ -165,7 +170,7 @@ def _format_value(value):
165170
return f"'{value.strftime('%Y-%m-%d %H:%M:%S')}'"
166171
return value
167172

168-
def where(self, **kwargs):
173+
def where(self, **kwargs) -> "Model":
169174
for key, value in kwargs.items():
170175
if isinstance(value, dict):
171176
for operator, condition in value.items():
@@ -180,65 +185,101 @@ def where(self, **kwargs):
180185

181186
return self
182187

183-
def create(self, **kwargs):
188+
def create(self, **kwargs) -> "Model":
184189
self._insert_data = kwargs
185190
return self
186191

187-
def update(self, **kwargs):
192+
def update(self, **kwargs) -> "Model":
188193
if not self._where_conditions:
189194
raise Exception("No conditions specified")
190195

191196
self._update_data = kwargs
192197
return self
193198

194-
def delete(self):
199+
def delete(self) -> "Model":
195200
if not self._where_conditions:
196201
raise Exception("No conditions specified")
197202

198203
self._delete_flag = True
199204
return self
200205

206+
def order_by(self, column: str, desc: bool = False) -> "Model":
207+
self._order_by = f"{_(column)} {'DESC' if desc else 'ASC'}"
208+
return self
209+
210+
def limit(self, limit: int) -> "Model":
211+
self._limit = limit
212+
return self
213+
214+
def offset(self, offset: int) -> "Model":
215+
self._offset = offset
216+
return self
217+
201218
@property
202-
def sql(self):
219+
def sql(self) -> str:
203220
if self._insert_data:
204221
keys = ",".join(_(key) for key in self._insert_data.keys())
205222
values = ",".join(
206223
f"{self._format_value(value)}" for value in self._insert_data.values()
207224
)
208-
sql = f"INSERT INTO {_(self.db_table)} ({keys}) VALUES ({values})"
209-
return sql
225+
_sql = f"INSERT INTO {_(self.db_table)} ({keys}) VALUES ({values})"
226+
return _sql
210227

211228
if self._where_conditions:
212229
where_clause = " AND ".join(self._where_conditions)
213230
if self._update_data:
214231
set_values = ", ".join(
215232
f"{_(key)} = '{value}'" for key, value in self._update_data.items()
216233
)
217-
return (
234+
_sql = (
218235
f"UPDATE {_(self.db_table)} SET {set_values} WHERE {where_clause}"
219236
)
237+
if self._order_by:
238+
_sql += f" ORDER BY {self._order_by}"
239+
if self._limit:
240+
_sql += f" LIMIT {self._limit}"
241+
if self._offset:
242+
_sql += f" OFFSET {self._offset}"
243+
return _sql
220244
elif self._delete_flag:
221-
return f"DELETE FROM {_(self.db_table)} WHERE {where_clause}"
245+
_sql = f"DELETE FROM {_(self.db_table)} WHERE {where_clause}"
222246
else:
223-
return f"SELECT * FROM {_(self.db_table)} WHERE {where_clause}"
247+
_sql = f"SELECT * FROM {_(self.db_table)} WHERE {where_clause}"
224248
else:
225-
return f"SELECT * FROM {_(self.db_table)}"
226-
227-
def execute(self):
249+
_sql = f"SELECT * FROM {_(self.db_table)}"
250+
if self._order_by:
251+
_sql += f" ORDER BY {self._order_by}"
252+
if self._limit:
253+
_sql += f" LIMIT {self._limit}"
254+
if self._offset:
255+
_sql += f" OFFSET {self._offset}"
256+
return _sql
257+
258+
def execute(self) -> int:
228259
logger.warning(self.sql)
229260
return self.connection.execute(self.sql)
230261

231-
def all(self):
262+
def all(self) -> List[Dict[str, Any]]:
232263
with self.connection as cursor:
233264
cursor.execute(self.sql)
234265
result = cursor.fetchall()
235266
return result
236267

237-
def one(self):
268+
def one(self) -> Optional[Dict[str, Any]]:
238269
with self.connection as cursor:
239270
cursor.execute(self.sql)
240271
result = cursor.fetchone()
241272
return result
242273

274+
def count(self) -> int:
275+
count_sql = f"SELECT COUNT(*) as count FROM {_(self.db_table)}"
276+
if self._where_conditions:
277+
count_sql += " WHERE " + " AND ".join(self._where_conditions)
278+
279+
with self.connection as cursor:
280+
cursor.execute(count_sql)
281+
result = cursor.fetchone()
282+
return result["count"] if result else 0
283+
243284
def __repr__(self):
244285
return f"<{self.__class__.__name__} {self.sql}>"

tests/test_x.py renamed to tests/test_all.py

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,27 @@ def test_create(model):
5151
).execute()
5252
> 0
5353
)
54+
for i in range(10):
55+
assert (
56+
model.create(
57+
name=f"qwe{i}",
58+
updated_at=datetime.date(datetime.now()),
59+
).execute()
60+
> 0
61+
)
62+
63+
64+
def test_order_by(model):
65+
assert model.order_by("id", desc=True).all() == model.all()
66+
67+
68+
def test_count(model):
69+
assert model.count() > 0
70+
71+
72+
def test_all(model):
73+
assert len(model.all()) > 0
74+
75+
76+
def test_one(model):
77+
assert model.one() is not None

0 commit comments

Comments
 (0)