This.

I would repeat with as strong an emphasis as possible the sanity
of using a dedicated test database - how else can you test schema
creation for example...

Dmitri writes:

> I agree that wrapping the functions is a sensible approach. Using
> wrap-transaction is precisely how I ended up doing it with the conman yesql
> wrapper https://github.com/luminus-framework/conman
>
> The approach I took there is to have the generated functions use the
> connection atom, and have with-transaction rebind it to the transactional
> connection within its scope. However, the functions also accept an explicit
> connection, and with-transaction also provides explicit access to the
> transactional connection:
>
> (with-transaction [t-conn conn]
>   (jdbc/db-set-rollback-only! t-conn)
>   (create-user!
>     {:id         "foo"
>      :first_name "Sam"
>      :last_name  "Smith"
>      :email      "sam.sm...@example.com"})
>   (get-user {:id "foo"}))
>
>
>
>
> This approach works for testing, since the connection can be passed
> explicitly, but I would argue that in practice it's better to use a
> separate test database instead of the dev instance.
>
> On Wednesday, August 5, 2015 at 11:11:19 AM UTC-4, James Reeves wrote:
>>
>> On 5 August 2015 at 14:03, Dmitri <dmitri....@gmail.com <javascript:>>
>> wrote:
>>
>>> What I'm talking about is whether it's a better pattern to leave a
>>> repetitive and error prone task to the user or encapsulate it in a single
>>> place. The whole discussion boils down to following options.
>>>
>>> The first option is that we keep functions pure and the connection is
>>> passed as a parameter by the person writing the code (the user). With this
>>> approach the burden is squarely on the user to remember to pass the correct
>>> connection to the function. This becomes error prone for things like
>>> transactions where the developer has to pass the transaction connection as
>>> opposed to the normal database connection. The worst part in this scenario
>>> is that the code will run except it won't run transactionally. This is a
>>> bug that is difficult to catch as it only surfaces in cases where the
>>> transaction should be rolled back.
>>>
>>
>> It's worth pointing out that you don't need to use dynamic or global vars
>> to avoid this scenario. You could just remove the original database
>> connection from scope:
>>
>>   (defn foobar* [tx]
>>     (foo tx)
>>     (bar tx))
>>
>>   (defn foobar [db]
>>     (sql/with-transaction [tx db] (foobar* tx))
>>
>> Or shadow the original binding:
>>
>>   (defn foobar [db]
>>     (sql/with-transaction [db db]
>>       (foo db)
>>       (bar db)))
>>
>> Ideally you also want a way of testing this behaviour, even with dynamic
>> or global scope. If it's critical to your application that database
>> operations run in a transaction, you should have a way of verifying that.
>>
>> For instance, you might use a protocol to factor out the operations on the
>> database:
>>
>>   (defprotocol Database
>>     (wrap-transaction [db f])
>>     (foo db)
>>     (bar db))
>>
>>   (defn foobar [db]
>>     (wrap-transaction db
>>       (fn [tx]
>>         (foo tx)
>>         (bar tx))))
>>
>> This allows tests to be written to verify that foo and bar are called
>> within wrap-transaction, and to verify our production implementation of the
>> protocol correctly wraps the function f in a SQL transaction.
>>
>> If you're writing something that depends upon behaviour that can't be
>> verified, you're going to run into problems no matter how you structure
>> your application.
>>
>>
>>> The alternative is to encapsulate the database connection management in
>>> the initialization logic in the namespace managing the connection. This way
>>> the query functions can be context aware and ensure that the correct
>>> connection is used automatically.
>>>
>>
>> Do you mean storing the database connection in a global var, not just a
>> dynamically scoped one?
>>
>> In such a case, how do you run tests without wiping the development
>> database? Do you run the tests in a separate process, or shut down the dev
>> server before running tests, or do you not mind if your development
>> database is cleared by your tests?
>>
>> - James
>>

--
Sent with my mu4e

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