activerecord-hierarchical_query 0.0.8 → 0.1.0

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