What have you found for these years?

2012-01-11

sequel gem pitfalls

updated 2012-01-11 17:56
Feature request: Connect to the database lazily

I was trying to use sequel because I am a bit disappointed with datamapper
nowadays, and I just want something simple. But then I encountered two
issues which are so hard to find out the solution, too few people are using
sequel, it seems no one was trying to do the same thing as me.

So I am writing this down. One issue I think might be sequel's bug,
and another issue, honestly, is more a "I am not doing it in a normal way".

ok so, I was using PostgreSQL, and it didn't accept AUTOINCREMENT,
but sequel is always trying to issue that modifier. I have to explicitly pass
`:auto_increment => false` in `primary_key :id`. This is so dumb.

The story hasn't finished. Then the :id (i.e. the primary key) won't
be auto-generated for us, and we cannot pass an id directly in sequel,
saying it is a restricted column. What here should be done, is passing
`:type => 'Serial'` because that's how we should do in PostgreSQL.

I ended up with his:

primary_key :id, :type => 'Serial', :auto_increment => false

Above I think might be a sequel bug, because that's not the document said.

Oh wait, maybe I knew why now. It might all because my trick to do a
lazy connection. I want to define my models before connecting to a database,
just as in datamapper, but sequel forbids me to do so. So I put a dummy
connection before defining the models:
Sequel::Model.db = Sequel.connect('sqlite:memory') # dummy connect
And then re-connect when I really want to connect to the database.
I guess that's why sequel was trying to pass AUTOINCREMENT, because
it thinks I were connecting to SQLite instead of PostgreSQL.

Arrrgghhh.. still dumb in my opinion. And I spent so much time debugging this...
Another issue was harder to find out. To find that, I dug into the source.

The serialization is broken and saying:
NoMethodError: super: no superclass method `data' for ...
I have no idea why. Now I knew that it's because I didn't create the table
before defining serialization, and that depends on the table!
It seems like sequel is creating the accessor methods by looking at the
table instead of looking at the schema...

So if I defined the serialization first, and then re-connect, then the orders
of methods would be wrong.

My solution and workaround is...

0. connect to dummy sqlite (in memory)
1. define the schema
2. create the table for dummy sqlite (in memory)
3. define serialization
4. define the rest of my model
5. re-connect to the real postgresql database

Fine. I am going to file an issue, asking for lazy connection.



updated 2012-01-11 17:57
Feature request: Connect to the database lazily

I want to define my models before connecting to the database,
but sequel didn't allow me to do so. Then I put a trick there:

First make it connected to a in-memory SQLite database,
then defining the model (i.e. define schema and serialization)
Lastly reconnect to the real database appropriately.

I didn't know this won't work well in sequel before,
spending a lot of time digging, trying, and googling around.

Below is what I am doing right now to workaround that:

``` ruby
Sequel::Model.db = Sequel.connect('sqlite:memory') # dummy connect

class Item < Sequel::Model
  plugin :schema
  set_schema do
    # HACK
    primary_key   :id, :type => 'Serial', :auto_increment => false
    Text        :data
  end

  # HACK
  create_table # this is needed! otherwise, the serialization would be
               # broken, due to different inclusion order or something

  plugin :serialization
  serialize_attributes [Yajl::Encoder.method(:encode),
                        Yajl::Parser .method(:parse)], :data
  # connect to the real database
  def self.connect
    self.db = Sequel.connect('postgres://example.com/database')
    self.db.loggers << Logger.new($stdout)
  end
end

# somewhere
Item.connect
```

I know that to support this, it might mean to rewrite a lot of
internal architecture inside sequel. But... I still hope if this
could be considered? Or, giving a better error message,
instead of crashing randomly?

Thank you!

0 retries:

Post a Comment

All texts are licensed under CC Attribution 3.0