Implements the Nested Sets pattern for hierarchical SQL queries.
Methods
Public Class methods
[ show source ]
# File lib/og/model/hierarchical.rb, line 14
14: def self.included_with_parameters(base, options)
15: c = {
16: :left => 'lft',
17: :right => 'rgt',
18: :type => Fixnum,
19: :parent => base.to_s.demodulize.underscore.downcase,
20: :children => base.to_s.demodulize.underscore.downcase.plural
21: }
22: c.update(options) if options
23:
24: parent = "#{c[:parent]}_oid"
25: left = c[:left]
26: right = c[:right]
27: children = c[:children]
28: child = children.singular
29:
30: if c[:scope].is_a?(Symbol) && c[:scope].to_s !~ /_oid$/
31: c[:scope] = "#{c[:scope]}_oid".intern
32: end
33:
34: scope = c[:scope]
35:
36: if scope
37: if scope.is_a?(Symbol)
38: scope = %{(#{scope} ? "#{scope} = \#{@#{scope}}" : "#{scope} IS NULL")}
39: end
40:
41: cond = 'condition => ' + scope
42: cond_and = ':condition => ' + scope + ' + " AND " +'
43: else
44: cond = ':condition => nil'
45: cond_and = ':condition => '
46: end
47:
48: base.module_eval "attr_accessor :\#{parent}, Fixnum, :sql_index => true\nattr_accessor :\#{left}, :\#{right}, \#{c[:type]}\n\ndef root?\n(@\#{parent}.nil? || @\#{parent} == 0) && (@\#{left} == 1) && (@\#{right} > @\#{left})\nend\n\ndef child?\n(@\#{parent} && @\#{parent} != 0) && (@\#{left} > 1) && (@\#{right} > @\#{left})\nend\n\ndef parent\nif root?\nnil\nelse\n\#{base}[@\#{parent}]\nend\nend\n\ndef \#{children}_count\nreturn (@\#{right} - @\#{left} - 1)/2\nend\n\ndef full_\#{children}(options = {})\noptions.update(\#{cond_and}\"(\#{left} BETWEEN \\#\\{@\#{left}\\} AND \\\#{@\#{right}})\")\n\#{base}.all(options)\nend\n\ndef \#{children}(options = {})\noptions.update(\#{cond_and}\"(\#{left} > \\#\\{@\#{left}\\}) AND (\#{right} < \\\#{@\#{right}})\")\n\#{base}.all(options)\nend\n\ndef direct_\#{children}(options = {})\noptions.update(\#{cond_and}\"\#{parent} = \\\#{pk}\")\n\#{base}.all(options)\nend\n\ndef add_\#{child}(child)\nself.reload if pk\nchild.reload if child.pk\n\nif @\#{left}.nil? || @\#{left} == 0 || @\#{right}.nil? || @\#{right} == 0\n@\#{left} = 1\n@\#{right} = 2\nend\n\nchild.\#{parent} = pk\nchild.\#{left} = pivot = @\#{right}\nchild.\#{right} = pivot + 1\n@\#{right} = pivot + 2\n\n\#{base}.transaction do\n\#{base}.update(\"\#{left} = (\#{left} + 2)\", \#{cond_and}\"\#{left} >= \\\#{pivot}\")\n\#{base}.update(\"\#{right} = (\#{right} + 2)\", \#{cond_and}\"\#{right} >= \\\#{pivot}\")\nend\n\nself.save\nchild.save\nend\n", __FILE__, __LINE__
49: end