composite_primary_keys 3.1.1 → 3.1.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -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