db_client_toolkit 0.0.1__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.
@@ -0,0 +1,316 @@
1
+ """
2
+ SQL查询构建器
3
+ 提供流畅的API来构建SQL查询
4
+ """
5
+
6
+ from typing import Any, List, Optional, Union
7
+ import logging
8
+
9
+
10
+ logger = logging.getLogger(__name__)
11
+
12
+
13
+ class QueryBuilder:
14
+ """
15
+ SQL查询构建器
16
+
17
+ 使用流畅接口(Fluent Interface)模式构建SQL查询
18
+ """
19
+
20
+ def __init__(self):
21
+ """初始化查询构建器"""
22
+ self.reset()
23
+
24
+ def reset(self) -> 'QueryBuilder':
25
+ """
26
+ 重置查询构建器
27
+
28
+ Returns:
29
+ QueryBuilder: 返回自身以支持链式调用
30
+ """
31
+ self._table: Optional[str] = None
32
+ self._fields: List[str] = ['*']
33
+ self._conditions: List[str] = []
34
+ self._joins: List[tuple] = []
35
+ self._group_by: List[str] = []
36
+ self._having: List[str] = []
37
+ self._order_by: List[tuple] = []
38
+ self._limit: Optional[int] = None
39
+ self._offset: Optional[int] = None
40
+ self._distinct: bool = False
41
+ return self
42
+
43
+ def table(self, table_name: str) -> 'QueryBuilder':
44
+ """
45
+ 设置表名
46
+
47
+ Args:
48
+ table_name: 表名
49
+
50
+ Returns:
51
+ QueryBuilder: 返回自身
52
+ """
53
+ self._table = table_name
54
+ return self
55
+
56
+ def select(self, *fields: str) -> 'QueryBuilder':
57
+ """
58
+ 选择字段
59
+
60
+ Args:
61
+ *fields: 字段列表
62
+
63
+ Returns:
64
+ QueryBuilder: 返回自身
65
+
66
+ Examples:
67
+ >>> builder.select('id', 'name', 'email')
68
+ >>> builder.select('COUNT(*) as total')
69
+ """
70
+ self._fields = list(fields) if fields else ['*']
71
+ return self
72
+
73
+ def distinct(self) -> 'QueryBuilder':
74
+ """
75
+ 使用DISTINCT
76
+
77
+ Returns:
78
+ QueryBuilder: 返回自身
79
+ """
80
+ self._distinct = True
81
+ return self
82
+
83
+ def where(self, condition: str) -> 'QueryBuilder':
84
+ """
85
+ 添加WHERE条件
86
+
87
+ Args:
88
+ condition: 条件表达式
89
+
90
+ Returns:
91
+ QueryBuilder: 返回自身
92
+
93
+ Examples:
94
+ >>> builder.where("age > 18")
95
+ >>> builder.where("status = 'active'")
96
+ """
97
+ self._conditions.append(condition)
98
+ return self
99
+
100
+ def where_in(self, field: str, values: List[Any]) -> 'QueryBuilder':
101
+ """
102
+ 添加IN条件
103
+
104
+ Args:
105
+ field: 字段名
106
+ values: 值列表
107
+
108
+ Returns:
109
+ QueryBuilder: 返回自身
110
+ """
111
+ if not values:
112
+ return self
113
+
114
+ values_str = ', '.join([f"'{v}'" if isinstance(v, str) else str(v) for v in values])
115
+ self._conditions.append(f"{field} IN ({values_str})")
116
+ return self
117
+
118
+ def where_between(self, field: str, start: Any, end: Any) -> 'QueryBuilder':
119
+ """
120
+ 添加BETWEEN条件
121
+
122
+ Args:
123
+ field: 字段名
124
+ start: 起始值
125
+ end: 结束值
126
+
127
+ Returns:
128
+ QueryBuilder: 返回自身
129
+ """
130
+ start_val = f"'{start}'" if isinstance(start, str) else start
131
+ end_val = f"'{end}'" if isinstance(end, str) else end
132
+ self._conditions.append(f"{field} BETWEEN {start_val} AND {end_val}")
133
+ return self
134
+
135
+ def where_like(self, field: str, pattern: str) -> 'QueryBuilder':
136
+ """
137
+ 添加LIKE条件
138
+
139
+ Args:
140
+ field: 字段名
141
+ pattern: 匹配模式
142
+
143
+ Returns:
144
+ QueryBuilder: 返回自身
145
+ """
146
+ self._conditions.append(f"{field} LIKE '{pattern}'")
147
+ return self
148
+
149
+ def join(self, table: str, condition: str, join_type: str = 'INNER') -> 'QueryBuilder':
150
+ """
151
+ 添加JOIN
152
+
153
+ Args:
154
+ table: 要JOIN的表
155
+ condition: JOIN条件
156
+ join_type: JOIN类型 (INNER, LEFT, RIGHT, FULL)
157
+
158
+ Returns:
159
+ QueryBuilder: 返回自身
160
+
161
+ Examples:
162
+ >>> builder.join('orders', 'users.id = orders.user_id')
163
+ >>> builder.join('profiles', 'users.id = profiles.user_id', 'LEFT')
164
+ """
165
+ self._joins.append((join_type.upper(), table, condition))
166
+ return self
167
+
168
+ def left_join(self, table: str, condition: str) -> 'QueryBuilder':
169
+ """LEFT JOIN的便捷方法"""
170
+ return self.join(table, condition, 'LEFT')
171
+
172
+ def right_join(self, table: str, condition: str) -> 'QueryBuilder':
173
+ """RIGHT JOIN的便捷方法"""
174
+ return self.join(table, condition, 'RIGHT')
175
+
176
+ def group_by(self, *fields: str) -> 'QueryBuilder':
177
+ """
178
+ 添加GROUP BY
179
+
180
+ Args:
181
+ *fields: 分组字段
182
+
183
+ Returns:
184
+ QueryBuilder: 返回自身
185
+ """
186
+ self._group_by.extend(fields)
187
+ return self
188
+
189
+ def having(self, condition: str) -> 'QueryBuilder':
190
+ """
191
+ 添加HAVING条件
192
+
193
+ Args:
194
+ condition: HAVING条件
195
+
196
+ Returns:
197
+ QueryBuilder: 返回自身
198
+ """
199
+ self._having.append(condition)
200
+ return self
201
+
202
+ def order_by(self, field: str, direction: str = 'ASC') -> 'QueryBuilder':
203
+ """
204
+ 添加ORDER BY
205
+
206
+ Args:
207
+ field: 排序字段
208
+ direction: 排序方向 (ASC/DESC)
209
+
210
+ Returns:
211
+ QueryBuilder: 返回自身
212
+ """
213
+ self._order_by.append((field, direction.upper()))
214
+ return self
215
+
216
+ def limit(self, limit: int) -> 'QueryBuilder':
217
+ """
218
+ 设置LIMIT
219
+
220
+ Args:
221
+ limit: 限制数量
222
+
223
+ Returns:
224
+ QueryBuilder: 返回自身
225
+ """
226
+ self._limit = limit
227
+ return self
228
+
229
+ def offset(self, offset: int) -> 'QueryBuilder':
230
+ """
231
+ 设置OFFSET
232
+
233
+ Args:
234
+ offset: 偏移量
235
+
236
+ Returns:
237
+ QueryBuilder: 返回自身
238
+ """
239
+ self._offset = offset
240
+ return self
241
+
242
+ def paginate(self, page: int, per_page: int = 10) -> 'QueryBuilder':
243
+ """
244
+ 分页查询
245
+
246
+ Args:
247
+ page: 页码(从1开始)
248
+ per_page: 每页数量
249
+
250
+ Returns:
251
+ QueryBuilder: 返回自身
252
+ """
253
+ self._limit = per_page
254
+ self._offset = (page - 1) * per_page
255
+ return self
256
+
257
+ def build(self) -> str:
258
+ """
259
+ 构建SQL查询
260
+
261
+ Returns:
262
+ str: 完整的SQL查询语句
263
+
264
+ Raises:
265
+ ValueError: 当缺少必需参数时
266
+ """
267
+ if not self._table:
268
+ raise ValueError("必须指定表名")
269
+
270
+ # SELECT子句
271
+ distinct_keyword = 'DISTINCT ' if self._distinct else ''
272
+ fields = ', '.join(self._fields)
273
+ query = f"SELECT {distinct_keyword}{fields} FROM {self._table}"
274
+
275
+ # JOIN子句
276
+ for join_type, table, condition in self._joins:
277
+ query += f" {join_type} JOIN {table} ON {condition}"
278
+
279
+ # WHERE子句
280
+ if self._conditions:
281
+ query += " WHERE " + " AND ".join(self._conditions)
282
+
283
+ # GROUP BY子句
284
+ if self._group_by:
285
+ query += " GROUP BY " + ", ".join(self._group_by)
286
+
287
+ # HAVING子句
288
+ if self._having:
289
+ query += " HAVING " + " AND ".join(self._having)
290
+
291
+ # ORDER BY子句
292
+ if self._order_by:
293
+ order_parts = [f"{field} {direction}" for field, direction in self._order_by]
294
+ query += " ORDER BY " + ", ".join(order_parts)
295
+
296
+ # LIMIT子句
297
+ if self._limit is not None:
298
+ query += f" LIMIT {self._limit}"
299
+
300
+ # OFFSET子句
301
+ if self._offset is not None:
302
+ query += f" OFFSET {self._offset}"
303
+
304
+ logger.debug(f"构建SQL: {query}")
305
+ return query
306
+
307
+ def __str__(self) -> str:
308
+ """返回构建的SQL语句"""
309
+ try:
310
+ return self.build()
311
+ except ValueError:
312
+ return "<QueryBuilder: incomplete>"
313
+
314
+ def __repr__(self) -> str:
315
+ """返回对象表示"""
316
+ return f"<QueryBuilder table={self._table}>"