Module: TreeNodes::ClassMethods

Defined in:
backend/app/model/mixins/tree_nodes.rb

Instance Method Summary (collapse)

Instance Method Details

- (Object) calculate_has_unpublished_ancestor(obj, check_root_record = true)



347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
# File 'backend/app/model/mixins/tree_nodes.rb', line 347

def calculate_has_unpublished_ancestor(obj, check_root_record = true)
  if check_root_record && obj.root_record_id
    return true if root_model[obj.root_record_id].publish == 0
  end

  if obj.parent_id
    parent = node_model[obj.parent_id]
    if parent.publish == 0
      return true
    else
      return calculate_has_unpublished_ancestor(parent, false)
    end
  end

  false
end

- (Object) calculate_object_graph(object_graph, opts = {})



365
366
367
368
369
370
371
372
373
374
375
376
377
378
# File 'backend/app/model/mixins/tree_nodes.rb', line 365

def calculate_object_graph(object_graph, opts = {})
  object_graph.each do |model, id_list|
    next if self != model

    ids = self.any_repo.filter(:parent_id => id_list).
               select(:id).map {|row|
      row[:id]
    }

    object_graph.add_objects(self, ids)
  end

  super
end

- (Object) create_from_json(json, opts = {})



265
266
267
268
269
270
271
272
273
274
275
276
277
# File 'backend/app/model/mixins/tree_nodes.rb', line 265

def create_from_json(json, opts = {})
  sequence = sequence_for(json)
  set_root_record(json, sequence, opts)
 
  obj = super
 
  migration = opts[:migration] ? opts[:migration].value : false
  if json[self.root_record_type] && json.position && !migration 
    obj.set_position_in_list(json.position, sequence)
  end

  obj
end

- (Object) handle_delete(ids_to_delete)



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
# File 'backend/app/model/mixins/tree_nodes.rb', line 381

def handle_delete(ids_to_delete)
  ids = self.filter(:id => ids_to_delete )
  # lets get a group of records that have unique parents or root_records
  parents = ids.select_group(:parent_id, :root_record_id).all   
  # we then nil out the parent id so deletes can do its thing 
  ids.update(:parent_id => nil)
  # trigger the deletes... 
  obj = super
  # now lets make sure there are no holes
  parents.each do |parent|
   children = self.filter(:root_record_id => parent[:root_record_id], :parent_id => parent[:parent_id], ~:position => nil )  
   parent_name = children.get(:parent_name) 
   children.update(:parent_name => Sequel.lit(DB.concat('CAST(id as CHAR(10))', "'_temp'"))) 
   children.order(:position).each_with_index do |row, i|
    row.update(:position => i)
   end
   children.update(:parent_name => parent_name) 
  end
  obj
end

- (Object) node_model



250
251
252
# File 'backend/app/model/mixins/tree_nodes.rb', line 250

def node_model
  Kernel.const_get(node_record_type.camelize)
end

- (Object) node_record_type



240
241
242
# File 'backend/app/model/mixins/tree_nodes.rb', line 240

def node_record_type
  @node_record_type
end

- (Object) resequence(repo_id)

this requences the class, which updates the Sequence with correct sequences



404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
# File 'backend/app/model/mixins/tree_nodes.rb', line 404

def resequence(repo_id)
  RequestContext.open(:repo_id => repo_id) do
    # get all the objects that are parents but not at top level or orphans 
    $stderr.puts "Resequencing for #{self.class.to_s} in repo #{repo_id}" 
    self.filter(~:position => nil, :repo_id => repo_id, ~:parent_id => nil, ~:root_record_id => nil ).select(:parent_id).group(:parent_id)
        .each do |obj| 
          $stderr.print "+" 
          self.filter(:parent_id => obj.parent_id).order(:position).each_with_index do |child, i| 
            $stderr.print "." 
            child.update_position_only(child.parent_id, i) 
        end 
    end 
    $stderr.puts "*"  
  end 
end

- (Object) root_model



245
246
247
# File 'backend/app/model/mixins/tree_nodes.rb', line 245

def root_model
  Kernel.const_get(root_record_type.camelize)
end

- (Object) root_record_type



236
237
238
# File 'backend/app/model/mixins/tree_nodes.rb', line 236

def root_record_type
  @root_record_type
end

- (Object) sequel_to_jsonmodel(objs, opts = {})



315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
# File 'backend/app/model/mixins/tree_nodes.rb', line 315

def sequel_to_jsonmodel(objs, opts = {})
  jsons = super

  jsons.zip(objs).each do |json, obj|
    if obj.root_record_id
      json[root_record_type] = {'ref' => uri_for(root_record_type, obj.root_record_id)}

      if obj.parent_id
        json.parent = {'ref' => uri_for(node_record_type, obj.parent_id)}
      end

      if obj.parent_name
        # Calculate the absolute (gapless) position of this node.  This
        # bridges the gap between the DB's view of position, which only
        # cares that the positions order correctly, with the API's view,
        # which speaks in absolute numbering (i.e. the first position is 0,
        # the second position is 1, etc.)

        json.position = obj.absolute_position
      end

    end

    if node_model.publishable?
      json['has_unpublished_ancestor'] = calculate_has_unpublished_ancestor(obj)
    end
  end

  jsons
end

- (Object) sequence_for(json)



255
256
257
258
259
260
261
262
263
# File 'backend/app/model/mixins/tree_nodes.rb', line 255

def sequence_for(json)
  if json[root_record_type]
    if json.parent
      "#{json.parent['ref']}_children_position"
    else
      "#{json[root_record_type]['ref']}_children_position"
    end
  end
end

- (Object) set_root_record(json, sequence, opts)



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
# File 'backend/app/model/mixins/tree_nodes.rb', line 280

def set_root_record(json, sequence, opts)
  opts["root_record_id"] = nil
  opts["parent_id"] = nil
  opts["parent_name"] = nil

  # 'parent_name' is a bit funny.  We need this column because the combination
  # of (parent, position) needs to be unique, to ensure that two siblings
  # don't occupy the same position when ordering them.  However, parent_id can
  # be NULL, meaning that the current node is at the top level of the tree.
  # This prevents the uniqueness check for working against top-level elements.
  #
  # So, parent_name gets used as a stand in in this case: it always has a
  # value for any node belonging to a hierarchy, and this value gets used in
  # the uniqueness check.

  if json[root_record_type]
    opts["root_record_id"] = parse_reference(json[root_record_type]['ref'], opts)[:id]

    if json.parent
      opts["parent_id"] = parse_reference(json.parent['ref'], opts)[:id]
      opts["parent_name"] = "#{opts['parent_id']}@#{self.node_record_type}"
    else
      opts["parent_name"] = "root@#{json[root_record_type]['ref']}"
    end

    opts["position"] = Sequence.get(sequence)

  else
    # This record isn't part of a tree hierarchy
    opts["parent_name"] = "orphan@#{SecureRandom.uuid}"
    opts["position"] = 0
  end
end

- (Object) tree_record_types(root, node)



231
232
233
234
# File 'backend/app/model/mixins/tree_nodes.rb', line 231

def tree_record_types(root, node)
  @root_record_type = root.to_s
  @node_record_type = node.to_s
end