Hierarchy of Objects with Sequel's many_to_many

posted 2012-Mar-20

I absolutely love Sequel, but the documentation for the plethora of options available for associate often confuse me.

If you have a table of objects that you want to arrange in a simple multiple parent/child hierarchy—multiple inheritance in ObjJob—whose data model looks like this:

Sequel.migration do
  change do
    create_table :items do
      primary_key :id
      # ...other properties...
    end
    create_table :hierarchy do
      primary_key :id
      foreign_key :parent_id, :items
      foreign_key :child_id,  :items
    end
  end
end

…then you can create child/parent many_to_many relationships like so:

class Item < Sequel::Model
  many_to_many :parents,  class: :Item, join_table: :hierarchy, left_key: :child_id,  right_key: :parent_id
  many_to_many :children, class: :Item, join_table: :hierarchy, left_key: :parent_id, right_key: :child_id
end

Seen in action:

>> p1 = Item.create name:"parent1"
#=> #<Item @values={:id=>1, :name=>"parent1"}>
>> p2 = Item.create name:"parent2"
#=> #<Item @values={:id=>2, :name=>"parent2"}>
>> c1 = Item.create name:"child1"
#=> #<Item @values={:id=>3, :name=>"child1"}>
>> c2 = Item.create name:"child2"
#=> #<Item @values={:id=>4, :name=>"child2"}>
>> DB[:hierarchy] << { parent_id:p1.pk, child_id:c1.pk }
#=> 1
>> DB[:hierarchy] << { parent_id:p1.pk, child_id:c2.pk }
#=> 2
>> DB[:hierarchy] << { parent_id:p2.pk, child_id:c1.pk }
#=> 3
>> p1.children
#=> [#<Item @values={:id=>3, :name=>"child1"}>, #<Item @values={:id=>4, :name=>"child2"}>]
>> p2.children
#=> [#<Item @values={:id=>3, :name=>"child1"}>]
>> c1.parents
#=> [#<Item @values={:id=>1, :name=>"parent1"}>, #<Item @values={:id=>2, :name=>"parent2"}>]
>> c2.parents
#=> [#<Item @values={:id=>1, :name=>"parent1"}>]
>> c2.children
#=> []
net.mind details contact résumé other
Phrogz.net