Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)?

like image 602
Kevin Avatar asked Aug 24 '11 15:08

Kevin


1 Answers

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.

like image 123
Nicolas Buduroi Avatar answered Oct 22 '22 19:10

Nicolas Buduroi