Sequel ORM: Right level of abstraction 2008-03-20

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)

"subset" above is Sequel shorthand for:

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

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 = 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).

blog comments powered by Disqus