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 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: