sql

All things SQL and JDBC...
emccue 2020-11-09T16:25:57.280Z

Got a fairly interesting error with taoensso.nippy last night

emccue 2020-11-09T16:26:24.280500Z

when I use it on data returned by jdbc/execute! it tries to serialize a non-serializable class

emccue 2020-11-09T16:27:40.280800Z

(def m (chat/messages-since
         system
         {:time (.minus (Instant/now) (Duration/ofDays 1))
          :n 1
          :participants [1 1]}))
2020-11-09 11:26:51,238 [nRepl-session-b5d597e4-c019-4378-829a-5e1bfdb10589] INFO  space.egge.db - Name:Query Logger, Connection:13, Time:10, Success:True, Type:Prepared, Batch:False, QuerySize:1, BatchSize:0, Query:["SELECT * FROM page_message
         WHERE created_at > ? AND
             ((page_id_from = ? AND page_id_to = ?) OR
              (page_id_from = ? AND page_id_to = ?))
         ORDER BY created_at ASC
         LIMIT ?"], Params:[(2020-11-08 11:26:51.2118528,1,1,1,1,1)] 
=> #'space.egge.main/m
m
=>
[#:page_message{:id 2,
                :page_id_from 1,
                :page_id_to 1,
                :contents {:hello "world"},
                :reactions [],
                :created_at #object[java.time.Instant 0x33e82c30 "2020-11-09T02:51:04.526352Z"],
                :updated_at #object[java.time.Instant 0x5aab54c4 "2020-11-09T02:51:04.526352Z"]}]
(type m)
=> clojure.lang.PersistentVector
(require '[taoensso.nippy :as nippy])
(nippy/freeze-to-string m)
=> nil
Execution error (ExceptionInfo) at taoensso.nippy/throw-unfreezable (nippy.clj:1001).
Unfreezable type: class next.jdbc.result_set$navize_row$fn__4663

emccue 2020-11-09T16:27:59.281200Z

so something somewhere in the results is hanging on to a reference to that function

emccue 2020-11-09T16:28:46.281600Z

using transit everything works fine and I am moving on with the project

emccue 2020-11-09T16:29:04.282Z

but its still an interesting error and I'm curious how it comes about

dpsutton 2020-11-09T16:36:01.282500Z

its the metadata for datafy i think. seems nippy serializes metadata and the metadata includes functions for datafy

emccue 2020-11-09T16:36:32.282700Z

oh that makes sense

emccue 2020-11-09T16:38:20.283600Z

(nippy/freeze-to-string (mapv #(with-meta % nil) m))
=>
"TlBZAG4BcAdqD3BhZ2VfbWVzc2FnZS9pZCoAAAACahlwYWdlX21lc3NhZ2UvcGFnZV9pZF9mcm9tKgAAAAFqF3BhZ2VfbWVzc2FnZS9wYWdlX2lkX3RvKgAAAAFqFXBhZ2VfbWVzc2FnZS9jb250ZW50c3ABagVoZWxsb2kFd29ybGRqFnBhZ2VfbWVzc2FnZS9yZWFjdGlvbnMRahdwYWdlX21lc3NhZ2UvY3JlYXRlZF9hdE8AAAAAX6iumB9ffoBqF3BhZ2VfbWVzc2FnZS91cGRhdGVkX2F0TwAAAABfqK6YH19+gA=="

dpsutton 2020-11-09T16:38:50.284200Z

you'd probably need to walk it but there is a dynamic var to do this for you so you don't walk twice

emccue 2020-11-09T16:38:51.284300Z

setting the binding seems better

emccue 2020-11-09T16:39:32.284600Z

(binding [nippy/*incl-metadata?* false]
  (nippy/freeze-to-string m))
=>
"TlBZAG4BcAdqD3BhZ2VfbWVzc2FnZS9pZCoAAAACahlwYWdlX21lc3NhZ2UvcGFnZV9pZF9mcm9tKgAAAAFqF3BhZ2VfbWVzc2FnZS9wYWdlX2lkX3RvKgAAAAFqFXBhZ2VfbWVzc2FnZS9jb250ZW50c3ABagVoZWxsb2kFd29ybGRqFnBhZ2VfbWVzc2FnZS9yZWFjdGlvbnMRahdwYWdlX21lc3NhZ2UvY3JlYXRlZF9hdE8AAAAAX6iumB9ffoBqF3BhZ2VfbWVzc2FnZS91cGRhdGVkX2F0TwAAAABfqK6YH19+gA=="

emccue 2020-11-09T16:39:41.284900Z

the more you know i guess

seancorfield 2020-11-09T18:01:08.286Z

Only the rows will have the metadata so running mapv over it should be sufficient, in case you want other metadata to be preserved.

frankitox 2020-11-09T19:53:31.291100Z

I found a problem when using next.jdbc . Basically when using (with-transact [tx ds] ...) if I have options on ds that I set with with-options then I lose them. So, for example, here I get a syntax error because I'm not transforming dashes into underscores in the :label/store-id attribute:

(let [ds (->> {:dbtype "postgres" ...}
              (jdbc/get-datasource)
              (jdbc/with-options jdbc/snake-kebab-opts))]
  (jdbc/with-transaction [tx ds]
    ...
    (sql/insert! tx :label
      {:label/name "Beverages"
       :label/store-id #uuid "610d75fa-7aeb-43d3-bcea-a26d1d2042ae"})))
But if I change it to explicitly take the options:
(let [ds (jdbc/get-datasource {:dbtype "postgres" ...})]
  (jdbc/with-transaction [tx ds]
    ...
    (sql/insert! tx :label
      {:label/name "Beverages"
       :label/store-id #uuid "610d75fa-7aeb-43d3-bcea-a26d1d2042ae"}
      jdbc/snake-kebab-opts)))
Then it runs smoothly. Is this a bug?

seancorfield 2020-11-09T20:59:11.291500Z

@franquito That is specified called out and explained in the documentation.

seancorfield 2020-11-09T21:00:20.291700Z

> Note: See the next.jdbc/with-option examples in the Datasources, Connections & Transactions below for some caveats around using this function.

frankitox 2020-11-09T21:00:47.291900Z

Gotcha. Thanks for the awesome lib 🙂

seancorfield 2020-11-09T21:01:15.292400Z

where it says: > Note: Because get-datasource and get-connection return plain JDBC objects (javax.sql.DataSource and java.sql.Connection respectively), next.jdbc/with-options cannot flow options across those calls, so if you are explicitly managing connections or transactions as above, you would need to have local bindings for the wrapped versions: And has examples to show how to handle that.

seancorfield 2020-11-09T21:01:34.292600Z

(with-open [con (jdbc/get-connection ds)]
  (let [con-opts (jdbc/with-options con some-options)]
    (jdbc/execute! con-opts ...) ; committed
    (jdbc/with-transaction [tx con-opts] ; will commit or rollback this group:
      (let [tx-opts (jdbc/with-options tx (:options con-opts)] ; <=== rewrapping tx with the same options from the connection
        (jdbc/execute! tx-opts ...)
        (jdbc/execute! tx-opts ...)
        (into [] (map :column) (jdbc/plan tx-opts ...))))
    (jdbc/execute! con-opts ...))) ; committed

seancorfield 2020-11-09T21:02:02.293Z

It uses with-options again on the tx.

frankitox 2020-11-09T21:04:34.294800Z

Ahh, that's better than my approach. Gotta read the docs then 😅

seancorfield 2020-11-09T21:25:24.295400Z

There's a lot of stuff in the docs -- even in just the Getting Started page. Definitely worth reading it all. Several times, probably.

seancorfield 2020-11-09T21:26:16.296400Z

I try to update the docs with each release, adding more and more information, as folks ask questions about usage etc. If you have any suggestions for improving the docs -- or the docstrings -- feel free to discuss here or create issues on GitHub.