Kevin
Kevin

Reputation: 25269

clojureql, open-global and with-results

Just trying to understand the purpose of clojureql's open-global and with-results. I started by reading this overview: How does ClojureQL compare to clojure.contrib.sql?

I thought for some reason that open-global would replace sql/with-connection, e.g. I thought this would work:

(def db {...}) ; connection details omitted
(open-global db) 

(println (:name (first @(table :users))) 

However this doesn't work. It seems I need to both do open-global and wrap the executing query in a (sql/with-connection db), which sort of surprised me (I thought open-global provided a default globally accessible connection). So since that doesn't appear to be the case I'm now left wondering exactly what it does.

Also...how does with-results differ from simply executing the query with @? Because it seems @(table :users) will leave me with a sequence that is the result of executing the query (isn't that what with-results does as well)?

Upvotes: 6

Views: 325

Answers (1)

Nicolas Buduroi
Nicolas Buduroi

Reputation: 3584

The difference between using deref (the @ symbol) versus with-results is quite subtle. Basically both do the same thing, the only difference being at which moment the query is actually executed. Both are actually just wrappers for the apply-on method of the Relation protocol, here's the code for with-results:

(defmacro with-results
  [[results tble] & body]
  `(apply-on ~tble (fn [~results] ~@body)))

And for deref:

(deref [this]
  (apply-on this doall))

As you can see deref is exactly the same as:

(with-results [res (table :users)] (doall res))

If you look at doall documentation, you'll see that it's a function that is used to walk throught a lazy sequence to force any side-effect, the result being that the sequence will be fully evaluated, thus not being lazy anymore but residing into memory.

So to give you a more down to earth explanation, using deref actually execute the query at the moment it is called, while using with-results the query will be executed lazily, that is when the result is actually consumed.

As for open-global, you were right about it, it really should open a globally available connection that will be used by ClojureQL when not specifying one using wiht-connection. The behavior you're observing is probably a bug, so I suggest you to report it on the IRC channel or to the ClojureQL issue tracker on Github. I've not used ClojureQL in a while but looking at the code, they seems to have transitionned to using clojure.java.jdbc instead of clojure.contrib.sql, something might have gone wrong there.

Upvotes: 3

Related Questions