honeysql

sheluchin 2023-10-16T13:47:46.655329Z

Do HoneySQL users do most of their DB interaction by executing HoneySQL expressions or is typing raw SQL into some DB GUI or CLI still a common part of the workflow?

p-himik 2023-10-16T14:09:51.129339Z

For me, the latter is still common but supplementary.

oly 2023-10-16T14:18:47.147229Z

I would say a mix, I gravitate towards composing the honeysql if I can as they are basically saved queries which you can compose, but often when working out a more complex query or working with more advanced db stuff I return to using a GUI

๐Ÿ‘† 1
seancorfield 2023-10-16T15:03:09.707999Z

I don't use a DB GUI or CLI at all. I use Clojure for all my DB stuff, either simple SQL and next.jdbc directly or HoneySQL and next.jdbc. Always written into a file and eval'd into a REPL.

sheluchin 2023-10-16T15:33:15.648699Z

@seancorfield what do you do to fill the gap of schema visualization that some GUI tools offer?

seancorfield 2023-10-16T15:41:46.477929Z

I haven't found that I need that. We have over 300 tables in our database so I'm not sure that a visual representation would be very readable? We can DESCRIBE and SHOW INDEX via next.jdbc, and datafy / nav allows me to navigate through the data in Portal from table to table.

2023-10-16T16:27:41.831729Z

For gnarly SQL (say I need to do a bunch of CTEs and some json stuff) Iโ€™ll pull up the DB console in IntelliJ. Once I get it right, Iโ€™ll Honey-ify it. Ideally, though, Iโ€™ve got enough prior art stored around that I can just grab something similar and edit that. My preference is the REPL + HoneySQL queries.

โž• 1
2023-10-16T18:30:13.524779Z

2023-10-16T18:32:54.567699Z

2023-10-16T18:34:15.995019Z

2023-10-16T18:34:16.419979Z

nate 2023-10-16T18:54:32.197729Z

I've been using New Relic at work more and I as I'm a command line addict, I quickly started using newrelic nrql query ... to send queries and get the results in a more extensible environment than my browser. NR's queries have backticks around the field names, and I am having some difficulty expressing that in honeysql. Here's an example query:

select `mulog/timestamp`, `mulog/event-name` from Log where `mulog/data.account` = 'foo-account-id' since 2 days ago limit 2000
The closest I've been able to get is this:
{:select [[[:raw "`mulog/timestamp`"]]
          [[:raw "`mulog/event-name`"]]]
 :from :Log
 :where [:= [[:raw "`mulog/timestamp`"]] "foo-account-id"]
 :limit 2000}
The backtick quoting is a little annoying. Is there some option I can pass to only quote that and not the table name? Also, how can I get the "since 2 days ago" in there?

Samuel Ludwig 2023-10-16T18:59:18.841399Z

hmmm, i think if you do (honeysql/format q {:dialect :mysql}) it should put backticks around names, im sure theres a specific option for that single behavior in there

nate 2023-10-16T19:04:22.725089Z

(-> {:select [:mulog/timestamp
              :mulog/event-name]
     :from :Log
     :where [:= [[:raw "`mulog/timestamp`"]] "foo-account-id"]
     :limit 2000}
    (sql/format {:inline true :dialect :mysql}))
yields
["SELECT `mulog`.`timestamp`, `mulog`.`event-name` FROM `Log` WHERE (`mulog/timestamp`) = 'foo-account-id' LIMIT 2000"]
Got the quoting, but the columns aren't right

seancorfield 2023-10-16T19:13:38.373859Z

Yeah, there's some weird aspects of NRQL that you just aren't going to be able to produce from HoneySQL as it stands right now.

seancorfield 2023-10-16T19:14:36.998089Z

You can use :'mulog/timestamp to produce mulog/timestamp as a column name but that defeats the quoting (by design) and there's no way to generate columns containing / right now.

seancorfield 2023-10-16T19:17:14.669399Z

As for since, you'd have to use register-clause! to add your own formatter. I don't have a good example for you right now because the closest formatter would wrap the expressions in parens which you don't want.

nate 2023-10-16T19:48:02.648529Z

makes sense, thank you for the information

seancorfield 2023-10-16T19:53:04.867069Z

I'm not averse to adding support for NRQL but it's going to be quite a bit of work since there's a lot of New Relic-specific quirks in that syntax.

nate 2023-10-16T19:55:37.005079Z

yeah, seeing that now

nate 2023-10-16T20:02:05.755669Z

this seems to work well enough:

(sql/register-clause! :since (fn [clause x] [(str (name clause) " " x)]) :limit)
with:
:since "2 days ago"

seancorfield 2023-10-16T20:47:32.991359Z

Yeah, I was thinking of :since [2 :days :ago] and formatting it fully but that works with a string ๐Ÿ™‚

nate 2023-10-16T22:32:31.638199Z

hahaha, that looks better

nate 2023-10-16T22:32:48.626609Z

will see how far this gets me and report back

seancorfield 2023-10-16T22:49:52.230499Z

The main convenience you'll want is to have a way to override the / and . splitting in column names...

seancorfield 2023-10-16T22:51:15.474359Z

(and you'll probably want it to not convert - to _ in column names as well?)

nate 2023-10-16T22:52:01.077629Z

yeah

nate 2023-10-16T22:52:03.675939Z

thank you

seancorfield 2023-10-16T22:53:06.630669Z

You only need the backtick quotes on names that contain stuff like /, ., and - right? I'm just thinking what this dialect might look like...

seancorfield 2023-10-16T22:55:22.288439Z

The main changes would be in format-entity that this dialect would have to force col-fn to (almost) identity I think and make the parts logic a no-op...

seancorfield 2023-10-16T23:03:51.480889Z

(format {:select [:mulog/timestamp :mulog/event-name]
           :from   :Log
           :where  [:= :mulog/data.account "foo-account-id"]}
          {:dialect :nrql :quoted nil :inline true})
;;=> ["SELECT `mulog/timestamp`, `mulog/event-name` FROM Log WHERE `mulog/data.account` = 'foo-account-id'"]
That's a start...

seancorfield 2023-10-16T23:05:23.470469Z

(I can make the :nrql dialect automatically select :quoted nil :inline true)

seancorfield 2023-10-16T23:10:19.720039Z

@nate Off the top of your head, do you remember if NRQL has ORDER BY and whether it comes before or after SINCE?

nate 2023-10-16T23:12:05.992029Z

I donโ€™t know if Iโ€™ve used order by before. I would assume it would be before since.

seancorfield 2023-10-16T23:12:43.910699Z

It's a bit more limited than I thought

seancorfield 2023-10-16T23:17:50.310669Z

OK, I don't have FACET or WITH TIMEZONE yet:

(format {:select [:mulog/timestamp :mulog/event-name]
           :from   :Log
           :where  [:= :mulog/data.account "foo-account-id"]
           :since  [2 :days :ago]}
          {:dialect :nrql :quoted nil :inline true})
produces
["SELECT `mulog/timestamp`, `mulog/event-name` FROM Log WHERE `mulog/data.account` = 'foo-account-id' SINCE 2 DAYS AGO"]

seancorfield 2023-10-16T23:18:20.174079Z

I'll push this to develop and you can try it out via git deps (it'll also push a new SNAPSHOT to Clojars shortly).

nate 2023-10-16T23:21:59.809439Z

Awesome! Thank you. Iโ€™ll try this out this evening.

seancorfield 2023-10-16T23:49:03.901989Z

https://github.com/seancorfield/honeysql/issues/510 has the current status of the work. It's pushed to develop and the latest 2.4.9999-SNAPSHOT.

nate 2023-10-17T03:07:33.661879Z

This works perfectly! I tried out since, until, compare-with, and timeseries. TIL about the arg to timeseries to specify the units.

seancorfield 2023-10-17T03:31:38.351499Z

Hmm, is that arg optional? I'll have to dig into some more of our NRQL queries at work and see what syntax we use.

seancorfield 2023-10-17T03:32:10.329589Z

Are you invoking the CLI nr1 query programmatically at this point, or still copy'n'pasting?

nate 2023-10-17T03:32:37.774579Z

I've always just put TIMESERIES without any arg, which I'm guessing defaults to TIMESERIES auto

nate 2023-10-17T03:33:41.162149Z

For my experiments just now, I was copy/pasting into the new relic web site, but for my previous hard-coded queries, I was running newrelic nrql query ... programmatically

nate 2023-10-17T03:33:52.260069Z

(via babashka.process/process)

๐Ÿ‘๐Ÿป 1
seancorfield 2023-10-17T03:39:11.473119Z

I guess :timeseries [:auto] works... I could tweak it so :timeseries :auto also works, which would be a bit more succinct but I'm not sure it's worth it?

nate 2023-10-17T03:50:08.083049Z

Hm. Consistency is good. But also, eliding unnecessary brackets is good. Hm.

nate 2023-10-17T03:50:36.227909Z

I lean toward the former.

seancorfield 2023-10-17T03:51:04.062049Z

The shortcut can always be added "later"...

nate 2023-10-17T03:51:52.442689Z

Agreed. Easier to loosen later.

seancorfield 2023-10-17T04:00:36.125039Z

Metric names with spaces in are a bit of a pain:

(sql/format {:select [[[:latest (keyword "Elastic/Search OK Count/value")]]
                        [[:latest (keyword "Elastic/Search Fail Count/value")]]
                        [[:* 100 [:latest :Sent/rate]] "Sent/rate x 100"]]
               :from :Metric
               :where [:and [:= :environment "production"]
                       [:= :process.name "match"]]
               :since [1 :day :ago]
               :timeseries [:auto]}
              {:dialect :nrql})
produces
["SELECT LATEST(`Elastic/Search OK Count/value`), LATEST(`Elastic/Search Fail Count/value`), 100 * LATEST(`Sent/rate`) AS `Sent/rate x 100` FROM Metric WHERE (environment = 'production') AND (`process.name` = 'match') SINCE 1 DAY AGO TIMESERIES auto"]
(taken from one of our dashboards at work)

nate 2023-10-17T04:01:59.540209Z

Could it just be the string instead?

seancorfield 2023-10-17T04:02:20.827049Z

Then it gets single quotes ' instead of backtick.

seancorfield 2023-10-17T04:03:39.829579Z

(our fault for using spaces in metric names, I guess... but...)

seancorfield 2023-10-17T04:04:51.719759Z

New Relic metrics can have any arbitrary name...

nate 2023-10-17T04:06:42.822019Z

Much more flexible than db column names.

seancorfield 2023-10-17T04:07:46.398109Z

It may be a problem that is not worth solving. I'll see whether anyone (else) ends up using this dialect and whether it causes them problems ๐Ÿ™‚

nate 2023-10-17T04:09:04.070769Z

Iโ€™ll try it out with our metrics too and see how it feels.

nate 2023-10-17T16:05:08.319259Z

Tried out the latest commit for facet, and tried to add it with multiple facets. Looked at the code and I think this is the change needed to make multiple facets work:

โฏ git di
diff --git a/src/honey/sql.cljc b/src/honey/sql.cljc
index 63b34fe..e4e6ce5 100644
--- a/src/honey/sql.cljc
+++ b/src/honey/sql.cljc
@@ -1447,7 +1447,7 @@ (def ^:private clause-format
          :returning       #'format-selects
          :with-data       #'format-with-data
          ;; NRQL extensions:
-         :facet           #'format-selector
+         :facet           #'format-selects
          :since           #'format-interval
          :until           #'format-interval
          :compare-with    #'format-interval
diff --git a/src/honey/sql/helpers.cljc b/src/honey/sql/helpers.cljc
index d43f533..844c068 100644
--- a/src/honey/sql/helpers.cljc
+++ b/src/honey/sql/helpers.cljc
@@ -1023,7 +1023,7 @@ (defn within-group
 (defn facet
   "(facet [:metric.name :alias])"
   [& args]
-  (generic-1 :facet args))
+  (generic :facet args))
 
 (defn since
   "(since 2 :days :ago)"

nate 2023-10-17T16:06:05.428479Z

Now :facet [[:mulog/event-name :foo] :container_name] translates to

FACET `mulog/event-name` AS foo, container_name

seancorfield 2023-10-17T16:06:39.150409Z

Ah yes. Less convenient to write a single facet but more flexible. I hadn't thought about multiple facets in a single statement

seancorfield 2023-10-17T16:07:22.994309Z

I'll make that change shortly (not at my desk yet).

๐Ÿ‘ 1
seancorfield 2023-10-17T18:59:40.832799Z

(that change has just been pushed -- thank you!)

nate 2023-10-17T19:33:45.570869Z

Thank you!

2023-10-16T23:24:34.851319Z

2023-10-28T21:05:16.638809Z