t-sql 3.0.0__tar.gz → 3.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.
- {t_sql-3.0.0 → t_sql-3.1.0}/PKG-INFO +19 -25
- {t_sql-3.0.0 → t_sql-3.1.0}/README.md +18 -24
- {t_sql-3.0.0 → t_sql-3.1.0}/pyproject.toml +1 -1
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_query_builder.py +36 -4
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_sqlite_integration.py +1 -1
- {t_sql-3.0.0 → t_sql-3.1.0}/tsql/query_builder.py +48 -4
- {t_sql-3.0.0 → t_sql-3.1.0}/.dockerignore +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/.github/workflows/publish.yml +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/.github/workflows/test.yml +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/.gitignore +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/Dockerfile +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/LICENSE +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/compose.yaml +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/context7.json +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/pytest.ini +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_alembic_integration.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_asyncpg_integration.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_different_object_types.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_escaped.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_escaped_binary_hex.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_helper_functions.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_injection_edge_cases.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_injection_protection_validation.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_injections_for_escaped.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_mysql_integration.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_parameter_names.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_sqlalchemy_integration.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_styles.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tests/test_tsql.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tsql/__init__.py +0 -0
- {t_sql-3.0.0 → t_sql-3.1.0}/tsql/styles.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: t-sql
|
|
3
|
-
Version: 3.
|
|
3
|
+
Version: 3.1.0
|
|
4
4
|
Summary: Safe SQL. SQL queries for python t-strings (PEP 750)
|
|
5
5
|
Project-URL: Homepage, https://github.com/nhumrich/t-sql
|
|
6
6
|
License-File: LICENSE
|
|
@@ -159,8 +159,7 @@ sql, params = query.render()
|
|
|
159
159
|
Quick INSERT queries:
|
|
160
160
|
|
|
161
161
|
```python
|
|
162
|
-
|
|
163
|
-
query = tsql.insert('users', values)
|
|
162
|
+
query = tsql.insert('users', id='abc123', name='bob', email='bob@example.com')
|
|
164
163
|
sql, params = query.render()
|
|
165
164
|
# ('INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['abc123', 'bob', 'bob@example.com'])
|
|
166
165
|
```
|
|
@@ -171,14 +170,9 @@ Quick UPDATE queries:
|
|
|
171
170
|
|
|
172
171
|
```python
|
|
173
172
|
# Update by ID
|
|
174
|
-
query = tsql.update('users',
|
|
173
|
+
query = tsql.update('users', 'abc123', email='new@example.com')
|
|
175
174
|
sql, params = query.render()
|
|
176
175
|
# ('UPDATE users SET email = ? WHERE id = ?', ['new@example.com', 'abc123'])
|
|
177
|
-
|
|
178
|
-
# Update with custom WHERE
|
|
179
|
-
query = tsql.update('users', {'email': 'new@example.com'}, where={'age': 25})
|
|
180
|
-
sql, params = query.render()
|
|
181
|
-
# ('UPDATE users SET email = ? WHERE age = ?', ['new@example.com', 25])
|
|
182
176
|
```
|
|
183
177
|
|
|
184
178
|
#### delete
|
|
@@ -271,8 +265,9 @@ query = Users.select().where(Users.id.in_([1, 2, 3]))
|
|
|
271
265
|
query = Users.select().where(Users.username.like('%john%'))
|
|
272
266
|
|
|
273
267
|
# ORDER BY
|
|
274
|
-
query = Posts.select().order_by(Posts.id)
|
|
275
|
-
query = Posts.select().order_by(
|
|
268
|
+
query = Posts.select().order_by(Posts.id) # defaults to ASC
|
|
269
|
+
query = Posts.select().order_by(Posts.id.desc())
|
|
270
|
+
query = Posts.select().order_by(Posts.created_at.asc(), Posts.id.desc())
|
|
276
271
|
|
|
277
272
|
# LIMIT and OFFSET
|
|
278
273
|
query = Posts.select().limit(10).offset(20)
|
|
@@ -291,47 +286,46 @@ The query builder supports INSERT, UPDATE, and DELETE with database-agnostic con
|
|
|
291
286
|
|
|
292
287
|
```python
|
|
293
288
|
# Basic insert
|
|
294
|
-
|
|
295
|
-
query = Users.insert(values)
|
|
289
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com')
|
|
296
290
|
sql, params = query.render()
|
|
297
291
|
# ('INSERT INTO users (id, username, email) VALUES (?, ?, ?)', ['abc123', 'john', 'john@example.com'])
|
|
298
292
|
|
|
299
293
|
# INSERT with RETURNING (Postgres/SQLite)
|
|
300
|
-
query = Users.insert(
|
|
294
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').returning()
|
|
301
295
|
sql, params = query.render()
|
|
302
296
|
# ('INSERT INTO users (id, username, email) VALUES (?, ?, ?) RETURNING *', [...])
|
|
303
297
|
|
|
304
298
|
# INSERT IGNORE (MySQL)
|
|
305
|
-
query = Users.insert(
|
|
299
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').ignore()
|
|
306
300
|
sql, params = query.render()
|
|
307
301
|
# ('INSERT IGNORE INTO users (id, username, email) VALUES (?, ?, ?)', [...])
|
|
308
302
|
|
|
309
303
|
# ON CONFLICT DO NOTHING (Postgres/SQLite)
|
|
310
|
-
query = Users.insert(
|
|
304
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_conflict_do_nothing()
|
|
311
305
|
# ('INSERT INTO users (...) VALUES (...) ON CONFLICT DO NOTHING', [...])
|
|
312
306
|
|
|
313
307
|
# ON CONFLICT DO NOTHING with specific conflict target (Postgres/SQLite)
|
|
314
|
-
query = Users.insert(
|
|
308
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_conflict_do_nothing(conflict_on='email')
|
|
315
309
|
# ('INSERT INTO users (...) VALUES (...) ON CONFLICT (email) DO NOTHING', [...])
|
|
316
310
|
|
|
317
311
|
# ON CONFLICT DO UPDATE (Postgres/SQLite upsert)
|
|
318
|
-
query = Users.insert(
|
|
312
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_conflict_update(conflict_on='id')
|
|
319
313
|
# ('INSERT INTO users (...) VALUES (...)
|
|
320
314
|
# ON CONFLICT (id) DO UPDATE SET username = EXCLUDED.username, email = EXCLUDED.email', [...])
|
|
321
315
|
|
|
322
316
|
# ON CONFLICT with custom update
|
|
323
|
-
query = Users.insert(
|
|
317
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_conflict_update(
|
|
324
318
|
conflict_on='id',
|
|
325
319
|
update={'username': 'updated_name'}
|
|
326
320
|
)
|
|
327
321
|
|
|
328
322
|
# ON DUPLICATE KEY UPDATE (MySQL)
|
|
329
|
-
query = Users.insert(
|
|
323
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_duplicate_key_update()
|
|
330
324
|
# ('INSERT INTO users (...) VALUES (...)
|
|
331
325
|
# ON DUPLICATE KEY UPDATE id = VALUES(id), username = VALUES(username), ...', [...])
|
|
332
326
|
|
|
333
327
|
# Chain multiple modifiers
|
|
334
|
-
query = (Users.insert(
|
|
328
|
+
query = (Users.insert(id='abc123', username='john', email='john@example.com')
|
|
335
329
|
.on_conflict_update(conflict_on='id')
|
|
336
330
|
.returning('id', 'username'))
|
|
337
331
|
```
|
|
@@ -340,22 +334,22 @@ query = (Users.insert(values)
|
|
|
340
334
|
|
|
341
335
|
```python
|
|
342
336
|
# Basic update (no WHERE = updates all rows!)
|
|
343
|
-
query = Users.update(
|
|
337
|
+
query = Users.update(email='newemail@example.com')
|
|
344
338
|
sql, params = query.render()
|
|
345
339
|
# ('UPDATE users SET email = ?', ['newemail@example.com'])
|
|
346
340
|
|
|
347
341
|
# UPDATE with WHERE
|
|
348
|
-
query = Users.update(
|
|
342
|
+
query = Users.update(email='newemail@example.com').where(Users.id == 'abc123')
|
|
349
343
|
sql, params = query.render()
|
|
350
344
|
# ('UPDATE users SET email = ? WHERE users.id = ?', ['newemail@example.com', 'abc123'])
|
|
351
345
|
|
|
352
346
|
# Multiple WHERE conditions
|
|
353
|
-
query = (Users.update(
|
|
347
|
+
query = (Users.update(email='newemail@example.com')
|
|
354
348
|
.where(Users.id == 'abc123')
|
|
355
349
|
.where(Users.age > 18))
|
|
356
350
|
|
|
357
351
|
# With RETURNING (Postgres/SQLite)
|
|
358
|
-
query = (Users.update(
|
|
352
|
+
query = (Users.update(email='new@example.com')
|
|
359
353
|
.where(Users.id == 'abc123')
|
|
360
354
|
.returning())
|
|
361
355
|
# ('UPDATE users SET email = ? WHERE users.id = ? RETURNING *', [...])
|
|
@@ -149,8 +149,7 @@ sql, params = query.render()
|
|
|
149
149
|
Quick INSERT queries:
|
|
150
150
|
|
|
151
151
|
```python
|
|
152
|
-
|
|
153
|
-
query = tsql.insert('users', values)
|
|
152
|
+
query = tsql.insert('users', id='abc123', name='bob', email='bob@example.com')
|
|
154
153
|
sql, params = query.render()
|
|
155
154
|
# ('INSERT INTO users (id, name, email) VALUES (?, ?, ?)', ['abc123', 'bob', 'bob@example.com'])
|
|
156
155
|
```
|
|
@@ -161,14 +160,9 @@ Quick UPDATE queries:
|
|
|
161
160
|
|
|
162
161
|
```python
|
|
163
162
|
# Update by ID
|
|
164
|
-
query = tsql.update('users',
|
|
163
|
+
query = tsql.update('users', 'abc123', email='new@example.com')
|
|
165
164
|
sql, params = query.render()
|
|
166
165
|
# ('UPDATE users SET email = ? WHERE id = ?', ['new@example.com', 'abc123'])
|
|
167
|
-
|
|
168
|
-
# Update with custom WHERE
|
|
169
|
-
query = tsql.update('users', {'email': 'new@example.com'}, where={'age': 25})
|
|
170
|
-
sql, params = query.render()
|
|
171
|
-
# ('UPDATE users SET email = ? WHERE age = ?', ['new@example.com', 25])
|
|
172
166
|
```
|
|
173
167
|
|
|
174
168
|
#### delete
|
|
@@ -261,8 +255,9 @@ query = Users.select().where(Users.id.in_([1, 2, 3]))
|
|
|
261
255
|
query = Users.select().where(Users.username.like('%john%'))
|
|
262
256
|
|
|
263
257
|
# ORDER BY
|
|
264
|
-
query = Posts.select().order_by(Posts.id)
|
|
265
|
-
query = Posts.select().order_by(
|
|
258
|
+
query = Posts.select().order_by(Posts.id) # defaults to ASC
|
|
259
|
+
query = Posts.select().order_by(Posts.id.desc())
|
|
260
|
+
query = Posts.select().order_by(Posts.created_at.asc(), Posts.id.desc())
|
|
266
261
|
|
|
267
262
|
# LIMIT and OFFSET
|
|
268
263
|
query = Posts.select().limit(10).offset(20)
|
|
@@ -281,47 +276,46 @@ The query builder supports INSERT, UPDATE, and DELETE with database-agnostic con
|
|
|
281
276
|
|
|
282
277
|
```python
|
|
283
278
|
# Basic insert
|
|
284
|
-
|
|
285
|
-
query = Users.insert(values)
|
|
279
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com')
|
|
286
280
|
sql, params = query.render()
|
|
287
281
|
# ('INSERT INTO users (id, username, email) VALUES (?, ?, ?)', ['abc123', 'john', 'john@example.com'])
|
|
288
282
|
|
|
289
283
|
# INSERT with RETURNING (Postgres/SQLite)
|
|
290
|
-
query = Users.insert(
|
|
284
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').returning()
|
|
291
285
|
sql, params = query.render()
|
|
292
286
|
# ('INSERT INTO users (id, username, email) VALUES (?, ?, ?) RETURNING *', [...])
|
|
293
287
|
|
|
294
288
|
# INSERT IGNORE (MySQL)
|
|
295
|
-
query = Users.insert(
|
|
289
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').ignore()
|
|
296
290
|
sql, params = query.render()
|
|
297
291
|
# ('INSERT IGNORE INTO users (id, username, email) VALUES (?, ?, ?)', [...])
|
|
298
292
|
|
|
299
293
|
# ON CONFLICT DO NOTHING (Postgres/SQLite)
|
|
300
|
-
query = Users.insert(
|
|
294
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_conflict_do_nothing()
|
|
301
295
|
# ('INSERT INTO users (...) VALUES (...) ON CONFLICT DO NOTHING', [...])
|
|
302
296
|
|
|
303
297
|
# ON CONFLICT DO NOTHING with specific conflict target (Postgres/SQLite)
|
|
304
|
-
query = Users.insert(
|
|
298
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_conflict_do_nothing(conflict_on='email')
|
|
305
299
|
# ('INSERT INTO users (...) VALUES (...) ON CONFLICT (email) DO NOTHING', [...])
|
|
306
300
|
|
|
307
301
|
# ON CONFLICT DO UPDATE (Postgres/SQLite upsert)
|
|
308
|
-
query = Users.insert(
|
|
302
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_conflict_update(conflict_on='id')
|
|
309
303
|
# ('INSERT INTO users (...) VALUES (...)
|
|
310
304
|
# ON CONFLICT (id) DO UPDATE SET username = EXCLUDED.username, email = EXCLUDED.email', [...])
|
|
311
305
|
|
|
312
306
|
# ON CONFLICT with custom update
|
|
313
|
-
query = Users.insert(
|
|
307
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_conflict_update(
|
|
314
308
|
conflict_on='id',
|
|
315
309
|
update={'username': 'updated_name'}
|
|
316
310
|
)
|
|
317
311
|
|
|
318
312
|
# ON DUPLICATE KEY UPDATE (MySQL)
|
|
319
|
-
query = Users.insert(
|
|
313
|
+
query = Users.insert(id='abc123', username='john', email='john@example.com').on_duplicate_key_update()
|
|
320
314
|
# ('INSERT INTO users (...) VALUES (...)
|
|
321
315
|
# ON DUPLICATE KEY UPDATE id = VALUES(id), username = VALUES(username), ...', [...])
|
|
322
316
|
|
|
323
317
|
# Chain multiple modifiers
|
|
324
|
-
query = (Users.insert(
|
|
318
|
+
query = (Users.insert(id='abc123', username='john', email='john@example.com')
|
|
325
319
|
.on_conflict_update(conflict_on='id')
|
|
326
320
|
.returning('id', 'username'))
|
|
327
321
|
```
|
|
@@ -330,22 +324,22 @@ query = (Users.insert(values)
|
|
|
330
324
|
|
|
331
325
|
```python
|
|
332
326
|
# Basic update (no WHERE = updates all rows!)
|
|
333
|
-
query = Users.update(
|
|
327
|
+
query = Users.update(email='newemail@example.com')
|
|
334
328
|
sql, params = query.render()
|
|
335
329
|
# ('UPDATE users SET email = ?', ['newemail@example.com'])
|
|
336
330
|
|
|
337
331
|
# UPDATE with WHERE
|
|
338
|
-
query = Users.update(
|
|
332
|
+
query = Users.update(email='newemail@example.com').where(Users.id == 'abc123')
|
|
339
333
|
sql, params = query.render()
|
|
340
334
|
# ('UPDATE users SET email = ? WHERE users.id = ?', ['newemail@example.com', 'abc123'])
|
|
341
335
|
|
|
342
336
|
# Multiple WHERE conditions
|
|
343
|
-
query = (Users.update(
|
|
337
|
+
query = (Users.update(email='newemail@example.com')
|
|
344
338
|
.where(Users.id == 'abc123')
|
|
345
339
|
.where(Users.age > 18))
|
|
346
340
|
|
|
347
341
|
# With RETURNING (Postgres/SQLite)
|
|
348
|
-
query = (Users.update(
|
|
342
|
+
query = (Users.update(email='new@example.com')
|
|
349
343
|
.where(Users.id == 'abc123')
|
|
350
344
|
.returning())
|
|
351
345
|
# ('UPDATE users SET email = ? WHERE users.id = ? RETURNING *', [...])
|
|
@@ -213,7 +213,7 @@ def test_order_by():
|
|
|
213
213
|
|
|
214
214
|
def test_order_by_desc():
|
|
215
215
|
"""Test ORDER BY with DESC"""
|
|
216
|
-
query = Users.select().order_by(
|
|
216
|
+
query = Users.select().order_by(Users.id.desc())
|
|
217
217
|
sql, params = query.render()
|
|
218
218
|
|
|
219
219
|
assert 'ORDER BY users.id DESC' in sql
|
|
@@ -221,7 +221,39 @@ def test_order_by_desc():
|
|
|
221
221
|
|
|
222
222
|
def test_order_by_multiple():
|
|
223
223
|
"""Test ORDER BY with multiple columns"""
|
|
224
|
-
query = Users.select().order_by(Users.username,
|
|
224
|
+
query = Users.select().order_by(Users.username, Users.id.desc())
|
|
225
|
+
sql, params = query.render()
|
|
226
|
+
|
|
227
|
+
assert 'ORDER BY users.username ASC, users.id DESC' in sql
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def test_order_by_asc_method():
|
|
231
|
+
"""Test ORDER BY with .asc() method"""
|
|
232
|
+
query = Users.select().order_by(Users.username.asc())
|
|
233
|
+
sql, params = query.render()
|
|
234
|
+
|
|
235
|
+
assert 'ORDER BY users.username ASC' in sql
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def test_order_by_desc_method():
|
|
239
|
+
"""Test ORDER BY with .desc() method"""
|
|
240
|
+
query = Users.select().order_by(Users.id.desc())
|
|
241
|
+
sql, params = query.render()
|
|
242
|
+
|
|
243
|
+
assert 'ORDER BY users.id DESC' in sql
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
def test_order_by_mixed_methods():
|
|
247
|
+
"""Test ORDER BY with mixed .asc() and .desc() methods"""
|
|
248
|
+
query = Users.select().order_by(Users.username.asc(), Users.id.desc())
|
|
249
|
+
sql, params = query.render()
|
|
250
|
+
|
|
251
|
+
assert 'ORDER BY users.username ASC, users.id DESC' in sql
|
|
252
|
+
|
|
253
|
+
|
|
254
|
+
def test_order_by_mixed_syntax():
|
|
255
|
+
"""Test ORDER BY with mixed method calls and bare columns"""
|
|
256
|
+
query = Users.select().order_by(Users.username, Users.id.desc())
|
|
225
257
|
sql, params = query.render()
|
|
226
258
|
|
|
227
259
|
assert 'ORDER BY users.username ASC, users.id DESC' in sql
|
|
@@ -242,7 +274,7 @@ def test_complex_query():
|
|
|
242
274
|
.join(Users, Posts.user_id == Users.id)
|
|
243
275
|
.where(Posts.id > 100)
|
|
244
276
|
.where(Users.id >= 5)
|
|
245
|
-
.order_by(
|
|
277
|
+
.order_by(Posts.id.desc())
|
|
246
278
|
.limit(20))
|
|
247
279
|
sql, params = query.render()
|
|
248
280
|
|
|
@@ -480,7 +512,7 @@ def test_complex_aggregation_query():
|
|
|
480
512
|
.where(Posts.id > 100)
|
|
481
513
|
.group_by(Posts.user_id)
|
|
482
514
|
.having(Posts.id > 5)
|
|
483
|
-
.order_by(
|
|
515
|
+
.order_by(Posts.user_id.desc())
|
|
484
516
|
.limit(10)
|
|
485
517
|
.offset(5))
|
|
486
518
|
sql, params = query.render()
|
|
@@ -331,7 +331,7 @@ async def test_query_builder_select(conn):
|
|
|
331
331
|
assert rows[0][0] == 'Alice'
|
|
332
332
|
|
|
333
333
|
# Test ORDER BY
|
|
334
|
-
query = TestUsers.select().order_by(
|
|
334
|
+
query = TestUsers.select().order_by(TestUsers.age.desc())
|
|
335
335
|
sql, params = query.render()
|
|
336
336
|
|
|
337
337
|
cursor = await conn.execute(sql, params)
|
|
@@ -16,6 +16,17 @@ except ImportError:
|
|
|
16
16
|
SAColumnType = None
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
class OrderByClause:
|
|
20
|
+
"""Represents a column with an ORDER BY direction (ASC/DESC)"""
|
|
21
|
+
|
|
22
|
+
def __init__(self, column: 'Column', direction: str):
|
|
23
|
+
self.column = column
|
|
24
|
+
self.direction = direction.upper()
|
|
25
|
+
|
|
26
|
+
def __repr__(self) -> str:
|
|
27
|
+
return f"OrderByClause({self.column!r}, {self.direction!r})"
|
|
28
|
+
|
|
29
|
+
|
|
19
30
|
class Column:
|
|
20
31
|
"""Represents a bound column (table + column name) for building queries"""
|
|
21
32
|
|
|
@@ -140,6 +151,28 @@ class Column:
|
|
|
140
151
|
"""Create an IS NOT NULL condition"""
|
|
141
152
|
return Condition(self, 'IS NOT', None)
|
|
142
153
|
|
|
154
|
+
def asc(self) -> OrderByClause:
|
|
155
|
+
"""Create an ascending ORDER BY clause
|
|
156
|
+
|
|
157
|
+
Returns:
|
|
158
|
+
OrderByClause for use in order_by()
|
|
159
|
+
|
|
160
|
+
Example:
|
|
161
|
+
Users.select().order_by(Users.username.asc())
|
|
162
|
+
"""
|
|
163
|
+
return OrderByClause(self, 'ASC')
|
|
164
|
+
|
|
165
|
+
def desc(self) -> OrderByClause:
|
|
166
|
+
"""Create a descending ORDER BY clause
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
OrderByClause for use in order_by()
|
|
170
|
+
|
|
171
|
+
Example:
|
|
172
|
+
Users.select().order_by(Users.created_at.desc())
|
|
173
|
+
"""
|
|
174
|
+
return OrderByClause(self, 'DESC')
|
|
175
|
+
|
|
143
176
|
|
|
144
177
|
class Table:
|
|
145
178
|
"""Base class for all table definitions. Provides query builder methods.
|
|
@@ -838,11 +871,22 @@ class SelectQueryBuilder(QueryBuilder):
|
|
|
838
871
|
"""Add a RIGHT JOIN clause"""
|
|
839
872
|
return self.join(table, on, 'RIGHT')
|
|
840
873
|
|
|
841
|
-
def order_by(self, *columns: Union[Column,
|
|
842
|
-
"""Add ORDER BY clause
|
|
874
|
+
def order_by(self, *columns: Union[Column, OrderByClause]) -> 'SelectQueryBuilder':
|
|
875
|
+
"""Add ORDER BY clause
|
|
876
|
+
|
|
877
|
+
Args:
|
|
878
|
+
columns: Column objects or OrderByClause objects (from .asc()/.desc())
|
|
879
|
+
|
|
880
|
+
Examples:
|
|
881
|
+
# Using .asc() and .desc() methods
|
|
882
|
+
Users.select().order_by(Users.username.asc(), Users.id.desc())
|
|
883
|
+
|
|
884
|
+
# Bare column defaults to ASC
|
|
885
|
+
Users.select().order_by(Users.username)
|
|
886
|
+
"""
|
|
843
887
|
for col in columns:
|
|
844
|
-
if isinstance(col,
|
|
845
|
-
self._order_by_columns.append(col)
|
|
888
|
+
if isinstance(col, OrderByClause):
|
|
889
|
+
self._order_by_columns.append((col.column, col.direction))
|
|
846
890
|
else:
|
|
847
891
|
self._order_by_columns.append((col, 'ASC'))
|
|
848
892
|
return self
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|