Skip to content

Commit 5be3ea5

Browse files
committed
added WhereRaw
1 parent fcf58ac commit 5be3ea5

File tree

3 files changed

+113
-0
lines changed

3 files changed

+113
-0
lines changed

docs/src/piccolo/query_clauses/where.rst

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ Equal / Not Equal
3030
b.name != 'Rustaceans'
3131
).run_sync()
3232
33+
-------------------------------------------------------------------------------
34+
3335
Greater than / less than
3436
------------------------
3537

@@ -42,6 +44,8 @@ You can use the ``<, >, <=, >=`` operators, which work as you expect.
4244
b.popularity >= 100
4345
).run_sync()
4446
47+
-------------------------------------------------------------------------------
48+
4549
like / ilike
4650
-------------
4751

@@ -64,6 +68,8 @@ The percentage operator is required to designate where the match should occur.
6468
6569
``ilike`` is identical, except it's case insensitive.
6670

71+
-------------------------------------------------------------------------------
72+
6773
not_like
6874
--------
6975

@@ -76,6 +82,8 @@ Usage is the same as ``like`` excepts it excludes matching rows.
7682
b.name.not_like('Py%')
7783
).run_sync()
7884
85+
-------------------------------------------------------------------------------
86+
7987
is_in / not_in
8088
--------------
8189

@@ -93,6 +101,8 @@ is_in / not_in
93101
b.name.not_in(['Rustaceans'])
94102
).run_sync()
95103
104+
-------------------------------------------------------------------------------
105+
96106
Complex queries - and / or
97107
---------------------------
98108

@@ -151,3 +161,31 @@ Rather than using the ``|`` and ``&`` characters, you can use the ``And`` and
151161
b.name == 'Pythonistas'
152162
)
153163
).run_sync()
164+
165+
-------------------------------------------------------------------------------
166+
167+
WhereRaw
168+
--------
169+
170+
In certain situations you may want to have raw SQL in your where clause. For
171+
example, there could be a Postgres function you need to call.
172+
173+
.. code-block:: python
174+
175+
from piccolo.columns.combination import WhereRaw
176+
177+
b = Band
178+
b.select().where(
179+
WhereRaw("name = 'Pythonistas'")
180+
).run_sync()
181+
182+
``WhereRaw`` can be combined into complex queries, just as you'd expect:
183+
184+
.. code-block:: python
185+
186+
from piccolo.columns.combination import WhereRaw
187+
188+
b = Band
189+
b.select().where(
190+
WhereRaw("name = 'Pythonistas'") | (b.popularity > 1000)
191+
).run_sync()

piccolo/columns/combination.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,27 @@ class Undefined:
5454
UNDEFINED = Undefined()
5555

5656

57+
class WhereRaw(CombinableMixin):
58+
def __init__(self, sql: str, *args: t.Any) -> None:
59+
"""
60+
Execute raw SQL queries in your where clause. Use with caution!
61+
62+
await Band.where(
63+
WhereRaw("name = 'Pythonistas'")
64+
)
65+
66+
Or passing in parameters:
67+
68+
await Band.where(
69+
WhereRaw("name = {}", 'Pythonistas')
70+
)
71+
"""
72+
self.querystring = QueryString(sql, *args)
73+
74+
def __str__(self):
75+
return self.querystring.__str__()
76+
77+
5778
class Where(CombinableMixin):
5879

5980
__slots__ = ("column", "value", "values", "operator")

tests/table/test_select.py

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from unittest import TestCase
22

33
from piccolo.apps.user.tables import BaseUser
4+
from piccolo.columns.combination import WhereRaw
45
from piccolo.query.methods.select import Count
56

67
from ..base import DBTestCase, postgres_only, sqlite_only
@@ -116,6 +117,59 @@ def test_where_less_equal_than(self):
116117
response, [{"name": "Pythonistas"}, {"name": "CSharps"}]
117118
)
118119

120+
def test_where_raw(self):
121+
"""
122+
Make sure raw SQL passed in to a where clause works as expected.
123+
"""
124+
self.insert_rows()
125+
126+
response = (
127+
Band.select(Band.name)
128+
.where(WhereRaw("name = 'Pythonistas'"))
129+
.run_sync()
130+
)
131+
132+
print(f"response = {response}")
133+
134+
self.assertEqual(response, [{"name": "Pythonistas"}])
135+
136+
def test_where_raw_with_args(self):
137+
"""
138+
Make sure raw SQL with args, passed in to a where clause, works
139+
as expected.
140+
"""
141+
self.insert_rows()
142+
143+
response = (
144+
Band.select(Band.name)
145+
.where(WhereRaw("name = {}", "Pythonistas"))
146+
.run_sync()
147+
)
148+
149+
print(f"response = {response}")
150+
151+
self.assertEqual(response, [{"name": "Pythonistas"}])
152+
153+
def test_where_raw_combined_with_where(self):
154+
"""
155+
Make sure WhereRaw can be combined with Where.
156+
"""
157+
self.insert_rows()
158+
159+
response = (
160+
Band.select(Band.name)
161+
.where(
162+
WhereRaw("name = 'Pythonistas'") | (Band.name == "Rustaceans")
163+
)
164+
.run_sync()
165+
)
166+
167+
print(f"response = {response}")
168+
169+
self.assertEqual(
170+
response, [{"name": "Pythonistas"}, {"name": "Rustaceans"}]
171+
)
172+
119173
def test_where_and(self):
120174
self.insert_rows()
121175

0 commit comments

Comments
 (0)