Specing a rails monkey patch

Hi all,

I wrote an ActiveRecord extension to emulate a db cursor:
http://pastie.org/236367

As you can see, the spec doesn’t really ensure that the records are
fetched in chunks. I’d like to mock the call to AR find and ensure that
it’s called with an incrementing offset.

Any advice?

Keith

PS If you’re interested, Jamis B. wrote a (mySQL specific) DB cursor:
http://weblog.jamisbuck.org/2007/4/6/faking-cursors-in-activerecord

On Fri, Jul 18, 2008 at 8:11 PM, Keith McDonnell [email protected]
wrote:

I wrote an ActiveRecord extension to emulate a db cursor:
http://pastie.org/236367
As you can see, the spec doesn’t really ensure that the records are fetched
in chunks. I’d like to mock the call to AR find and ensure that it’s called
with an incrementing offset.

I’m using cursors to walk a table with close to a million rows at times.

I am just wrapping the action in a transaction and then declaring the
cursor within the transaction and then walking the table with a
find_by_sql with an SQL fetch command.

It works well.

Any reason you aren’t doing it this way? Could just call it with a
block…

Mikel

Hi Mikel,

Thanks for the feedback. Much appreciated.

I’m using cursors to walk a table with close to a million rows at
times.

I am just wrapping the action in a transaction and then declaring the
cursor within the transaction and then walking the table with a
find_by_sql with an SQL fetch command.

It works well.

Any reason you aren’t doing it this way? Could just call it with a
block…

I /could/ use an SQL cursor but:

  • I wanted to write a method that could be re-used by the other
    developers on the team.

  • our code base is polluted with SQL, ostensibly for “performance”
    reasons. I’m trying to refactor out unnecessary SQL.

  • raw speed is less important that ensuring that the production db
    doesn’t crash, ie it doesn’t matter if the updates take an hour or two
    once the live site doesn’t slow down considerably. Our max # rows is 3.3
    million.

I don’t know if these are valid reasons however :slight_smile:

Thanks for your suggested solution (transaction, cursor, find_by_sql &
fetch). I’ll play around with it & see what I can do. Can’t immediately
envision how to spec it though.

Keith

Sorry, hit the tab and enter key too soon :slight_smile:

You’d stub out the model.

class DummyModel
acts_as_curseable
end

it “should ask the database to set up a transaction” do
DummyModel.connection.should_receive(“BEGIN;”).once
… then the execution code to make that happen
end

it “should ask the database to set up a cursor” do
DummyModel.connection.should_receive(“DECLARE dummy_model_cursor
CURSOR FOR…;”).once
… then the execution code to make that happen
end

it “should tell the database to give it another X rows” do
DummyModel.should_receive(:find_by_sql).with(“FETCH 500 FROM
dummy_model_cursor;”)
… then the execution code to make that happen
end

Hope that sort of starts you off :slight_smile:

And if you like ‘acts_as_curseable’ for the plugin name, I want
acknowledgement :smiley:

On Mon, Jul 21, 2008 at 6:38 PM, Keith McDonnell [email protected]
wrote:

I /could/ use an SQL cursor but:
I don’t know if these are valid reasons however :slight_smile:

The only thing you gain with a direct SQL cursor is the guarantee of
hitting each row exactly once without having to pull down all the IDs
into an array first.

Thanks for your suggested solution (transaction, cursor, find_by_sql &
fetch). I’ll play around with it & see what I can do. Can’t immediately
envision how to spec it though.

You’d stub out the model.

class Record

end