composite_primary_keys 8.1.3 → 8.1.4

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: 5dcd8c948f14181d3e5ebb97a5a79f124e7e9cef
4
- data.tar.gz: 435b1a7ffaf2c481b09b268fd28585112a092f44
3
+ metadata.gz: 8ca795714eef0beaa1a0e91a07b09b1735b12242
4
+ data.tar.gz: 41e87e3f7ae758e975809e56d8c7a3396d604f4c
5
5
  SHA512:
6
- metadata.gz: c38c11665ea24815069cd8c2c14701108cc1516663cba835eb044db3ebcabc26d46dee9db88d9c2c6923d992ee3c0b8293825ca3f2af88411641a1ed0a4bff67
7
- data.tar.gz: cd22418296a7ffbd27c5ece78c7bc835be47bd50b4a4ed51c96bea564225fa3ebc9782fb60ba6b02a76d7784074c56c2df82d7d3e443cd7e17053ab8a25b43f9
6
+ metadata.gz: 1f142511ba73692d9599bafdf78b26e61405a76b34b4de455f313a248fec5b6a75240f56eb9f6ef87ec299edd9db3ac5fc2b7849e51ed84b1efb16e852fa62c5
7
+ data.tar.gz: ebf3f4281ee1c7c372a8b035a2e7a2a8651f7972a673c38555de38449b05d781696971eb7f507f912322c4527a28664216d4f8c69cfaafb5d11f09a71c8aea20
@@ -1,3 +1,8 @@
1
+ == 8.1.4 (2016-07-27)
2
+
3
+ * Create OR predicates in a nicely balanced tree fixing #320 (Nathan Samson)
4
+ * Fix find in batches (apurvis)
5
+
1
6
  == 8.1.3 (2016-04-16)
2
7
 
3
8
  * Make CPK work for Arel::Attributes::Attribute (Rick Xing)
@@ -53,6 +53,70 @@ module ActiveRecord
53
53
  def composite?
54
54
  false
55
55
  end
56
+
57
+ def find_in_batches(options = {})
58
+ return super unless primary_key.is_a?(Array)
59
+
60
+ # Unfortunately .count uses a subquery temp table, which is a big problem when your table is large
61
+ number_of_rows = count(primary_key.first)
62
+ batch_size = options[:batch_size] || 100000
63
+ row_number = 0
64
+
65
+ while row_number < number_of_rows
66
+ end_row_number = row_number + batch_size - 1
67
+ end_row_number = number_of_rows - 1 if end_row_number > number_of_rows - 1
68
+
69
+ # Force the necessary sorting; AR as is will sort a PK table incorrectly
70
+ start_key = order(*primary_key).
71
+ offset(row_number).
72
+ first.
73
+ attributes.
74
+ slice(*primary_key)
75
+
76
+ end_key = order(*(primary_key.map { |k| "#{k} ASC" })).
77
+ offset(end_row_number).
78
+ first.
79
+ attributes.
80
+ slice(*primary_key)
81
+
82
+ relation = self
83
+ lower_bounds = []
84
+ upper_bounds = []
85
+
86
+ # Iterate through the PKs positionally; when we have found a discrepancy between start and end
87
+ # then we know that's where the boundaries are
88
+ primary_key.each do |col|
89
+ if start_key[col] == end_key[col]
90
+ relation = relation.where("#{col} = '#{start_key[col]}'")
91
+ else
92
+ lower_bounds << [col, start_key[col]]
93
+ upper_bounds << [col, end_key[col]]
94
+ end
95
+ end
96
+
97
+ relation = relation.where(build_batch_case(lower_bounds, '>')) unless lower_bounds.empty?
98
+ relation = relation.where(build_batch_case(upper_bounds, '<')) unless upper_bounds.empty?
99
+
100
+ yield(relation.order(*primary_key))
101
+
102
+ row_number = end_row_number + 1
103
+ end
104
+ end
105
+
106
+ private
107
+
108
+ def build_batch_case(bounds, operator)
109
+ bounds = bounds.dup
110
+ bound = bounds.shift
111
+ if bounds.empty?
112
+ "#{bound[0]} #{operator}= '#{bound[1]}' "
113
+ else
114
+ sql_case = "CASE WHEN #{bound[0]} = '#{bound[1]}' THEN "
115
+ sql_case += build_batch_case(bounds, operator)
116
+ sql_case += "ELSE #{bound[0]} #{operator} '#{bound[1]}' END "
117
+ sql_case
118
+ end
119
+ end
56
120
  end
57
121
 
58
122
  def composite?
@@ -8,17 +8,22 @@ module CompositePrimaryKeys
8
8
  end
9
9
  end
10
10
 
11
- def cpk_or_predicate(predicates)
11
+ def cpk_or_predicate(predicates, group = true)
12
12
  if predicates.length <= 1
13
13
  predicates.first
14
14
  else
15
- predicates_copy = predicates.dup
16
- predicate = predicates_copy.shift
15
+ split_point = predicates.length / 2
16
+ predicates_first_half = predicates[0...split_point]
17
+ predicates_second_half = predicates[split_point..-1]
17
18
 
18
- or_predicate = predicates_copy.inject(predicate) do |mem, predicate|
19
- ::Arel::Nodes::Or.new(mem, predicate)
19
+ or_predicate = ::Arel::Nodes::Or.new(cpk_or_predicate(predicates_first_half, false),
20
+ cpk_or_predicate(predicates_second_half, false))
21
+
22
+ if group
23
+ ::Arel::Nodes::Grouping.new(or_predicate)
24
+ else
25
+ or_predicate
20
26
  end
21
- ::Arel::Nodes::Grouping.new(or_predicate)
22
27
  end
23
28
  end
24
29
 
@@ -53,4 +58,4 @@ ActiveRecord::Associations::JoinDependency::JoinAssociation.send(:include, Compo
53
58
  ActiveRecord::Associations::Preloader::Association.send(:include, CompositePrimaryKeys::Predicates)
54
59
  ActiveRecord::Associations::HasManyThroughAssociation.send(:include, CompositePrimaryKeys::Predicates)
55
60
  ActiveRecord::Relation.send(:include, CompositePrimaryKeys::Predicates)
56
- ActiveRecord::PredicateBuilder.send(:extend, CompositePrimaryKeys::Predicates)
61
+ ActiveRecord::PredicateBuilder.send(:extend, CompositePrimaryKeys::Predicates)
@@ -2,7 +2,7 @@ module CompositePrimaryKeys
2
2
  module VERSION
3
3
  MAJOR = 8
4
4
  MINOR = 1
5
- TINY = 3
5
+ TINY = 4
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
@@ -1,12 +1,12 @@
1
- class ReferenceType < ActiveRecord::Base
2
- self.primary_key = :reference_type_id
3
- has_many :reference_codes, :foreign_key => "reference_type_id", :dependent => :destroy
4
- accepts_nested_attributes_for :reference_codes
5
-
6
- validates_presence_of :type_label, :abbreviation
7
- validates_uniqueness_of :type_label
8
-
9
- before_destroy do |record|
10
- a = record
11
- end
12
- end
1
+ class ReferenceType < ActiveRecord::Base
2
+ self.primary_key = :reference_type_id
3
+ has_many :reference_codes, :foreign_key => "reference_type_id", :dependent => :destroy
4
+ accepts_nested_attributes_for :reference_codes
5
+
6
+ validates_presence_of :type_label, :abbreviation
7
+ validates_uniqueness_of :type_label
8
+
9
+ before_destroy do |record|
10
+ a = record
11
+ end
12
+ end
@@ -1,5 +1,5 @@
1
- class Tariff < ActiveRecord::Base
2
- self.primary_keys = [:tariff_id, :start_date]
3
- has_many :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
4
- has_many :products, :through => :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
5
- end
1
+ class Tariff < ActiveRecord::Base
2
+ self.primary_keys = [:tariff_id, :start_date]
3
+ has_many :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
4
+ has_many :products, :through => :product_tariffs, :foreign_key => [:tariff_id, :tariff_start_date]
5
+ end
@@ -0,0 +1,30 @@
1
+ require File.expand_path('../abstract_unit', __FILE__)
2
+
3
+ class TestFindInBatches < ActiveSupport::TestCase
4
+ fixtures :capitols
5
+
6
+ def test_in_batches
7
+ capitols = []
8
+ Capitol.find_in_batches do |chunk|
9
+ capitols += chunk.map(&:country)
10
+ end
11
+ assert_equal(capitols, ['Canada', 'France', 'Mexico', 'The Netherlands'])
12
+ end
13
+
14
+ def test_in_small_batches
15
+ capitols = []
16
+ Capitol.find_in_batches(batch_size: 2) do |chunk|
17
+ capitols += chunk.map(&:country)
18
+ end
19
+
20
+ assert_equal(capitols, ['Canada', 'France', 'Mexico', 'The Netherlands'])
21
+ end
22
+
23
+ def test_in_one_unit_batch
24
+ capitols = []
25
+ Capitol.find_in_batches(batch_size: 1) do |chunk|
26
+ capitols += chunk.map(&:country)
27
+ end
28
+ assert_equal(capitols, ['Canada', 'France', 'Mexico', 'The Netherlands'])
29
+ end
30
+ end
@@ -22,6 +22,25 @@ class TestEqual < ActiveSupport::TestCase
22
22
  assert_equal(with_quoted_identifiers(expected), pred.to_sql)
23
23
  end
24
24
 
25
+ def test_or_with_many_values
26
+ dep = Arel::Table.new(:departments)
27
+
28
+ predicates = Array.new
29
+
30
+ number_of_predicates = 30000 # This should really be big
31
+ number_of_predicates.times do |i|
32
+ predicates << dep[:id].eq(i)
33
+ end
34
+
35
+ connection = ActiveRecord::Base.connection
36
+ quoted = "#{connection.quote_table_name('departments')}.#{connection.quote_column_name('id')}"
37
+ expected_ungrouped = ((0...number_of_predicates).map { |i| "#{quoted} = #{i}" }).join(' OR ')
38
+ expected = "(#{expected_ungrouped})"
39
+
40
+ pred = cpk_or_predicate(predicates)
41
+ assert_equal(with_quoted_identifiers(expected), pred.to_sql)
42
+ end
43
+
25
44
  # def test_and
26
45
  # dep = Arel::Table.new(:departments)
27
46
  #
@@ -38,4 +57,4 @@ class TestEqual < ActiveSupport::TestCase
38
57
  # pred = cpk_and_predicate(predicates)
39
58
  # assert_equal(with_quoted_identifiers(expected), pred.to_sql)
40
59
  # end
41
- end
60
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: composite_primary_keys
3
3
  version: !ruby/object:Gem::Version
4
- version: 8.1.3
4
+ version: 8.1.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Charlie Savage
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-04-16 00:00:00.000000000 Z
11
+ date: 2016-07-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - '='
60
60
  - !ruby/object:Gem::Version
61
- version: 0.3.20
61
+ version: 0.4.4
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - '='
67
67
  - !ruby/object:Gem::Version
68
- version: 0.3.20
68
+ version: 0.4.4
69
69
  description: Composite key support for ActiveRecord
70
70
  email:
71
71
  executables: []
@@ -233,6 +233,7 @@ files:
233
233
  - test/test_equal.rb
234
234
  - test/test_exists.rb
235
235
  - test/test_find.rb
236
+ - test/test_find_in_batches.rb
236
237
  - test/test_habtm.rb
237
238
  - test/test_ids.rb
238
239
  - test/test_miscellaneous.rb
@@ -268,7 +269,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
268
269
  version: '0'
269
270
  requirements: []
270
271
  rubyforge_project:
271
- rubygems_version: 2.5.1
272
+ rubygems_version: 2.6.6
272
273
  signing_key:
273
274
  specification_version: 4
274
275
  summary: Composite key support for ActiveRecord
@@ -294,6 +295,7 @@ test_files:
294
295
  - test/test_equal.rb
295
296
  - test/test_exists.rb
296
297
  - test/test_find.rb
298
+ - test/test_find_in_batches.rb
297
299
  - test/test_habtm.rb
298
300
  - test/test_ids.rb
299
301
  - test/test_miscellaneous.rb