Also keep in mind that a dynamically-bound variable is global state,
even if it's unbound by default. You might want to keep your library as
simple and possible and just pass it as the first argument. That also
greatly simplifies usage with Stuartsierra's component design.

A `with-connection' macro is easy to build and can be implemented by the
user, adapted perfectly to his domain.

James Reeves <ja...@booleanknot.com> writes:

> 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.

-- 

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