I have this kind of where clauses.
(h/where
(when (:id filter-options)
[:= :id (:id filter-options)])
(when (seq (:ids filter-options))
[:in :id (:ids filter-options)])
(when (:user-id filter-options)
[:= :user-id (:user-id filter-options)])
(when (seq (:user-ids filter-options))
[:in :user-id (:user-ids filter-options)])
(when (:crop-id filter-options)
[:= :crop-id (:crop-id filter-options)])
(when (seq (:crop-ids filter-options))
[:in :crop-id (:crop-ids filter-options)])
; ... and many more filters ...
)
I felt like "https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/operators/member-access-operators#null-conditional-operators--and-" was what I needed.
The attempt I made was to (register-fn! :?= ...) but it seems that I cannot return nil from formatter.(sql/register-fn! :?=
(fn [_op [l r]]
(when (some? l)
[:= l r])))
(sql/format [:and [:?= nil :a]])
; => [""]
is it possible to make it ["TRUE"] or so?I think you can replace (when (some? r) ...) with (if (nil? r) true ...).
oh my
returning [true] works, but ["WHERE true AND true AND true"] 😅
Yeah, no way around that without either overriding handling of the :where clause or filtering the conditions themselves.
This is how I'd write something like that (I don't use helper functions generally):
(let [conds (filter peek [[:= :id (:id filter-options) ...])
sqlmap {:select :id :from :t}]
(cond-> sqlmap
(seq conds)
(assoc :where (into [:and] conds))))yes indeed, yet it is prevailing pattern for our code base. so I was looking for syntax extension.
I would use cond-> for this and just thread through multiple h/where calls:
(cond-> sql
(:id filter-options)
(h/where [:= :id (:id filter-options)])
..)
(that should do some simplification of the DSL to produce less redundant SQL)