The usual way to do this is via dynamic vars, e.g.

    (def ^:dynamic *conn*)

    (defmacro with-connection [conn & body]
      `(binding [*conn* conn] ~@body))

    (defn insert [m]
      (db/insert *conn* m))

But while this approach removes repetition, it also adds complexity. It's
harder to compose functions that rely on dynamic vars, and their operation
is less predictable, as they rely on an outer scope that might not be
obvious.

Clojure generally puts a greater emphasis on KISS than DRY. Combining
arguments into a map is fine, but explicit arguments are usually better
than implicit arguments like dynamic vars.

- James

On 12 April 2015 at 17:07, Sam Raker <sam.ra...@gmail.com> wrote:

> I'm working with Monger[1], and have been thinking about connection
> encapsulation. I've currently got a `myproject.mongo` ns with private `db`
> and `coll` vars. I've got a public `insert` method along the lines of
>
> (defn insert [m] (mc/insert db coll m))
>
> where `mc/insert` is, perhaps unsurprisingly, monger.collection/insert. To
> properly encapsulate my db-related vars, my options seem to be:
>
> 1) Replicate that `insert` func for every potentially-relevant mongo
> action (too much boilerplate/not DRY, I'd have to go back and add new funcs
> if I wanted more functionality)
>
> 2) Write a function along the lines of
>
> (defn with-connection [f & args] (apply f (concat [db coll] args))
>
> which is fine I GUESS but is only func-level
>
> 3) Write a macro that inserts `db` and `coll` in the proper places, so
> that one could do something like
> (defn fake-upsert [m]
>   (with-conn
>     (if-let [existing (mc/find-one-as-map {:_id (:_id m)})]
>       (mc/update existing m)
>       (mc/insert m))))
>
> and then `with-conn` would search through the code, identify the
> `monger.collection`-namespaced vars, and rewrite the code to put in `db`
> and `coll` arguments so it'd end up looking like
>
> ...
> (if-let [existing (mc/find-one-as-map db coll {:_id (:_id m})]...
>    (mc/update db coll existing m)..
>
> and so on. This seems like my cleanest option, especially because it could
> be extended with an options map, à la
>
> (defn mongo-to-another-db [m]
>    (with-conn {"monger.collection" [monger-db monger-coll]
>                "another-db.adapter" [another-db-uri another-db-username
> another-db-password]}
>       (adapter/insert (mc/find-one-as-map {:foo "bar"}))))
>
> I haven't been able to figure out how quite to do this, yet. I need,
> basically, a way to iterate through tokens in source code, examine each
> token, and then add a token and its relevant args if it's in the options
> map, or the token alone if it's not.
>
> Is this reasonable? Does this or something like it already exist? Is there
> something obvious my general macro mediocrity is preventing me from seeing?
>
>
> Thanks!
> -sam
>
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clojure@googlegroups.com
> Note that posts from new members are moderated - please be patient with
> your first post.
> To unsubscribe from this group, send email to
> clojure+unsubscr...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> ---
> You received this message because you are subscribed to the Google Groups
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to clojure+unsubscr...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to