activerecord-hierarchical_query 0.1.1 → 0.1.2
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 +9 -1
- data/lib/active_record/hierarchical_query/cte/query_builder.rb +2 -2
- data/lib/active_record/hierarchical_query/cte/union_term.rb +3 -7
- data/lib/active_record/hierarchical_query/join_builder.rb +17 -8
- data/lib/active_record/hierarchical_query/version.rb +1 -1
- data/spec/active_record/hierarchical_query_spec.rb +22 -0
- data/spec/schema.rb +6 -1
- data/spec/support/models.rb +6 -1
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c51bb399108f367e30e8bde8ea46171451212228
|
4
|
+
data.tar.gz: 385d34aa8caa4777f50e0a2c8a7b9d84c0c30dd1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d3bad1f4d790f159e86c1870184e43afc7b3c196394b8330d52b8cd25a582ba098b609cf2193213017838fb426f2cdebf22c53ce8b372bb211cb272c95bd7332
|
7
|
+
data.tar.gz: 02b43b6cfb15595885d4d326b6ddd6cced8c34fc7d8dff3c7c1aa11eca5119852276b7d3238f78f13f6634bc9fd62b8e5eaf72505a30aff1f201d4c50d60b731
|
data/README.md
CHANGED
@@ -246,7 +246,7 @@ end
|
|
246
246
|
|
247
247
|
## DISTINCT
|
248
248
|
By default, the union term in the Common Table Expression uses a `UNION ALL`. If you want
|
249
|
-
to `SELECT DISTINCT` CTE values, add a query option for `distinct
|
249
|
+
to `SELECT DISTINCT` CTE values, add a query option for `distinct`:
|
250
250
|
```ruby
|
251
251
|
Category.join_recursive do |query|
|
252
252
|
query.connect_by(id: :parent_id)
|
@@ -255,6 +255,14 @@ Category.join_recursive do |query|
|
|
255
255
|
end
|
256
256
|
```
|
257
257
|
|
258
|
+
If you want to join CTE terms by `UNION DISTINCT`, pass an option to `join_recursive`:
|
259
|
+
```ruby
|
260
|
+
Category.join_recursive(union_type: :distinct) do |query|
|
261
|
+
query.connect_by(id: :parent_id)
|
262
|
+
.start_with(id: node_1.id)
|
263
|
+
end
|
264
|
+
```
|
265
|
+
|
258
266
|
## Generated SQL queries
|
259
267
|
|
260
268
|
Under the hood this extensions builds `INNER JOIN` to recursive subquery.
|
@@ -56,11 +56,11 @@ module ActiveRecord
|
|
56
56
|
end
|
57
57
|
|
58
58
|
def union_term
|
59
|
-
@union_term ||= UnionTerm.new(self)
|
59
|
+
@union_term ||= UnionTerm.new(self, @options)
|
60
60
|
end
|
61
61
|
|
62
62
|
def build_select
|
63
|
-
if @query.distinct_value
|
63
|
+
if @query.distinct_value
|
64
64
|
@arel.project(recursive_table[Arel.star]).distinct
|
65
65
|
else
|
66
66
|
@arel.project(recursive_table[Arel.star])
|
@@ -6,8 +6,9 @@ module ActiveRecord
|
|
6
6
|
module CTE
|
7
7
|
class UnionTerm
|
8
8
|
# @param [ActiveRecord::HierarchicalQuery::CTE::QueryBuilder] builder
|
9
|
-
def initialize(builder)
|
9
|
+
def initialize(builder, options = {})
|
10
10
|
@builder = builder
|
11
|
+
@union_type = options.fetch(:union_type, :all)
|
11
12
|
end
|
12
13
|
|
13
14
|
def bind_values
|
@@ -19,12 +20,7 @@ module ActiveRecord
|
|
19
20
|
end
|
20
21
|
|
21
22
|
private
|
22
|
-
|
23
|
-
def union_type
|
24
|
-
return @builder.options[:union_type] if @builder.options[:union_type].present?
|
25
|
-
|
26
|
-
:all
|
27
|
-
end
|
23
|
+
attr_reader :union_type
|
28
24
|
|
29
25
|
def recursive_term
|
30
26
|
@rt ||= RecursiveTerm.new(@builder)
|
@@ -6,6 +6,7 @@ module ActiveRecord
|
|
6
6
|
# @param [ActiveRecord::HierarchicalQuery::Query] query
|
7
7
|
# @param [ActiveRecord::Relation] join_to
|
8
8
|
# @param [#to_s] subquery_alias
|
9
|
+
# @param [Hash] options (:outer_join_hierarchical, :union_type)
|
9
10
|
def initialize(query, join_to, subquery_alias, options = {})
|
10
11
|
@query = query
|
11
12
|
@builder = CTE::QueryBuilder.new(query, options: options)
|
@@ -15,13 +16,7 @@ module ActiveRecord
|
|
15
16
|
end
|
16
17
|
|
17
18
|
def build
|
18
|
-
|
19
|
-
# default option when flag is not specified is to include only entries participating
|
20
|
-
# in a hierarchy
|
21
|
-
join_sql = @options[:outer_join_hierarchical] == true ? outer_join.to_sql : inner_join.to_sql
|
22
|
-
|
23
|
-
relation = @relation.joins(join_sql)
|
24
|
-
|
19
|
+
relation = @relation.joins(joined_arel_node)
|
25
20
|
# copy bound variables from inner subquery (remove duplicates)
|
26
21
|
relation.bind_values |= bind_values
|
27
22
|
# add ordering by "__order_column"
|
@@ -31,6 +26,10 @@ module ActiveRecord
|
|
31
26
|
end
|
32
27
|
|
33
28
|
private
|
29
|
+
def joined_arel_node
|
30
|
+
@options[:outer_join_hierarchical] == true ? outer_join : inner_join
|
31
|
+
end
|
32
|
+
|
34
33
|
def inner_join
|
35
34
|
Arel::Nodes::InnerJoin.new(aliased_subquery, constraint)
|
36
35
|
end
|
@@ -40,7 +39,7 @@ module ActiveRecord
|
|
40
39
|
end
|
41
40
|
|
42
41
|
def aliased_subquery
|
43
|
-
|
42
|
+
SubqueryAlias.new(subquery, @alias)
|
44
43
|
end
|
45
44
|
|
46
45
|
def subquery
|
@@ -78,6 +77,16 @@ module ActiveRecord
|
|
78
77
|
def order_columns
|
79
78
|
[@query.recursive_table[@query.ordering_column_name].asc]
|
80
79
|
end
|
80
|
+
|
81
|
+
# This node is required to support joins to aliased Arel nodes
|
82
|
+
class SubqueryAlias < Arel::Nodes::As
|
83
|
+
attr_reader :table_name
|
84
|
+
|
85
|
+
def initialize(subquery, alias_node)
|
86
|
+
super
|
87
|
+
@table_name = alias_node.name
|
88
|
+
end
|
89
|
+
end
|
81
90
|
end
|
82
91
|
end
|
83
92
|
end
|
@@ -306,4 +306,26 @@ describe ActiveRecord::HierarchicalQuery do
|
|
306
306
|
end
|
307
307
|
end
|
308
308
|
end
|
309
|
+
|
310
|
+
describe 'Testing bind variables' do
|
311
|
+
let!(:article) { Article.create!(category: child_2, title: 'Alpha') }
|
312
|
+
|
313
|
+
let(:subquery) do
|
314
|
+
klass.join_recursive do |query|
|
315
|
+
query.
|
316
|
+
start_with(parent_id: child_1.id).
|
317
|
+
connect_by(id: :parent_id)
|
318
|
+
end
|
319
|
+
end
|
320
|
+
|
321
|
+
let(:outer_query) do
|
322
|
+
Article.where(category_id: subquery, title: 'Alpha')
|
323
|
+
end
|
324
|
+
|
325
|
+
subject(:result) { outer_query.to_a }
|
326
|
+
|
327
|
+
it 'returns result without throwing an error' do
|
328
|
+
expect(result).to include(article)
|
329
|
+
end
|
330
|
+
end
|
309
331
|
end
|
data/spec/schema.rb
CHANGED
data/spec/support/models.rb
CHANGED
@@ -16,6 +16,7 @@ class Category < ActiveRecord::Base
|
|
16
16
|
|
17
17
|
belongs_to :parent, class_name: 'Category'
|
18
18
|
has_many :children, class_name: 'Category'
|
19
|
+
has_many :articles
|
19
20
|
|
20
21
|
before_save :generate_name, unless: :name?
|
21
22
|
before_save :count_depth
|
@@ -36,4 +37,8 @@ class Category < ActiveRecord::Base
|
|
36
37
|
def ancestors
|
37
38
|
parent ? parent.ancestors + [parent] : []
|
38
39
|
end
|
39
|
-
end
|
40
|
+
end
|
41
|
+
|
42
|
+
class Article < ActiveRecord::Base
|
43
|
+
belongs_to :category
|
44
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activerecord-hierarchical_query
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexei Mikhailov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-08-
|
11
|
+
date: 2016-08-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -17,6 +17,9 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: 3.1.0
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 5.0.0
|
20
23
|
type: :runtime
|
21
24
|
prerelease: false
|
22
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -24,6 +27,9 @@ dependencies:
|
|
24
27
|
- - ">="
|
25
28
|
- !ruby/object:Gem::Version
|
26
29
|
version: 3.1.0
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 5.0.0
|
27
33
|
- !ruby/object:Gem::Dependency
|
28
34
|
name: bundler
|
29
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -152,4 +158,3 @@ test_files:
|
|
152
158
|
- spec/schema.rb
|
153
159
|
- spec/spec_helper.rb
|
154
160
|
- spec/support/models.rb
|
155
|
-
has_rdoc:
|