Class: ActsAsRecursiveTree::Builders::RelationBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/acts_as_recursive_tree/builders/relation_builder.rb

Overview

Constructs the Arel necessary for recursion.

Direct Known Subclasses

Ancestors, Descendants

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(klass, ids, exclude_ids: false, &block) ⇒ RelationBuilder

Returns a new instance of RelationBuilder.



21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 21

def initialize(klass, ids, exclude_ids: false, &block)
  @klass       = klass
  @config      = klass._recursive_tree_config
  @ids         = ActsAsRecursiveTree::Options::Values.create(ids, @config)
  @without_ids = exclude_ids

  @query_opts = get_query_options(block)

  rand_int              = random.rand(1_000_000)
  @recursive_temp_table = Arel::Table.new("recursive_#{klass.table_name}_#{rand_int}_temp")
  @travers_loc_table    = Arel::Table.new("traverse_#{rand_int}_loc")
end

Instance Attribute Details

#idsObject (readonly)

Returns the value of attribute ids.



14
15
16
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 14

def ids
  @ids
end

#klassObject (readonly)

Returns the value of attribute klass.



14
15
16
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 14

def klass
  @klass
end

#recursive_temp_tableObject (readonly)

Returns the value of attribute recursive_temp_table.



14
15
16
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 14

def recursive_temp_table
  @recursive_temp_table
end

#travers_loc_tableObject (readonly)

Returns the value of attribute travers_loc_table.



14
15
16
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 14

def travers_loc_table
  @travers_loc_table
end

#without_idsObject (readonly)

Returns the value of attribute without_ids.



14
15
16
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 14

def without_ids
  @without_ids
end

Class Method Details

.build(klass, ids, exclude_ids: false, &block) ⇒ Object



8
9
10
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 8

def self.build(klass, ids, exclude_ids: false, &block)
  new(klass, ids, exclude_ids: exclude_ids, &block).build
end

Instance Method Details

#apply_depth(select_manager) ⇒ Object



65
66
67
68
69
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 65

def apply_depth(select_manager)
  return select_manager unless depth_present?

  select_manager.where(depth.apply_to(travers_loc_table[depth_column]))
end

#apply_except_id(relation) ⇒ Object



60
61
62
63
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 60

def apply_except_id(relation)
  return relation unless without_ids
  relation.where(ids.apply_negated_to(base_table[primary_key]))
end

#apply_parent_type_column(arel_condition) ⇒ Object



116
117
118
119
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 116

def apply_parent_type_column(arel_condition)
  return arel_condition unless parent_type_column.present?
  arel_condition.and(base_table[parent_type_column].eq(klass.base_class))
end

#apply_query_opts_condition(relation) ⇒ Object



131
132
133
134
135
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 131

def apply_query_opts_condition(relation)
  # check with nil? and not #present?/#blank? which will execute the query
  return relation if condition.nil?
  relation.merge(condition)
end

#base_tableObject



49
50
51
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 49

def base_table
  klass.arel_table
end

#buildObject



53
54
55
56
57
58
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 53

def build
  relation = Strategy.for_query_options(@query_opts).build(self)

  relation = apply_except_id(relation)
  relation
end

#build_base_join_select(select_manager) ⇒ Object



121
122
123
124
125
126
127
128
129
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 121

def build_base_join_select(select_manager)
  klass.select(
    base_table[primary_key],
    base_table[parent_key],
    Arel.sql(
      (travers_loc_table[depth_column] + 1).to_sql
    ).as(depth_column.to_s)
  ).unscope(where: :type).joins(select_manager.join_sources)
end

#build_base_selectObject



90
91
92
93
94
95
96
97
98
99
100
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 90

def build_base_select
  id_node = base_table[primary_key]

  base_table.where(
    ids.apply_to(id_node)
  ).project(
    id_node,
    base_table[parent_key],
    Arel.sql('0').as(depth_column.to_s)
  )
end

#build_cte_tableObject



83
84
85
86
87
88
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 83

def build_cte_table
  Arel::Nodes::As.new(
    travers_loc_table,
    build_base_select.union(build_union_select)
  )
end

#build_union_selectObject



102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 102

def build_union_select
  join_condition = apply_parent_type_column(
    traversal_strategy.build(self)
  )

  select_manager = base_table.join(travers_loc_table).on(join_condition)

  # need to use ActiveRecord here for merging relation
  relation = build_base_join_select(select_manager)

  relation = apply_query_opts_condition(relation)
  relation.arel
end

#create_select_manger(column = nil) ⇒ Object



71
72
73
74
75
76
77
78
79
80
81
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 71

def create_select_manger(column = nil)
  projections = if column
    travers_loc_table[column]
  else
    Arel.star
  end

  select_mgr = travers_loc_table.project(projections).with(:recursive, build_cte_table)

  apply_depth(select_mgr)
end

#get_query_options(proc) ⇒ ActsAsRecursiveTree::Options::QueryOptions

Constructs a new QueryOptions and yield it to the proc if one is present. Subclasses may override this method to provide sane defaults.

Parameters:

  • proc (Proc)

    a proc or nil

Returns:



41
42
43
44
45
46
47
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 41

def get_query_options(proc)
  opts = ActsAsRecursiveTree::Options::QueryOptions.new

  proc.call(opts) if proc

  opts
end