Module: FastTree::Model

Extended by:
ActiveSupport::Concern
Defined in:
lib/fast_tree.rb,
lib/fast_tree/model.rb,
lib/fast_tree/model/subtree/traverse.rb

Defined Under Namespace

Modules: ClassMethods, Subtree Classes: InvalidTreeStructureError

Instance Method Summary collapse

Instance Method Details

#add_child(node) ⇒ Object

Instance Methods



148
149
150
151
152
153
154
155
156
157
# File 'lib/fast_tree/model.rb', line 148

def add_child(node)
  # bulk update nodes by a sql query
  _update_nodes(r_ptr, r_ptr, "r_ptr >= #{r_ptr}")

  # child node's pointer
  node.l_ptr = r_ptr
  node.r_ptr = r_ptr + 1
  node.depth = depth + 1
  node.save
end

#childrenObject



275
276
277
278
279
# File 'lib/fast_tree/model.rb', line 275

def children
  self.class.where(self.class.arel_table[:l_ptr].gt(l_ptr))
            .where(self.class.arel_table[:r_ptr].lt(r_ptr))
            .where(depth: depth + 1)
end

#copy_to(node) ⇒ Object



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
# File 'lib/fast_tree/model.rb', line 170

def copy_to(node)
  # create empty space into which subtree embedded
  _update_nodes(node.l_ptr, node.r_ptr, "r_ptr >= #{node.r_ptr}", width + 1)

  # self and node may be updated by shifting
  self.reload
  node.reload

  bias = node.r_ptr - r_ptr - 1
  base_depth = depth
  self.subtree.each do |st_node|
    attributes = st_node.attributes.to_h
    attributes.delete("id")
    attributes["l_ptr"] += bias
    attributes["r_ptr"] += bias
    attributes["depth"] += node.depth - base_depth + 1
    self.class.create(attributes)
  end
end

#create_child(attributes = {}, &block) ⇒ Object



159
160
161
162
163
164
165
166
167
168
# File 'lib/fast_tree/model.rb', line 159

def create_child(attributes = {}, &block)
  # bulk update nodes by a sql query
  _update_nodes(r_ptr, r_ptr, "r_ptr >= #{r_ptr}")

  # create child
  attributes[:l_ptr] = r_ptr
  attributes[:r_ptr] = r_ptr + 1
  attributes[:depth] = depth + 1
  self.class.create(attributes, &block)
end

#has_children?Boolean

Returns:

  • (Boolean)


260
261
262
# File 'lib/fast_tree/model.rb', line 260

def has_children?
  l_ptr != r_ptr - 1
end

#leaf?Boolean

Returns:

  • (Boolean)


256
257
258
# File 'lib/fast_tree/model.rb', line 256

def leaf?
  l_ptr == r_ptr - 1
end

#move_to(node) ⇒ Object



190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
# File 'lib/fast_tree/model.rb', line 190

def move_to(node)
  # NOTE:
  # copy_to and remove change node ids
  # move operation should change nothing but left and right pointers

  # create empty spaces under the node
  _update_nodes(node.r_ptr, node.r_ptr, "r_ptr >= #{node.r_ptr}", width + 1)

  self.reload
  node.reload

  # remember where the node were
  empty_space_left = self.l_ptr
  empty_space_right = self.r_ptr

  # move subtree under the given node
  bias = node.r_ptr - r_ptr - 1
  base_depth = depth
  self.subtree.each do |st_node|
    st_node.l_ptr += bias
    st_node.r_ptr += bias
    st_node.depth += node.depth - base_depth + 1
    st_node.save
  end

  self.reload
  node.reload

  # fill (virtual) empty spaces that will be created by moving subtree
  _update_nodes(empty_space_left, empty_space_right, "r_ptr > #{empty_space_right}", - (width + 1))
end

#parentObject

Getter Methods



268
269
270
271
272
273
# File 'lib/fast_tree/model.rb', line 268

def parent
  self.class.where(self.class.arel_table[:l_ptr].lt(l_ptr))
            .where(self.class.arel_table[:r_ptr].gt(r_ptr))
            .where(depth: depth - 1)
            .try(:first)
end

#pathObject



233
234
235
236
237
# File 'lib/fast_tree/model.rb', line 233

def path
  self.class.where(self.class.arel_table[:l_ptr].lteq(l_ptr))
            .where(self.class.arel_table[:r_ptr].gteq(r_ptr))
            .order(l_ptr: :asc)
end


239
240
241
# File 'lib/fast_tree/model.rb', line 239

def print_subtree
  self.class.print_subtree(self)
end

#removeObject



222
223
224
225
226
227
228
229
230
231
# File 'lib/fast_tree/model.rb', line 222

def remove
  # remove subtree
  n_destroyed = self.class.find_subtree_by_root(self).destroy_all

  # fill empty space
  _update_nodes(l_ptr, r_ptr, "r_ptr >= #{r_ptr}", - (width + 1))

  # return count of destroyed nodes
  n_destroyed
end

#root?Boolean

Boolean Methods

Returns:

  • (Boolean)


252
253
254
# File 'lib/fast_tree/model.rb', line 252

def root?
  self.l_ptr == 0
end

#widthObject



243
244
245
# File 'lib/fast_tree/model.rb', line 243

def width
  r_ptr - l_ptr
end