Module: Dagable::InstanceMethods

Defined in:
lib/dagable/instance_methods.rb

Overview

Instance methods mixed into every dagable model. Provides the public API for managing edges and traversing the DAG.

Instance Method Summary collapse

Instance Method Details

#add_child(child) ⇒ Object

Adds child as a direct child of this node. Creates the edge record and updates the ancestry table with all implied transitive paths.

Parameters:

  • child (ActiveRecord::Base)

    the node to add as child

Raises:



28
29
30
31
32
33
34
35
# File 'lib/dagable/instance_methods.rb', line 28

def add_child(child)
  ActiveRecord::Base.transaction do
    raise Errors::CyclicAssociation.new(self, child) if self_and_predecessors.exists?(id: child.id)

    edge = child_edges.find_or_create_by!(child_id: child.id)
    edge.link_ancestries
  end
end

#add_parent(parent) ⇒ Object

Adds parent as a direct parent of this node. Creates the edge record and updates the ancestry table with all implied transitive paths.

Parameters:

  • parent (ActiveRecord::Base)

    the node to add as parent

Raises:



13
14
15
16
17
18
19
20
# File 'lib/dagable/instance_methods.rb', line 13

def add_parent(parent)
  ActiveRecord::Base.transaction do
    raise Errors::CyclicAssociation.new(parent, self) if self_and_successors.exists?(id: parent.id)

    edge = parent_edges.find_or_create_by!(parent_id: parent.id)
    edge.link_ancestries
  end
end

#predecessorsActiveRecord::Relation

Returns all transitive ancestors (excluding self) as an ActiveRecord::Relation.

Returns:

  • (ActiveRecord::Relation)


102
103
104
105
106
107
108
109
# File 'lib/dagable/instance_methods.rb', line 102

def predecessors
  ancestry_table = ancestry_class.table_name
  model_table = self.class.table_name

  self.class
      .joins("INNER JOIN #{ancestry_table} ON #{ancestry_table}.predecessor_id = #{model_table}.id")
      .where("#{ancestry_table}.successor_id = ? AND #{ancestry_table}.depth > 0", id)
end

#remove_child(child) ⇒ Object

Removes child as a direct child of this node. Destroys the edge record; the edge’s destroy callbacks repair ancestry incrementally, touching only the region reachable through the removed edge.

Parameters:

  • child (ActiveRecord::Base)

    the child node to disconnect



42
43
44
45
46
# File 'lib/dagable/instance_methods.rb', line 42

def remove_child(child)
  ActiveRecord::Base.transaction do
    child_edges.where(child_id: child.id).destroy_all
  end
end

#remove_parent(parent) ⇒ Object

Removes parent as a direct parent of this node. Destroys the edge record; the edge’s destroy callbacks repair ancestry incrementally, touching only the region reachable through the removed edge.

Parameters:

  • parent (ActiveRecord::Base)

    the parent node to disconnect



53
54
55
56
57
# File 'lib/dagable/instance_methods.rb', line 53

def remove_parent(parent)
  ActiveRecord::Base.transaction do
    parent_edges.where(parent_id: parent.id).destroy_all
  end
end

#self_and_predecessorsActiveRecord::Relation

Returns this node and all its transitive ancestors as an ActiveRecord::Relation via a single ancestry table JOIN.

Returns:

  • (ActiveRecord::Relation)


76
77
78
79
80
81
82
83
# File 'lib/dagable/instance_methods.rb', line 76

def self_and_predecessors
  ancestry_table = ancestry_class.table_name
  model_table = self.class.table_name

  self.class
      .joins("INNER JOIN #{ancestry_table} ON #{ancestry_table}.predecessor_id = #{model_table}.id")
      .where("#{ancestry_table}.successor_id = ?", id)
end

#self_and_successorsActiveRecord::Relation

Returns this node and all its transitive descendants as an ActiveRecord::Relation via a single ancestry table JOIN.

Returns:

  • (ActiveRecord::Relation)


63
64
65
66
67
68
69
70
# File 'lib/dagable/instance_methods.rb', line 63

def self_and_successors
  ancestry_table = ancestry_class.table_name
  model_table = self.class.table_name

  self.class
      .joins("INNER JOIN #{ancestry_table} ON #{ancestry_table}.successor_id = #{model_table}.id")
      .where("#{ancestry_table}.predecessor_id = ?", id)
end

#successorsActiveRecord::Relation

Returns all transitive descendants (excluding self) as an ActiveRecord::Relation.

Returns:

  • (ActiveRecord::Relation)


89
90
91
92
93
94
95
96
# File 'lib/dagable/instance_methods.rb', line 89

def successors
  ancestry_table = ancestry_class.table_name
  model_table = self.class.table_name

  self.class
      .joins("INNER JOIN #{ancestry_table} ON #{ancestry_table}.successor_id = #{model_table}.id")
      .where("#{ancestry_table}.predecessor_id = ? AND #{ancestry_table}.depth > 0", id)
end