Skip to content

Commit b3e888a

Browse files
authored
1374 Add NullIf function (#1375)
* add `NullIf` function * remove `default=None`
1 parent 1a179da commit b3e888a

4 files changed

Lines changed: 70 additions & 2 deletions

File tree

docs/src/piccolo/functions/conditional.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,9 @@ Coalesce
77
--------
88

99
.. autoclass:: Coalesce
10+
11+
12+
NullIf
13+
------
14+
15+
.. autoclass:: NullIf

piccolo/apps/playground/commands/run.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class Venue(Table):
7272
id: Serial
7373
name = Varchar(length=100)
7474
capacity = Integer(default=0)
75+
address = Text(null=True)
7576

7677
@classmethod
7778
def get_readable(cls) -> Readable:

piccolo/query/functions/conditional.py

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,45 @@ def __init__(
7878
placeholders = ", ".join("{}" for _ in args)
7979

8080
super().__init__(f"COALESCE({placeholders})", *args, alias=alias)
81+
82+
83+
class NullIf(QueryString):
84+
def __init__(
85+
self,
86+
identifier: Union[Column, QueryString],
87+
value: Union[BasicTypes, QueryString],
88+
alias: Optional[str] = None,
89+
):
90+
"""
91+
Returns null if the value in the database equals ``value``.
92+
93+
An example is where a ``Varchar`` or ``Text`` column contains a mix of
94+
empty strings and null. We might want to standardise the response so
95+
it's just null.
96+
97+
For example::
98+
99+
class Venue(Table):
100+
name = Varchar()
101+
address = Text(null=True)
102+
103+
>>> await Venue.select(Venue.name, NullIf(Venue.address, ''))
104+
[{'name': 'Amazing venue', 'address': None}]
105+
106+
"""
107+
# Preserve the original alias from the column.
108+
109+
from piccolo.columns import Column
110+
111+
if isinstance(identifier, Column):
112+
alias = (
113+
alias
114+
or identifier._alias
115+
or identifier._meta.get_default_alias()
116+
)
117+
elif isinstance(identifier, QueryString):
118+
alias = alias or identifier._alias
119+
120+
#######################################################################
121+
122+
super().__init__("NULLIF({}, {})", identifier, value, alias=alias)

tests/query/functions/test_conditional.py

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
from piccolo.columns import Integer
2-
from piccolo.query.functions.conditional import Coalesce
1+
from piccolo.columns import Integer, Text, Varchar
2+
from piccolo.query.functions.conditional import Coalesce, NullIf
33
from piccolo.table import Table
44
from piccolo.testing.test_case import AsyncTableTest
55

@@ -23,3 +23,22 @@ async def test_coalesce(self):
2323
async def test_coalesce_pipe_syntax(self):
2424
response = await Band.select(Band.popularity | 10)
2525
self.assertListEqual(response, [{"popularity": 10}])
26+
27+
28+
class Venue(Table):
29+
name = Varchar()
30+
address = Text(null=True)
31+
32+
33+
class TestNullIf(AsyncTableTest):
34+
35+
tables = [Venue]
36+
37+
async def test_null_if(self):
38+
await Venue({Venue.name: "Amazing Venue", Venue.address: ""}).save()
39+
40+
response = await Venue.select(Venue.name, NullIf(Venue.address, ""))
41+
42+
self.assertListEqual(
43+
response, [{"name": "Amazing Venue", "address": None}]
44+
)

0 commit comments

Comments
 (0)