honeysql

Discussion of https://github.com/seancorfield/honeysql :slightly_smiling_face:
2018-06-27T01:39:08.000151Z

seancorfield 2018-06-27T01:43:43.000226Z

<!here> This channel is connected to the HoneySQL repo on GitHub (since the library is getting a bunch of updates). If it gets too noisy for folks, I'll dial that back.

seancorfield 2018-06-27T01:45:11.000103Z

I suppose it's a good time to announce that I'm taking over maintenance from @michaelblume who has been a great steward for the library for quite a while, and now has other pressures on his time.

bja 2018-06-27T01:46:01.000341Z

@seancorfield thank you for doing this.

seancorfield 2018-06-27T01:46:13.000252Z

If folks have time, I'd appreciate some eyes over https://github.com/jkk/honeysql/pull/217 which adds multi-table delete capability (previously requested in PRs 27 and 60!).

bja 2018-06-27T01:46:14.000018Z

and thanks to @michaelblume for his previous stewardship

bja 2018-06-27T01:46:29.000198Z

HoneySQL has remained my favorite way to build dynamic SQL in any language for the last few years

richiardiandrea 2018-06-27T02:21:00.000047Z

Thank you both for your previous and future work on this

richiardiandrea 2018-06-27T02:22:08.000107Z

Just curious, do you folks test the output of honeysql before the format? I wonder what is the best testing strategy for it

seancorfield 2018-06-27T02:25:27.000086Z

There's a combination of testing going on: the README examples are all used as tests and then there are specific formatting tests. The specific tests generally check that the data structure formats to the correct SQL. The README tests mostly check that the helpers combine (to produce the right data) and can be formatted to the correct SQL.

👍 1
seancorfield 2018-06-27T02:27:05.000153Z

It's fair to say that there just aren't enough tests overall tho'... Micheal was (quite rightly) sitting on some PRs that were submitted without tests. I'm slowly working through those, creating new PRs with tests (both README examples, and specific tests).

seancorfield 2018-06-27T02:27:30.000004Z

I'm probably going to update https://github.com/jkk/honeysql/pull/61 tomorrow (which already supercedes https://github.com/jkk/honeysql/pull/28).

seancorfield 2018-06-27T02:28:22.000278Z

Part of the problem there is that those PRs are old and are against the version of HoneySQL before conversion to .cljc happened (so they can't possibly be merged now).

richiardiandrea 2018-06-27T02:35:42.000267Z

I meant more in a real app...I guess I was kind of wondering if I am doing it right :)

seancorfield 2018-06-27T03:22:36.000104Z

@richiardiandrea Ah, I get it... I think when Fumiko started using it heavily, she wrapped format so that it also printed the SQL to the console for debugging...

seancorfield 2018-06-27T03:24:04.000281Z

I would most certainly test at the generated SQL level, rather than the data level, since that's what's important. And I pretty much only ever use the DSL helpers rather than building the data structure directly.

👍 1
bja 2018-06-27T03:33:42.000057Z

I wrap format and jdbc/query and jdbc/execute! into exec-runner and query-runner that take a db-spec/pool and a honeysql map. This let's me handle various debugging/analysis/benchmarking via binding variables

bja 2018-06-27T03:34:22.000091Z

For my code, I test the generated maps except in the case where I have my own fn helpers or clauses, and then I test those as part of our internal utility library

bja 2018-06-27T03:34:46.000157Z

I treat the format call as a black box except during reply testing

seancorfield 2018-06-27T03:38:35.000005Z

@bja Are there things that HoneySQL and/or clojure.java.jdbc could provide out of the box, to make your life easier?

bja 2018-06-27T03:49:44.000031Z

I don't think so. You actually built in an explain hook that I need to take advantage of rather than my home rolled stuff

bja 2018-06-27T03:50:27.000102Z

If you factor our the misc debugging things, it's basically a composition of honeysql.core/format and the correct jdbc function

seancorfield 2018-06-27T03:50:50.000254Z

There's still no direct, easy way to access the actual SQL being passed to the JDBC driver itself. Explain is a bit different.

bja 2018-06-27T03:51:19.000055Z

Just so our user API is (query-runner db (-> (select :foo) ...))

seancorfield 2018-06-27T03:51:35.000004Z

@bja have you seen the :return-keys stuff for execute! in the last few releases?

seancorfield 2018-06-27T03:52:01.000017Z

0.7.7 now lets you run :row-fn and :result-set-fn over the generated keys' result set.

bja 2018-06-27T03:52:04.000169Z

Unfortunately only at a glance. I've been super busy being a one man show at my company

bja 2018-06-27T03:52:33.000010Z

Clojure is probably the only way I can still keep this thing afloat

bja 2018-06-27T03:52:40.000126Z

And maintain sanity

bja 2018-06-27T03:52:48.000105Z

Postgres plus honeysql is a bit part of it

bja 2018-06-27T03:53:03.000026Z

Big part of it

bja 2018-06-27T03:53:42.000009Z

I need to migrate to a newer jdbc to take advantage of the reducible querysets

seancorfield 2018-06-27T03:53:45.000022Z

Well, HoneySQL's insert stuff -- which I didn't even know had been added! -- looks to work with execute! rather than the java.jdbc insert! stuff 🙂 so I figured beefing up execute! would be useful.

seancorfield 2018-06-27T03:54:07.000053Z

Oh, yeah, we've starting using reducible-query at work... enjoying that 🙂

richiardiandrea 2018-06-27T03:54:14.000242Z

I found that the honey map testing is sometimes odd because of the records all over the place

bja 2018-06-27T03:54:26.000205Z

Yeah, I only use jdbc/query, jdbc/execute! And with-db-transaction?? regularly

bja 2018-06-27T03:55:00.000094Z

I might have the name on the transaction thing wrong

seancorfield 2018-06-27T03:55:27.000139Z

@richiardiandrea Ah, yes, all the data readers are backed by records... I can see that being weird to test.

bja 2018-06-27T03:55:54.000211Z

The way I use java.jdbc, anything that returns results goes in a jdbc/query and everything else in the jdbc/execute!

bja 2018-06-27T03:56:11.000271Z

But I run ddl separately since I don't have dynic needs there

bja 2018-06-27T03:56:25.000148Z

Dynamic

seancorfield 2018-06-27T03:56:58.000035Z

DDL is a big pain. There's really no good solution for that (as far as DSLs or other high-level stuff goes).

richiardiandrea 2018-06-27T03:57:21.000253Z

Probably a to-map would do the job in the tests

bja 2018-06-27T03:57:26.000057Z

We use a utility that sorts .SQL files in a directory and then calls psql

bja 2018-06-27T03:57:41.000260Z

It's been the only sane solution for ddl

bja 2018-06-27T03:58:16.000224Z

Everything else makes weird or dumb assumptions or wants me to learn some half-baked dsl with a ton of edge cases

bja 2018-06-27T03:59:10.000259Z

The script monitors the success and writes a log into a metadata table

seancorfield 2018-06-27T03:59:15.000120Z

@bja we do something similar, except directly in Clojure with db-do-commands to run all our migrations.

bja 2018-06-27T03:59:19.000145Z

Simple stuff, but just enough

bja 2018-06-27T03:59:39.000025Z

Our script is actually in clojure, but we shell out to psql

bja 2018-06-27T04:00:17.000197Z

I don't remember at the time why, but we were under a time crunch and that was a fast path to success

seancorfield 2018-06-27T04:00:25.000126Z

(i.e., a directory full of .sql files, read by Clojure and run via db-do-commands -- and we have a dblevel in the database that we use to determine which migrations to actually apply... that works in dev, for level 0, and production too)

bja 2018-06-27T04:01:44.000064Z

We just maintain an ID in the filename. It's ordered, but not necessarily sequential

bja 2018-06-27T04:01:59.000035Z

We usually use Unix epoch

bja 2018-06-27T04:02:14.000212Z

It made working with multiple branches easier

bja 2018-06-27T04:03:09.000132Z

Filenames are like NNNNN-name.direction.sql

bja 2018-06-27T04:03:33.000172Z

And if you want fancy stuff like transactions you have to write begin yourself

bja 2018-06-27T04:03:42.000007Z

It's a struggle

bja 2018-06-27T04:06:11.000111Z

We inter the filename, timestamp, and source into the DB on success

richiardiandrea 2018-06-27T04:08:47.000228Z

Are the SQL files loading testing data? Honestly dumb question, why are they ordered by date?

bja 2018-06-27T04:12:11.000225Z

DDL

bja 2018-06-27T04:12:19.000190Z

Sometimes we modify previous ddl

bja 2018-06-27T04:12:36.000026Z

Alter statements or mass data updates

bja 2018-06-27T04:12:51.000201Z

i.e. some gdpr deletes a couple months ago

seancorfield 2018-06-27T04:14:09.000004Z

Ours are either NNNNN_name.sql or NNNNNdev_name.sql and we run all of them on dev/CI, but we only run the non-dev ones on QA/production. And ours are strictly ordered by NNNNN (although we sort on the whole filename).

richiardiandrea 2018-06-27T04:14:22.000222Z

Oh ok got it

seancorfield 2018-06-27T04:15:15.000032Z

So on dev/ci we can retroactively apply changes by modifying earlier migrations. On QA/production it's strictly incremental, based on the last NNNNN in the database.

👍 1
seancorfield 2018-06-27T04:17:47.000189Z

We developed a programmatic GDPR erasure tool so we can run it on demand whenever a member asks for their personal data to be "forgotten".

bja 2018-06-27T04:23:43.000085Z

We did too. During discovery, we determined we had a ton of unused data that was a liability.

bja 2018-06-27T04:24:07.000088Z

So we deleted that data enmass

bja 2018-06-27T04:25:14.000090Z

Some half finished or abandoned features from the last 5 years

2018-06-27T17:02:15.000532Z

2018-06-27T17:21:00.000461Z

2018-06-27T17:21:00.000522Z

seancorfield 2018-06-27T17:21:37.000015Z

Thanks @richiardiandrea!

richiardiandrea 2018-06-27T17:21:55.000395Z

well thank you 😉

2018-06-27T17:22:24.000522Z

2018-06-27T17:22:25.000016Z

2018-06-27T18:09:28.000168Z

2018-06-27T18:17:26.000434Z

seancorfield 2018-06-27T18:19:14.000095Z

@richiardiandrea Your PR left the O/S update stuff in place so Lumo 1.9.0-alpha worked because the newer libstdc++ was installed. I'm trying Lumo 1.8.0 now without the O/S update stuff.

richiardiandrea 2018-06-27T18:21:13.000107Z

yeah I was thinking about that, but lumo will probably release this at some point and I kind of opted was testing against the newer version

richiardiandrea 2018-06-27T18:21:32.000512Z

unless it significantly slows down the build it should be good

seancorfield 2018-06-27T18:23:15.000455Z

Lumo 1.8.0 worked. Also removing the Leiningen install works. I'm going to add .m2 to the cache I think, which should speed up subsequent builds.

👍 1
2018-06-27T18:25:05.000088Z

seancorfield 2018-06-27T18:27:07.000359Z

@richiardiandrea Do you think it's reasonable to cache .nvm as well?

richiardiandrea 2018-06-27T18:28:25.000157Z

@seancorfield we don't do it in lumo: https://github.com/anmonteiro/lumo/blob/master/.travis.yml#L16-L23

seancorfield 2018-06-27T18:29:15.000362Z

Right, but you're not relying on a fixed version of Lumo being installed... I'll try it and see what happens 🙂

2018-06-27T18:29:45.000205Z

richiardiandrea 2018-06-27T18:30:03.000170Z

ah you mean the global lumo...if it's installed in there it probably makes sense yes

richiardiandrea 2018-06-27T18:30:54.000293Z

lumo can also be installed as executable so maybe it is easier to control where it goes

seancorfield 2018-06-27T18:31:45.000538Z

Wow, caching ~/.m2 makes a big difference! 🙂

richiardiandrea 2018-06-27T18:32:16.000556Z

ah ah yeah 😄

2018-06-27T22:13:15.000319Z