This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # adventofcode (21)
- # announcements (4)
- # babashka (35)
- # beginners (36)
- # calva (76)
- # cider (16)
- # clj-kondo (24)
- # clj-on-windows (12)
- # clojure (70)
- # clojure-europe (7)
- # clojure-nl (13)
- # clojure-spec (3)
- # clojure-uk (3)
- # clojurescript (34)
- # conjure (11)
- # cursive (22)
- # datomic (30)
- # deps-new (2)
- # emacs (36)
- # fulcro (28)
- # gratitude (4)
- # honeysql (16)
- # hugsql (8)
- # introduce-yourself (5)
- # jobs (1)
- # malli (4)
- # missionary (6)
- # off-topic (129)
- # other-languages (34)
- # polylith (3)
- # reagent (9)
- # reitit (27)
- # releases (13)
- # remote-jobs (1)
- # reveal (1)
- # shadow-cljs (2)
- # tools-build (3)
- # tools-deps (18)
- # web-security (7)
- # xtdb (4)
Folks, I'm looking at https://github.com/seancorfield/honeysql/issues/374 and trying to figure out the best path forward here. The TL;DR is that HoneySQL has always treated
:is as a synonym for
:is-not as a synonym for
:<> which is not quite correct. In addition, equality and inequality when one operand or the other is
nil is special-cased and always produces
IS NULL or
IS NOT NULL as appropriate -- which means that
[:= a :col] when
a evaluates to
col IS NULL but when
a evaluates to, say, 42 produces
42 = col (well,
? = col and a parameter of 42).
At issue here is that
IS/`IS NOT` are not synonyms for
=/`<>` for Boolean operands or situations where the second operand is
nil (`NULL`). I verified this on MySQL (in addition to what's in that issue).
So this is definitely a bug but I'm concerned that fixing it is going to silently change the behavior of existing code.
The existing behavior with
=/`<>` and one operand being
nil is intended to be a convenience, so you can just write
[:= :col foo] and get either
col = ? (and the parameter value of
col IS NULL depending on the value of
col = NULL here would always be an empty result.
I think that behavior should be retained because, well, it's convenient and I suspect quite a bit of code out there relies on that happening.
But that aliasing behavior is not correct for Boolean columns (`BIT(1)` in MySQL) when testing for
UNKNOWN but that is not yet supported by HoneySQL) -- because
col IS NOT TRUE and
col <> TRUE behave differently if
col can be
(and right now there's no way to get the correct
IS NOT behavior for Boolean columns because HoneySQL turns those into
If I just remove the aliasing (which would be "correct"), any existing code using
:is-not is potentially going to change behavior in a subtle way (which is worse than just "breaking").
[:= a :col] or
[:is a :col] transforms to
col IS NULL if
a happens to be
NULL = col produces no matches and
NULL IS col is a syntax error so that is a special case that is also problematic)
I think, clearly, whatever I do has to have at the very least a dynamic var that folks can set to select the behavior. We certainly have code at work that explicitly relies on being able to do
[:= :col nil] /
[:<> :col nil] and get
col IS NULL /
col IS NOT NULL so I'm loathed to change that behavior.
The first time I used honeysql I had to triple check about this. In the end, I came to like the := behavior because I thought it was just a nice way when dealing with explicit nils. Especially when passing in a literal nil.
I think that is/is-not should be left as is though. Clearly the caller knows what they're doing.
[:is a :col] should probably produce correct sql, ordering wise and/or throw if a is not nil.
Thanks @orestis That's useful feedback. I think I am beginning to lean toward just removing the aliasing for
:is/`:is-not` and warning folks in the change log about this (and updating the docs in several places to show examples of this behavior and the subtle differences).
Check your code for
We'll see whether it actually breaks any real code...