activerecord-hierarchical_query 0.0.8 → 0.1.0

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: 71bc88ee032e123ae1e612a9a589e5ee4b3f87b2
4
- data.tar.gz: e8dea5c43cd1b41450635836f4a56bdcb95a77ce
3
+ metadata.gz: 35f6d79b615d8ca821c2258b9287f10044ed997c
4
+ data.tar.gz: 4dc56871743b3a2d9bd2dc920d1195894dfc8aa5
5
5
  SHA512:
6
- metadata.gz: bd73d0c3ccd15dc9217e629db225993c5fc7f73b3375804bfa80abd72a530906a915644b0080fa4a7f796f1b72e3078b3770a9980a62cbba4687d96a94a35870
7
- data.tar.gz: 6d58bbd3b65d443482ce233fff71aafa2d03509da62130518c5fa4fb541b5f6bf97e98d90a6ab85cf81e7bc385e6f1cdb56b24a21b12f461f93694a1cd781f05
6
+ metadata.gz: 7cd10f34571215ba462f81ebd552667a432f38bfd7f84eb4cc25c05dcc006623c0b7f4e0f4f24211f1bd2874ce4458bee0bec1a43db61109cd7227105606c4fc
7
+ data.tar.gz: 2936034c375afb978a9c5b5a8f7c69cc4cd36690315affa3c1e3fde2433b84fbf20eb3a07cac37461f672ea5f753702c4045cf1566c1da6df3cdcce393fe8252
data/README.md CHANGED
@@ -244,6 +244,17 @@ Category.join_recursive do |query|
244
244
  end
245
245
  ```
246
246
 
247
+ ## DISTINCT
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`
250
+ ```ruby
251
+ Category.join_recursive do |query|
252
+ query.connect_by(id: :parent_id)
253
+ .start_with(id: node_1.id)
254
+ .distinct
255
+ end
256
+ ```
257
+
247
258
  ## Generated SQL queries
248
259
 
249
260
  Under the hood this extensions builds `INNER JOIN` to recursive subquery.
@@ -297,7 +308,7 @@ ORDER BY "categories__recursive"."__order_column" ASC
297
308
 
298
309
  If you want to use a `LEFT OUTER JOIN` instead of an `INNER JOIN`, add a query option for `outer_join_hierarchical`. This option allows the query to return non-hierarchical entries:
299
310
  ```ruby
300
- .join_recursive(outer_join_hierarchical: true)
311
+ .join_recursive(outer_join_hierarchical: true)
301
312
  ```
302
313
 
303
314
  If, when joining the recursive view to the main table, you want to change the foreign_key on the recursive view from the primary key of the main table to another column:
@@ -58,7 +58,11 @@ module ActiveRecord
58
58
  end
59
59
 
60
60
  def build_select
61
- @arel.project(recursive_table[Arel.star])
61
+ if @query.distinct_value == true
62
+ @arel.project(recursive_table[Arel.star]).distinct
63
+ else
64
+ @arel.project(recursive_table[Arel.star])
65
+ end
62
66
  end
63
67
 
64
68
  def build_limits
@@ -79,4 +83,4 @@ module ActiveRecord
79
83
  end
80
84
  end
81
85
  end
82
- end
86
+ end
@@ -6,19 +6,20 @@ module ActiveRecord
6
6
  # @param [ActiveRecord::HierarchicalQuery::Query] query
7
7
  # @param [ActiveRecord::Relation] join_to
8
8
  # @param [#to_s] subquery_alias
9
- def initialize(query, join_to, subquery_alias, join_options = {})
9
+ def initialize(query, join_to, subquery_alias, options = {})
10
10
  @query = query
11
11
  @builder = CTE::QueryBuilder.new(query)
12
12
  @relation = join_to
13
13
  @alias = Arel::Table.new(subquery_alias, ActiveRecord::Base)
14
- @join_options = join_options
14
+ @options = options
15
15
  end
16
16
 
17
17
  def build
18
18
  # outer joins to include non-hierarchical entries if specified
19
19
  # default option when flag is not specified is to include only entries participating
20
20
  # in a hierarchy
21
- join_sql = @join_options[:outer_join_hierarchical].present? ? outer_join.to_sql : inner_join.to_sql
21
+ join_sql = @options[:outer_join_hierarchical] == true ? outer_join.to_sql : inner_join.to_sql
22
+
22
23
  relation = @relation.joins(join_sql)
23
24
 
24
25
  # copy bound variables from inner subquery (remove duplicates)
@@ -59,7 +60,7 @@ module ActiveRecord
59
60
  end
60
61
 
61
62
  def custom_foreign_key
62
- @join_options[:foreign_key]
63
+ @options[:foreign_key]
63
64
  end
64
65
 
65
66
  def foreign_key
@@ -20,7 +20,8 @@ module ActiveRecord
20
20
  :limit_value,
21
21
  :offset_value,
22
22
  :order_values,
23
- :nocycle_value
23
+ :nocycle_value,
24
+ :distinct_value
24
25
 
25
26
  # @api private
26
27
  CHILD_SCOPE_METHODS = :where, :joins, :group, :having, :bind
@@ -36,6 +37,7 @@ module ActiveRecord
36
37
  @offset_value = nil
37
38
  @nocycle_value = false
38
39
  @order_values = []
40
+ @distinct_value = false
39
41
  end
40
42
 
41
43
  # Specify root scope of the hierarchy.
@@ -270,6 +272,14 @@ module ActiveRecord
270
272
  @klass.arel_table
271
273
  end
272
274
 
275
+ # Turn on select distinct option in the CTE.
276
+ #
277
+ # @return [ActiveRecord::HierarchicalQuery::Query] self
278
+ def distinct
279
+ @distinct_value = true
280
+ self
281
+ end
282
+
273
283
  # @return [Arel::Nodes::Node]
274
284
  # @api private
275
285
  def join_conditions
@@ -1,5 +1,5 @@
1
1
  module ActiveRecord
2
2
  module HierarchicalQuery
3
- VERSION = '0.0.8'
3
+ VERSION = '0.1.0'
4
4
  end
5
5
  end
@@ -214,14 +214,6 @@ describe ActiveRecord::HierarchicalQuery do
214
214
  end
215
215
  end
216
216
 
217
- describe ':outer_join_hierarchical' do
218
- it 'build an outer join' do
219
- expect(
220
- klass.join_recursive(outer_join_hierarchical: true) { connect_by(id: :parent_id) }.to_sql
221
- ).to match /LEFT OUTER JOIN/
222
- end
223
- end
224
-
225
217
  describe ':foreign_key' do
226
218
  it 'uses described foreign_key when joining table to recursive view' do
227
219
  expect(
@@ -229,5 +221,62 @@ describe ActiveRecord::HierarchicalQuery do
229
221
  ).to match /categories\"\.\"id\" = \"categories__recursive\"\.\"some_column/
230
222
  end
231
223
  end
224
+
225
+ describe ':outer_join_hierarchical' do
226
+ subject { klass.join_recursive(outer_join_hierarchical: value) { connect_by(id: :parent_id) }.to_sql }
227
+
228
+ let(:value) { true }
229
+ let(:inner_join) {
230
+ /INNER JOIN \(WITH RECURSIVE \"categories__recursive\"/
231
+ }
232
+
233
+ it 'builds an outer join' do
234
+ expect(subject).to match /LEFT OUTER JOIN \(WITH RECURSIVE \"categories__recursive\"/
235
+ end
236
+
237
+ context 'value is false' do
238
+ let(:value) { false }
239
+
240
+ it 'builds an inner join' do
241
+ expect(subject).to match inner_join
242
+ end
243
+ end
244
+
245
+ context 'value is a string' do
246
+ let(:value) { 'foo' }
247
+
248
+ it 'builds an inner join' do
249
+ expect(subject).to match inner_join
250
+ end
251
+ end
252
+
253
+ context 'key is absent' do
254
+ subject { klass.join_recursive { connect_by(id: :parent_id) }.to_sql }
255
+
256
+ it 'builds an inner join' do
257
+ expect(subject).to match inner_join
258
+ end
259
+ end
260
+ end
261
+ end
262
+
263
+ describe ':distinct query method' do
264
+ subject { klass.join_recursive { connect_by(id: :parent_id).distinct }.to_sql }
265
+
266
+ let(:select) {
267
+ /SELECT \"categories__recursive\"/
268
+ }
269
+
270
+ it 'selects using a distinct option after joining table to recursive view' do
271
+ expect(subject).to match /SELECT DISTINCT \"categories__recursive\"/
272
+ end
273
+
274
+ context 'distinct method is absent' do
275
+ subject { klass.join_recursive { connect_by(id: :parent_id) }.to_sql }
276
+
277
+ it 'selects without using a distinct' do
278
+ expect(subject).to match select
279
+ end
280
+ end
232
281
  end
233
282
  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.0.8
4
+ version: 0.1.0
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-07-07 00:00:00.000000000 Z
11
+ date: 2016-07-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -141,7 +141,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
141
141
  version: '0'
142
142
  requirements: []
143
143
  rubyforge_project:
144
- rubygems_version: 2.4.8
144
+ rubygems_version: 2.4.3
145
145
  signing_key:
146
146
  specification_version: 4
147
147
  summary: Recursively traverse trees using a single SQL query
@@ -152,3 +152,4 @@ test_files:
152
152
  - spec/schema.rb
153
153
  - spec/spec_helper.rb
154
154
  - spec/support/models.rb
155
+ has_rdoc: