Module: OQGraph::ClassMethods

Defined in:
lib/acts_as_oqgraph.rb

Instance Method Summary collapse

Instance Method Details

#acts_as_oqgraph(options = {}) ⇒ Object

Usage:

Class Foo < ActiveRecord::Base

acts_as_oqgraph  +options+
....

end

Options: :class_name - The name of the edge class, defaults to current class name appended with Edge. eg FooEdge :table_name - The name of the edge table, defaults to table name of the specified class, eg foo_edges :oqgraph_table_name - the name of the volatile oqgraph table. Default foo_edge_oqgraph :from_key - The from key field in the edge table. Default ‘from_id’ :to_key - The to key field in the edge table. Default: ‘to_id’ :weight_column - The weight field in the edge table.

Setup: This gem requires the use of MySQL or MariaDB with the OQGraph engine plugin. For details of this see: openquery.com/products/graph-engine

You will need a table for the edges with the following schema:

create_table foo_edges do |t|
    t.integer from_id
    t.integer to_id
    t.double weight
end

The field names and table name can be changed via the options listed above.

The gem will automatically create the oqgraph table. To rebuild the oqgraph table do:

Model.rebuild_graph

Examples of use:

Creating and removing edges:

foo.create_edge_to(bar)
bar.create_edge_to(baz, 2.0)
foo.remove_edge_to(bar) : Note that this removes ALL edges to bar from foo.

or alternatively:

foo.outgoing_nodes << bar
foo.outgoing_nodes

Examining edges:

foo.originating 
  returns [foo]
baz.originating
  returns [foo, bar,baz]
bar.reachable
  returns [bar, baz]
foo.reachable?(baz)
  returns true

Path Finding:

foo.shortest_path_to(baz)
 returns [foo, bar,baz]

With breadth first edge weights are not taken into account:

foo.shortest_path_to(baz, :method => :breadth_first)

All these methods return the node object with an additional weight field. This enables you to query the weights associated with the edges found.



71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
# File 'lib/acts_as_oqgraph.rb', line 71

def acts_as_oqgraph(options = {})
  
  unless check_for_oqgraph_engine 
    raise "acts_as_oqgraph requires the OQGRAPH engine. Install the oqgraph plugin with the following SQL: INSTALL PLUGIN oqgraph SONAME 'oqgraph_engine.so'"
  end
  
  class_name = options[:class_name] || "#{self.name}Edge"
  edge_table_name = options[:table_name] || class_name.pluralize.underscore
  oqgraph_table_name = options[:oqgraph_table_name] || "#{self.name}Oqgraph".underscore  
  from_key = options[:from_key] || 'from_id'
  to_key = options[:to_key]   || 'to_id' 
  weight_column = options[:weight_column] || 'weight'
  # Create the Edge Model
  eval <<-EOS
    class ::#{class_name} < ::GraphEdge
      set_table_name "#{edge_table_name}"
      
      belongs_to :from, :class_name => '#{self.name}', :foreign_key => '#{from_key}'
      belongs_to :to, :class_name => '#{self.name}', :foreign_key => '#{to_key}'
      
      cattr_accessor :node_class, :oqgraph_table_name, :to_key, :from_key, :weight_column
      
      @@oqgraph_table_name = '#{oqgraph_table_name}'
      @@from_key = '#{from_key}'
      @@to_key = '#{to_key}'
      @@node_class = #{self}
      @@weight_column = '#{weight_column}'
      
      create_graph_table
    end
  EOS
  
  has_many :outgoing_edges, {
     :class_name => class_name,
     :foreign_key => from_key,
     :include => :to,
     :dependent => :destroy
   }
  
  has_many :incoming_edges, {
     :class_name => class_name,
     :foreign_key => to_key,
     :include => :from,
     :dependent => :destroy
   }
  
  has_many :outgoing_nodes, :through => :outgoing_edges, :source => :to
  has_many :incoming_nodes, :through => :incoming_edges, :source => :from
                              
  class_eval <<-EOF
    include OQGraph::InstanceMethods
    
    def self.edge_class
      #{class_name.classify}
    end
    
    def self.edge_table
      '#{edge_table_name}'
    end
    
    def self.rebuild_graph
      edge_class.create_graph_table
    end
  EOF
end