honeysql

Discussion of https://github.com/seancorfield/honeysql :slightly_smiling_face:
2021-02-24T18:58:51.018700Z

how can I create an insert-into query where one of the column names has a dot in it? running into this when upgrading from 0.9.4 to the latest 1.0.461. ex:

(-> (apply h/columns [:name_first (keyword "name.last") :col2])
    (h/insert-into :properties)
    (h/values
      (lazy-seq [["Jon" "Smith" 34]
                 ["Andrew" "Cooper" 12]
                 ["Jane" "Daniels" 56]]))
    (honeysql.format/format))
=>
["INSERT INTO properties (name_first, name.last, col2) VALUES (?, ?, 34), (?, ?, 12), (?, ?, 56)"
 "Jon"
 "Smith"
 "Andrew"
 "Cooper"
 "Jane"
 "Daniels"]

2021-02-24T18:59:14.019100Z

I want the SQL to be INSERT INTO properties (name_first, "name.last", col2) VALUES (?, ?, 34), (?, ?, 12), (?, ?, 56)

2021-02-24T19:01:59.019500Z

well, really, all of the column names could be quoted, that would be nice

seancorfield 2021-02-24T19:03:40.020Z

@jeffrey.wayne.evans Which "latest"? 1.0 or 2.0?

2021-02-24T19:04:05.020200Z

sorry. 1.0.461

seancorfield 2021-02-24T19:18:00.021500Z

Looking over the 1.0 code, I don't think there's any way to prevent the dot-splitting -- it seems to be guarded by quoting being OFF so it looks like you definitely cannot have quoting ON and avoid the splitting.

seancorfield 2021-02-24T19:22:47.023300Z

You can't avoid it in 2.0 either since insert column names are a context where the namespace portion of a name is ignored -- and you can only avoid dot-splitting if you have a namespace-qualified name, e.g., properties/name.last in your case.

seancorfield 2021-02-24T19:23:13.023900Z

It's pretty deeply baked into HoneySQL, in both versions, that foo.bar means "table foo, column bar".

2021-02-24T19:24:22.024700Z

hmm, interesting. thanks for checking. I need to do a bit more homework to understand how it was doing what we wanted before

seancorfield 2021-02-24T19:28:59.025600Z

There were certainly some big changes in how names were handled in the 0.9.x series of releases -- some changes had to be reverted, some spawned extra options and/or dynamic vars.

seancorfield 2021-02-24T19:29:59.026100Z

I don't think I've ever seen a DB schema where column names contain dots tho'...

2021-02-24T21:01:44.026700Z

oh, I’ve seen every godawful thing like that. and I’m guessing some of my coworkers have too, since there is a test written for it

2021-02-24T21:44:38.028Z

Could you do (sql/raw "\"name.last\"") as a workaround?

seancorfield 2021-02-24T21:48:58.029Z

@codonnell Not in the middle of a column name list, no. But you could, possibly, pass a string into columns maybe? (I haven't tried -- that just occurred to me)

seancorfield 2021-02-24T21:51:20.029300Z

Nope, that won't work.

seancorfield 2021-02-24T21:52:02.029700Z

Oh, yeah -- @codonnell wins the prize after all!

user=> (-> (insert-into :properties) (columns :name_first (sql/raw "name.last") :col2) (values [["Jon" "Smith" 34] ["Andrew" "Cooper" 12] ["Jane" "Daniels" 56]]) (sql/format))
["INSERT INTO properties (name_first, name.last, col2) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)" "Jon" "Smith" 34 "Andrew" "Cooper" 12 "Jane" "Daniels" 56]
user=> 

seancorfield 2021-02-24T21:52:44.030500Z

Although it will not quote it:

user=> (-> (insert-into :properties) (columns :name_first (sql/raw "name.last") :col2) (values [["Jon" "Smith" 34] ["Andrew" "Cooper" 12] ["Jane" "Daniels" 56]]) (sql/format :quoting :ansi))
["INSERT INTO \"properties\" (\"name_first\", name.last, \"col2\") VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)" "Jon" "Smith" 34 "Andrew" "Cooper" 12 "Jane" "Daniels" 56]
user=> 

seancorfield 2021-02-24T21:53:21.030900Z

So you'd need to do that manually:

user=> (-> (insert-into :properties) (columns :name_first (sql/raw "\"name.last\"") :col2) (values [["Jon" "Smith" 34] ["Andrew" "Cooper" 12] ["Jane" "Daniels" 56]]) (sql/format))
["INSERT INTO properties (name_first, \"name.last\", col2) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)" "Jon" "Smith" 34 "Andrew" "Cooper" 12 "Jane" "Daniels" 56]
user=> 

2021-02-24T21:53:42.031100Z

aha, thanks to both of you! should work

2021-02-24T21:54:16.031600Z

Whew! 😅

2021-02-24T21:54:57.032300Z

granted, we are actually passing in things that reify ToSql already, so it will take me a bit of time to figure out how to adjust things. but that’s my problem

seancorfield 2021-02-24T21:54:58.032400Z

And in v2:

user=> (-> (insert-into :properties) (columns :name_first [:raw "\"name.last\""] :col2) (values [["Jon" "Smith" 34] ["Andrew" "Cooper" 12] ["Jane" "Daniels" 56]]) (sql/format))
["INSERT INTO properties (name_first, \"name.last\", col2) VALUES (?, ?, ?), (?, ?, ?), (?, ?, ?)" "Jon" "Smith" 34 "Andrew" "Cooper" 12 "Jane" "Daniels" 56]

seancorfield 2021-02-24T21:58:24.033700Z

@jeffrey.wayne.evans I'm curious what things you have reifying ToSql? That whole system goes away in v2 (and as you can see, sql/raw becomes just a regular "function call" expression -- a.k.a "special syntax" -- in v2).

2021-02-24T22:03:44.034400Z

well, I’m still quite new to this codebase, so I definitely can’t answer any type of historical/“why” questions, but the relevant sections are https://github.com/metabase/metabase/blob/master/test/metabase/test/data/sql/ddl.clj#L85-L89 and https://github.com/metabase/metabase/blob/master/src/metabase/util/honeysql_extensions.clj

2021-02-24T22:06:01.035300Z

er, sorry, this particular one (the Identifier ) is a defrecord, not a reify