Search code examples
sqlclojurejndiread-eval-print-loop

clojure.contrib.sql and REPL interaction


We have a Clojure web app which uses jndi to create a connection to the database. The code to query the database looks something like this:

(def jndi-name {:name "jndi name"})

(defn query [q]
  (sql/with-connection {:name "jndi name"}
    (sql/with-query-results rs q
      (time (vec rs)))))

The jndi configuration is loaded from a jetty.xml file when jetty is lauched. However it doesn't work in the REPL making development somewhat impractical.

Is there any way to structure the code so that when not running in a server, the db config is loaded from a config file rather than the jetty.xml when no jndi context is available?


Solution

  • The problem is, your way of connecting to the database will not always be though JNDI; for instance, when testing or on the REPL, you might want to manage your own connection pool.

    I suggest you keep your db spec as a var. Thus the only change to your code is to rename the variable; because you intend to rebind it, it's common to use asterisks:

    (def *db-spec* {:name "jndi name"})
    
    (defn query [q]
      (sql/with-connection *db-spec*
        (sql/with-query-results rs q
          (time (vec rs)))))
    
    (query "select * from Students")
    

    And when testing on the repl, simply create your own data source with, say, Commons-DBCP and rebind your db spec to that.

    (def ds (doto (BasicDataSource.)
              (.setDriverClassName "oracle.jdbc.OracleDriver")
              (.setUsername "tiger")
              (.setPassword "scott")))
    
    (binding [*db-spec* {:datasource ds}]
      (query "select * from Students"))