This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-05-12
Channels
- # aleph (6)
- # announcements (11)
- # babashka (24)
- # beginners (127)
- # calva (33)
- # chlorine-clover (5)
- # cider (7)
- # clara (9)
- # cljs-dev (54)
- # cljsrn (5)
- # clojure (61)
- # clojure-australia (8)
- # clojure-bay-area (11)
- # clojure-europe (36)
- # clojure-italy (3)
- # clojure-nl (3)
- # clojure-spec (6)
- # clojure-taiwan (1)
- # clojure-uk (8)
- # clojurescript (94)
- # code-reviews (2)
- # community-development (6)
- # conjure (26)
- # core-typed (1)
- # cursive (3)
- # datahike (4)
- # datomic (14)
- # events (1)
- # graphql (1)
- # honeysql (49)
- # introduce-yourself (5)
- # jobs-discuss (15)
- # kaocha (6)
- # lsp (8)
- # malli (1)
- # meander (5)
- # nrepl (1)
- # off-topic (21)
- # other-languages (1)
- # pathom (13)
- # podcasts (1)
- # polylith (1)
- # reitit (16)
- # shadow-cljs (50)
- # spacemacs (11)
- # sql (11)
- # tools-deps (21)
- # unrepl (1)
- # vim (9)
Hello. What's the story around using your own Records/types with honeysql V2 . In version 1 there seems to be a honeysql.format/ToSQL
protocol to tell honeysql how to deal with Record parameters. In v2 this seems to be gone?
When I pass in a record type as a parameter to honeysql v2's format function it incorrectly parses the record fields as sql clauses:
:message "Unknown SQL clauses: :beginning, :end"
Any thoughts on how to solve this in v2 is much appreciated. The use case would be to pass the record as a parameter value that can then be handled by next.jdbc's settable parameter protocol which would dispatch on the Record type.
Edit: Since breaking changes can be introduced with V2, perhaps this would be a good time to just not treat Records as SQL clauses maps?
Edit 2: The expression in question where interval
in the select statement is the record in question.
{:with [[:workday (workday-upsert m)]]
:insert-into [[:work-intervals [:workday-id :interval]]
{:select [:workday.id interval]
:from :workday}]
:returning :*}
So I think the problem is related to how the format-selectable-dsl
function checks if something is a map, which records are.
https://github.com/seancorfield/honeysql/blob/v2/src/honey/sql.cljc#L257
It seems the code should check that something is both a map and not a record, but I'm not sure if this is then something that would have to be done a lot of places.
Edit: I've not had the chance to test this in practice, but could test this after work today if you'd be interested in a pull-request for this.
@snorremd I think you can wrap such things with [:lift ..]
That’s the “escape” mechanism for passing sequential and map-like types through as parameter values, if I’m understanding what you’re trying to do…
So something like this?
(-> {:insert-into [[:foo [:interval]]
{:select [[:lift (->Interval nil nil)]]
:from :test}]}
hsql/format)
Produced an error:
; Execution error (ExceptionInfo) at honey.sql/format-dsl (sql.cljc:891).
; Unknown SQL clauses: :beginning, :end
:select
expects a sequence of expressions, but those can be aliased, so a function call without an alias still needs to be written as if it did have one — the docs have examples and talk about this.
{:select [[[:lift (->Interval nil nil)]]] ..
should do it.
Hi everybody!
I begin to playing with honeysql and I wonder how I can do SELECT (first_name, last_name) as name
user=> (sql/format {:select [[[:composite :first_name :last_name] :name]]})
["SELECT (first_name, last_name) AS name"]
I tried and it gives me this error:
Assert failed: Alias should have two parts[:composite :first_name :last_name]
(= 2 (count x))
It works with the helpers function call:
(h/format {:select [[(composite :first_name :last_name) :name]]})
I prefer the first syntax. Any idea?
You have missed a level of nesting. Funnily enough I was just explaining this to someone else…
:select [:a :b :c]
=> SELECT a, b, c
:select [:a [:b :c]]
=> SELECT a, b AS c
:select [:a [[:foo :bar] :c]]
=> SELECT a, FOO(bar) AS c
And as I showed above:
user=> (sql/format {:select [[[:composite :first_name :last_name] :name]]})
["SELECT (first_name, last_name) AS name"]
Note the nesting level.If I add spaces it might be easier to see:
user=> (sql/format {:select [ [ [:composite :first_name :last_name] :name ] ]})
["SELECT (first_name, last_name) AS name"]
No success, always same error with a simple copy paste:
user=> (sql/format {:select [[[:composite :first_name :last_name] :name]]})
Execution error (AssertionError) at honeysql.format/seq->sql (format.cljc:385).
Assert failed: Alias should have two parts[:composite :first_name :last_name]
(= 2 (count x))
You’re using HoneySQL V2?
No "1.0.461"
OK I move to v2, thx
Sorry, yeah, what I suggested is for V2. On V1, you’d have to use the helper I think or sql/call
.
I supposed sqlite is not well supported. With particulary syntax like:
SELECT first_name || " " || last_name as name FROM users;
[:|| :first_name " " :last_name]
should work.
:select [ [ [:|| ...] :name ] ]
user=> (sql/format {:select [ [ [:|| :first_name " " :last_name] :name ] ]})
["SELECT first_name || ? || last_name AS name" " "]
Several DBs have ||
as a string concatenation operator.Great, very relevant. Thanks a lot.
[:composite :first_name :last_name]
is a function call/operator syntax
[[:composite :first_name :last_name] :name]
is an aliased expression
and :select
takes a sequence of expressions
Oh I had missed :composite
Perfect, thanks!
https://github.com/seancorfield/honeysql/tree/v2#composite-types (README) — although the usage shown is with insert
rather than select
Last thing, is there an equivalent of "%pattern%"
for a where clause?
Not sure what you mean.
[:like :first_name "%foo%"]
?
BTW, it can be really inefficient to query with a leading %
in a regex — it will do a full table scan in all cases.
Trailing %
is OK, because SQL can use the stem value (the portion before the %
) to narrow down the index range, assuming you have an index on the column 🙂
Oh thanks, very useful information.
So with your snippet, if I want pass a var so I'll do [:like :first_name (str "%" foo "%")]
or is a cleaner way to do it?
If you have just a string and you want it to be a SQL regex and match anywhere in the column value, you have to add the %
yourself.
I think :like
will be case sensitive in most cases (depends on the DB and how it is setup) so there’s also :ilike
for a case-insensitive comparison
Great, thanks. 👍