fast_tree 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ef95899f36c494fb5bc3cea8317205591f61dae7
4
- data.tar.gz: f84331649e1fbf73db8853f7629ef8b7144f69a4
3
+ metadata.gz: 1a2408d73a49d03de109154c5bc8897bfcbeadaf
4
+ data.tar.gz: 48bda26709f050ccc1b56ac535220aaf89169696
5
5
  SHA512:
6
- metadata.gz: 7a5137010f0f12bf4e6c03543814b542d218c61fecc8aee0e886e7fc7c66a6c39d2f51b1bcd9e843ef50ed99f07333e48002859ea5412dcb8d2b2e6d6ef94f9c
7
- data.tar.gz: 8a6291deac4b760f876f50f24a2fec8c65262a1bf20b60c3a67041d60d4e6cdd4e13f3b789f71782c33a2e9c16f55782aacfde2534d60a5e8e5508082d9b66fd
6
+ metadata.gz: 59bd83c3ee0bb38e65dfe8ce9152619a18c65b06eddedfb65b765581e7afd354fc4687f82d25d86058c4d12894e20ad278c8eaa48802eafd4d2e4f30c78ee74f
7
+ data.tar.gz: c89f948f54b279fc8a857764995353abac0bf56e0bbb38e1ba6ef5afcb6e952757df66db150a1ce5c92211a813f2cd77feecb115d7036100c4baf7e71a210796
data/README.md CHANGED
@@ -24,18 +24,30 @@ $ gem install fast_tree
24
24
  ## Usage
25
25
 
26
26
  `fast_tree` provides a generator which adds left and right pointers used in nested sets model to your model class.
27
- Even if you have created a class or not, execute following commands in the terminal:
27
+ Even if you have created a target class or not, execute following commands in your terminal:
28
28
 
29
29
  ```bash
30
30
  $ bin/rails g fast_tree YOUR_MODEL_NAME
31
31
  ```
32
32
 
33
- After executing the command, add following sentence into your model:
33
+ and, execute migration by `bundle exec rake db:migrate`.
34
+
35
+ After that, add the following line into your model:
34
36
 
35
37
  ```ruby
36
38
  include FastTree::Model
37
39
  ```
38
40
 
41
+ It seems like:
42
+
43
+ ```ruby
44
+ class YOUR_MODEL_NAME < ApplicationRecord
45
+ include FastTree::Model
46
+
47
+ ...
48
+ end
49
+ ```
50
+
39
51
  Finally, you can use several methods as class methods and instance methods.
40
52
 
41
53
  If you are interested in how it works, see the section "How It Works" below.
@@ -137,6 +149,63 @@ target = YOUR_MODEL_NAME.second
137
149
  root_of_subtree.move_to(targe)
138
150
  ```
139
151
 
152
+ ### Find root
153
+
154
+ To get the root node from the tree,
155
+
156
+ ```
157
+ root = YOUR_MODEL_NAME.find_root
158
+ ```
159
+
160
+ ### Deal with subtrees
161
+
162
+ To get subtree from a root node,
163
+
164
+ ```ruby
165
+ # root can be any node in the tree
166
+ root = YOUR_MODEL_NAME.take
167
+ root.subtree.each do |node|
168
+ # do something
169
+ end
170
+ ```
171
+
172
+ NOTE: `subtree` method returns ActiveRelation, so that you can use `each`, `map` or anything you want!
173
+
174
+ ### Tree traverse algorithms
175
+
176
+ In `fast_tree`, several tree-traverse algorithms, such as DFS and BFS, are provided.
177
+
178
+ #### DFS (Depth First Search)
179
+
180
+ To get nodes by DFS,
181
+
182
+ ```ruby
183
+ root = YOUR_MODEL_NAME.take
184
+ root.subtree.dfs.each do |node|
185
+ # do something
186
+ end
187
+ ```
188
+
189
+ #### BFS (Breadth First Search)
190
+
191
+ To get nodes by BFS,
192
+
193
+ ```ruby
194
+ root = YOUR_MODEL_NAME.take
195
+ root.subtree.bfs.each do |node|
196
+ # do something
197
+ end
198
+ ```
199
+
200
+ ### Boolean methods
201
+
202
+ `fast_tree` provides several boolean methods, such as:
203
+
204
+ - root?
205
+ - leaf?
206
+ - has_children?
207
+
208
+ , as instance methods.
140
209
 
141
210
  ## How It Works
142
211
  The migration file will create a migration file, such as:
@@ -148,11 +217,13 @@ class AddFastTreeToTestTrees < ActiveRecord::Migration[5.0]
148
217
  ## Pointers
149
218
  t.integer :l_ptr
150
219
  t.integer :r_ptr
220
+ t.integer :depth
151
221
 
152
222
  end
153
223
 
154
224
  add_index :test_trees, :l_ptr
155
225
  add_index :test_trees, :r_ptr
226
+ add_index :test_trees, :depth
156
227
  end
157
228
 
158
229
  def self.down
@@ -0,0 +1,20 @@
1
+ module FastTree
2
+ module Model
3
+ module Subtree
4
+ module Traverse
5
+ extend ActiveSupport::Concern
6
+
7
+ included do
8
+ scope :bfs, -> { order(depth: :asc, l_ptr: :asc) }
9
+ scope :dfs, -> { order(l_ptr: :asc) }
10
+ end
11
+
12
+ def subtree
13
+ self.class.where(self.class.arel_table[:l_ptr].gteq(l_ptr))
14
+ .where(self.class.arel_table[:r_ptr].lteq(r_ptr))
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -2,6 +2,11 @@ module FastTree
2
2
  module Model
3
3
  extend ActiveSupport::Concern
4
4
 
5
+ included do
6
+ include FastTree::Model::Subtree::Traverse
7
+ end
8
+
9
+
5
10
  # =================
6
11
  # Class Methods
7
12
  # =================
@@ -13,22 +18,28 @@ module FastTree
13
18
  # ====================
14
19
 
15
20
  def add_parent(parent, children, &block)
21
+ parent_depth = children.first.depth
22
+
16
23
  # create space for parent
17
24
  ptrs = _create_parent_embedded_space(children)
18
25
 
19
26
  # parent node's pointer
20
27
  parent.l_ptr = ptrs[:l_ptr]
21
28
  parent.r_ptr = ptrs[:r_ptr]
29
+ parent.depth = parent_depth
22
30
  parent.save
23
31
  end
24
32
 
25
33
  def create_parent(attributes = {}, children, &block)
34
+ parent_depth = children.first.depth
35
+
26
36
  # create space for parent
27
37
  ptrs = _create_parent_embedded_space(children)
28
38
 
29
39
  # parent node's pointer
30
40
  attributes[:l_ptr] = ptrs[:l_ptr]
31
41
  attributes[:r_ptr] = ptrs[:r_ptr]
42
+ attributes[:depth] = parent_depth
32
43
 
33
44
  self.create(attributes, &block)
34
45
  end
@@ -40,6 +51,7 @@ module FastTree
40
51
  else
41
52
  attributes[:l_ptr] = 0
42
53
  attributes[:r_ptr] = 1
54
+ attributes[:depth] = 0
43
55
  self.create(attributes, &block)
44
56
  end
45
57
  end
@@ -69,6 +81,12 @@ UPDATE #{self.to_s.underscore.pluralize}
69
81
  WHEN l_ptr > #{right}
70
82
  THEN r_ptr + 2
71
83
  ELSE r_ptr
84
+ END,
85
+ depth = CASE
86
+ WHEN l_ptr >= #{left}
87
+ AND r_ptr <= #{right}
88
+ THEN depth + 1
89
+ ELSE depth
72
90
  END
73
91
  WHERE r_ptr > #{left}
74
92
  EOS
@@ -134,6 +152,7 @@ UPDATE #{self.to_s.underscore.pluralize}
134
152
  # child node's pointer
135
153
  node.l_ptr = r_ptr
136
154
  node.r_ptr = r_ptr + 1
155
+ node.depth = depth + 1
137
156
  node.save
138
157
  end
139
158
 
@@ -144,6 +163,7 @@ UPDATE #{self.to_s.underscore.pluralize}
144
163
  # create child
145
164
  attributes[:l_ptr] = r_ptr
146
165
  attributes[:r_ptr] = r_ptr + 1
166
+ attributes[:depth] = depth + 1
147
167
  self.class.create(attributes, &block)
148
168
  end
149
169
 
@@ -154,19 +174,17 @@ UPDATE #{self.to_s.underscore.pluralize}
154
174
  _update_nodes(node.l_ptr, node.r_ptr, "r_ptr >= #{r_ptr}", width + 1)
155
175
 
156
176
  bias = node.l_ptr + 1 - l_ptr
177
+ base_depth = depth
157
178
  subtree.each do |st_node|
158
179
  attributes = st_node.attributes.to_h
159
180
  attributes.delete("id")
160
- attributes["l_ptr"] = attributes["l_ptr"] + bias
161
- attributes["r_ptr"] = attributes["r_ptr"] + bias
181
+ attributes["l_ptr"] += bias
182
+ attributes["r_ptr"] += bias
183
+ attributes["depth"] += node.depth - base_depth + 1
162
184
  self.class.create(attributes)
163
185
  end
164
186
  end
165
187
 
166
- def depth
167
- path.size - 1
168
- end
169
-
170
188
  def move_to(node)
171
189
  # NOTE:
172
190
  # copy_to and remove change node ids
@@ -184,9 +202,11 @@ UPDATE #{self.to_s.underscore.pluralize}
184
202
 
185
203
  # move subtree under the given node
186
204
  bias = node.l_ptr + 1 - l_ptr
205
+ base_depth = depth
187
206
  subtree.each do |st_node|
188
207
  st_node.l_ptr += bias
189
208
  st_node.r_ptr += bias
209
+ st_node.depth += node.depth - base_depth + 1
190
210
  st_node.save
191
211
  end
192
212
  end
@@ -217,6 +237,23 @@ UPDATE #{self.to_s.underscore.pluralize}
217
237
  end
218
238
 
219
239
 
240
+ #
241
+ # Boolean Methods
242
+ #
243
+
244
+ def root?
245
+ self.l_ptr == 0
246
+ end
247
+
248
+ def leaf?
249
+ l_ptr == r_ptr - 1
250
+ end
251
+
252
+ def has_children?
253
+ l_ptr != r_ptr - 1
254
+ end
255
+
256
+
220
257
  protected
221
258
 
222
259
  def _update_nodes(left, right, condition, diff = 2)
@@ -1,3 +1,3 @@
1
1
  module FastTree
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/fast_tree.rb CHANGED
@@ -1,11 +1,13 @@
1
1
  require 'rails'
2
2
 
3
- module FastTree
4
-
5
- # =====================================
6
- # Implementation of Fast Tree Structure
7
- # =====================================
8
3
 
4
+ module FastTree
9
5
  autoload :Model, 'fast_tree/model'
10
6
 
7
+ module Model
8
+ module Subtree
9
+ autoload :Traverse, 'fast_tree/model/subtree/traverse'
10
+ end
11
+ end
12
+
11
13
  end
@@ -26,6 +26,7 @@ module ActiveRecord
26
26
  ## Pointers
27
27
  t.integer :l_ptr
28
28
  t.integer :r_ptr
29
+ t.integer :depth
29
30
  RUBY
30
31
  end
31
32
 
@@ -12,5 +12,6 @@ class FastTreeCreate<%= table_name.camelize %> < ActiveRecord::Migration<%= migr
12
12
 
13
13
  add_index :<%= table_name %>, :l_ptr
14
14
  add_index :<%= table_name %>, :r_ptr
15
+ add_index :<%= table_name %>, :depth
15
16
  end
16
17
  end
@@ -10,6 +10,7 @@ class AddFastTreeTo<%= table_name.camelize %> < ActiveRecord::Migration<%= migra
10
10
 
11
11
  add_index :<%= table_name %>, :l_ptr
12
12
  add_index :<%= table_name %>, :r_ptr
13
+ add_index :<%= table_name %>, :depth
13
14
  end
14
15
 
15
16
  def self.down
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_tree
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chisato Hasegawa
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-02-07 00:00:00.000000000 Z
11
+ date: 2017-02-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -64,6 +64,7 @@ files:
64
64
  - Rakefile
65
65
  - lib/fast_tree.rb
66
66
  - lib/fast_tree/model.rb
67
+ - lib/fast_tree/model/subtree/traverse.rb
67
68
  - lib/fast_tree/version.rb
68
69
  - lib/generators/active_record/fast_tree_generator.rb
69
70
  - lib/generators/active_record/templates/migration.rb
@@ -91,7 +92,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
91
92
  version: '0'
92
93
  requirements: []
93
94
  rubyforge_project:
94
- rubygems_version: 2.5.1
95
+ rubygems_version: 2.5.2
95
96
  signing_key:
96
97
  specification_version: 4
97
98
  summary: '["Rails plugin for Fast Tree Structure", "fast_tree is an implementation