2008-03-20 15:26 UTC Sequel ORM: Right level of abstraction

Posted in: , , , ,
The more I use Sequel, the more I am coming to believe the level of abstraction it picks is just right. You use operations that mirror SQL, but in a mostly Ruby-ish way. Most importantly SQL is so completely wrapped that I've yet to see any need to write "raw" SQL.

Let me take a couple of examples based on my blog code.

To get the list of the 10 most recent pages for a tag, I do this:

Item.join(:tags,:item_id).filter{:name == tag}.published.latest(10)

"published" and "latest" are methods in the model, that both work on the Sequel dataset:

class Item < Sequel::Model
  subset(:published) {:published_at != nil}

def dataset.latest(l = nil) return order_by(:published_at.desc).limit(l) if (l) return order_by(:published_at.desc) end end

"subset" above is Sequel shorthand for:

  def dataset.published
     filter{:published != nil}
  end

Which means the original statement translates into SQL like this:

irb(main):005:0> Item.join(:tags,:item_id).filter{:name == "ruby"}.published.latest(10).sql
=> "SELECT items.* FROM items INNER JOIN tags ON (tags.item_id = items.id) WHERE (name = 'ruby') AND (NOT (published_at IS NULL)) ORDER BY published_at DESC LIMIT 10"

Notice the "sql" method call? You can call that on any Sequel dataset to see what SQL it will use. If I want to run it, I use any of the normal enumerable methods, such as each, collect etc. to process the dataset, as you'd expect.

The syntax feels so natural that I find myself almost exclusively using IRB to execute queries against my database. Since it doesn't need a model to work (you can replace "Item" above with DB[:items], and any of the pure Sequel calls will still work without having the Item class) it works fine for ad-hoc queries too. It's in effect pretty close to being a replacement for Ruby-DBI with far more of a Ruby feel.

The key thing for me, though, is not feeling constrained and at the same time not having to dip down into ugly hacks such as adding actual SQL queries (If you really need to, Sequel will let you do that too - so far I've not had a reason - and if you do, you can still add support for it by extending the dataset so you can contain all the SQL ugliness in one place).



Comments - Newest first

2009-02-13 16:02 UTC
Soh Dubom
Hi Vidar. Although it's Sequel related, maybe it's not the right place to post the following subject, but I'll post here because it may be of interest of others too. One thing I didn't find much literature is about how to design and deal with the connection state of a Sequel object. By searching at the google-groups or the documentation or even $ y DB.methods I see that we have: connect, disconnect, test_connection and pool as some methods to perform. And the following conclusions:

A. Sequel.connect establishes the Database object The connection to the database isn't made until the first query is done

B. DB.test_connection establishes a connection. Once the connection is established, it is left open indefinitely?

B1. DB.test_connection only tests that a connection can be acquired?

C. DB.disconnect to close all available connections or just for the DB object. I may have another DB2 object, right?

I'm unsure which one is correct, B or B1

Now let's consider the following code for main.rb file:

---------------------------------------------- # establishes the connection object DB = Sequel.connect "sqlite://models/test.db", :max_connections => 10, :encoding => 'unicode', :logger => Logger.new('models/test.log')

require "models/user.rb" load "models/user.rb"

DB.disconnect ----------------------------------------------

---------------------------------------------- get '/users' do @users = User.all # auto-open a connection? DB.disconnect haml :'/user/index' end ----------------------------------------------

The doubts:

1. Should I call DB.disconnect?

2. The DB object should be unique in my whole app, so it's better to implement a singleton?

I believe you have a better understanding o how Sequel works than most of us (newbies) and it would be nice if you could illustrate how to do it right.

regards, Soh :-)

About me

E-mail: vidar@hokstad.com Skype: vhokstad
Twitter: vhokstad
View my LinkedIn profile.

I was born April 21st, 1975, in Oslo, Norway. Since 2000 I've been living in London, UK. I'm married and we just had our first child, Tristan Ikemefuna Hokstad.

I'm working for Aardvark Media as Director of Technology. I'm also currently on the board of SpatialQ, a startup in the GIS space, and an advisor to Skoach, a startup doing a time management app for people with ADD.

Twitter Updates

    follow me on Twitter