Em 24-04-2012 14:31, Jeremy Evans escreveu:
On Tuesday, April 24, 2012 9:40:58 AM UTC-7, Rodrigo Rosenfeld Rosas wrote:

    Em 24-04-2012 12:27, Jeremy Evans escreveu:
    On Tuesday, April 24, 2012 6:55:29 AM UTC-7, Rodrigo Rosenfeld
    Rosas wrote:

        Moving on, the problem is that I'd like to have a set of
        records to be created for context, but only once or it would
        be too slow to run the spec.


    Then just add the records before the spec and delete them after:

      before(:all){# Add some records here}
      after(:all){# Delete the records here}

    This is not that easy. For example, if you write
    FactoryGirl.create(:user), this might as well create a role or
    other records in the database. It is hard to keep track of every
    record created behind the scenes, so it would be a nightmare to
    maintain something like this.


In general, if you don't care about concurrency (i.e. you run your specs in a single thread), it's safe to just do the following in the after block:

  [:table1, :table2, :table3, ...].each{|t| DB[t].delete}

No, I start my specs with some populated data for some tables that shouldn't change unless in some specific examples, but I'd like them to rollback to the original state at the end of the examples. I do really want to use savepoints instead of a truncate strategy or I'd be already using DatabaseCleaner for that.

Your suggested approach wouldn't work pretty well as there are some database constraints that would require a certain order in the tables as well. This is pretty hard to maintain anyway and it is much slower than "truncate table1, table2, ...".

Making sure to list every table that could be modified by the related specs. I do this in apps where the tests don't use transactions (as they are testing an out-of-process webserver), and it's simple to maintain.

        I'd like to be able to do something like this:

        context "some sample records exists" do
          before(:all) do
            @sample_records_transaction = DB.transaction(savepoint: true)
            create_sample_records
          end

          after(:all) { @sample_records_transaction.rollback! } # or
        even raise Rollback

          # examples here
        end

        Could you please add support for using transactions this way?


    No.  Because of how the connection pool works, you need to use
    blocks for transactions.

    Sorry, could you please elaborate on this? What do you mean?


You need to understand how Sequel's connection pool works.

I was just looking at the code.

Unlike some other database libraries, it doesn't leak connections and require manual cleanup later, it uses a block-based connection checkin/checkout.

Yes, I noticed that.

By design, there is no method that allows you to checkout a connection without forcing a checkin later. With transactions, you need to ensure that all database queries use the same connection (the one that started the transaction).

Yes, I've realized that too. This makes it really hard to me to manually create the savepoints by myself while still using Sequel transaction support in the around(:each) block.

The way to do that is checking out a connection at the start of the transaction block, and checking in the connection at the end of the transaction block. You cannot just checkout a connection to issue the BEGIN and then check the connection back in, as the connection code theoretically be used by other threads that should not be operating inside the transaction.

Sorry this is where I got confused. Could you please give me a concrete example?

    You are free to implement such things yourself if you want.  In
    single threaded mode, you could probably get something that works OK.

    Sorry, but I couldn't understand what is the thread-safety role here.


I'm sure if you read the connection pool and transaction related code, you probably would. You could then probably also figure out how to implement what you want yourself.

I've read the code and I understand why it is difficult to allow the usage I proposed in my previous message. But I couldn't figure it out how to implement what I want by myself.

To hopefully be more clear: what you want is not implemented because it is a bad idea, not because it is difficult to implement.

Then please point me to some example on how I could do that manually as I'm having troubles on understanding how to do that by myself.

For example, I'd need to issue the BEGIN in the before(:all) to finally issue the ROLLBACK TO SAVEPOINT in the after(:all).

But I need a connection from the pool for being able to do that, and I can't get one because I have to use it inside a block.

Also when the before(:each) is called, Sequel.transaction wouldn't know what is the current depth level.

So, as you can see, I'm totally lost on how to approach that.

If I was going to run my specs concurrently, I'd make sure that a different connection would be used for each "describe" block and I wouldn't run multiple examples of the same outer-most block concurrently.

Could you please give me some hint on how to achieve that with Sequel?

Thanks in advance,
Rodrigo.

--
You received this message because you are subscribed to the Google Groups 
"sequel-talk" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/sequel-talk?hl=en.

Reply via email to