simple_nested_set 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/core_ext/hash/extract_nested_set_attributes.rb +8 -0
- data/lib/simple_nested_set/act_macro.rb +4 -3
- data/lib/simple_nested_set/class_methods.rb +0 -8
- data/lib/simple_nested_set/instance_methods.rb +4 -13
- data/lib/simple_nested_set/move/by_attributes.rb +4 -0
- data/lib/simple_nested_set/move/to_target.rb +52 -30
- data/lib/simple_nested_set/nested_set.rb +8 -29
- data/lib/simple_nested_set/version.rb +1 -1
- data/lib/simple_nested_set.rb +3 -0
- metadata +4 -3
@@ -4,15 +4,16 @@ module SimpleNestedSet
|
|
4
4
|
return if acts_as_nested_set?
|
5
5
|
|
6
6
|
include SimpleNestedSet::InstanceMethods
|
7
|
-
extend
|
7
|
+
extend SimpleNestedSet::ClassMethods
|
8
8
|
|
9
9
|
define_callbacks :move, :terminator => "result == false"
|
10
10
|
|
11
|
-
before_validation lambda { |r| r.nested_set.init_as_node }
|
11
|
+
before_validation lambda { |r| r.nested_set.init_as_node }, :if => :new_record?
|
12
12
|
before_destroy lambda { |r| r.nested_set.prune_branch }
|
13
|
+
after_save lambda { |r| r.nested_set.save! }
|
13
14
|
|
14
15
|
belongs_to :parent, :class_name => self.name
|
15
|
-
has_many :children, :foreign_key => :parent_id, :class_name =>
|
16
|
+
has_many :children, :foreign_key => :parent_id, :class_name => self.name
|
16
17
|
|
17
18
|
default_scope :order => :lft
|
18
19
|
|
@@ -10,14 +10,6 @@ module SimpleNestedSet
|
|
10
10
|
set_callback(:move, :after, *args, &block)
|
11
11
|
end
|
12
12
|
|
13
|
-
def create(attributes)
|
14
|
-
nested_set_class.with_move_by_attributes(attributes) { super }
|
15
|
-
end
|
16
|
-
|
17
|
-
def create!(attributes)
|
18
|
-
nested_set_class.with_move_by_attributes(attributes) { super }
|
19
|
-
end
|
20
|
-
|
21
13
|
# Returns the first root node (with the given scope if any)
|
22
14
|
def root(scope = nil)
|
23
15
|
roots(scope).first
|
@@ -3,16 +3,12 @@ require 'active_support/core_ext/hash/keys'
|
|
3
3
|
module SimpleNestedSet
|
4
4
|
module InstanceMethods
|
5
5
|
def nested_set
|
6
|
-
@
|
6
|
+
@_nested_set ||= nested_set_class.new(self)
|
7
7
|
end
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def update_attributes!(attributes)
|
15
|
-
nested_set.with_move_by_attributes(attributes) { super }
|
9
|
+
def attributes=(attributes)
|
10
|
+
@_nested_set_attributes = attributes.extract_nested_set_attributes!
|
11
|
+
super
|
16
12
|
end
|
17
13
|
|
18
14
|
# recursively populates the parent and children associations of self and
|
@@ -22,11 +18,6 @@ module SimpleNestedSet
|
|
22
18
|
self
|
23
19
|
end
|
24
20
|
|
25
|
-
# Returns the level of this object in the tree, root level is 0
|
26
|
-
def level
|
27
|
-
parent_id.nil? ? 0 : ancestors.count
|
28
|
-
end
|
29
|
-
|
30
21
|
# Returns true if this is a root node.
|
31
22
|
def root?
|
32
23
|
parent_id.blank?
|
@@ -38,6 +38,10 @@ module SimpleNestedSet
|
|
38
38
|
attributes.symbolize_keys!
|
39
39
|
attributes.each { |key, value| attributes[key] = nil if value == 'null' }
|
40
40
|
|
41
|
+
[:parent, :left, :right].each do |key|
|
42
|
+
attributes[:"#{key}_id"] = attributes.delete(key).id if attributes.key?(key)
|
43
|
+
end
|
44
|
+
|
41
45
|
# if left_id is given but blank, set right_id to leftmost sibling
|
42
46
|
attributes[:right_id] = siblings.first.id if blank_given?(:left_id) && siblings.any?
|
43
47
|
|
@@ -15,17 +15,66 @@ module SimpleNestedSet
|
|
15
15
|
|
16
16
|
def perform
|
17
17
|
node.run_callbacks(:move) do
|
18
|
-
# reload
|
19
18
|
unless bound == node.rgt || bound == node.lft # there would be no change
|
20
19
|
nested_set.transaction do
|
21
|
-
#
|
22
|
-
|
20
|
+
# puts ActiveRecord::Base.send(:sanitize_sql_array, query)
|
21
|
+
update_structure!
|
22
|
+
update_denormalizations!
|
23
23
|
end
|
24
24
|
end
|
25
25
|
reload
|
26
26
|
end
|
27
27
|
end
|
28
28
|
|
29
|
+
def update_structure!
|
30
|
+
sql = <<-sql
|
31
|
+
lft = CASE
|
32
|
+
WHEN lft BETWEEN :a AND :b THEN lft + :d - :b
|
33
|
+
WHEN lft BETWEEN :c AND :d THEN lft + :a - :c
|
34
|
+
ELSE lft END,
|
35
|
+
|
36
|
+
rgt = CASE
|
37
|
+
WHEN rgt BETWEEN :a AND :b THEN rgt + :d - :b
|
38
|
+
WHEN rgt BETWEEN :c AND :d THEN rgt + :a - :c
|
39
|
+
ELSE rgt END,
|
40
|
+
|
41
|
+
parent_id = CASE
|
42
|
+
WHEN id = :id THEN :parent_id
|
43
|
+
ELSE parent_id END
|
44
|
+
sql
|
45
|
+
|
46
|
+
a, b, c, d = boundaries
|
47
|
+
sql = [sql, { :a => a, :b => b, :c => c, :d => d, :id => id, :parent_id => parent_id }]
|
48
|
+
nested_set.update_all(sql)
|
49
|
+
end
|
50
|
+
|
51
|
+
def update_denormalizations!
|
52
|
+
sql = []
|
53
|
+
sql << denormalize_level_query if node.has_attribute?(:level)
|
54
|
+
sql << denormalize_path_query if node.has_attribute?(:path)
|
55
|
+
nested_set.update_all(sql.join(',')) unless sql.blank?
|
56
|
+
end
|
57
|
+
|
58
|
+
def denormalize_level_query
|
59
|
+
<<-sql
|
60
|
+
level = (
|
61
|
+
SELECT count(id)
|
62
|
+
FROM #{table_name} as l
|
63
|
+
WHERE l.lft < #{table_name}.lft AND l.rgt > #{table_name}.rgt
|
64
|
+
)
|
65
|
+
sql
|
66
|
+
end
|
67
|
+
|
68
|
+
def denormalize_path_query
|
69
|
+
<<-sql
|
70
|
+
path = (
|
71
|
+
SELECT GROUP_CONCAT(slug, '/')
|
72
|
+
FROM #{table_name} as l
|
73
|
+
WHERE l.lft <= #{table_name}.lft AND l.rgt >= #{table_name}.rgt AND parent_id IS NOT NULL
|
74
|
+
)
|
75
|
+
sql
|
76
|
+
end
|
77
|
+
|
29
78
|
def reload
|
30
79
|
target.nested_set.reload if target
|
31
80
|
node.nested_set.reload
|
@@ -66,33 +115,6 @@ module SimpleNestedSet
|
|
66
115
|
@roots ||= node.nested_set.roots
|
67
116
|
end
|
68
117
|
|
69
|
-
def query
|
70
|
-
sql = <<-sql
|
71
|
-
lft = CASE
|
72
|
-
WHEN lft BETWEEN :a AND :b THEN lft + :d - :b
|
73
|
-
WHEN lft BETWEEN :c AND :d THEN lft + :a - :c
|
74
|
-
ELSE lft END,
|
75
|
-
|
76
|
-
rgt = CASE
|
77
|
-
WHEN rgt BETWEEN :a AND :b THEN rgt + :d - :b
|
78
|
-
WHEN rgt BETWEEN :c AND :d THEN rgt + :a - :c
|
79
|
-
ELSE rgt END,
|
80
|
-
|
81
|
-
parent_id = CASE
|
82
|
-
WHEN id = :id THEN :parent_id
|
83
|
-
ELSE parent_id END,
|
84
|
-
|
85
|
-
level = (
|
86
|
-
SELECT count(id)
|
87
|
-
FROM #{table_name} as t
|
88
|
-
WHERE t.lft < #{table_name}.lft AND rgt > #{table_name}.rgt
|
89
|
-
)
|
90
|
-
sql
|
91
|
-
# TODO name a, b, c, d in a more reasonable way
|
92
|
-
a, b, c, d = boundaries
|
93
|
-
[sql, { :a => a, :b => b, :c => c, :d => d, :id => id, :parent_id => parent_id }]
|
94
|
-
end
|
95
|
-
|
96
118
|
def table_name
|
97
119
|
node.class.quoted_table_name
|
98
120
|
end
|
@@ -1,7 +1,5 @@
|
|
1
1
|
module SimpleNestedSet
|
2
2
|
class NestedSet < ActiveRecord::Relation
|
3
|
-
NESTED_SET_ATTRIBUTES = [:parent_id, :left_id, :right_id]
|
4
|
-
|
5
3
|
class_inheritable_accessor :node_class, :scope_names
|
6
4
|
|
7
5
|
class << self
|
@@ -21,24 +19,6 @@ module SimpleNestedSet
|
|
21
19
|
c.merge(name => scope.respond_to?(name) ? scope.send(name) : scope[name])
|
22
20
|
end
|
23
21
|
end
|
24
|
-
|
25
|
-
def with_move_by_attributes(attributes, node = nil)
|
26
|
-
node_class.transaction do
|
27
|
-
nested_set_attributes = extract_nested_set_attributes!(attributes)
|
28
|
-
yield.tap do |result|
|
29
|
-
unless nested_set_attributes.empty?
|
30
|
-
node ||= result
|
31
|
-
node.nested_set.move_by_attributes(nested_set_attributes)
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def extract_nested_set_attributes!(attributes)
|
38
|
-
result = attributes.slice(*NESTED_SET_ATTRIBUTES)
|
39
|
-
attributes.except!(*NESTED_SET_ATTRIBUTES)
|
40
|
-
result
|
41
|
-
end
|
42
22
|
end
|
43
23
|
|
44
24
|
attr_reader :node
|
@@ -48,9 +28,11 @@ module SimpleNestedSet
|
|
48
28
|
@node = args.first if args.size == 1
|
49
29
|
@where_values = self.class.scope(node).instance_variable_get(:@where_values) if node
|
50
30
|
end
|
51
|
-
|
52
|
-
def
|
53
|
-
|
31
|
+
|
32
|
+
def save!
|
33
|
+
attributes = node.instance_variable_get(:@_nested_set_attributes)
|
34
|
+
node.instance_variable_set(:@_nested_set_attributes, nil)
|
35
|
+
move_by_attributes(attributes) unless attributes.blank?
|
54
36
|
end
|
55
37
|
|
56
38
|
# Returns true if the node has the same scope as the given node
|
@@ -60,7 +42,7 @@ module SimpleNestedSet
|
|
60
42
|
|
61
43
|
# reload left, right, and parent
|
62
44
|
def reload
|
63
|
-
node.reload(:select => 'lft, rgt, parent_id')
|
45
|
+
node.reload(:select => 'lft, rgt, parent_id') unless node.new_record?
|
64
46
|
end
|
65
47
|
|
66
48
|
def populate_associations(nodes)
|
@@ -74,11 +56,8 @@ module SimpleNestedSet
|
|
74
56
|
|
75
57
|
# before validation set lft and rgt to the end of the tree
|
76
58
|
def init_as_node
|
77
|
-
|
78
|
-
|
79
|
-
node.lft, node.rgt = max_right + 1, max_right + 2
|
80
|
-
end
|
81
|
-
true
|
59
|
+
max_right = maximum(:rgt) || 0
|
60
|
+
node.lft, node.rgt = max_right + 1, max_right + 2
|
82
61
|
end
|
83
62
|
|
84
63
|
# Prunes a branch off of the tree, shifting all of the elements on the right
|
data/lib/simple_nested_set.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
1
|
require 'active_record'
|
2
|
+
require 'core_ext/hash/extract_nested_set_attributes'
|
2
3
|
|
3
4
|
module SimpleNestedSet
|
5
|
+
ATTRIBUTES = [:parent, :parent_id, :left_id, :right_id]
|
6
|
+
|
4
7
|
autoload :ActMacro, 'simple_nested_set/act_macro'
|
5
8
|
autoload :ClassMethods, 'simple_nested_set/class_methods'
|
6
9
|
autoload :InstanceMethods, 'simple_nested_set/instance_methods'
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_nested_set
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 21
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 0
|
9
|
-
-
|
10
|
-
version: 0.0.
|
9
|
+
- 5
|
10
|
+
version: 0.0.5
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Sven Fuchs
|
@@ -100,6 +100,7 @@ extensions: []
|
|
100
100
|
extra_rdoc_files: []
|
101
101
|
|
102
102
|
files:
|
103
|
+
- lib/core_ext/hash/extract_nested_set_attributes.rb
|
103
104
|
- lib/simple_nested_set.rb
|
104
105
|
- lib/simple_nested_set/act_macro.rb
|
105
106
|
- lib/simple_nested_set/class_methods.rb
|