Saturday, April 19, 2008

Sequel with single table inheritance

I've been trying to create single table inheritance for Sequel just as it is done in ActiveRecord. After having this done I came to conclusion, that Sequel is very, VERY well thought, much better than ActiveRecord, that's for sure. The dataset class, which gathers info about the SQL query but NOT executing it is very flexible solution. Look at this:


class Model < ActiveRecord::Base
def objects
Object.find(:all, :conditions => ["model_id = ? AND field1 > 34", id], :order => "field2 DESC")
end
end



class Model < Sequel::Model
def objects
Object.filter(:model_id => id).order("sth")
end
end


ActiveRecord's solution is less flexible, because we cannot for example limit the objects with SQL -- they are already retrieved from DB! Sequel allows us to do so, because it does NO SQL query until we tell him to do so, thus allowing to add additional conditions/limit:
model.objects.limit(3)

We can chain those methods and then do .all to retrieve the objects. Cool!

AR simulates it a BIT, because has_many relation returns special proxy object not an array, but it's only half-solution because after one filter we cannot add another, we cannot chain them.

And going back to STI from title:

class Person < Sequel::Model
def before_save()
self.object_type = self.class.name.tableize.singularize
end
end

class Contestant < Person
set_dataset(dataset.filter({:object_type => name.tableize.singularize}))
end

class Judge < Person
set_dataset(dataset.filter({:object_type => name.tableize.singularize}))
end


The judge and contestant models have modified datasets. Default dataset which is:
SELECT * FROM table
has added filter object_type = class_name
and now looks like this
SELECT * FROM table WHERE object_type = "judge"

Now all the queries are built on base of this query selecting only rows that have the object_type of specific class. Elegant and well thought (though there might be some better solution, I'm still Sequel beginner ;))

1 comment(s):

Anonymous said...

Looks like in the latest version of sequel
set_sti_key :type

should do the trick!