activerecord-hierarchical_query 0.0.2 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +59 -30
- data/lib/active_record/hierarchical_query.rb +11 -11
- data/lib/active_record/hierarchical_query/cte/columns.rb +2 -15
- data/lib/active_record/hierarchical_query/cte/cycle_detector.rb +54 -0
- data/lib/active_record/hierarchical_query/cte/non_recursive_term.rb +32 -11
- data/lib/active_record/hierarchical_query/cte/query_builder.rb +82 -0
- data/lib/active_record/hierarchical_query/cte/recursive_term.rb +27 -13
- data/lib/active_record/hierarchical_query/cte/union_term.rb +10 -6
- data/lib/active_record/hierarchical_query/join_builder.rb +31 -10
- data/lib/active_record/hierarchical_query/orderings.rb +113 -0
- data/lib/active_record/hierarchical_query/{builder.rb → query.rb} +66 -36
- data/lib/active_record/hierarchical_query/version.rb +1 -1
- data/lib/arel/nodes/postgresql.rb +26 -6
- data/spec/active_record/hierarchical_query_spec.rb +56 -32
- data/spec/database.yml +1 -9
- data/spec/schema.rb +2 -2
- data/spec/spec_helper.rb +2 -4
- data/spec/support/models.rb +4 -4
- metadata +28 -33
- data/lib/active_record/hierarchical_query/adapters.rb +0 -34
- data/lib/active_record/hierarchical_query/adapters/abstract.rb +0 -41
- data/lib/active_record/hierarchical_query/adapters/postgresql.rb +0 -19
- data/lib/active_record/hierarchical_query/cte/query.rb +0 -65
- data/lib/active_record/hierarchical_query/visitors/orderings.rb +0 -87
- data/lib/active_record/hierarchical_query/visitors/postgresql/cycle_detector.rb +0 -49
- data/lib/active_record/hierarchical_query/visitors/postgresql/orderings.rb +0 -70
- data/lib/active_record/hierarchical_query/visitors/visitor.rb +0 -17
@@ -3,29 +3,43 @@ module ActiveRecord
|
|
3
3
|
module CTE
|
4
4
|
class RecursiveTerm
|
5
5
|
# @return [ActiveRecord::HierarchicalQuery::CTE::Query]
|
6
|
-
attr_reader :
|
6
|
+
attr_reader :builder
|
7
7
|
|
8
|
-
delegate :
|
9
|
-
:join_conditions,
|
10
|
-
:adapter,
|
11
|
-
:to => :query
|
8
|
+
delegate :query, to: :builder
|
12
9
|
|
13
|
-
# @param [ActiveRecord::HierarchicalQuery::CTE::
|
14
|
-
def initialize(
|
15
|
-
@
|
10
|
+
# @param [ActiveRecord::HierarchicalQuery::CTE::QueryBuilder] builder
|
11
|
+
def initialize(builder)
|
12
|
+
@builder = builder
|
13
|
+
end
|
14
|
+
|
15
|
+
def bind_values
|
16
|
+
scope.bind_values
|
16
17
|
end
|
17
18
|
|
18
19
|
def arel
|
19
|
-
arel = scope.
|
20
|
-
.
|
21
|
-
.join(recursive_table).on(join_conditions)
|
20
|
+
arel = scope.arel
|
21
|
+
.join(query.recursive_table).on(query.join_conditions)
|
22
22
|
|
23
|
-
|
23
|
+
builder.cycle_detector.apply_to_recursive(arel)
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
27
27
|
def scope
|
28
|
-
query.
|
28
|
+
@scope ||= query.child_scope_value.select(columns)
|
29
|
+
end
|
30
|
+
|
31
|
+
def columns
|
32
|
+
columns = builder.columns.to_a
|
33
|
+
columns << ordering if query.orderings.any?
|
34
|
+
columns
|
35
|
+
end
|
36
|
+
|
37
|
+
def ordering
|
38
|
+
column_name = query.ordering_column_name
|
39
|
+
left = query.recursive_table[column_name]
|
40
|
+
right = query.orderings.row_number_expression
|
41
|
+
|
42
|
+
Arel::Nodes::ArrayConcat.new(left, right)
|
29
43
|
end
|
30
44
|
end
|
31
45
|
end
|
@@ -5,22 +5,26 @@ module ActiveRecord
|
|
5
5
|
module HierarchicalQuery
|
6
6
|
module CTE
|
7
7
|
class UnionTerm
|
8
|
-
# @param [ActiveRecord::HierarchicalQuery::CTE::
|
9
|
-
def initialize(
|
10
|
-
@
|
8
|
+
# @param [ActiveRecord::HierarchicalQuery::CTE::QueryBuilder] builder
|
9
|
+
def initialize(builder)
|
10
|
+
@builder = builder
|
11
|
+
end
|
12
|
+
|
13
|
+
def bind_values
|
14
|
+
non_recursive_term.bind_values + recursive_term.bind_values
|
11
15
|
end
|
12
16
|
|
13
17
|
def arel
|
14
|
-
non_recursive_term.union(:all, recursive_term)
|
18
|
+
non_recursive_term.arel.union(:all, recursive_term.arel)
|
15
19
|
end
|
16
20
|
|
17
21
|
private
|
18
22
|
def recursive_term
|
19
|
-
RecursiveTerm.new(@
|
23
|
+
@rt ||= RecursiveTerm.new(@builder)
|
20
24
|
end
|
21
25
|
|
22
26
|
def non_recursive_term
|
23
|
-
NonRecursiveTerm.new(@
|
27
|
+
@nrt ||= NonRecursiveTerm.new(@builder)
|
24
28
|
end
|
25
29
|
end
|
26
30
|
end
|
@@ -1,21 +1,26 @@
|
|
1
|
+
require 'active_record/hierarchical_query/cte/query_builder'
|
2
|
+
|
1
3
|
module ActiveRecord
|
2
4
|
module HierarchicalQuery
|
3
5
|
class JoinBuilder
|
4
|
-
|
5
|
-
|
6
|
-
# @param [ActiveRecord::HierarchicalQuery::CTE::Query] query
|
6
|
+
# @param [ActiveRecord::HierarchicalQuery::Query] query
|
7
7
|
# @param [ActiveRecord::Relation] join_to
|
8
8
|
# @param [#to_s] subquery_alias
|
9
9
|
def initialize(query, join_to, subquery_alias)
|
10
10
|
@query = query
|
11
|
+
@builder = CTE::QueryBuilder.new(query)
|
11
12
|
@relation = join_to
|
12
13
|
@alias = Arel::Table.new(subquery_alias, ActiveRecord::Base)
|
13
14
|
end
|
14
15
|
|
15
16
|
def build
|
16
17
|
relation = @relation.joins(inner_join.to_sql)
|
18
|
+
# copy bound variables from inner subquery
|
19
|
+
relation.bind_values += bind_values
|
20
|
+
# add ordering by "__order_column"
|
21
|
+
relation.order_values += order_columns if ordered?
|
17
22
|
|
18
|
-
|
23
|
+
relation
|
19
24
|
end
|
20
25
|
|
21
26
|
private
|
@@ -23,6 +28,22 @@ module ActiveRecord
|
|
23
28
|
Arel::Nodes::InnerJoin.new(aliased_subquery, constraint)
|
24
29
|
end
|
25
30
|
|
31
|
+
def aliased_subquery
|
32
|
+
Arel::Nodes::As.new(subquery, @alias)
|
33
|
+
end
|
34
|
+
|
35
|
+
def subquery
|
36
|
+
Arel::Nodes::Grouping.new(cte_arel.ast)
|
37
|
+
end
|
38
|
+
|
39
|
+
def cte_arel
|
40
|
+
@cte_arel ||= @builder.build_arel
|
41
|
+
end
|
42
|
+
|
43
|
+
def constraint
|
44
|
+
Arel::Nodes::On.new(primary_key.eq(foreign_key))
|
45
|
+
end
|
46
|
+
|
26
47
|
def primary_key
|
27
48
|
@relation.table[@relation.klass.primary_key]
|
28
49
|
end
|
@@ -31,16 +52,16 @@ module ActiveRecord
|
|
31
52
|
@alias[@query.klass.primary_key]
|
32
53
|
end
|
33
54
|
|
34
|
-
def
|
35
|
-
|
55
|
+
def bind_values
|
56
|
+
@builder.bind_values
|
36
57
|
end
|
37
58
|
|
38
|
-
def
|
39
|
-
|
59
|
+
def ordered?
|
60
|
+
@query.orderings.any?
|
40
61
|
end
|
41
62
|
|
42
|
-
def
|
43
|
-
|
63
|
+
def order_columns
|
64
|
+
[@query.recursive_table[@query.ordering_column_name].asc]
|
44
65
|
end
|
45
66
|
end
|
46
67
|
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
module ActiveRecord
|
2
|
+
module HierarchicalQuery
|
3
|
+
class Orderings
|
4
|
+
NATURAL_SORT_TYPES = Set[
|
5
|
+
:integer, :float, :decimal,
|
6
|
+
:datetime, :timestamp, :time, :date,
|
7
|
+
:boolean, :itet, :cidr, :ltree
|
8
|
+
]
|
9
|
+
|
10
|
+
include Enumerable
|
11
|
+
|
12
|
+
attr_reader :order_values, :table
|
13
|
+
|
14
|
+
# @param [Array] order_values
|
15
|
+
# @param [Arel::Table] table
|
16
|
+
def initialize(order_values, table)
|
17
|
+
@order_values, @table = order_values, table
|
18
|
+
@values = nil # cached orderings
|
19
|
+
end
|
20
|
+
|
21
|
+
def each(&block)
|
22
|
+
return @values.each(&block) if @values
|
23
|
+
return enum_for(__method__) unless block_given?
|
24
|
+
|
25
|
+
@values = []
|
26
|
+
|
27
|
+
order_values.each do |value|
|
28
|
+
Array.wrap(as_orderings(value)).each do |ordering|
|
29
|
+
@values << ordering
|
30
|
+
|
31
|
+
yield ordering
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
@values
|
36
|
+
end
|
37
|
+
|
38
|
+
# Returns order expression to be inserted into SELECT clauses of both
|
39
|
+
# non-recursive and recursive terms.
|
40
|
+
#
|
41
|
+
# @return [Arel::Nodes::Node] order expression
|
42
|
+
def row_number_expression
|
43
|
+
if raw_ordering?
|
44
|
+
order_attribute
|
45
|
+
else
|
46
|
+
Arel.sql("ROW_NUMBER() OVER (ORDER BY #{map(&:to_sql).join(', ')})")
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def as_orderings(value)
|
52
|
+
case value
|
53
|
+
when Arel::Nodes::Ordering
|
54
|
+
value
|
55
|
+
|
56
|
+
when Arel::Nodes::Node, Arel::Attributes::Attribute
|
57
|
+
value.asc
|
58
|
+
|
59
|
+
when Symbol
|
60
|
+
table[value].asc
|
61
|
+
|
62
|
+
when Hash
|
63
|
+
value.map { |field, dir| table[field].send(dir) }
|
64
|
+
|
65
|
+
when String
|
66
|
+
value.split(',').map do |expr|
|
67
|
+
string_as_ordering(expr)
|
68
|
+
end
|
69
|
+
|
70
|
+
else
|
71
|
+
raise 'Unknown expression in ORDER BY SIBLINGS clause'
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def string_as_ordering(expr)
|
76
|
+
expr.strip!
|
77
|
+
|
78
|
+
if expr.gsub!(/\bdesc\z/i, '')
|
79
|
+
Arel.sql(expr).desc
|
80
|
+
else
|
81
|
+
expr.gsub!(/\basc\z/i, '')
|
82
|
+
Arel.sql(expr).asc
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def raw_ordering?
|
87
|
+
ordered_by_attribute? &&
|
88
|
+
(column = order_column) &&
|
89
|
+
NATURAL_SORT_TYPES.include?(column.type)
|
90
|
+
end
|
91
|
+
|
92
|
+
def ordered_by_attribute?
|
93
|
+
one? && first.ascending? && order_attribute.is_a?(Arel::Attributes::Attribute)
|
94
|
+
end
|
95
|
+
|
96
|
+
def order_attribute
|
97
|
+
first.expr
|
98
|
+
end
|
99
|
+
|
100
|
+
def order_column
|
101
|
+
table = order_attribute.relation
|
102
|
+
|
103
|
+
if table.engine == ActiveRecord::Base
|
104
|
+
columns = table.engine.connection_pool.columns_hash[table.name]
|
105
|
+
else
|
106
|
+
columns = table.engine.columns_hash
|
107
|
+
end
|
108
|
+
|
109
|
+
columns[order_attribute.name.to_s]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -2,12 +2,16 @@
|
|
2
2
|
|
3
3
|
require 'active_support/core_ext/array/extract_options'
|
4
4
|
|
5
|
-
require 'active_record/hierarchical_query/
|
5
|
+
require 'active_record/hierarchical_query/orderings'
|
6
6
|
require 'active_record/hierarchical_query/join_builder'
|
7
|
+
require 'arel/nodes/postgresql'
|
7
8
|
|
8
9
|
module ActiveRecord
|
9
10
|
module HierarchicalQuery
|
10
|
-
class
|
11
|
+
class Query
|
12
|
+
# @api private
|
13
|
+
ORDERING_COLUMN_NAME = '__order_column'.freeze
|
14
|
+
|
11
15
|
# @api private
|
12
16
|
attr_reader :klass,
|
13
17
|
:start_with_value,
|
@@ -19,15 +23,15 @@ module ActiveRecord
|
|
19
23
|
:nocycle_value
|
20
24
|
|
21
25
|
# @api private
|
22
|
-
CHILD_SCOPE_METHODS = :where, :joins, :group, :having
|
26
|
+
CHILD_SCOPE_METHODS = :where, :joins, :group, :having, :bind
|
23
27
|
|
24
28
|
def initialize(klass)
|
25
29
|
@klass = klass
|
26
|
-
@query = CTE::Query.new(self)
|
27
30
|
|
28
|
-
|
31
|
+
# start with :all
|
32
|
+
@start_with_value = klass.__send__(HierarchicalQuery::DELEGATOR_SCOPE)
|
29
33
|
@connect_by_value = nil
|
30
|
-
@child_scope_value = klass
|
34
|
+
@child_scope_value = klass.__send__(HierarchicalQuery::DELEGATOR_SCOPE)
|
31
35
|
@limit_value = nil
|
32
36
|
@offset_value = nil
|
33
37
|
@nocycle_value = false
|
@@ -38,43 +42,49 @@ module ActiveRecord
|
|
38
42
|
#
|
39
43
|
# @example When scope given
|
40
44
|
# MyModel.join_recursive do |hierarchy|
|
41
|
-
# hierarchy.start_with(MyModel.where(:
|
42
|
-
# .connect_by(:
|
45
|
+
# hierarchy.start_with(MyModel.where(parent_id: nil))
|
46
|
+
# .connect_by(id: :parent_id)
|
43
47
|
# end
|
44
48
|
#
|
45
49
|
# @example When Hash given
|
46
50
|
# MyModel.join_recursive do |hierarchy|
|
47
|
-
# hierarchy.start_with(:
|
48
|
-
# .connect_by(:
|
51
|
+
# hierarchy.start_with(parent_id: nil)
|
52
|
+
# .connect_by(id: :parent_id)
|
49
53
|
# end
|
50
54
|
#
|
55
|
+
# @example When String given
|
56
|
+
# MyModel.join_recursive do |hierarchy|
|
57
|
+
# hierararchy.start_with('parent_id = ?', 1)
|
58
|
+
# .connect_by(id: :parent_id)
|
59
|
+
# end
|
60
|
+
#
|
51
61
|
# @example When block given
|
52
62
|
# MyModel.join_recursive do |hierarchy|
|
53
|
-
# hierarchy.start_with { |root| root.where(:
|
54
|
-
# .connect_by(:
|
63
|
+
# hierarchy.start_with { |root| root.where(parent_id: nil) }
|
64
|
+
# .connect_by(id: :parent_id)
|
55
65
|
# end
|
56
66
|
#
|
57
67
|
# @example When block with arity=0 given
|
58
68
|
# MyModel.join_recursive do |hierarchy|
|
59
|
-
# hierarchy.start_with { where(:
|
60
|
-
# .connect_by(:
|
69
|
+
# hierarchy.start_with { where(parent_id: nil) }
|
70
|
+
# .connect_by(id: :parent_id)
|
61
71
|
# end
|
62
72
|
#
|
63
73
|
# @example Specify columns for root relation (PostgreSQL-specific)
|
64
74
|
# MyModel.join_recursive do |hierarchy|
|
65
75
|
# hierarchy.start_with { select('ARRAY[id] AS _path') }
|
66
|
-
# .connect_by(:
|
67
|
-
# .select('_path || id', :
|
76
|
+
# .connect_by(id: :parent_id)
|
77
|
+
# .select('_path || id', start_with: false) # `start_with: false` tells not to include this expression into START WITH clause
|
68
78
|
# end
|
69
79
|
#
|
70
|
-
# @param [ActiveRecord::Relation, Hash, nil] scope root scope (optional).
|
71
|
-
# @return [ActiveRecord::HierarchicalQuery::
|
72
|
-
def start_with(scope = nil, &block)
|
80
|
+
# @param [ActiveRecord::Relation, Hash, String, nil] scope root scope (optional).
|
81
|
+
# @return [ActiveRecord::HierarchicalQuery::Query] self
|
82
|
+
def start_with(scope = nil, *arguments, &block)
|
73
83
|
raise ArgumentError, 'START WITH: scope or block expected, none given' unless scope || block
|
74
84
|
|
75
85
|
case scope
|
76
|
-
when Hash
|
77
|
-
@start_with_value = klass.where(scope)
|
86
|
+
when Hash, String
|
87
|
+
@start_with_value = klass.where(scope, *arguments)
|
78
88
|
|
79
89
|
when ActiveRecord::Relation
|
80
90
|
@start_with_value = scope
|
@@ -103,7 +113,7 @@ module ActiveRecord
|
|
103
113
|
# @example Specify relationship with Hash (traverse descendants)
|
104
114
|
# MyModel.join_recursive do |hierarchy|
|
105
115
|
# # join child rows with condition `parent.id = child.parent_id`
|
106
|
-
# hierarchy.connect_by(:
|
116
|
+
# hierarchy.connect_by(id: :parent_id)
|
107
117
|
# end
|
108
118
|
#
|
109
119
|
# @example Specify relationship with block (traverse descendants)
|
@@ -117,7 +127,7 @@ module ActiveRecord
|
|
117
127
|
# @yieldparam [Arel::Table] parent parent rows table instance.
|
118
128
|
# @yieldparam [Arel::Table] child child rows table instance.
|
119
129
|
# @yieldreturn [Arel::Nodes::Node] relationship condition expressed as Arel node.
|
120
|
-
# @return [ActiveRecord::HierarchicalQuery::
|
130
|
+
# @return [ActiveRecord::HierarchicalQuery::Query] self
|
121
131
|
def connect_by(conditions = nil, &block)
|
122
132
|
# convert hash to block which returns Arel node
|
123
133
|
if conditions
|
@@ -136,7 +146,7 @@ module ActiveRecord
|
|
136
146
|
#
|
137
147
|
# @param [Array<Symbol, String, Arel::Attributes::Attribute, Arel::Nodes::Node>] columns
|
138
148
|
# @option columns [true, false] :start_with include given columns to START WITH clause (true by default)
|
139
|
-
# @return [ActiveRecord::HierarchicalQuery::
|
149
|
+
# @return [ActiveRecord::HierarchicalQuery::Query] self
|
140
150
|
def select(*columns)
|
141
151
|
options = columns.extract_options!
|
142
152
|
|
@@ -166,6 +176,7 @@ module ActiveRecord
|
|
166
176
|
# @!method joins(*tables)
|
167
177
|
# @!method group(*values)
|
168
178
|
# @!method having(*conditions)
|
179
|
+
# @!method bind(value)
|
169
180
|
CHILD_SCOPE_METHODS.each do |method|
|
170
181
|
define_method(method) do |*args|
|
171
182
|
@child_scope_value = @child_scope_value.public_send(method, *args)
|
@@ -177,7 +188,7 @@ module ActiveRecord
|
|
177
188
|
# Specifies a limit for the number of records to retrieve.
|
178
189
|
#
|
179
190
|
# @param [Fixnum] value
|
180
|
-
# @return [ActiveRecord::HierarchicalQuery::
|
191
|
+
# @return [ActiveRecord::HierarchicalQuery::Query] self
|
181
192
|
def limit(value)
|
182
193
|
@limit_value = value
|
183
194
|
|
@@ -187,7 +198,7 @@ module ActiveRecord
|
|
187
198
|
# Specifies the number of rows to skip before returning row
|
188
199
|
#
|
189
200
|
# @param [Fixnum] value
|
190
|
-
# @return [ActiveRecord::HierarchicalQuery::
|
201
|
+
# @return [ActiveRecord::HierarchicalQuery::Query] self
|
191
202
|
def offset(value)
|
192
203
|
@offset_value = value
|
193
204
|
|
@@ -198,18 +209,18 @@ module ActiveRecord
|
|
198
209
|
#
|
199
210
|
# @example
|
200
211
|
# MyModel.join_recursive do |hierarchy|
|
201
|
-
# hierarchy.connect_by(:
|
212
|
+
# hierarchy.connect_by(id: :parent_id)
|
202
213
|
# .order_siblings(:name)
|
203
214
|
# end
|
204
215
|
#
|
205
216
|
# @example
|
206
217
|
# MyModel.join_recursive do |hierarchy|
|
207
|
-
# hierarchy.connect_by(:
|
218
|
+
# hierarchy.connect_by(id: :parent_id)
|
208
219
|
# .order_siblings('name DESC, created_at ASC')
|
209
220
|
# end
|
210
221
|
#
|
211
222
|
# @param [<Symbol, String, Arel::Nodes::Node, Arel::Attributes::Attribute>] columns
|
212
|
-
# @return [ActiveRecord::HierarchicalQuery::
|
223
|
+
# @return [ActiveRecord::HierarchicalQuery::Query] self
|
213
224
|
def order_siblings(*columns)
|
214
225
|
@order_values += columns
|
215
226
|
|
@@ -221,7 +232,7 @@ module ActiveRecord
|
|
221
232
|
# endless loops if your tree could contain cycles.
|
222
233
|
#
|
223
234
|
# @param [true, false] value
|
224
|
-
# @return [ActiveRecord::HierarchicalQuery::
|
235
|
+
# @return [ActiveRecord::HierarchicalQuery::Query] self
|
225
236
|
def nocycle(value = true)
|
226
237
|
@nocycle_value = value
|
227
238
|
self
|
@@ -232,25 +243,26 @@ module ActiveRecord
|
|
232
243
|
#
|
233
244
|
# @example
|
234
245
|
# MyModel.join_recursive do |hierarchy|
|
235
|
-
# hierarchy.connect_by(:
|
236
|
-
# .start_with(:
|
246
|
+
# hierarchy.connect_by(id: :parent_id)
|
247
|
+
# .start_with(parent_id: nil) { select(:depth) }
|
237
248
|
# .select(hierarchy.table[:depth])
|
238
249
|
# .where(hierarchy.prior[:depth].lteq 1)
|
239
250
|
# end
|
240
251
|
#
|
241
252
|
# @return [Arel::Table]
|
242
253
|
def prior
|
243
|
-
@
|
254
|
+
@recursive_table ||= Arel::Table.new("#{table.name}__recursive")
|
244
255
|
end
|
245
256
|
alias_method :previous, :prior
|
257
|
+
alias_method :recursive_table, :prior
|
246
258
|
|
247
259
|
# Returns object representing child rows table,
|
248
260
|
# so it could be used in complex WHEREs.
|
249
261
|
#
|
250
262
|
# @example
|
251
263
|
# MyModel.join_recursive do |hierarchy|
|
252
|
-
# hierarchy.connect_by(:
|
253
|
-
# .start_with(:
|
264
|
+
# hierarchy.connect_by(id: :parent_id)
|
265
|
+
# .start_with(parent_id: nil) { select(:depth) }
|
254
266
|
# .select(hierarchy.table[:depth])
|
255
267
|
# .where(hierarchy.prior[:depth].lteq 1)
|
256
268
|
# end
|
@@ -258,19 +270,37 @@ module ActiveRecord
|
|
258
270
|
@klass.arel_table
|
259
271
|
end
|
260
272
|
|
273
|
+
# @return [Arel::Nodes::Node]
|
274
|
+
# @api private
|
275
|
+
def join_conditions
|
276
|
+
connect_by_value.call(recursive_table, table)
|
277
|
+
end
|
278
|
+
|
279
|
+
# @return [ActiveRecord::HierarchicalQuery::Orderings]
|
280
|
+
# @api private
|
281
|
+
def orderings
|
282
|
+
@orderings ||= Orderings.new(order_values, table)
|
283
|
+
end
|
284
|
+
|
285
|
+
# @api private
|
286
|
+
def ordering_column_name
|
287
|
+
ORDERING_COLUMN_NAME
|
288
|
+
end
|
289
|
+
|
261
290
|
# Builds recursive query and joins it to given +relation+.
|
262
291
|
#
|
263
292
|
# @api private
|
264
293
|
# @param [ActiveRecord::Relation] relation
|
265
294
|
# @param [Hash] join_options
|
266
295
|
# @option join_options [#to_s] :as joined table alias
|
296
|
+
# @api private
|
267
297
|
def join_to(relation, join_options = {})
|
268
298
|
raise 'Recursive query requires CONNECT BY clause, please use #connect_by method' unless
|
269
299
|
connect_by_value
|
270
300
|
|
271
301
|
table_alias = join_options.fetch(:as, "#{table.name}__recursive")
|
272
302
|
|
273
|
-
JoinBuilder.new(
|
303
|
+
JoinBuilder.new(self, relation, table_alias).build
|
274
304
|
end
|
275
305
|
|
276
306
|
private
|