composite_primary_keys 3.1.1 → 3.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.
@@ -1,4 +1,12 @@
1
- == 3.1.1 2010-02-07
1
+ == 3.1.2 2011-02-26
2
+ * Add back in support for find('3,3') which makes it possible to
3
+ do find(params[id]). This implementation is simpler than earlier version
4
+ improving code readability.
5
+ * Support for finding multiple records either via find([1,2], [3,4])
6
+ * Remove to_composite_ids method which is no longer needed
7
+
8
+
9
+ == 3.1.1 2011-02-07
2
10
  * Implement id_before_type_cast (Jason Lewis)
3
11
  * Add in tests for Model.includes(:other_model)
4
12
  * Fix object comparison with nil in composite primary keys (StackNG)
@@ -125,8 +125,7 @@ module ActiveRecord
125
125
  def quoted_id #:nodoc:
126
126
  [self.class.primary_keys, ids].
127
127
  transpose.
128
- map {|attr_name,id| quote_value(id, column_for_attribute(attr_name))}.
129
- to_composite_ids
128
+ map {|attr_name,id| quote_value(id, column_for_attribute(attr_name))}
130
129
  end
131
130
 
132
131
  # Sets the primary ID.
@@ -1,29 +1,42 @@
1
- # TODO - This code doesn't work with ActiveRecord 3.0.3...
2
-
3
1
  #module ActiveRecord
4
2
  # module Calculations
3
+ # alias :execute_simple_calculation_original :execute_simple_calculation
4
+ #
5
5
  # def execute_simple_calculation(operation, column_name, distinct)
6
- # # CPK changes
7
6
  # if column_name.kind_of?(Array)
8
- # columns = column_name.map do |primary_key_column|
9
- # table[primary_key_column].to_sql
10
- # end
11
- # projection = "DISTINCT #{columns.join(',')}"
12
- # subquery = "(#{table.project(projection).to_sql}) AS subquery"
13
- # relation = Arel::Table.new(subquery).project(Arel::SqlLiteral.new('*').count)
14
- # type_cast_calculated_value(@klass.connection.select_value(relation.to_sql),
15
- # column_for(column_name.first), operation)
7
+ # execute_simple_calculation_cpk(operation, column_name, distinct)
16
8
  # else
17
- # column = if @klass.column_names.include?(column_name.to_s)
18
- # Arel::Attribute.new(@klass.unscoped, column_name)
19
- # else
20
- # Arel::SqlLiteral.new(column_name == :all ? "*" : column_name.to_s)
21
- # end
9
+ # execute_simple_calculation_original(operation, column_name, distinct)
10
+ # end
11
+ # end
12
+ #
13
+ # def execute_simple_calculation_cpk(operation, column_name, distinct)
14
+ # # SELECT COUNT(field1, field2) doens't work so make a subquery
15
+ # # like SELECT COUNT(*) FROM (SELECT DISTINCT field1, field2)
22
16
  #
23
- # # Postgresql doesn't like ORDER BY when there are no GROUP BY
24
- # relation = except(:order).select(operation == 'count' ? column.count(distinct) : column.send(operation))
25
- # type_cast_calculated_value(@klass.connection.select_value(relation.to_sql), column_for(column_name), operation)
17
+ # columns = column_name.map do |primary_key_column|
18
+ # table[primary_key_column]
26
19
  # end
20
+ #
21
+ # subquery = clone.project(columns)
22
+ # subquery = "(#{subquery.to_sql}) AS calculation_subquery"
23
+ # relation = Arel::Table.new(Arel::SqlLiteral.new(subquery))#.project(Arel::SqlLiteral.new('*').count)
24
+ # puts relation.to_sql
25
+ #
26
+ # #projection = "DISTINCT #{columns.join(',')}"
27
+ # #subquery = "(#{table.project(projection).to_sql}) AS subquery"
28
+ #
29
+ # #select_value = ::Arel::Nodes::Count.new(columns, distinct)
30
+ # # relation.select_values = columns
31
+ # # puts @klass.connection.select_value(relation.to_sql)
32
+ ##
33
+ # #type_cast_calculated_value(@klass.connection.select_value(relation.to_sql), column_for(column_name), operation)
34
+ # #relation.select_values = [count_node]
35
+ # #projection = "DISTINCT #{columns.join(',')}"
36
+ # #subquery = "(#{table.project(projection).to_sql}) AS subquery"
37
+ # #relation = Arel::Table.new(subquery).project(Arel::SqlLiteral.new('*').count)
38
+ # type_cast_calculated_value(@klass.connection.select_value(relation.to_sql),
39
+ # column_for(column_name.first), operation)
27
40
  # end
28
41
  # end
29
42
  #end
@@ -6,10 +6,6 @@ module CompositePrimaryKeys
6
6
  def to_composite_keys
7
7
  CompositeKeys.new(self)
8
8
  end
9
-
10
- def to_composite_ids
11
- Array.new(self)
12
- end
13
9
  end
14
10
 
15
11
  class CompositeKeys < Array
@@ -74,34 +74,49 @@ module CompositePrimaryKeys
74
74
  end
75
75
 
76
76
  def find_with_ids(*ids, &block)
77
- return to_a.find(&block) if block_given?
78
-
79
- ids = ids.first if ids.last == nil
80
- ids = [ids.to_composite_ids] if not ids.first.kind_of?(Array)
81
-
82
- ids.each do |id_set|
83
- unless id_set.is_a?(Array)
84
- raise "Ids must be in an Array, instead received: #{id_set.inspect}"
77
+ return to_a.find { |*block_args| yield(*block_args) } if block_given?
78
+
79
+ # Supports:
80
+ # find('1,2') -> ['1,2']
81
+ # find(1,2) -> [1,2]
82
+ # find([1,2]) -> [['1,2']]
83
+ # find([1,2], [3,4]) -> [[1,2],[3,4]]
84
+ #
85
+ # Does *not* support:
86
+ # find('1,2', '3,4') -> ['1,2','3,4']
87
+
88
+ # Normalize incoming data. Note the last arg can be nil. Happens
89
+ # when find is called with nil options like the reload method does.
90
+ ids.compact!
91
+ ids = [ids] unless ids.first.kind_of?(Array)
92
+
93
+ results = ids.map do |cpk_ids|
94
+ cpk_ids = if cpk_ids.length == 1
95
+ cpk_ids.first.split(CompositePrimaryKeys::ID_SEP).to_composite_keys
96
+ else
97
+ cpk_ids.to_composite_keys
85
98
  end
86
- unless id_set.length == @klass.primary_keys.length
87
- raise "#{id_set.inspect}: Incorrect number of primary keys for #{@klass.name}: #{@klass.primary_keys.inspect}"
99
+
100
+ unless cpk_ids.length == @klass.primary_keys.length
101
+ raise "#{cpk_ids.inspect}: Incorrect number of primary keys for #{@klass.name}: #{@klass.primary_keys.inspect}"
88
102
  end
89
- end
90
103
 
91
- new_relation = clone
92
- ids.each do |id_set|
93
- [@klass.primary_keys, id_set].transpose.map do |key, id|
104
+ new_relation = clone
105
+ [@klass.primary_keys, cpk_ids].transpose.map do |key, id|
94
106
  new_relation = new_relation.where(key => id)
95
107
  end
96
- end
108
+
109
+ records = new_relation.to_a
97
110
 
98
- result = new_relation.to_a
111
+ if records.empty?
112
+ conditions = new_relation.arel.where_sql
113
+ raise(::ActiveRecord::RecordNotFound,
114
+ "Couldn't find #{@klass.name} with ID=#{cpk_ids} #{conditions}")
115
+ end
116
+ records
117
+ end.flatten
99
118
 
100
- if result.size == ids.size
101
- ids.size == 1 ? result[0] : result
102
- else
103
- raise ::ActiveRecord::RecordNotFound, "Couldn't find all #{@klass.name} with IDs (#{ids.inspect})"
104
- end
119
+ ids.length == 1 ? results.first : results
105
120
  end
106
121
  end
107
122
  end
@@ -1,7 +1,7 @@
1
1
  class Fixture
2
2
  def [](key)
3
3
  if key.is_a? Array
4
- key.map { |a_key| self[a_key.to_s] }.to_composite_ids
4
+ key.map { |a_key| self[a_key.to_s] }
5
5
  else
6
6
  @fixture[key]
7
7
  end
@@ -2,7 +2,7 @@ module CompositePrimaryKeys
2
2
  module VERSION #:nodoc:
3
3
  MAJOR = 3
4
4
  MINOR = 1
5
- TINY = 1
5
+ TINY = 2
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
@@ -1,6 +1,9 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require 'rubygems'
4
+ gem 'RedCloth'
5
+ gem 'syntax'
6
+
4
7
  require 'redcloth'
5
8
  require 'syntax/convertors/html'
6
9
  require 'erb'
@@ -8,8 +8,8 @@ end
8
8
  desc 'Upload website files to rubyforge'
9
9
  task :website_upload do
10
10
  config = YAML.load(File.read(File.expand_path("~/.rubyforge/user-config.yml")))
11
- host = "cfis@rubyforge.org"
12
- remote_dir = "/var/www/gforge-projects/compositekeys"
11
+ host = "#{config["username"]}@rubyforge.org"
12
+ remote_dir = "/var/www/gforge-projects/compositekeys/"
13
13
  local_dir = 'website'
14
14
  sh %{scp -r #{local_dir}/* #{host}:#{remote_dir}}
15
15
  end
@@ -0,0 +1,53 @@
1
+ # assoc_test.rb
2
+
3
+ path = File.expand_path(File.join(File.basename(__FILE__), "..", "lib", "composite_primary_keys"))
4
+ puts path
5
+
6
+ require File.join(path)
7
+ require 'active_record'
8
+
9
+ $configuration = {
10
+ :adapter => 'postgresql',
11
+ :database => 'cpk_test',
12
+ :username => 'postgres'
13
+ }
14
+
15
+ ActiveRecord::Base.establish_connection($configuration) unless ActiveRecord::Base.connected?
16
+
17
+ module GlobePG
18
+ class PGBase < ActiveRecord::Base
19
+ self.abstract_class = true
20
+ # establish_connection($configuration) unless connected?
21
+ end
22
+ end
23
+
24
+ module GlobePG
25
+ class TeacherToSchool < PGBase
26
+ set_table_name 'teacher_to_school'
27
+ set_primary_keys ['teacherid', 'schoolid']
28
+
29
+ belongs_to :globe_teacher, :foreign_key => 'teacherid'
30
+ belongs_to :globe_school, :foreign_key => 'schoolid'
31
+ end
32
+ end
33
+
34
+ module GlobePG
35
+ class GlobeSchool < PGBase
36
+ set_table_name 'globe_school'
37
+ set_primary_key 'schoolid'
38
+ has_many :teacher_to_schools, :foreign_key => :schoolid
39
+ has_many :globe_teachers, :through => :teacher_to_schools
40
+ end
41
+ end
42
+
43
+ module GlobePG
44
+ class GlobeTeacher < PGBase
45
+ set_table_name 'globe_teacher'
46
+ set_primary_key 'teacherid'
47
+ has_many :teacher_to_schools, :foreign_key => :teacherid
48
+ has_many :globe_schools, :through => :teacher_to_schools
49
+ end
50
+ end
51
+
52
+ teacher = GlobePG::GlobeTeacher.find_by_teacherid('ZZGLOBEY')
53
+ p teacher.globe_schools
@@ -164,3 +164,9 @@ create table seats (
164
164
  customer integer,
165
165
  primary key (flight_number, seat)
166
166
  );
167
+
168
+ create table capitols (
169
+ country text not null,
170
+ city text not null,
171
+ primary key (country, city)
172
+ );
@@ -21,10 +21,9 @@ gender_male:
21
21
  reference_code: 1
22
22
  code_label: MALE
23
23
  abbreviation: Male
24
+
24
25
  gender_female:
25
26
  reference_type_id: 2
26
27
  reference_code: 2
27
28
  code_label: FEMALE
28
- abbreviation: Female
29
-
30
-
29
+ abbreviation: Female
@@ -0,0 +1,51 @@
1
+ # setup_db.rb
2
+ require 'dbi'
3
+
4
+ # Run "createdb cpk_test" first
5
+
6
+ teacher_to_school = %Q{
7
+ create table teacher_to_school(
8
+ schoolid varchar(8),
9
+ teacherid varchar(8),
10
+ datebegin date,
11
+ teacherrole varchar(20),
12
+ primary key (schoolid, teacherid)
13
+ );
14
+
15
+ }
16
+
17
+ globe_teacher = %Q{
18
+ create table globe_teacher(
19
+ teacherid varchar(8) primary key,
20
+ currentschoolid varchar(8),
21
+ userid varchar(16)
22
+ );
23
+
24
+ }
25
+
26
+ globe_school = %Q{
27
+ create table globe_school(
28
+ schoolid varchar(8) primary key,
29
+ schoolname varchar(100) not null,
30
+ city varchar(35) not null
31
+ )
32
+
33
+ }
34
+
35
+ add_records = [
36
+ "insert into globe_teacher values ('ZZGLOBEY', 'ZZGLOBE1',
37
+ 'dberger');",
38
+ "insert into globe_school values ('ZZCOUCAR', 'NCAR Foothills Lab',
39
+ 'Boulder');",
40
+ "insert into globe_school values ('ZZGLOBE1', 'The GLOBE Program',
41
+ 'Boulder');",
42
+ "insert into teacher_to_school values('ZZGLOBE1', 'ZZGLOBEY', '1-JUN-2010', 'GLOBE OFFICE');",
43
+ "insert into teacher_to_school values('ZZCOUCAR', 'ZZGLOBEY', '1-AUG-2010', 'GLOBE Teacher');"
44
+ ]
45
+
46
+ DBI.connect('dbi:Pg:cpk_test', 'postgres') do |dbh|
47
+ dbh.execute(teacher_to_school)
48
+ dbh.execute(globe_teacher)
49
+ dbh.execute(globe_school)
50
+ add_records.each{ |sql| dbh.execute(sql) }
51
+ end
@@ -26,9 +26,9 @@ class TestAssociations < ActiveSupport::TestCase
26
26
  end
27
27
 
28
28
  def test_count
29
- assert_equal 2, Product.count(:include => :product_tariffs)
30
- assert_equal 3, Tariff.count(:include => :product_tariffs)
31
- assert_equal 2, Tariff.count(:group => :start_date).size
29
+ assert_equal(2, Product.count(:include => :product_tariffs))
30
+ assert_equal(3, Tariff.count(:include => :product_tariffs))
31
+ assert_equal(2, Tariff.count(:group => :start_date))
32
32
  end
33
33
 
34
34
  def test_products
@@ -21,10 +21,4 @@ class CompositeArraysTest < ActiveSupport::TestCase
21
21
  assert_equal CompositePrimaryKeys::CompositeKeys, keys.class
22
22
  assert_equal '1,2,3', keys.to_s
23
23
  end
24
-
25
- def test_to_composite_ids
26
- keys = [1,2,3].to_composite_ids
27
- assert_equal Array, keys.class
28
- assert_equal '123', keys.to_s
29
- end
30
24
  end
@@ -4,66 +4,54 @@ require 'abstract_unit'
4
4
  class TestFind < ActiveSupport::TestCase
5
5
  fixtures :capitols, :reference_types, :reference_codes, :suburbs
6
6
 
7
- CLASSES = {
8
- :single => {
9
- :class => ReferenceType,
10
- :primary_keys => [:reference_type_id],
11
- },
12
- :dual => {
13
- :class => ReferenceCode,
14
- :primary_keys => [:reference_type_id, :reference_code],
15
- },
16
- :dual_strs => {
17
- :class => ReferenceCode,
18
- :primary_keys => ['reference_type_id', 'reference_code'],
19
- },
20
- }
21
-
22
- def setup
23
- self.class.classes = CLASSES
7
+ def test_find_first
8
+ ref_code = ReferenceCode.find(:first, :order => 'reference_type_id, reference_code')
9
+ assert_kind_of(ReferenceCode, ref_code)
10
+ assert_equal([1,1], ref_code.id)
24
11
  end
25
12
 
26
- def test_find_first
27
- testing_with do
28
- obj = @klass.find(:first)
29
- assert obj
30
- assert_equal @klass, obj.class
31
- end
13
+ def test_find_last
14
+ ref_code = ReferenceCode.find(:last, :order => 'reference_type_id, reference_code')
15
+ assert_kind_of(ReferenceCode, ref_code)
16
+ assert_equal([2,2], ref_code.id)
32
17
  end
33
18
 
34
- def test_find
35
- testing_with do
36
- found = @klass.find(*first_id) # e.g. find(1,1) or find 1,1
37
- assert found
38
- assert_equal @klass, found.class
39
- assert_equal found, @klass.find(found.id)
40
- end
19
+ def test_find_one
20
+ ref_code = ReferenceCode.find([1,3])
21
+ assert_not_nil(ref_code)
22
+ assert_equal([1,3], ref_code.id)
41
23
  end
42
24
 
43
- def test_find_composite_ids
44
- testing_with do
45
- found = @klass.find(first_id) # e.g. find([1,1].to_composite_ids)
46
- assert found
47
- assert_equal @klass, found.class
48
- assert_equal found, @klass.find(found.id)
49
- end
25
+ def test_find_one_string
26
+ ref_code = ReferenceCode.find('1,3')
27
+ assert_kind_of(ReferenceCode, ref_code)
28
+ assert_equal([1,3], ref_code.id)
50
29
  end
51
30
 
52
- def things_to_look_at
53
- testing_with do
54
- assert_equal found, @klass.find(found.id.to_s) # fails for 2+ keys
55
- end
31
+ def test_find_some
32
+ ref_codes = ReferenceCode.find([1,3], [2,1])
33
+ assert_kind_of(Array, ref_codes)
34
+ assert_equal(2, ref_codes.length)
35
+
36
+ ref_code = ref_codes[0]
37
+ assert_equal([1,3], ref_code.id)
38
+
39
+ ref_code = ref_codes[1]
40
+ assert_equal([2,1], ref_code.id)
56
41
  end
57
42
 
58
43
  def test_find_with_strings_as_composite_keys
59
- found = Capitol.find('The Netherlands', 'Amsterdam')
60
- assert found
44
+ capitol = Capitol.find(['The Netherlands', 'Amsterdam'])
45
+ assert_kind_of(Capitol, capitol)
46
+ assert_equal(['The Netherlands', 'Amsterdam'], capitol.id)
61
47
  end
62
48
 
63
49
  def test_not_found
64
- assert_raise(::ActiveRecord::RecordNotFound) do
50
+ error = assert_raise(::ActiveRecord::RecordNotFound) do
65
51
  ReferenceCode.find(['999', '999'])
66
52
  end
53
+ assert_equal("Couldn't find ReferenceCode with ID=999,999 WHERE \"reference_codes\".\"reference_type_id\" = 999 AND \"reference_codes\".\"reference_code\" = 999",
54
+ error.message)
67
55
  end
68
56
 
69
57
  def test_find_last_suburb
@@ -76,4 +64,4 @@ class TestFind < ActiveSupport::TestCase
76
64
  suburb = Suburb.find(:last, :order => 'suburbs.city_id DESC')
77
65
  assert_equal([1,1], suburb.id)
78
66
  end
79
- end
67
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: composite_primary_keys
3
3
  version: !ruby/object:Gem::Version
4
- hash: 1
4
+ hash: 7
5
5
  prerelease:
6
6
  segments:
7
7
  - 3
8
8
  - 1
9
- - 1
10
- version: 3.1.1
9
+ - 2
10
+ version: 3.1.2
11
11
  platform: ruby
12
12
  authors:
13
13
  - Dr Nic Williams
@@ -16,7 +16,7 @@ autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
18
18
 
19
- date: 2011-02-05 00:00:00 -08:00
19
+ date: 2011-02-26 00:00:00 -07:00
20
20
  default_executable:
21
21
  dependencies:
22
22
  - !ruby/object:Gem::Dependency
@@ -112,6 +112,7 @@ files:
112
112
  - test/connections/native_oracle_enhanced/connection.rb
113
113
  - test/connections/native_postgresql/connection.rb
114
114
  - test/connections/native_sqlite/connection.rb
115
+ - test/db_test.rb
115
116
  - test/debug.log
116
117
  - test/fixtures/article.rb
117
118
  - test/fixtures/articles.yml
@@ -181,6 +182,7 @@ files:
181
182
  - test/plugins/pagination.rb
182
183
  - test/plugins/pagination_helper.rb
183
184
  - test/README_tests.txt
185
+ - test/setup.rb
184
186
  - test/test_associations.rb
185
187
  - test/test_attributes.rb
186
188
  - test/test_attribute_methods.rb
@@ -232,15 +234,17 @@ required_rubygems_version: !ruby/object:Gem::Requirement
232
234
  requirements: []
233
235
 
234
236
  rubyforge_project: compositekeys
235
- rubygems_version: 1.5.0
237
+ rubygems_version: 1.5.2
236
238
  signing_key:
237
239
  specification_version: 3
238
240
  summary: Composite key support for ActiveRecord
239
241
  test_files:
240
242
  - test/abstract_unit.rb
243
+ - test/db_test.rb
241
244
  - test/debug.log
242
245
  - test/hash_tricks.rb
243
246
  - test/README_tests.txt
247
+ - test/setup.rb
244
248
  - test/test_associations.rb
245
249
  - test/test_attributes.rb
246
250
  - test/test_attribute_methods.rb