5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
# File 'lib/with_recursive_tree.rb', line 5
def with_recursive_tree(primary_key: :id, foreign_key: :parent_id, foreign_key_type: nil, order: nil)
include InstanceMethods
scope_condition = foreign_key_type.present? ? -> { where foreign_key_type => self.class.name } : -> { self }
belongs_to :parent, scope_condition, class_name: name, primary_key: primary_key, foreign_key: foreign_key, inverse_of: :children, optional: true
has_many :children, -> { scope_condition.call.order(order) }, class_name: name, primary_key: primary_key, foreign_key: foreign_key, inverse_of: :parent
define_singleton_method(:with_recursive_tree_primary_key) { primary_key }
define_singleton_method(:with_recursive_tree_foreign_key) { foreign_key }
define_singleton_method(:with_recursive_tree_foreign_key_type) { foreign_key_type }
define_singleton_method(:with_recursive_tree_order) { order || primary_key }
define_singleton_method(:with_recursive_tree_order_column) do
if with_recursive_tree_order.is_a?(Hash)
with_recursive_tree_order.keys.first
else
with_recursive_tree_order.to_s.split(" ").first
end
end
if foreign_key_type.present?
before_save do
if send(:"#{foreign_key}_changed?")
if send(foreign_key).present?
send(:"#{foreign_key_type}=", self.class.name) if send(foreign_key_type).blank?
elsif send(foreign_key).nil?
send(:"#{foreign_key_type}=", nil) unless send(foreign_key_type) == self.class.name
end
end
end
end
scope :bfs, -> {
if defined?(ActiveRecord::ConnectionAdapters::MySQL)
order(:depth, with_recursive_tree_order)
else
order(:depth)
end
}
scope :dfs, -> do
if defined?(ActiveRecord::ConnectionAdapters::MySQL)
order(with_recursive_tree_order, :path)
elsif defined?(ActiveRecord::ConnectionAdapters::PostgreSQL)
order(:path)
elsif defined?(ActiveRecord::ConnectionAdapters::SQLite3)
self
end
end
scope :roots, -> {
if with_recursive_tree_foreign_key_type.present?
where(with_recursive_tree_foreign_key => nil)
.where(with_recursive_tree_foreign_key_type => [nil, name])
.or(
where.not(with_recursive_tree_foreign_key => nil)
.where.not(with_recursive_tree_foreign_key_type => name)
)
else
where with_recursive_tree_foreign_key => nil
end
}
end
|