This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-08-02
Channels
- # announcements (11)
- # aws (3)
- # babashka (34)
- # beginners (20)
- # biff (2)
- # calva (3)
- # cherry (29)
- # cider (6)
- # cljs-dev (9)
- # clojure (124)
- # clojure-europe (12)
- # clojure-norway (5)
- # clojure-uk (2)
- # clojurescript (32)
- # conjure (11)
- # datalevin (1)
- # datomic (16)
- # deps-new (1)
- # etaoin (6)
- # holy-lambda (10)
- # honeysql (28)
- # hyperfiddle (21)
- # jackdaw (2)
- # jobs (2)
- # leiningen (15)
- # missionary (12)
- # off-topic (132)
- # other-languages (1)
- # pathom (13)
- # rdf (10)
- # re-frame (8)
- # reagent (5)
- # releases (1)
- # remote-jobs (4)
- # shadow-cljs (32)
- # tools-deps (6)
- # vim (15)
- # xtdb (24)
I want to generate dynamic sql where conditions with honeysql . Here is my code that has achieved the result I want. Is there a better or easy way to write it?
(defn select-audit-list
[conn {revitId :revitId
type :type
pro :pro
username :username}]
(let [con (data.common/with-logging conn)]
(let [
wheresql (cond-> [:and [:= revitId :RevitID]]
(not (empty? type)) (conj [:in :Type type])
(not (empty? pro)) (conj [:in :Pro pro])
(not (empty? username)) (conj [:in :username username]))
sqlmap {:select :*
:from :audit
:where wheresql}]
sqlmap
(sql/format sqlmap {:inline true}))))
(def args {
:revitId "123"
:type [1 2 3]
:pro ["p1" "p2" "p3"]
:username ["user1"]
})
(select-audit-list nil args)
==> ["SELECT * FROM audit WHERE ('123' = RevitID) AND (Type IN (1, 2, 3)) AND (Pro IN ('p1', 'p2', 'p3')) AND (username IN ('user1'))"]
(select-audit-list2 nil (assoc args :username []))
==> ["SELECT * FROM audit WHERE ('123' = RevitID) AND (Type IN (1, 2, 3)) AND (Pro IN ('p1', 'p2', 'p3'))"]
Using the where
helper would make this easier since it takes care of the connectives:
(require [honey.sql.helpers :refer [where]])
...
(cond-> (where := :revitId :RevitID)
(seq type) (where :in :Type type)
(seq pro) (where :in :Pro pro)
(seq username) (where :in :username username))
Assuming you're using HoneySQL 2.xAs an example:
user=> (let [username "test" type [1 2 3] revitId 42] #_=> (cond-> (where := revitId :RevitID)
#_=> (seq type) (where :in :Type type)
#_=> (seq username) (where := username :username)
#_=> :and (select :*) #_=> :then (from :table)
#_=> :format (sql/format)))
["SELECT * FROM table WHERE (? = RevitID) AND (Type IN (?, ?, ?)) AND (? = username)" 42 1 2 3 "test"]
user=>
(I know that's not quite the data you have but it should give you an idea of what I'm suggesting)Note, in particular, that (seq foo)
is more idiomatic than (not (empty? foo))
per the empty?
docstring:
clojure.core/empty?
([coll])
Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))
Thank you very much @U04V70XH6
FYI. We’ve built some fns on top of honey to make stuff a bit more fluent and saves us from runtime errors:
(def none [:= true false])
(def all [:= true true])
(defn in
[column-name values]
(if (seq values)
[:in column-name (set values)]
none))
(defn and [& clauses]
(into [:and] (seq clauses)))
(defn or [& clauses]
(into [:or] (seq clauses)))
(defn lift [x]
[:lift x])
now that's interesting
the in
bit especially
filtering of nil clauses would be useful, so you could go (and (when (seq type) (in :Type type)) (when (seq pro) (in :Pro pro)))
(defmacro in-when
[condition column-name values]
`(when ~condition
[:in ~column-name ~values]))
(defn and [& clauses]
(let [c (remove nil? clauses)]
(when (seq c)
(if (second c)
(into [:and] (seq c))
(first c)))))
you could do the same with or
The and
and or
are nice in so far that you can write (pq/and foo bar baz)
but, it’s a bit sucky in this situation (apply pq/and (map lol xs))
Hello guys.
How can I use :drop-table
clause with table names such as user
(reserved names)
I’m trying these things
(sql/format {:drop-table "foo"})
=> ["DROP TABLE FOO"]
(sql/format {:drop-table :foo})
=> ["DROP TABLE foo"]
and it doesn’t work
Check the docs for the :quoted
option. You can also select the :dialect
to get the quoting store you want for your database.
wanted to run some functions by you to see if you're interested in something like this in honeysql. putting it in this thread
they're rather a lot but if you have multiple queries and need to merge their concerns this gets you there. I'm not a huge fan but it ended up being something we needed. it perhaps could be written better
Looks interesting but I have a couple of concerns:
a) it assumes there is a helper for every clause -- which isn't true out of the box
b) it won't work for any clauses registered by users
c) does ns-publics
and resolve
work in ClojureScript?
ahhh ok good call. never mind!
I'm sure there would be a way to handle this well, but maybe it's not a good call overall
I recommend always using the helpers to builder queries and just keep threading stuff together instead of building separate pieces and trying to merge them after the fact.
that ship has sailed a bit, for a number of reasons, but mostly my colleagues don't like to use the helpers ¯\(ツ)/¯
Hmm, maybe there's a lesson to be had in that then? 😉
well, sure, I agree