Skip to content

Commit 0063093

Browse files
committed
Raw queries can now be parameterised
1 parent 1da3ac1 commit 0063093

File tree

5 files changed

+45
-8
lines changed

5 files changed

+45
-8
lines changed

docs/src/piccolo/query_types/raw.rst

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,12 @@ Should you need to, you can execute raw SQL.
1111
[{'name': 'Pythonistas', 'manager': 1, 'popularity': 1000, 'id': 1},
1212
{'name': 'Rustaceans', 'manager': 2, 'popularity': 500, 'id': 2}]
1313
14-
.. warning:: Be careful to avoid SQL injection attacks. Don't substitute user submitted data into your SQL strings.
14+
It's recommended that you parameterise any values. Use curly braces ``{}`` as
15+
placeholders:
16+
17+
.. code-block:: python
18+
19+
>>> Band.raw('select * from band where name = {}', 'Pythonistas').run_sync()
20+
[{'name': 'Pythonistas', 'manager': 1, 'popularity': 1000, 'id': 1}]
21+
22+
.. warning:: Be careful to avoid SQL injection attacks. Don't add any user submitted data into your SQL strings, unless it's parameterised.

piccolo/query/methods/raw.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@
55

66

77
class Raw(Query):
8-
98
@property
109
def querystring(self) -> QueryString:
1110
return self.base
12-
13-
def __str__(self):
14-
return self.querystring.__str__()

piccolo/query/methods/select.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ def querystring(self) -> QueryString:
134134

135135
#######################################################################
136136

137+
# If no columns have been specified for selection, select all columns
138+
# on the table:
137139
if len(self.columns_delegate.selected_columns) == 0:
138140
self.columns_delegate.selected_columns = self.table._meta.columns
139141

piccolo/table.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -272,13 +272,17 @@ def insert(cls, *rows: "Table") -> Insert:
272272
return query
273273

274274
@classmethod
275-
def raw(cls, sql: str) -> Raw:
275+
def raw(cls, sql: str, *args: t.Any) -> Raw:
276276
"""
277277
Execute raw SQL queries on the underlying engine - use with caution!
278278
279-
await Band.raw('select * from foo')
279+
await Band.raw('select * from band')
280+
281+
Or passing in parameters:
282+
283+
await Band.raw("select * from band where name = {}", 'Pythonistas')
280284
"""
281-
return Raw(table=cls, base=QueryString(sql))
285+
return Raw(table=cls, base=QueryString(sql, *args))
282286

283287
@classmethod
284288
def select(cls) -> Select:

tests/table/test_raw.py

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
from ..base import DBTestCase
2+
from ..example_project.tables import Band, Concert
3+
4+
5+
class TestRaw(DBTestCase):
6+
def test_raw_without_args(self):
7+
self.insert_row()
8+
9+
response = Band.raw("select * from band").run_sync()
10+
11+
self.assertDictEqual(
12+
response[0],
13+
{"id": 1, "name": "Pythonistas", "manager": 1, "popularity": 1000},
14+
)
15+
16+
def test_raw_with_args(self):
17+
self.insert_rows()
18+
19+
response = Band.raw(
20+
"select * from band where name = {}", "Pythonistas"
21+
).run_sync()
22+
23+
self.assertTrue(len(response) == 1)
24+
self.assertDictEqual(
25+
response[0],
26+
{"id": 1, "name": "Pythonistas", "manager": 1, "popularity": 1000},
27+
)

0 commit comments

Comments
 (0)