-
Notifications
You must be signed in to change notification settings - Fork 313
Description
Consider following code:
from pypika import PostgreSQLQuery as Query
from pypika import Table
t = Table("t")
q1 = Query.update(t).where(t.id == 1)
q2 = Query.update(t).where(t.id == 1).returning(t.star)
Those queries will result in following strings
>>> str(q1)
''
>>> str(q2)
' RETURNING "t".*'
The reason for such behaviour is that in PostgreSQLQueryBuilder.get_sql
there is no check if super(PostgreSQLQueryBuilder, self).get_sql()
returns an empty string.
Rationale:
You may be wondering if such a query is even valid and I would argue that it is and has some usages. My arguments are as follow:
- When building an update query conditionally, it can happen that
set()
wouldn't be called because eg. a request wouldn't perform any update. See code below:
query = Query.update(t)
if param1 is not None:
query = query.set(t.param1, param1)
if param2 is not None:
query = query.set(t.param2, param2)
return execute(query.where(t.id = 1).returning(t.star))
In the above example te most elegant way IMO is to return an empty string for such query. Alternatives would be to either inspect private members QueryBuilder._updates
(no-no) or checking if at least one parameter is not None
(too much unnecessary code)
- Behaviour of
QueryBuilder.get_sql
for an empty update query is defined in such a way that if no column is updated, then an empty string is returned. I think that for the sake of consistency, the implementation ofPostgreSQLQueryBuilder
should follow the same behaviour.
Proposal:
If you agree with me and I have your blessing, I can implement the fix. My fix would return empty string if super(PostgreSQLQueryBuilder, self).get_sql()
returns an empty string. From what I can see, very similar situation also happens with PostgreSQLQueryBuilder.on_conflict
, so this case will also be covered.
Three unit tests for the following queries will be added:
q1 = Query.update(t).where(t.id == 1).returning(t.star)
q2 = Query.into(t).on_conflict(t.a).do_nothing()
q3 = Query.into(t).returning(t.star)