activerecord-hierarchical_query 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f07d2ec47ffaa6e83ba6fb27cb027773298ad8dc
4
- data.tar.gz: cde6840a2e9f1334185a747ac5467850653dfa3d
3
+ metadata.gz: c51bb399108f367e30e8bde8ea46171451212228
4
+ data.tar.gz: 385d34aa8caa4777f50e0a2c8a7b9d84c0c30dd1
5
5
  SHA512:
6
- metadata.gz: 3f009457c44deec3eef278505d1e898141fce5e730ddf9245783cfa19efa4245b5c2ed4c4e7b61df45307e476fcbf2138aabc714815d96fc83048e9b35c0c12c
7
- data.tar.gz: cbcdb8aa27269c2a6011b1c35a160a280af281c23ce7c2e07bdac044703f26bf06a733f7fafc78e4a9addc4f2493b03690202a880a65d6e15b798e225090c929
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 == true
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
- # outer joins to include non-hierarchical entries if specified
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
- Arel::Nodes::As.new(subquery, @alias)
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
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module HierarchicalQuery
3
- VERSION = '0.1.1'
3
+ VERSION = '0.1.2'
4
4
  end
5
5
  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
@@ -7,4 +7,9 @@ ActiveRecord::Schema.define(version: 0) do
7
7
  t.column :depth, :integer
8
8
  t.column :position, :integer
9
9
  end
10
- end
10
+
11
+ create_table :articles, force: true do |t|
12
+ t.column :category_id, :integer
13
+ t.column :title, :string
14
+ end
15
+ end
@@ -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.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-16 00:00:00.000000000 Z
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: