Class: ActsAsRecursiveTree::Builders::RelationBuilder
- Inherits:
-
Object
- Object
- ActsAsRecursiveTree::Builders::RelationBuilder
- Defined in:
- lib/acts_as_recursive_tree/builders/relation_builder.rb
Overview
Constructs the Arel necessary for recursion.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#ids ⇒ Object
readonly
Returns the value of attribute ids.
-
#klass ⇒ Object
readonly
Returns the value of attribute klass.
-
#without_ids ⇒ Object
readonly
Returns the value of attribute without_ids.
Class Method Summary collapse
Instance Method Summary collapse
- #add_pg_cycle_detection(union_query) ⇒ Object
- #apply_depth(select_manager) ⇒ Object
- #apply_except_id(relation) ⇒ Object
- #apply_parent_type_column(arel_condition) ⇒ Object
- #apply_query_opts_condition(relation) ⇒ Object
- #base_table ⇒ Object
- #build ⇒ Object
- #build_base_join_select(select_manager) ⇒ Object
-
#build_base_select ⇒ Object
Builds SQL: SELECT id, parent_id, 0 AS depth FROM base_table WHERE id = 123.
- #build_cte_table ⇒ Object
- #build_union_select ⇒ Object
- #config ⇒ Object
- #create_select_manger(column = nil) ⇒ Object
-
#get_query_options ⇒ ActsAsRecursiveTree::Options::QueryOptions
Constructs a new QueryOptions and yield it to the proc if one is present.
-
#initialize(klass, ids, exclude_ids: false, &block) ⇒ RelationBuilder
constructor
A new instance of RelationBuilder.
- #recursive_temp_table ⇒ Object
- #travers_loc_table ⇒ Object
Constructor Details
#initialize(klass, ids, exclude_ids: false, &block) ⇒ RelationBuilder
Returns a new instance of RelationBuilder.
23 24 25 26 27 28 29 30 31 32 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 23 def initialize(klass, ids, exclude_ids: false, &block) @klass = klass @ids = ActsAsRecursiveTree::Options::Values.create(ids, klass._recursive_tree_config) @without_ids = exclude_ids @query_opts = (&block) # random seed for the temp tables @rand_int = SecureRandom.rand(1_000_000) end |
Instance Attribute Details
#ids ⇒ Object (readonly)
Returns the value of attribute ids.
17 18 19 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 17 def ids @ids end |
#klass ⇒ Object (readonly)
Returns the value of attribute klass.
17 18 19 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 17 def klass @klass end |
#without_ids ⇒ Object (readonly)
Returns the value of attribute without_ids.
17 18 19 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 17 def without_ids @without_ids end |
Class Method Details
.build(klass, ids, exclude_ids: false, &block) ⇒ Object
11 12 13 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 11 def self.build(klass, ids, exclude_ids: false, &block) new(klass, ids, exclude_ids:, &block).build end |
Instance Method Details
#add_pg_cycle_detection(union_query) ⇒ Object
94 95 96 97 98 99 100 101 102 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 94 def add_pg_cycle_detection(union_query) return union_query unless config.cycle_detection? Arel::Nodes::InfixOperation.new( '', union_query, Arel.sql("CYCLE #{primary_key} SET is_cycle USING path") ) end |
#apply_depth(select_manager) ⇒ Object
71 72 73 74 75 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 71 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
65 66 67 68 69 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 65 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
132 133 134 135 136 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 132 def apply_parent_type_column(arel_condition) return arel_condition if parent_type_column.blank? arel_condition.and(base_table[parent_type_column].eq(klass.base_class)) end |
#apply_query_opts_condition(relation) ⇒ Object
148 149 150 151 152 153 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 148 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_table ⇒ Object
55 56 57 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 55 def base_table klass.arel_table end |
#build ⇒ Object
59 60 61 62 63 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 59 def build relation = Strategies.(@query_opts).build(self) apply_except_id(relation) end |
#build_base_join_select(select_manager) ⇒ Object
138 139 140 141 142 143 144 145 146 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 138 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_select ⇒ Object
Builds SQL: SELECT id, parent_id, 0 AS depth FROM base_table WHERE id = 123
106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 106 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_table ⇒ Object
85 86 87 88 89 90 91 92 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 85 def build_cte_table Arel::Nodes::As.new( travers_loc_table, add_pg_cycle_detection( build_base_select.union(build_union_select) ) ) end |
#build_union_select ⇒ Object
118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 118 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 |
#config ⇒ Object
42 43 44 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 42 def config klass._recursive_tree_config end |
#create_select_manger(column = nil) ⇒ Object
77 78 79 80 81 82 83 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 77 def create_select_manger(column = nil) projections = column ? travers_loc_table[column] : Arel.star select_mgr = travers_loc_table.project(projections).with(:recursive, build_cte_table) apply_depth(select_mgr) end |
#get_query_options ⇒ 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.
51 52 53 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 51 def (&) ActsAsRecursiveTree::Options::QueryOptions.from(&) end |
#recursive_temp_table ⇒ Object
34 35 36 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 34 def recursive_temp_table @recursive_temp_table ||= Arel::Table.new("recursive_#{klass.table_name}_#{@rand_int}_temp") end |
#travers_loc_table ⇒ Object
38 39 40 |
# File 'lib/acts_as_recursive_tree/builders/relation_builder.rb', line 38 def travers_loc_table @travers_loc_table ||= Arel::Table.new("traverse_#{@rand_int}_loc") end |